Module Name: src
Committed By: jdolecek
Date: Sat Aug 20 19:47:44 UTC 2016
Modified Files:
src/sys/ufs/ext2fs: ext2fs.h ext2fs_alloc.c ext2fs_bswap.c
ext2fs_extern.h ext2fs_vfsops.c
Log Message:
add support for GDT_CSUM AKA uninit_bg feature
To generate a diff of this commit:
cvs rdiff -u -r1.47 -r1.48 src/sys/ufs/ext2fs/ext2fs.h
cvs rdiff -u -r1.48 -r1.49 src/sys/ufs/ext2fs/ext2fs_alloc.c
cvs rdiff -u -r1.23 -r1.24 src/sys/ufs/ext2fs/ext2fs_bswap.c
cvs rdiff -u -r1.54 -r1.55 src/sys/ufs/ext2fs/ext2fs_extern.h
cvs rdiff -u -r1.199 -r1.200 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.47 src/sys/ufs/ext2fs/ext2fs.h:1.48
--- src/sys/ufs/ext2fs/ext2fs.h:1.47 Mon Aug 15 18:46:11 2016
+++ src/sys/ufs/ext2fs/ext2fs.h Sat Aug 20 19:47:44 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ext2fs.h,v 1.47 2016/08/15 18:46:11 jdolecek Exp $ */
+/* $NetBSD: ext2fs.h,v 1.48 2016/08/20 19:47:44 jdolecek Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
@@ -249,10 +249,10 @@ struct m_ext2fs {
int64_t e2fs_qbmask; /* ~fs_bmask - for use with quad size */
int32_t e2fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
int32_t e2fs_ncg; /* number of cylinder groups */
- int32_t e2fs_ngdb; /* number of group descriptor block */
+ 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 per group */
- struct ext2_gd *e2fs_gd; /* group descripors */
+ int32_t e2fs_itpg; /* number of inode table blocks per group */
+ struct ext2_gd *e2fs_gd; /* group descriptors (data not byteswapped) */
};
@@ -366,7 +366,8 @@ struct m_ext2fs {
| EXT2F_ROCOMPAT_LARGEFILE \
| EXT2F_ROCOMPAT_HUGE_FILE \
| EXT2F_ROCOMPAT_EXTRA_ISIZE \
- | EXT2F_ROCOMPAT_DIR_NLINK)
+ | EXT2F_ROCOMPAT_DIR_NLINK \
+ | EXT2F_ROCOMPAT_GDT_CSUM)
#define EXT2F_INCOMPAT_SUPP (EXT2F_INCOMPAT_FTYPE \
| EXT2F_INCOMPAT_EXTENTS \
| EXT2F_INCOMPAT_FLEX_BG)
@@ -415,15 +416,35 @@ struct m_ext2fs {
struct ext2_gd {
uint32_t ext2bgd_b_bitmap; /* blocks bitmap block */
uint32_t ext2bgd_i_bitmap; /* inodes bitmap block */
- uint32_t ext2bgd_i_tables; /* inodes table block */
+ uint32_t ext2bgd_i_tables; /* first inodes table block */
uint16_t ext2bgd_nbfree; /* number of free blocks */
uint16_t ext2bgd_nifree; /* number of free inodes */
uint16_t ext2bgd_ndirs; /* number of directories */
- uint16_t reserved;
- uint32_t reserved2[3];
+
+ /*
+ * Following only valid when either GDT_CSUM (AKA uninit_bg)
+ * or METADATA_CKSUM feature is on
+ */
+ uint16_t ext2bgd_flags; /* ext4 bg flags (INODE_UNINIT, ...)*/
+ uint32_t ext2bgd_exclude_bitmap_lo; /* snapshot exclude bitmap */
+ uint16_t ext2bgd_block_bitmap_csum_lo; /* Low block bitmap checksum */
+ uint16_t ext2bgd_inode_bitmap_csum_lo; /* Low inode bitmap checksum */
+ 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.
+ */
};
+#define E2FS_BG_INODE_UNINIT 0x0001 /* Inode bitmap not used/initialized */
+#define E2FS_BG_BLOCK_UNINIT 0x0002 /* Block bitmap not used/initialized */
+#define E2FS_BG_INODE_ZEROED 0x0004 /* On-disk inode table initialized */
+#define E2FS_HAS_GD_CSUM(fs) \
+ EXT2F_HAS_ROCOMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM|EXT2F_ROCOMPAT_METADATA_CKSUM) != 0
+
/*
* If the EXT2F_ROCOMPAT_SPARSESUPER flag is set, the cylinder group has a
* copy of the super and cylinder group descriptors blocks only if it's
@@ -457,13 +478,10 @@ cg_has_sb(int i)
# define fs2h16(x) (x)
# define fs2h32(x) (x)
# define fs2h64(x) (x)
-# define e2fs_sbload(old, new) memcpy((new), (old), SBSIZE);
-# define e2fs_cgload(old, new, size) memcpy((new), (old), (size));
-# define e2fs_sbsave(old, new) memcpy((new), (old), SBSIZE);
-# define e2fs_cgsave(old, new, size) memcpy((new), (old), (size));
+# define e2fs_sbload(old, new) memcpy((new), (old), SBSIZE)
+# define e2fs_sbsave(old, new) memcpy((new), (old), SBSIZE)
#else
void e2fs_sb_bswap(struct ext2fs *, struct ext2fs *);
-void e2fs_cg_bswap(struct ext2_gd *, struct ext2_gd *, int);
# define h2fs16(x) bswap16(x)
# define h2fs32(x) bswap32(x)
# define h2fs64(x) bswap64(x)
@@ -471,11 +489,13 @@ void e2fs_cg_bswap(struct ext2_gd *, str
# define fs2h32(x) bswap32(x)
# define fs2h64(x) bswap64(x)
# define e2fs_sbload(old, new) e2fs_sb_bswap((old), (new))
-# define e2fs_cgload(old, new, size) e2fs_cg_bswap((old), (new), (size));
# define e2fs_sbsave(old, new) e2fs_sb_bswap((old), (new))
-# define e2fs_cgsave(old, new, size) e2fs_cg_bswap((old), (new), (size));
#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.
@@ -491,7 +511,7 @@ void e2fs_cg_bswap(struct ext2_gd *, str
*/
#define ino_to_cg(fs, x) (((x) - 1) / (fs)->e2fs.e2fs_ipg)
#define ino_to_fsba(fs, x) \
- ((fs)->e2fs_gd[ino_to_cg((fs), (x))].ext2bgd_i_tables + \
+ (fs2h32((fs)->e2fs_gd[ino_to_cg((fs), (x))].ext2bgd_i_tables) + \
(((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.48 src/sys/ufs/ext2fs/ext2fs_alloc.c:1.49
--- src/sys/ufs/ext2fs/ext2fs_alloc.c:1.48 Sat Aug 13 07:40:10 2016
+++ src/sys/ufs/ext2fs/ext2fs_alloc.c Sat Aug 20 19:47:44 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ext2fs_alloc.c,v 1.48 2016/08/13 07:40:10 christos Exp $ */
+/* $NetBSD: ext2fs_alloc.c,v 1.49 2016/08/20 19:47:44 jdolecek Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ext2fs_alloc.c,v 1.48 2016/08/13 07:40:10 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_alloc.c,v 1.49 2016/08/20 19:47:44 jdolecek Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -72,6 +72,8 @@ __KERNEL_RCSID(0, "$NetBSD: ext2fs_alloc
#include <sys/syslog.h>
#include <sys/kauth.h>
+#include <lib/libkern/crc16.h>
+
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/ufs/ufsmount.h>
@@ -88,6 +90,9 @@ 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 *);
/*
* Allocate a block in the file system.
@@ -191,7 +196,11 @@ ext2fs_valloc(struct vnode *pvp, int mod
return error;
}
ip = VTOI(*vpp);
- if (ip->i_e2fs_mode && ip->i_e2fs_nlink != 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)) {
printf("mode = 0%o, nlinks %d, inum = %llu, fs = %s\n",
ip->i_e2fs_mode, ip->i_e2fs_nlink,
(unsigned long long)ip->i_number, fs->e2fs_fsmnt);
@@ -229,10 +238,10 @@ ext2fs_dirpref(struct m_ext2fs *fs)
maxspace = 0;
mincg = -1;
for (cg = 0; cg < fs->e2fs_ncg; cg++)
- if ( fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree) {
- if (mincg == -1 || fs->e2fs_gd[cg].ext2bgd_nbfree > maxspace) {
+ if (fs2h16(fs->e2fs_gd[cg].ext2bgd_nifree) >= avgifree) {
+ if (mincg == -1 || fs2h16(fs->e2fs_gd[cg].ext2bgd_nbfree) > maxspace) {
mincg = cg;
- maxspace = fs->e2fs_gd[cg].ext2bgd_nbfree;
+ maxspace = fs2h16(fs->e2fs_gd[cg].ext2bgd_nbfree);
}
}
return mincg;
@@ -356,7 +365,7 @@ ext2fs_alloccg(struct inode *ip, int cg,
if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0)
return 0;
error = bread(ip->i_devvp, EXT2_FSBTODB(fs,
- fs->e2fs_gd[cg].ext2bgd_b_bitmap),
+ fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap)),
(int)fs->e2fs_bsize, B_MODIFY, &bp);
if (error) {
return 0;
@@ -365,6 +374,14 @@ ext2fs_alloccg(struct inode *ip, int cg,
if (dtog(fs, bpref) != cg)
bpref = 0;
+
+ /* initialize block bitmap now if uninit */
+ if (__predict_false(E2FS_HAS_GD_CSUM(fs) &&
+ (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_BLOCK_UNINIT)))) {
+ ext2fs_init_bb(fs, cg, &fs->e2fs_gd[cg], bbp);
+ fs->e2fs_gd[cg].ext2bgd_flags &= h2fs16(~E2FS_BG_BLOCK_UNINIT);
+ }
+
if (bpref != 0) {
bpref = dtogd(fs, bpref);
/*
@@ -412,7 +429,7 @@ gotit:
#endif
setbit(bbp, (daddr_t)bno);
fs->e2fs.e2fs_fbcount--;
- fs->e2fs_gd[cg].ext2bgd_nbfree--;
+ ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg], -1, 0, 0, 0);
fs->e2fs_fmod = 1;
bdwrite(bp);
return cg * fs->e2fs.e2fs_fpg + fs->e2fs.e2fs_first_dblock + bno;
@@ -442,12 +459,23 @@ ext2fs_nodealloccg(struct inode *ip, int
if (fs->e2fs_gd[cg].ext2bgd_nifree == 0)
return 0;
error = bread(ip->i_devvp, EXT2_FSBTODB(fs,
- fs->e2fs_gd[cg].ext2bgd_i_bitmap),
+ fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap)),
(int)fs->e2fs_bsize, B_MODIFY, &bp);
if (error) {
return 0;
}
ibp = (char *)bp->b_data;
+
+ KASSERT(!E2FS_HAS_GD_CSUM(fs) || (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_INODE_ZEROED)) != 0);
+
+ /* initialize inode bitmap now if uninit */
+ if (__predict_false(E2FS_HAS_GD_CSUM(fs) &&
+ (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_INODE_UNINIT)))) {
+ KASSERT(fs2h16(fs->e2fs_gd[cg].ext2bgd_nifree) == fs->e2fs.e2fs_ipg);
+ memset(ibp, 0, fs->e2fs_bsize);
+ fs->e2fs_gd[cg].ext2bgd_flags &= h2fs16(~E2FS_BG_INODE_UNINIT);
+ }
+
if (ipref) {
ipref %= fs->e2fs.e2fs_ipg;
if (isclr(ibp, ipref))
@@ -471,17 +499,15 @@ ext2fs_nodealloccg(struct inode *ip, int
map = ibp[i] ^ 0xff;
if (map == 0) {
printf("fs = %s\n", fs->e2fs_fsmnt);
- panic("ext2fs_nodealloccg: block not in map");
+ panic("ext2fs_nodealloccg: inode not in map");
}
ipref = i * NBBY + ffs(map) - 1;
gotit:
setbit(ibp, ipref);
fs->e2fs.e2fs_ficount--;
- fs->e2fs_gd[cg].ext2bgd_nifree--;
+ ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg],
+ 0, -1, ((mode & IFMT) == IFDIR) ? 1 : 0, ipref);
fs->e2fs_fmod = 1;
- if ((mode & IFMT) == IFDIR) {
- fs->e2fs_gd[cg].ext2bgd_ndirs++;
- }
bdwrite(bp);
return cg * fs->e2fs.e2fs_ipg + ipref + 1;
}
@@ -502,6 +528,9 @@ 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);
+
if ((u_int)bno >= fs->e2fs.e2fs_bcount) {
printf("bad block %lld, ino %llu\n", (long long)bno,
(unsigned long long)ip->i_number);
@@ -509,7 +538,7 @@ ext2fs_blkfree(struct inode *ip, daddr_t
return;
}
error = bread(ip->i_devvp,
- EXT2_FSBTODB(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
+ EXT2_FSBTODB(fs, fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap)),
(int)fs->e2fs_bsize, B_MODIFY, &bp);
if (error) {
return;
@@ -524,8 +553,7 @@ ext2fs_blkfree(struct inode *ip, daddr_t
}
clrbit(bbp, bno);
fs->e2fs.e2fs_fbcount++;
- fs->e2fs_gd[cg].ext2bgd_nbfree++;
-
+ ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg], 1, 0, 0, 0);
fs->e2fs_fmod = 1;
bdwrite(bp);
}
@@ -546,13 +574,18 @@ ext2fs_vfree(struct vnode *pvp, ino_t in
pip = VTOI(pvp);
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,
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);
+
error = bread(pip->i_devvp,
- EXT2_FSBTODB(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
+ EXT2_FSBTODB(fs, fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap)),
(int)fs->e2fs_bsize, B_MODIFY, &bp);
if (error) {
return 0;
@@ -568,10 +601,8 @@ ext2fs_vfree(struct vnode *pvp, ino_t in
}
clrbit(ibp, ino);
fs->e2fs.e2fs_ficount++;
- fs->e2fs_gd[cg].ext2bgd_nifree++;
- if ((mode & IFMT) == IFDIR) {
- fs->e2fs_gd[cg].ext2bgd_ndirs--;
- }
+ ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg],
+ 0, 1, ((mode & IFMT) == IFDIR) ? -1 : 0, 0);
fs->e2fs_fmod = 1;
bdwrite(bp);
return 0;
@@ -631,3 +662,150 @@ ext2fs_fserr(struct m_ext2fs *fs, u_int
log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->e2fs_fsmnt, cp);
}
+
+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);
+ /*
+ * If we allocated inode on bigger offset than what was
+ * ever used before, bump the itable_unused count. This
+ * member only ever grows, and is used only for initialization
+ * !INODE_ZEROED groups with used inodes. Of course, by the
+ * 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));
+ }
+
+ KASSERT(!E2FS_HAS_GD_CSUM(fs) || gd->ext2bgd_itable_unused_lo <= gd->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 (E2FS_HAS_GD_CSUM(fs))
+ gd->ext2bgd_checksum = ext2fs_cg_get_csum(fs, cg, gd);
+}
+
+/*
+ * Compute group description csum. Structure data must be LE (not host).
+ * Returned as LE (disk encoding).
+ */
+static uint16_t
+ext2fs_cg_get_csum(struct m_ext2fs *fs, int cg, struct ext2_gd *gd)
+{
+ uint16_t crc;
+ uint32_t cg_bswapped = h2fs32((uint32_t)cg);
+ size_t off;
+
+ if (!EXT2F_HAS_ROCOMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM))
+ return 0;
+
+ off = offsetof(struct ext2_gd, ext2bgd_checksum);
+
+ 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 */
+
+ return h2fs16(crc);
+}
+
+static void
+ext2fs_init_bb(struct m_ext2fs *fs, int cg, struct ext2_gd *gd, char *bbp)
+{
+ int i;
+
+ memset(bbp, 0, fs->e2fs_bsize);
+
+ /*
+ * No block was ever allocated on this cg before, so the only used
+ * blocks are metadata blocks on start of the group. We could optimize
+ * this to set by bytes, but since this is done once per the group
+ * in lifetime of filesystem, it really is not worth it.
+ */
+ for(i=0; i < fs->e2fs.e2fs_bpg - fs2h16(gd->ext2bgd_nbfree); i++)
+ setbit(bbp, i);
+}
+
+/*
+ * Verify csum and initialize itable if not done already
+ */
+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;
+ struct buf *bp;
+ int cg, i, error;
+
+ if (!E2FS_HAS_GD_CSUM(fs))
+ return 0;
+
+ 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);
+ return EINVAL;
+ }
+
+ /* if mounting read-write, zero itable if not already done */
+ if (ronly || (gd->ext2bgd_flags & h2fs16(E2FS_BG_INODE_ZEROED)) != 0)
+ continue;
+
+ /*
+ * We are skipping already used inodes, zero rest of itable
+ * blocks. First block to zero could be only partial wipe, all
+ * others are wiped completely. This might take a while,
+ * there could be many inode table blocks. We use
+ * delayed writes, so this shouldn't block for very
+ * long.
+ */
+ ioff = fs->e2fs.e2fs_ipg - fs2h16(gd->ext2bgd_itable_unused_lo);
+ boff = (ioff % fs->e2fs_ipb) * EXT2_DINODE_SIZE(fs);
+
+ 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);
+ if (error) {
+ printf("ext2fs_cg_verify_and_initialize: can't read itable block");
+ return error;
+ }
+ 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);
+ clrbuf(bp);
+ }
+
+ bdwrite(bp);
+ }
+
+ gd->ext2bgd_flags |= h2fs16(E2FS_BG_INODE_ZEROED);
+ gd->ext2bgd_checksum = ext2fs_cg_get_csum(fs, cg, gd);
+ fs->e2fs_fmod = 1;
+ }
+
+ return 0;
+}
Index: src/sys/ufs/ext2fs/ext2fs_bswap.c
diff -u src/sys/ufs/ext2fs/ext2fs_bswap.c:1.23 src/sys/ufs/ext2fs/ext2fs_bswap.c:1.24
--- src/sys/ufs/ext2fs/ext2fs_bswap.c:1.23 Mon Aug 15 18:29:34 2016
+++ src/sys/ufs/ext2fs/ext2fs_bswap.c Sat Aug 20 19:47:44 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ext2fs_bswap.c,v 1.23 2016/08/15 18:29:34 jdolecek Exp $ */
+/* $NetBSD: ext2fs_bswap.c,v 1.24 2016/08/20 19:47:44 jdolecek Exp $ */
/*
* Copyright (c) 1997 Manuel Bouyer.
@@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ext2fs_bswap.c,v 1.23 2016/08/15 18:29:34 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_bswap.c,v 1.24 2016/08/20 19:47:44 jdolecek Exp $");
#include <sys/types.h>
#include <ufs/ext2fs/ext2fs.h>
@@ -83,21 +83,6 @@ e2fs_sb_bswap(struct ext2fs *old, struct
}
void
-e2fs_cg_bswap(struct ext2_gd *old, struct ext2_gd *new, int size)
-{
- int i;
-
- for (i = 0; i < (size / (int)sizeof(struct ext2_gd)); i++) {
- new[i].ext2bgd_b_bitmap = bswap32(old[i].ext2bgd_b_bitmap);
- new[i].ext2bgd_i_bitmap = bswap32(old[i].ext2bgd_i_bitmap);
- new[i].ext2bgd_i_tables = bswap32(old[i].ext2bgd_i_tables);
- new[i].ext2bgd_nbfree = bswap16(old[i].ext2bgd_nbfree);
- new[i].ext2bgd_nifree = bswap16(old[i].ext2bgd_nifree);
- new[i].ext2bgd_ndirs = bswap16(old[i].ext2bgd_ndirs);
- }
-}
-
-void
e2fs_i_bswap(struct ext2fs_dinode *old, struct ext2fs_dinode *new, size_t isize)
{
/* preserve non-swapped and unused fields */
Index: src/sys/ufs/ext2fs/ext2fs_extern.h
diff -u src/sys/ufs/ext2fs/ext2fs_extern.h:1.54 src/sys/ufs/ext2fs/ext2fs_extern.h:1.55
--- src/sys/ufs/ext2fs/ext2fs_extern.h:1.54 Fri Aug 19 00:05:43 2016
+++ src/sys/ufs/ext2fs/ext2fs_extern.h Sat Aug 20 19:47:44 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ext2fs_extern.h,v 1.54 2016/08/19 00:05:43 jdolecek Exp $ */
+/* $NetBSD: ext2fs_extern.h,v 1.55 2016/08/20 19:47:44 jdolecek Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
@@ -100,6 +100,7 @@ int ext2fs_valloc(struct vnode *, int, k
daddr_t ext2fs_blkpref(struct inode *, daddr_t, int, int32_t *);
void ext2fs_blkfree(struct inode *, daddr_t);
int ext2fs_vfree(struct vnode *, ino_t, int);
+int ext2fs_cg_verify_and_initialize(struct vnode *, struct m_ext2fs *, int);
/* ext2fs_balloc.c */
int ext2fs_balloc(struct inode *, daddr_t, int, kauth_cred_t,
Index: src/sys/ufs/ext2fs/ext2fs_vfsops.c
diff -u src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.199 src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.200
--- src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.199 Sun Aug 14 11:44:54 2016
+++ src/sys/ufs/ext2fs/ext2fs_vfsops.c Sat Aug 20 19:47:44 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ext2fs_vfsops.c,v 1.199 2016/08/14 11:44:54 jdolecek Exp $ */
+/* $NetBSD: ext2fs_vfsops.c,v 1.200 2016/08/20 19:47:44 jdolecek Exp $ */
/*
* Copyright (c) 1989, 1991, 1993, 1994
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.199 2016/08/14 11:44:54 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.200 2016/08/20 19:47:44 jdolecek Exp $");
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
@@ -723,6 +723,12 @@ ext2fs_mountfs(struct vnode *devvp, stru
bp = NULL;
}
+ error = ext2fs_cg_verify_and_initialize(devvp, m_fs, ronly);
+ if (error) {
+ kmem_free(m_fs->e2fs_gd, m_fs->e2fs_ngdb * m_fs->e2fs_bsize);
+ goto out;
+ }
+
mp->mnt_data = ump;
mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev;
mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_EXT2FS);
@@ -834,7 +840,15 @@ ext2fs_statvfs(struct mount *mp, struct
fs->e2fs_itpg;
overhead = fs->e2fs.e2fs_first_dblock +
fs->e2fs_ncg * overhead_per_group;
- if (EXT2F_HAS_ROCOMPAT_FEATURE(fs, EXT2F_ROCOMPAT_SPARSESUPER)) {
+ if (EXT2F_HAS_COMPAT_FEATURE(fs, EXT2F_COMPAT_SPARSESUPER2)) {
+ /*
+ * Superblock and group descriptions is in group zero,
+ * then optionally 0, 1 or 2 extra copies.
+ */
+ ngroups = 1
+ + (fs->e2fs.e4fs_backup_bgs[0] ? 1 : 0)
+ + (fs->e2fs.e4fs_backup_bgs[1] ? 1 : 0);
+ } else if (EXT2F_HAS_ROCOMPAT_FEATURE(fs, EXT2F_ROCOMPAT_SPARSESUPER)) {
for (i = 0, ngroups = 0; i < fs->e2fs_ncg; i++) {
if (cg_has_sb(i))
ngroups++;