Module Name: src Committed By: christos Date: Fri Aug 25 16:50:23 UTC 2023
Modified Files: src/sys/ufs/ext2fs: ext2fs.h ext2fs_alloc.c ext2fs_vfsops.c Log Message: Support INCOMPAT_64BIT on ext4 (Vladimir 'phcoder' Serbinenko) To generate a diff of this commit: cvs rdiff -u -r1.48 -r1.49 src/sys/ufs/ext2fs/ext2fs.h cvs rdiff -u -r1.52 -r1.53 src/sys/ufs/ext2fs/ext2fs_alloc.c cvs rdiff -u -r1.221 -r1.222 src/sys/ufs/ext2fs/ext2fs_vfsops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/ufs/ext2fs/ext2fs.h diff -u src/sys/ufs/ext2fs/ext2fs.h:1.48 src/sys/ufs/ext2fs/ext2fs.h:1.49 --- src/sys/ufs/ext2fs/ext2fs.h:1.48 Sat Aug 20 15:47:44 2016 +++ src/sys/ufs/ext2fs/ext2fs.h Fri Aug 25 12:50:23 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: ext2fs.h,v 1.48 2016/08/20 19:47:44 jdolecek Exp $ */ +/* $NetBSD: ext2fs.h,v 1.49 2023/08/25 16:50:23 christos Exp $ */ /* * Copyright (c) 1982, 1986, 1993 @@ -252,6 +252,7 @@ struct m_ext2fs { int32_t e2fs_ngdb; /* number of group descriptor blocks */ int32_t e2fs_ipb; /* number of inodes per block */ int32_t e2fs_itpg; /* number of inode table blocks per group */ + uint8_t e2fs_group_desc_shift; /* binary log group desc size */ struct ext2_gd *e2fs_gd; /* group descriptors (data not byteswapped) */ }; @@ -370,7 +371,8 @@ struct m_ext2fs { | EXT2F_ROCOMPAT_GDT_CSUM) #define EXT2F_INCOMPAT_SUPP (EXT2F_INCOMPAT_FTYPE \ | EXT2F_INCOMPAT_EXTENTS \ - | EXT2F_INCOMPAT_FLEX_BG) + | EXT2F_INCOMPAT_FLEX_BG \ + | EXT2F_INCOMPAT_64BIT) /* * Feature set definitions @@ -432,10 +434,14 @@ struct ext2_gd { uint16_t ext2bgd_itable_unused_lo; /* Low unused inode offset */ uint16_t ext2bgd_checksum; /* Group desc checksum */ - /* - * XXX disk32 Further fields only exist if 64BIT feature is on - * and superblock desc_size > 32, not supported for now. - */ + uint32_t ext2bgd_b_bitmap_hi; /* blocks bitmap block (high bits) */ + uint32_t ext2bgd_i_bitmap_hi; /* inodes bitmap block (high bits) */ + uint32_t ext2bgd_i_tables_hi; /* inodes table block (high bits) */ + uint16_t ext2bgd_nbfree_hi; /* number of free blocks (high bits) */ + uint16_t ext2bgd_nifree_hi; /* number of free inodes (high bits) */ + uint16_t ext2bgd_ndirs_hi; /* number of directories (high bits) */ + uint16_t reserved_hi; + uint32_t reserved2_hi[3]; }; #define E2FS_BG_INODE_UNINIT 0x0001 /* Inode bitmap not used/initialized */ @@ -492,15 +498,15 @@ void e2fs_sb_bswap(struct ext2fs *, stru # define e2fs_sbsave(old, new) e2fs_sb_bswap((old), (new)) #endif -/* Group descriptors are not byte swapped */ -#define e2fs_cgload(old, new, size) memcpy((new), (old), (size)) -#define e2fs_cgsave(old, new, size) memcpy((new), (old), (size)) - /* * Turn file system block numbers into disk block addresses. * This maps file system blocks to device size blocks. */ #define EXT2_FSBTODB(fs, b) ((b) << (fs)->e2fs_fsbtodb) +#define EXT2_FSBTODB64(fs, b, b_hi) \ + (((((uint64_t)(b_hi)) << 32) | (b)) << (fs)->e2fs_fsbtodb) +#define EXT2_FSBTODB64OFF(fs, b, b_hi, off) \ + ((((((uint64_t)(b_hi)) << 32) | (b)) + (off)) << (fs)->e2fs_fsbtodb) #define EXT2_DBTOFSB(fs, b) ((b) >> (fs)->e2fs_fsbtodb) /* @@ -510,9 +516,11 @@ void e2fs_sb_bswap(struct ext2fs *, stru * inode number to file system block address. */ #define ino_to_cg(fs, x) (((x) - 1) / (fs)->e2fs.e2fs_ipg) -#define ino_to_fsba(fs, x) \ - (fs2h32((fs)->e2fs_gd[ino_to_cg((fs), (x))].ext2bgd_i_tables) + \ - (((x) - 1) % (fs)->e2fs.e2fs_ipg) / (fs)->e2fs_ipb) +#define _e2fs_gd(fs, x) (fs)->e2fs_gd[ino_to_cg((fs), (x))] +#define ino_to_fsba(fs, x) \ + (fs2h32(_e2fs_gd(fs, x).ext2bgd_i_tables) + \ + (((uint64_t)fs2h32(_e2fs_gd(fs, x).ext2bgd_i_tables_hi)) << 32) + \ + (((x) - 1) % (fs)->e2fs.e2fs_ipg) / (fs)->e2fs_ipb) #define ino_to_fsbo(fs, x) (((x) - 1) % (fs)->e2fs_ipb) /* Index: src/sys/ufs/ext2fs/ext2fs_alloc.c diff -u src/sys/ufs/ext2fs/ext2fs_alloc.c:1.52 src/sys/ufs/ext2fs/ext2fs_alloc.c:1.53 --- src/sys/ufs/ext2fs/ext2fs_alloc.c:1.52 Sun May 28 12:38:55 2017 +++ src/sys/ufs/ext2fs/ext2fs_alloc.c Fri Aug 25 12:50:23 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: ext2fs_alloc.c,v 1.52 2017/05/28 16:38:55 hannken Exp $ */ +/* $NetBSD: ext2fs_alloc.c,v 1.53 2023/08/25 16:50:23 christos Exp $ */ /* * Copyright (c) 1982, 1986, 1989, 1993 @@ -60,7 +60,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ext2fs_alloc.c,v 1.52 2017/05/28 16:38:55 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ext2fs_alloc.c,v 1.53 2023/08/25 16:50:23 christos Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -90,9 +90,11 @@ static u_long ext2fs_hashalloc(struct in daddr_t (*)(struct inode *, int, daddr_t, int)); static daddr_t ext2fs_nodealloccg(struct inode *, int, daddr_t, int); static daddr_t ext2fs_mapsearch(struct m_ext2fs *, char *, daddr_t); -static __inline void ext2fs_cg_update(struct m_ext2fs *, int, struct ext2_gd *, int, int, int, daddr_t); -static uint16_t ext2fs_cg_get_csum(struct m_ext2fs *, int, struct ext2_gd *); -static void ext2fs_init_bb(struct m_ext2fs *, int, struct ext2_gd *, char *); +static __inline void ext2fs_cg_update(struct m_ext2fs *, int, + struct ext2_gd *, int, int, int, daddr_t); +static uint16_t ext2fs_cg_get_csum(struct m_ext2fs *, int, struct ext2_gd *); +static void ext2fs_init_bb(struct m_ext2fs *, int, struct ext2_gd *, + char *); /* * Allocate a block in the file system. @@ -212,13 +214,21 @@ ext2fs_dirpref(struct m_ext2fs *fs) avgifree = fs->e2fs.e2fs_ficount / fs->e2fs_ncg; maxspace = 0; mincg = -1; - for (cg = 0; cg < fs->e2fs_ncg; cg++) - if (fs2h16(fs->e2fs_gd[cg].ext2bgd_nifree) >= avgifree) { - if (mincg == -1 || fs2h16(fs->e2fs_gd[cg].ext2bgd_nbfree) > maxspace) { - mincg = cg; - maxspace = fs2h16(fs->e2fs_gd[cg].ext2bgd_nbfree); - } + for (cg = 0; cg < fs->e2fs_ncg; cg++) { + uint32_t nifree = + (fs2h16(fs->e2fs_gd[cg].ext2bgd_nifree_hi) << 16) + | fs2h16(fs->e2fs_gd[cg].ext2bgd_nifree); + if (nifree < avgifree) { + continue; } + uint32_t nbfree = + (fs2h16(fs->e2fs_gd[cg].ext2bgd_nbfree_hi) << 16) + | fs2h16(fs->e2fs_gd[cg].ext2bgd_nbfree); + if (mincg == -1 || nbfree > maxspace) { + mincg = cg; + maxspace = nbfree; + } + } return mincg; } @@ -333,14 +343,15 @@ ext2fs_alloccg(struct inode *ip, int cg, struct m_ext2fs *fs; char *bbp; struct buf *bp; - /* XXX ondisk32 */ int error, bno, start, end, loc; fs = ip->i_e2fs; - if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0) + if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0 && + fs->e2fs_gd[cg].ext2bgd_nbfree_hi == 0) return 0; - error = bread(ip->i_devvp, EXT2_FSBTODB(fs, - fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap)), + error = bread(ip->i_devvp, EXT2_FSBTODB64(fs, + fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap), + fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap_hi)), (int)fs->e2fs_bsize, B_MODIFY, &bp); if (error) { return 0; @@ -403,8 +414,8 @@ ext2fs_alloccg(struct inode *ip, int cg, gotit: #ifdef DIAGNOSTIC if (isset(bbp, (daddr_t)bno)) { - printf("ext2fs_alloccgblk: cg=%d bno=%d fs=%s\n", - cg, bno, fs->e2fs_fsmnt); + printf("%s: cg=%d bno=%d fs=%s\n", __func__, + cg, bno, fs->e2fs_fsmnt); panic("ext2fs_alloccg: dup alloc"); } #endif @@ -437,10 +448,12 @@ ext2fs_nodealloccg(struct inode *ip, int if (ipref == -1) ipref = 0; fs = ip->i_e2fs; - if (fs->e2fs_gd[cg].ext2bgd_nifree == 0) + if (fs->e2fs_gd[cg].ext2bgd_nifree == 0 || + fs->e2fs_gd[cg].ext2bgd_nifree_hi == 0) return 0; - error = bread(ip->i_devvp, EXT2_FSBTODB(fs, - fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap)), + error = bread(ip->i_devvp, EXT2_FSBTODB64(fs, + fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap), + fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap_hi)), (int)fs->e2fs_bsize, B_MODIFY, &bp); if (error) { return 0; @@ -470,17 +483,17 @@ ext2fs_nodealloccg(struct inode *ip, int start = 0; loc = skpc(0xff, len, &ibp[0]); if (loc == 0) { - printf("cg = %d, ipref = %lld, fs = %s\n", - cg, (long long)ipref, fs->e2fs_fsmnt); - panic("ext2fs_nodealloccg: map corrupted"); + printf("%s: cg = %d, ipref = %lld, fs = %s\n", __func__, + cg, (long long)ipref, fs->e2fs_fsmnt); + panic("%s: map corrupted", __func__); /* NOTREACHED */ } } i = start + len - loc; map = ibp[i] ^ 0xff; if (map == 0) { - printf("fs = %s\n", fs->e2fs_fsmnt); - panic("ext2fs_nodealloccg: inode not in map"); + printf("%s: fs = %s\n", __func__, fs->e2fs_fsmnt); + panic("%s: inode not in map", __func__); } ipref = i * NBBY + ffs(map) - 1; gotit: @@ -510,27 +523,29 @@ ext2fs_blkfree(struct inode *ip, daddr_t fs = ip->i_e2fs; cg = dtog(fs, bno); - KASSERT(!E2FS_HAS_GD_CSUM(fs) || (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_BLOCK_UNINIT)) == 0); + KASSERT(!E2FS_HAS_GD_CSUM(fs) || + (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_BLOCK_UNINIT)) == 0); if ((u_int)bno >= fs->e2fs.e2fs_bcount) { - printf("bad block %lld, ino %llu\n", (long long)bno, - (unsigned long long)ip->i_number); + printf("%s: bad block %jd, ino %ju\n", + __func__, (intmax_t)bno, (uintmax_t)ip->i_number); ext2fs_fserr(fs, ip->i_uid, "bad block"); return; } - error = bread(ip->i_devvp, - EXT2_FSBTODB(fs, fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap)), - (int)fs->e2fs_bsize, B_MODIFY, &bp); + error = bread(ip->i_devvp, EXT2_FSBTODB64(fs, + fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap), + fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap_hi)), + (int)fs->e2fs_bsize, B_MODIFY, &bp); if (error) { return; } bbp = (char *)bp->b_data; bno = dtogd(fs, bno); if (isclr(bbp, bno)) { - printf("dev = 0x%llx, block = %lld, fs = %s\n", - (unsigned long long)ip->i_dev, (long long)bno, + printf("%s: dev = %#jx, block = %jd, fs = %s\n", __func__, + (uintmax_t)ip->i_dev, (intmax_t)bno, fs->e2fs_fsmnt); - panic("blkfree: freeing free block"); + panic("%s: freeing free block", __func__); } clrbit(bbp, bno); fs->e2fs.e2fs_fbcount++; @@ -557,28 +572,30 @@ ext2fs_vfree(struct vnode *pvp, ino_t in fs = pip->i_e2fs; if ((u_int)ino > fs->e2fs.e2fs_icount || (u_int)ino < EXT2_FIRSTINO) - panic("ifree: range: dev = 0x%llx, ino = %llu, fs = %s", - (unsigned long long)pip->i_dev, (unsigned long long)ino, + panic("%s: range: dev = %#jx, ino = %ju, fs = %s", + __func__, (uintmax_t)pip->i_dev, (uintmax_t)ino, fs->e2fs_fsmnt); cg = ino_to_cg(fs, ino); - KASSERT(!E2FS_HAS_GD_CSUM(fs) || (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_INODE_UNINIT)) == 0); + KASSERT(!E2FS_HAS_GD_CSUM(fs) || + (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_INODE_UNINIT)) == 0); - error = bread(pip->i_devvp, - EXT2_FSBTODB(fs, fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap)), - (int)fs->e2fs_bsize, B_MODIFY, &bp); + error = bread(pip->i_devvp, EXT2_FSBTODB64(fs, + fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap), + fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap_hi)), + (int)fs->e2fs_bsize, B_MODIFY, &bp); if (error) { return 0; } ibp = (char *)bp->b_data; ino = (ino - 1) % fs->e2fs.e2fs_ipg; if (isclr(ibp, ino)) { - printf("dev = 0x%llx, ino = %llu, fs = %s\n", - (unsigned long long)pip->i_dev, - (unsigned long long)ino, fs->e2fs_fsmnt); + printf("%s: dev = %#jx, ino = %ju, fs = %s\n", __func__, + (uintmax_t)pip->i_dev, + (uintmax_t)ino, fs->e2fs_fsmnt); if (fs->e2fs_ronly == 0) - panic("ifree: freeing free inode"); + panic("%s: freeing free inode", __func__); } clrbit(ibp, ino); fs->e2fs.e2fs_ficount++; @@ -616,17 +633,17 @@ ext2fs_mapsearch(struct m_ext2fs *fs, ch start = 0; loc = skpc(0xff, len, &bbp[start]); if (loc == 0) { - printf("start = %d, len = %d, fs = %s\n", - start, len, fs->e2fs_fsmnt); - panic("ext2fs_alloccg: map corrupted"); + printf("%s: start = %d, len = %d, fs = %s\n", + __func__, start, len, fs->e2fs_fsmnt); + panic("%s: map corrupted", __func__); /* NOTREACHED */ } } i = start + len - loc; map = bbp[i] ^ 0xff; if (map == 0) { - printf("fs = %s\n", fs->e2fs_fsmnt); - panic("ext2fs_mapsearch: block not in map"); + printf("%s: fs = %s\n", __func__, fs->e2fs_fsmnt); + panic("%s: block not in map", __func__); } return i * NBBY + ffs(map) - 1; } @@ -647,9 +664,12 @@ ext2fs_fserr(struct m_ext2fs *fs, u_int static __inline void ext2fs_cg_update(struct m_ext2fs *fs, int cg, struct ext2_gd *gd, int nbfree, int nifree, int ndirs, daddr_t ioff) { - /* XXX disk32 */ if (nifree) { - gd->ext2bgd_nifree = h2fs16(fs2h16(gd->ext2bgd_nifree) + nifree); + uint32_t ext2bgd_nifree = fs2h16(gd->ext2bgd_nifree) | + (fs2h16(gd->ext2bgd_nifree_hi) << 16); + ext2bgd_nifree += nifree; + gd->ext2bgd_nifree = h2fs16(ext2bgd_nifree); + gd->ext2bgd_nifree_hi = h2fs16(ext2bgd_nifree >> 16); /* * If we allocated inode on bigger offset than what was * ever used before, bump the itable_unused count. This @@ -658,19 +678,34 @@ ext2fs_cg_update(struct m_ext2fs *fs, in * time we get here the itables are already zeroed, but * e2fstools fsck.ext4 still checks this. */ - if (E2FS_HAS_GD_CSUM(fs) && nifree < 0 && (ioff+1) >= (fs->e2fs.e2fs_ipg - fs2h16(gd->ext2bgd_itable_unused_lo))) { - gd->ext2bgd_itable_unused_lo = h2fs16(fs->e2fs.e2fs_ipg - (ioff + 1)); + if (E2FS_HAS_GD_CSUM(fs) && nifree < 0 && + (ioff + 1) >= (fs->e2fs.e2fs_ipg - + fs2h16(gd->ext2bgd_itable_unused_lo))) { + gd->ext2bgd_itable_unused_lo = + h2fs16(fs->e2fs.e2fs_ipg - (ioff + 1)); } - KASSERT(!E2FS_HAS_GD_CSUM(fs) || gd->ext2bgd_itable_unused_lo <= gd->ext2bgd_nifree); + KASSERT(!E2FS_HAS_GD_CSUM(fs) || + gd->ext2bgd_itable_unused_lo <= ext2bgd_nifree); } - if (nbfree) - gd->ext2bgd_nbfree = h2fs16(fs2h16(gd->ext2bgd_nbfree) + nbfree); - - if (ndirs) - gd->ext2bgd_ndirs = h2fs16(fs2h16(gd->ext2bgd_ndirs) + ndirs); + if (nbfree) { + uint32_t ext2bgd_nbfree = fs2h16(gd->ext2bgd_nbfree) + | (fs2h16(gd->ext2bgd_nbfree_hi) << 16); + ext2bgd_nbfree += nbfree; + gd->ext2bgd_nbfree = h2fs16(ext2bgd_nbfree); + gd->ext2bgd_nbfree_hi = h2fs16(ext2bgd_nbfree >> 16); + + } + + if (ndirs) { + uint32_t ext2bgd_ndirs = fs2h16(gd->ext2bgd_ndirs) + | (fs2h16(gd->ext2bgd_ndirs_hi) << 16); + ext2bgd_ndirs += ndirs; + gd->ext2bgd_ndirs = h2fs16(ext2bgd_ndirs); + gd->ext2bgd_ndirs_hi = h2fs16(ext2bgd_ndirs >> 16); + } if (E2FS_HAS_GD_CSUM(fs)) gd->ext2bgd_checksum = ext2fs_cg_get_csum(fs, cg, gd); @@ -684,6 +719,7 @@ static uint16_t ext2fs_cg_get_csum(struct m_ext2fs *fs, int cg, struct ext2_gd *gd) { uint16_t crc; + size_t cgsize = 1 << fs->e2fs_group_desc_shift; uint32_t cg_bswapped = h2fs32((uint32_t)cg); size_t off; @@ -695,7 +731,7 @@ ext2fs_cg_get_csum(struct m_ext2fs *fs, crc = crc16(~0, (uint8_t *)fs->e2fs.e2fs_uuid, sizeof(fs->e2fs.e2fs_uuid)); crc = crc16(crc, (uint8_t *)&cg_bswapped, sizeof(cg_bswapped)); crc = crc16(crc, (uint8_t *)gd, off); - /* XXX ondisk32 */ + crc = crc16(crc, (uint8_t *)gd + off + 2, cgsize - (off + 2)); return h2fs16(crc); } @@ -723,7 +759,6 @@ ext2fs_init_bb(struct m_ext2fs *fs, int int ext2fs_cg_verify_and_initialize(struct vnode *devvp, struct m_ext2fs *fs, int ronly) { - /* XXX disk32 */ struct ext2_gd *gd; ino_t ioff; size_t boff; @@ -733,17 +768,20 @@ ext2fs_cg_verify_and_initialize(struct v if (!E2FS_HAS_GD_CSUM(fs)) return 0; - for(cg=0; cg < fs->e2fs_ncg; cg++) { + for(cg = 0; cg < fs->e2fs_ncg; cg++) { gd = &fs->e2fs_gd[cg]; /* Verify checksum */ - if (gd->ext2bgd_checksum != ext2fs_cg_get_csum(fs, cg, gd)) { - printf("ext2fs_cg_verify_and_initialize: group %d invalid csum\n", cg); + uint16_t csum = ext2fs_cg_get_csum(fs, cg, gd); + if (gd->ext2bgd_checksum != csum) { + printf("%s: group %d invalid csum (%#x != %#x)\n", + __func__, cg, gd->ext2bgd_checksum, csum); return EINVAL; } /* if mounting read-write, zero itable if not already done */ - if (ronly || (gd->ext2bgd_flags & h2fs16(E2FS_BG_INODE_ZEROED)) != 0) + if (ronly || + (gd->ext2bgd_flags & h2fs16(E2FS_BG_INODE_ZEROED)) != 0) continue; /* @@ -760,23 +798,27 @@ ext2fs_cg_verify_and_initialize(struct v for(i = ioff / fs->e2fs_ipb; i < fs->e2fs_itpg; i++) { if (boff) { /* partial wipe, must read old data */ - error = bread(devvp, - EXT2_FSBTODB(fs, fs2h32(gd->ext2bgd_i_tables) + i), - (int)fs->e2fs_bsize, B_MODIFY, &bp); + error = bread(devvp, EXT2_FSBTODB64OFF(fs, + fs2h32(gd->ext2bgd_i_tables), + fs2h32(gd->ext2bgd_i_tables_hi), i), + (int)fs->e2fs_bsize, B_MODIFY, &bp); if (error) { - printf("ext2fs_cg_verify_and_initialize: can't read itable block"); + printf("%s: can't read itable block", + __func__); return error; } - memset((char *)bp->b_data + boff, 0, fs->e2fs_bsize - boff); + memset((char *)bp->b_data + boff, 0, + fs->e2fs_bsize - boff); boff = 0; } else { /* * Complete wipe, don't need to read data. This * assumes nothing else is changing the data. */ - bp = getblk(devvp, - EXT2_FSBTODB(fs, fs2h32(gd->ext2bgd_i_tables) + i), - (int)fs->e2fs_bsize, 0, 0); + bp = getblk(devvp, EXT2_FSBTODB64OFF(fs, + fs2h32(gd->ext2bgd_i_tables), + fs2h32(gd->ext2bgd_i_tables_hi), i), + (int)fs->e2fs_bsize, 0, 0); clrbuf(bp); } Index: src/sys/ufs/ext2fs/ext2fs_vfsops.c diff -u src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.221 src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.222 --- src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.221 Sun May 22 07:27:36 2022 +++ src/sys/ufs/ext2fs/ext2fs_vfsops.c Fri Aug 25 12:50:23 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: ext2fs_vfsops.c,v 1.221 2022/05/22 11:27:36 andvar Exp $ */ +/* $NetBSD: ext2fs_vfsops.c,v 1.222 2023/08/25 16:50:23 christos Exp $ */ /* * Copyright (c) 1989, 1991, 1993, 1994 @@ -60,7 +60,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.221 2022/05/22 11:27:36 andvar Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.222 2023/08/25 16:50:23 christos Exp $"); #if defined(_KERNEL_OPT) #include "opt_compat_netbsd.h" @@ -159,6 +159,58 @@ static const struct ufs_ops ext2fs_ufsop .uo_bufwr = ext2fs_bufwr, }; +static void +e2fs_cgload(const char *ondisk, struct ext2_gd *inmemory, int cg_size, + int shift_cg_entry_size) +{ + + if (shift_cg_entry_size == 6) { + memcpy(inmemory, ondisk, cg_size); + return; + } + + const char *iptr = ondisk; + struct ext2_gd *optr = inmemory; + int sh = 1 << shift_cg_entry_size; + int lim = cg_size >> shift_cg_entry_size; + if (shift_cg_entry_size > 6) { + for (int i = 0; i < lim; i++, optr++, iptr += sh) { + memcpy(optr, iptr, sizeof(*optr)); + } + } else { + for (int i = 0; i < lim; i++, optr++, iptr += sh) { + memcpy(optr, iptr, 32); + memset((char *)optr + 32, 0, sizeof(*optr) - 32); + } + } +} + +static void +e2fs_cgsave(const struct ext2_gd *inmemory, char *ondisk, int cg_size, + int shift_cg_entry_size) +{ + + if (shift_cg_entry_size == 6) { + memcpy(ondisk, inmemory, cg_size); + return; + } + + const struct ext2_gd *iptr = inmemory; + char *optr = ondisk; + int sh = 1 << shift_cg_entry_size; + int lim = cg_size >> shift_cg_entry_size; + if (shift_cg_entry_size > 6) { + for (int i = 0; i < lim; i++, iptr++, optr += sh) { + memcpy(optr, iptr, sizeof(*iptr)); + memset(optr + sizeof(*optr), 0, sh - sizeof(*iptr)); + } + } else { + for (int i = 0; i < lim; i++, iptr++, optr += sh) { + memcpy(optr, iptr, 32); + } + } +} + /* Fill in the inode uid/gid from ext2 halves. */ void ext2fs_set_inode_guid(struct inode *ip) @@ -506,11 +558,13 @@ ext2fs_loadvnode_content(struct m_ext2fs struct ext2fs_dinode *din; int error = 0; - din = (struct ext2fs_dinode *)((char *)bp->b_data + (ino_to_fsbo(fs, ino) * EXT2_DINODE_SIZE(fs))); + din = (struct ext2fs_dinode *)((char *)bp->b_data + + (ino_to_fsbo(fs, ino) * EXT2_DINODE_SIZE(fs))); /* sanity checks - inode data NOT byteswapped at this point */ if (EXT2_DINODE_FITS(din, e2di_extra_isize, EXT2_DINODE_SIZE(fs)) - && (EXT2_DINODE_SIZE(fs) - EXT2_REV0_DINODE_SIZE) < fs2h16(din->e2di_extra_isize)) + && (EXT2_DINODE_SIZE(fs) - EXT2_REV0_DINODE_SIZE) + < fs2h16(din->e2di_extra_isize)) { printf("ext2fs: inode %"PRIu64" bad extra_isize %u", ino, din->e2di_extra_isize); @@ -571,8 +625,8 @@ ext2fs_reload(struct mount *mp, kauth_cr fs = ump->um_e2fs; /* - * Step 2: re-read superblock from disk. Copy in new superblock, and compute - * in-memory values. + * Step 2: re-read superblock from disk. Copy in new superblock, and + * compute in-memory values. */ error = bread(devvp, SBLOCK, SBSIZE, 0, &bp); if (error) @@ -597,9 +651,9 @@ ext2fs_reload(struct mount *mp, kauth_cr if (error) { return error; } - e2fs_cgload((struct ext2_gd *)bp->b_data, + e2fs_cgload(bp->b_data, &fs->e2fs_gd[i * fs->e2fs_bsize / sizeof(struct ext2_gd)], - fs->e2fs_bsize); + fs->e2fs_bsize, 1 << fs->e2fs_group_desc_shift); brelse(bp, 0); } @@ -704,8 +758,10 @@ ext2fs_mountfs(struct vnode *devvp, stru m_fs->e2fs_fmod = 1; } + int32_t sh = m_fs->e2fs_bsize >> m_fs->e2fs_group_desc_shift; /* XXX: should be added in ext2fs_sbfill()? */ - m_fs->e2fs_gd = kmem_alloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize, KM_SLEEP); + m_fs->e2fs_gd = kmem_alloc(m_fs->e2fs_ngdb * sh + * sizeof(struct ext2_gd), KM_SLEEP); for (i = 0; i < m_fs->e2fs_ngdb; i++) { error = bread(devvp, EXT2_FSBTODB(m_fs, m_fs->e2fs.e2fs_first_dblock + @@ -716,10 +772,8 @@ ext2fs_mountfs(struct vnode *devvp, stru m_fs->e2fs_ngdb * m_fs->e2fs_bsize); goto out; } - e2fs_cgload((struct ext2_gd *)bp->b_data, - &m_fs->e2fs_gd[ - i * m_fs->e2fs_bsize / sizeof(struct ext2_gd)], - m_fs->e2fs_bsize); + e2fs_cgload(bp->b_data, &m_fs->e2fs_gd[i * sh], + m_fs->e2fs_bsize, m_fs->e2fs_group_desc_shift); brelse(bp, 0); bp = NULL; } @@ -1109,7 +1163,9 @@ ext2fs_newvnode(struct mount *mp, struct ip = VTOI(vp); - KASSERT(!E2FS_HAS_GD_CSUM(fs) || (fs->e2fs_gd[ino_to_cg(fs, ino)].ext2bgd_flags & h2fs16(E2FS_BG_INODE_ZEROED)) != 0); + KASSERT(!E2FS_HAS_GD_CSUM(fs) || + (fs->e2fs_gd[ino_to_cg(fs, ino)].ext2bgd_flags & + h2fs16(E2FS_BG_INODE_ZEROED)) != 0); /* check for already used inode; makes sense only for ZEROED itable */ if (__predict_false(ip->i_e2fs_mode && ip->i_e2fs_nlink != 0)) { @@ -1156,14 +1212,17 @@ ext2fs_newvnode(struct mount *mp, struct /* Initialize extra_isize according to what is set in superblock */ if (EXT2F_HAS_ROCOMPAT_FEATURE(ip->i_e2fs, EXT2F_ROCOMPAT_EXTRA_ISIZE) && EXT2_DINODE_SIZE(ip->i_e2fs) > EXT2_REV0_DINODE_SIZE) { - ip->i_din.e2fs_din->e2di_extra_isize = ip->i_e2fs->e2fs.e4fs_want_extra_isize; + ip->i_din.e2fs_din->e2di_extra_isize = + ip->i_e2fs->e2fs.e4fs_want_extra_isize; } /* Set create time if possible */ - if (EXT2_DINODE_FITS(ip->i_din.e2fs_din, e2di_crtime, EXT2_DINODE_SIZE(ip->i_e2fs))) { + if (EXT2_DINODE_FITS(ip->i_din.e2fs_din, e2di_crtime, + EXT2_DINODE_SIZE(ip->i_e2fs))) { struct timespec now; vfs_timestamp(&now); - EXT2_DINODE_TIME_SET(&now, ip->i_din.e2fs_din, e2di_crtime, EXT2_DINODE_SIZE(ip->i_e2fs)); + EXT2_DINODE_TIME_SET(&now, ip->i_din.e2fs_din, e2di_crtime, + EXT2_DINODE_SIZE(ip->i_e2fs)); } /* Initialize the vnode from the inode. */ @@ -1277,7 +1336,7 @@ ext2fs_cgupdate(struct ufsmount *mp, int 1 /* superblock */ + i), fs->e2fs_bsize, 0, 0); e2fs_cgsave(&fs->e2fs_gd[ i * fs->e2fs_bsize / sizeof(struct ext2_gd)], - (struct ext2_gd *)bp->b_data, fs->e2fs_bsize); + bp->b_data, fs->e2fs_bsize, fs->e2fs_group_desc_shift); if (waitfor == MNT_WAIT) error = bwrite(bp); else @@ -1305,7 +1364,8 @@ ext2fs_sbfill(struct m_ext2fs *m_fs, int if (fs->e2fs_magic != E2FS_MAGIC) return EINVAL; if (fs->e2fs_rev > E2FS_REV1) { - printf("ext2fs: unsupported revision number: %x\n", fs->e2fs_rev); + printf("ext2fs: unsupported revision number: %#x\n", + fs->e2fs_rev); return EINVAL; } if (fs->e2fs_log_bsize > 2) { @@ -1348,7 +1408,17 @@ ext2fs_sbfill(struct m_ext2fs *m_fs, int m_fs->e2fs_qbmask = m_fs->e2fs_bsize - 1; m_fs->e2fs_bmask = ~m_fs->e2fs_qbmask; - if ((u32 = m_fs->e2fs_bsize / sizeof(struct ext2_gd)) == 0) { + if (!(fs->e2fs_features_incompat & EXT2F_INCOMPAT_64BIT) || + (fs->e2fs_rev == E2FS_REV0)) + m_fs->e2fs_group_desc_shift = 5; + else { + for (m_fs->e2fs_group_desc_shift = 0; + (1 << m_fs->e2fs_group_desc_shift) + < fs->e3fs_desc_size; + m_fs->e2fs_group_desc_shift++); + } + + if ((u32 = (m_fs->e2fs_bsize >> m_fs->e2fs_group_desc_shift)) == 0) { /* Unlikely to happen */ printf("ext2fs: invalid block size\n"); return EINVAL; @@ -1379,7 +1449,8 @@ ext2fs_sbfill(struct m_ext2fs *m_fs, int u32 = fs->e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP; if (u32) { snprintb(buf, sizeof(buf), EXT2F_INCOMPAT_BITS, u32); - printf("ext2fs: unsupported incompat features: %s\n", buf); + printf("ext2fs: unsupported incompat features: %s\n", + buf); #ifndef EXT2_IGNORE_INCOMPAT_FEATURES return EINVAL; #endif @@ -1401,3 +1472,4 @@ ext2fs_sbfill(struct m_ext2fs *m_fs, int return 0; } +