Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 4 Mar 2019 10:42:25 +0000 (UTC)
From:      Fedor Uporov <fsu@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r344751 - head/sys/fs/ext2fs
Message-ID:  <201903041042.x24AgPmq007674@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: fsu
Date: Mon Mar  4 10:42:25 2019
New Revision: 344751
URL: https://svnweb.freebsd.org/changeset/base/344751

Log:
  Make superblock reading logic more strict.
  
  Add more on-disk superblock consistency checks to ext2_compute_sb_data() function.
  It should decrease the probability of mounting filesystems with corrupted superblock data.
  
  Reviewed by:    pfg
  MFC after:      1 week
  
  Differential Revision:    https://reviews.freebsd.org/D19322

Modified:
  head/sys/fs/ext2fs/ext2_alloc.c
  head/sys/fs/ext2fs/ext2_extern.h
  head/sys/fs/ext2fs/ext2_vfsops.c
  head/sys/fs/ext2fs/ext2fs.h

Modified: head/sys/fs/ext2fs/ext2_alloc.c
==============================================================================
--- head/sys/fs/ext2fs/ext2_alloc.c	Mon Mar  4 06:43:00 2019	(r344750)
+++ head/sys/fs/ext2fs/ext2_alloc.c	Mon Mar  4 10:42:25 2019	(r344751)
@@ -457,7 +457,7 @@ noinodes:
 /*
  * 64-bit compatible getters and setters for struct ext2_gd from ext2fs.h
  */
-static uint64_t
+uint64_t
 e2fs_gd_get_b_bitmap(struct ext2_gd *gd)
 {
 
@@ -465,7 +465,7 @@ e2fs_gd_get_b_bitmap(struct ext2_gd *gd)
 	    gd->ext2bgd_b_bitmap);
 }
 
-static uint64_t
+uint64_t
 e2fs_gd_get_i_bitmap(struct ext2_gd *gd)
 {
 
@@ -754,7 +754,7 @@ ext2_hashalloc(struct inode *ip, int cg, long pref, in
 	return (0);
 }
 
-static unsigned long
+static uint64_t
 ext2_cg_number_gdb_nometa(struct m_ext2fs *fs, int cg)
 {
 
@@ -768,7 +768,7 @@ ext2_cg_number_gdb_nometa(struct m_ext2fs *fs, int cg)
 	    EXT2_DESCS_PER_BLOCK(fs));
 }
 
-static unsigned long
+static uint64_t
 ext2_cg_number_gdb_meta(struct m_ext2fs *fs, int cg)
 {
 	unsigned long metagroup;
@@ -784,7 +784,7 @@ ext2_cg_number_gdb_meta(struct m_ext2fs *fs, int cg)
 	return (0);
 }
 
-static unsigned long
+uint64_t
 ext2_cg_number_gdb(struct m_ext2fs *fs, int cg)
 {
 	unsigned long first_meta_bg, metagroup;

Modified: head/sys/fs/ext2fs/ext2_extern.h
==============================================================================
--- head/sys/fs/ext2fs/ext2_extern.h	Mon Mar  4 06:43:00 2019	(r344750)
+++ head/sys/fs/ext2fs/ext2_extern.h	Mon Mar  4 10:42:25 2019	(r344751)
@@ -91,6 +91,7 @@ int	ext2_dirrewrite(struct inode *,
 int	ext2_dirempty(struct inode *, ino_t, struct ucred *);
 int	ext2_checkpath(struct inode *, struct inode *, struct ucred *);
 int	ext2_cg_has_sb(struct m_ext2fs *fs, int cg);
+uint64_t	ext2_cg_number_gdb(struct m_ext2fs *fs, int cg);
 int	ext2_inactive(struct vop_inactive_args *);
 int	ext2_htree_add_entry(struct vnode *, struct ext2fs_direct_2 *,
 	    struct componentname *);
@@ -104,6 +105,8 @@ int	ext2_htree_lookup(struct inode *, const char *, in
 int	ext2_search_dirblock(struct inode *, void *, int *, const char *, int,
 	    int *, doff_t *, doff_t *, doff_t *, struct ext2fs_searchslot *);
 uint32_t	e2fs_gd_get_ndirs(struct ext2_gd *gd);
+uint64_t	e2fs_gd_get_b_bitmap(struct ext2_gd *);
+uint64_t	e2fs_gd_get_i_bitmap(struct ext2_gd *);
 uint64_t	e2fs_gd_get_i_tables(struct ext2_gd *);
 void	ext2_sb_csum_set_seed(struct m_ext2fs *);
 int	ext2_sb_csum_verify(struct m_ext2fs *);

Modified: head/sys/fs/ext2fs/ext2_vfsops.c
==============================================================================
--- head/sys/fs/ext2fs/ext2_vfsops.c	Mon Mar  4 06:43:00 2019	(r344750)
+++ head/sys/fs/ext2fs/ext2_vfsops.c	Mon Mar  4 10:42:25 2019	(r344751)
@@ -98,7 +98,7 @@ VFS_SET(ext2fs_vfsops, ext2fs, 0);
 
 static int	ext2_check_sb_compat(struct ext2fs *es, struct cdev *dev,
 		    int ronly);
-static int	compute_sb_data(struct vnode * devvp,
+static int	ext2_compute_sb_data(struct vnode * devvp,
 		    struct ext2fs * es, struct m_ext2fs * fs);
 
 static const char *ext2_opts[] = { "acls", "async", "noatime", "noclusterr", 
@@ -321,7 +321,7 @@ ext2_check_sb_compat(struct ext2fs *es, struct cdev *d
 }
 
 static e4fs_daddr_t
-cg_location(struct m_ext2fs *fs, int number)
+ext2_cg_location(struct m_ext2fs *fs, int number)
 {
 	int cg, descpb, logical_sb, has_super = 0;
 
@@ -350,82 +350,196 @@ cg_location(struct m_ext2fs *fs, int number)
 	    fs->e2fs->e2fs_first_dblock);
 }
 
+static int
+ext2_cg_validate(struct m_ext2fs *fs)
+{
+	uint64_t b_bitmap;
+	uint64_t i_bitmap;
+	uint64_t i_tables;
+	uint64_t first_block, last_block, last_cg_block;
+	struct ext2_gd *gd;
+	unsigned int i, cg_count;
+
+	first_block = fs->e2fs->e2fs_first_dblock;
+	last_cg_block = ext2_cg_number_gdb(fs, 0);
+	cg_count = fs->e2fs_gcount;
+
+	for (i = 0; i < fs->e2fs_gcount; i++) {
+		gd = &fs->e2fs_gd[i];
+
+		if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) ||
+		    i == fs->e2fs_gcount - 1) {
+			last_block = fs->e2fs_bcount - 1;
+		} else {
+			last_block = first_block +
+			    (EXT2_BLOCKS_PER_GROUP(fs) - 1);
+		}
+
+		if ((cg_count == fs->e2fs_gcount) &&
+		    !(gd->ext4bgd_flags & EXT2_BG_INODE_ZEROED))
+			cg_count = i;
+
+		b_bitmap = e2fs_gd_get_b_bitmap(gd);
+		if (b_bitmap == 0) {
+			printf("ext2fs: cg %u: block bitmap is zero\n", i);
+			return (EINVAL);
+
+		}
+		if (b_bitmap <= last_cg_block) {
+			printf("ext2fs: cg %u: block bitmap overlaps gds\n", i);
+			return (EINVAL);
+		}
+		if (b_bitmap < first_block || b_bitmap > last_block) {
+			printf("ext2fs: cg %u: block bitmap not in group, blk=%ju\n",
+			    i, b_bitmap);
+			return (EINVAL);
+		}
+
+		i_bitmap = e2fs_gd_get_i_bitmap(gd);
+		if (i_bitmap == 0) {
+			printf("ext2fs: cg %u: inode bitmap is zero\n", i);
+			return (EINVAL);
+		}
+		if (i_bitmap <= last_cg_block) {
+			printf("ext2fs: cg %u: inode bitmap overlaps gds\n", i);
+			return (EINVAL);
+		}
+		if (i_bitmap < first_block || i_bitmap > last_block) {
+			printf("ext2fs: cg %u: inode bitmap not in group blk=%ju\n",
+			    i, i_bitmap);
+			return (EINVAL);
+		}
+
+		i_tables = e2fs_gd_get_i_tables(gd);
+		if (i_tables == 0) {
+			printf("ext2fs: cg %u: inode table is zero\n", i);
+			return (EINVAL);
+		}
+		if (i_tables <= last_cg_block) {
+			printf("ext2fs: cg %u: inode talbes overlaps gds\n", i);
+			return (EINVAL);
+		}
+		if (i_tables < first_block ||
+		    i_tables + fs->e2fs_itpg - 1 > last_block) {
+			printf("ext2fs: cg %u: inode tables not in group blk=%ju\n",
+			    i, i_tables);
+			return (EINVAL);
+		}
+
+		if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG))
+			first_block += EXT2_BLOCKS_PER_GROUP(fs);
+	}
+
+	return (0);
+}
+
 /*
  * This computes the fields of the m_ext2fs structure from the
  * data in the ext2fs structure read in.
  */
 static int
-compute_sb_data(struct vnode *devvp, struct ext2fs *es,
+ext2_compute_sb_data(struct vnode *devvp, struct ext2fs *es,
     struct m_ext2fs *fs)
 {
-	int g_count = 0, error;
-	int i, j;
 	struct buf *bp;
 	uint32_t e2fs_descpb, e2fs_gdbcount_alloc;
+	int i, j;
+	int g_count = 0;
+	int error;
 
-	fs->e2fs_bcount = es->e2fs_bcount;
-	fs->e2fs_rbcount = es->e2fs_rbcount;
-	fs->e2fs_fbcount = es->e2fs_fbcount;
-	if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) {
-		fs->e2fs_bcount |= (uint64_t)(es->e4fs_bcount_hi) << 32;
-		fs->e2fs_rbcount |= (uint64_t)(es->e4fs_rbcount_hi) << 32;
-		fs->e2fs_fbcount |= (uint64_t)(es->e4fs_fbcount_hi) << 32;
+	/* Check checksum features */
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) &&
+	    EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
+		printf("ext2fs: incorrect checksum features combination\n");
+		return (EINVAL);
 	}
+
+	/* Precompute checksum seed for all metadata */
+	ext2_sb_csum_set_seed(fs);
+
+	/* Verify sb csum if possible */
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
+		error = ext2_sb_csum_verify(fs);
+		if (error) {
+			return (error);
+		}
+	}
+
+	/* Check for block size = 1K|2K|4K */
+	if (es->e2fs_log_bsize > 2) {
+		printf("ext2fs: bad block size: %d\n", es->e2fs_log_bsize);
+		return (EINVAL);
+	}
+
 	fs->e2fs_bshift = EXT2_MIN_BLOCK_LOG_SIZE + es->e2fs_log_bsize;
 	fs->e2fs_bsize = 1U << fs->e2fs_bshift;
 	fs->e2fs_fsbtodb = es->e2fs_log_bsize + 1;
 	fs->e2fs_qbmask = fs->e2fs_bsize - 1;
+
+	/* Check for fragment size */
+	if (es->e2fs_log_fsize >
+	    (EXT2_MAX_FRAG_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE)) {
+		printf("ext2fs: invalid log cluster size: %u\n",
+		    es->e2fs_log_fsize);
+		return (EINVAL);
+	}
+
 	fs->e2fs_fsize = EXT2_MIN_FRAG_SIZE << es->e2fs_log_fsize;
-	if (fs->e2fs_fsize)
-		fs->e2fs_fpb = fs->e2fs_bsize / fs->e2fs_fsize;
-	fs->e2fs_bpg = es->e2fs_bpg;
-	fs->e2fs_fpg = es->e2fs_fpg;
-	fs->e2fs_ipg = es->e2fs_ipg;
+	if (fs->e2fs_fsize != fs->e2fs_bsize) {
+		printf("ext2fs: fragment size (%u) != block size %u\n",
+		    fs->e2fs_fsize, fs->e2fs_bsize);
+		return (EINVAL);
+	}
+
+	fs->e2fs_fpb = fs->e2fs_bsize / fs->e2fs_fsize;
+
+	/* Check reserved gdt blocks for future filesystem expansion */
+	if (es->e2fs_reserved_ngdb > (fs->e2fs_bsize / 4)) {
+		printf("ext2fs: number of reserved GDT blocks too large: %u\n",
+		    es->e2fs_reserved_ngdb);
+		return (EINVAL);
+	}
+
 	if (es->e2fs_rev == E2FS_REV0) {
 		fs->e2fs_isize = E2FS_REV0_INODE_SIZE;
 	} else {
 		fs->e2fs_isize = es->e2fs_inode_size;
 
 		/*
+		 * Check first ino.
+		 */
+		if (es->e2fs_first_ino < EXT2_FIRSTINO) {
+			printf("ext2fs: invalid first ino: %u\n",
+			    es->e2fs_first_ino);
+			return (EINVAL);
+		}
+
+		/*
 		 * Simple sanity check for superblock inode size value.
 		 */
 		if (EXT2_INODE_SIZE(fs) < E2FS_REV0_INODE_SIZE ||
 		    EXT2_INODE_SIZE(fs) > fs->e2fs_bsize ||
 		    (fs->e2fs_isize & (fs->e2fs_isize - 1)) != 0) {
-			printf("ext2fs: invalid inode size %d\n",
+			printf("ext2fs: invalid inode size %u\n",
 			    fs->e2fs_isize);
-			return (EIO);
+			return (EINVAL);
 		}
 	}
-	/* Check for extra isize in big inodes. */
-	if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_EXTRA_ISIZE) &&
-	    EXT2_INODE_SIZE(fs) < sizeof(struct ext2fs_dinode)) {
-		printf("ext2fs: no space for extra inode timestamps\n");
-		return (EINVAL);
-	}
-	/* Check checksum features */
-	if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) &&
-	    EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
-		printf("ext2fs: incorrect checksum features combination\n");
-		return (EINVAL);
-	}
-	/* Check for group descriptor size */
+
+	/* Check group descriptors */
 	if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) &&
-	    (es->e3fs_desc_size != sizeof(struct ext2_gd))) {
-		printf("ext2fs: group descriptor size unsupported %d\n",
-		    es->e3fs_desc_size);
-		return (EINVAL);
+	    es->e3fs_desc_size != E2FS_64BIT_GD_SIZE) {
+			printf("ext2fs: unsupported 64bit descriptor size %u\n",
+			    es->e3fs_desc_size);
+			return (EINVAL);
 	}
-	/* Check for block size = 1K|2K|4K */
-	if (es->e2fs_log_bsize > 2) {
-		printf("ext2fs: bad block size: %d\n", es->e2fs_log_bsize);
+
+	fs->e2fs_bpg = es->e2fs_bpg;
+	fs->e2fs_fpg = es->e2fs_fpg;
+	if (fs->e2fs_bpg == 0 || fs->e2fs_fpg == 0) {
+		printf("ext2fs: zero blocks/fragments per group\n");
 		return (EINVAL);
 	}
-	/* Check for group size */
-	if (fs->e2fs_bpg == 0) {
-		printf("ext2fs: zero blocks per group\n");
-		return (EINVAL);
-	}
 	if (fs->e2fs_bpg != fs->e2fs_bsize * 8) {
 		printf("ext2fs: non-standard group size unsupported %d\n",
 		    fs->e2fs_bpg);
@@ -433,26 +547,56 @@ compute_sb_data(struct vnode *devvp, struct ext2fs *es
 	}
 
 	fs->e2fs_ipb = fs->e2fs_bsize / EXT2_INODE_SIZE(fs);
-	if (fs->e2fs_ipg == 0) {
-		printf("ext2fs: zero inodes per group\n");
+	if (fs->e2fs_ipb == 0 ||
+	    fs->e2fs_ipb > fs->e2fs_bsize / E2FS_REV0_INODE_SIZE) {
+		printf("ext2fs: bad inodes per block size\n");
 		return (EINVAL);
 	}
-	fs->e2fs_itpg = fs->e2fs_ipg / fs->e2fs_ipb;
-	/* Check for block consistency */
-	if (es->e2fs_first_dblock >= fs->e2fs_bcount) {
-		printf("ext2fs: invalid first data block\n");
+
+	fs->e2fs_ipg = es->e2fs_ipg;
+	if (fs->e2fs_ipg < fs->e2fs_ipb || fs->e2fs_ipg >  fs->e2fs_bsize * 8) {
+		printf("ext2fs: invalid inodes per group: %u\n", fs->e2fs_ipb);
 		return (EINVAL);
 	}
+
+	fs->e2fs_itpg = fs->e2fs_ipg / fs->e2fs_ipb;
+
+	fs->e2fs_bcount = es->e2fs_bcount;
+	fs->e2fs_rbcount = es->e2fs_rbcount;
+	fs->e2fs_fbcount = es->e2fs_fbcount;
+	if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) {
+		fs->e2fs_bcount |= (uint64_t)(es->e4fs_bcount_hi) << 32;
+		fs->e2fs_rbcount |= (uint64_t)(es->e4fs_rbcount_hi) << 32;
+		fs->e2fs_fbcount |= (uint64_t)(es->e4fs_fbcount_hi) << 32;
+	}
 	if (fs->e2fs_rbcount > fs->e2fs_bcount ||
 	    fs->e2fs_fbcount > fs->e2fs_bcount) {
 		printf("ext2fs: invalid block count\n");
 		return (EINVAL);
 	}
-	/* s_resuid / s_resgid ? */
+	if (es->e2fs_first_dblock >= fs->e2fs_bcount) {
+		printf("ext2fs: first data block out of range\n");
+		return (EINVAL);
+	}
+
 	fs->e2fs_gcount = howmany(fs->e2fs_bcount - es->e2fs_first_dblock,
 	    EXT2_BLOCKS_PER_GROUP(fs));
+	if (fs->e2fs_gcount > ((uint64_t)1 << 32) - EXT2_DESCS_PER_BLOCK(fs)) {
+		printf("ext2fs: groups count too large: %u\n", fs->e2fs_gcount);
+		return (EINVAL);
+	}
+
+	/* Check for extra isize in big inodes. */
+	if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_EXTRA_ISIZE) &&
+	    EXT2_INODE_SIZE(fs) < sizeof(struct ext2fs_dinode)) {
+		printf("ext2fs: no space for extra inode timestamps\n");
+		return (EINVAL);
+	}
+
+	/* s_resuid / s_resgid ? */
+
 	if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) {
-		e2fs_descpb = fs->e2fs_bsize / sizeof(struct ext2_gd);
+		e2fs_descpb = fs->e2fs_bsize / E2FS_64BIT_GD_SIZE;
 		e2fs_gdbcount_alloc = howmany(fs->e2fs_gcount, e2fs_descpb);
 	} else {
 		e2fs_descpb = fs->e2fs_bsize / E2FS_REV0_GD_SIZE;
@@ -467,7 +611,7 @@ compute_sb_data(struct vnode *devvp, struct ext2fs *es
 
 	for (i = 0; i < fs->e2fs_gdbcount; i++) {
 		error = bread(devvp,
-		    fsbtodb(fs, cg_location(fs, i)),
+		    fsbtodb(fs, ext2_cg_location(fs, i)),
 		    fs->e2fs_bsize, NOCRED, &bp);
 		if (error) {
 			free(fs->e2fs_contigdirs, M_EXT2MNT);
@@ -489,9 +633,13 @@ compute_sb_data(struct vnode *devvp, struct ext2fs *es
 		brelse(bp);
 		bp = NULL;
 	}
-	/* Precompute checksum seed for all metadata */
-	ext2_sb_csum_set_seed(fs);
-	/* Verfy cg csum */
+
+	/* Validate cgs consistency */
+	error = ext2_cg_validate(fs);
+	if (error)
+		return (error);
+
+	/* Verfy cgs csum */
 	if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) ||
 	    EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
 		error = ext2_gd_csum_verify(fs, devvp->v_rdev);
@@ -578,7 +726,7 @@ ext2_reload(struct mount *mp, struct thread *td)
 	fs = VFSTOEXT2(mp)->um_e2fs;
 	bcopy(bp->b_data, fs->e2fs, sizeof(struct ext2fs));
 
-	if ((error = compute_sb_data(devvp, es, fs)) != 0) {
+	if ((error = ext2_compute_sb_data(devvp, es, fs)) != 0) {
 		brelse(bp);
 		return (error);
 	}
@@ -715,7 +863,7 @@ ext2_mountfs(struct vnode *devvp, struct mount *mp)
 	    M_EXT2MNT, M_WAITOK);
 	mtx_init(EXT2_MTX(ump), "EXT2FS", "EXT2FS Lock", MTX_DEF);
 	bcopy(es, ump->um_e2fs->e2fs, (u_int)sizeof(struct ext2fs));
-	if ((error = compute_sb_data(devvp, ump->um_e2fs->e2fs, ump->um_e2fs)))
+	if ((error = ext2_compute_sb_data(devvp, ump->um_e2fs->e2fs, ump->um_e2fs)))
 		goto out;
 
 	/*
@@ -1204,7 +1352,7 @@ ext2_cgupdate(struct ext2mount *mp, int waitfor)
 
 	for (i = 0; i < fs->e2fs_gdbcount; i++) {
 		bp = getblk(mp->um_devvp, fsbtodb(fs,
-		    cg_location(fs, i)),
+		    ext2_cg_location(fs, i)),
 		    fs->e2fs_bsize, 0, 0, 0);
 		if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) {
 			memcpy(bp->b_data, &fs->e2fs_gd[

Modified: head/sys/fs/ext2fs/ext2fs.h
==============================================================================
--- head/sys/fs/ext2fs/ext2fs.h	Mon Mar  4 06:43:00 2019	(r344750)
+++ head/sys/fs/ext2fs/ext2fs.h	Mon Mar  4 10:42:25 2019	(r344751)
@@ -395,6 +395,7 @@ struct ext2_gd {
 };
 
 #define	E2FS_REV0_GD_SIZE (sizeof(struct ext2_gd) / 2)
+#define	E2FS_64BIT_GD_SIZE (sizeof(struct ext2_gd))
 
 /*
  * Macro-instructions used to manage several block sizes
@@ -408,8 +409,8 @@ struct ext2_gd {
  * Macro-instructions used to manage fragments
  */
 #define	EXT2_MIN_FRAG_SIZE		1024
-#define	EXT2_MAX_FRAG_SIZE		4096
-#define	EXT2_MIN_FRAG_LOG_SIZE		  10
+#define	EXT2_MIN_FRAG_LOG_SIZE		10
+#define	EXT2_MAX_FRAG_LOG_SIZE		30
 #define	EXT2_FRAG_SIZE(s)		(EXT2_SB(s)->e2fs_fsize)
 #define	EXT2_FRAGS_PER_BLOCK(s)		(EXT2_SB(s)->e2fs_fpb)
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201903041042.x24AgPmq007674>