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