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;
 }
+

Reply via email to