Home | History | Annotate | Line # | Download | only in ext2fs
ext2fs_alloc.c revision 1.57
      1  1.57   msaitoh /*	$NetBSD: ext2fs_alloc.c,v 1.57 2024/05/13 00:24:19 msaitoh Exp $	*/
      2   1.1    bouyer 
      3   1.1    bouyer /*
      4   1.1    bouyer  * Copyright (c) 1982, 1986, 1989, 1993
      5   1.1    bouyer  *	The Regents of the University of California.  All rights reserved.
      6   1.1    bouyer  *
      7   1.1    bouyer  * Redistribution and use in source and binary forms, with or without
      8   1.1    bouyer  * modification, are permitted provided that the following conditions
      9   1.1    bouyer  * are met:
     10   1.1    bouyer  * 1. Redistributions of source code must retain the above copyright
     11   1.1    bouyer  *    notice, this list of conditions and the following disclaimer.
     12   1.1    bouyer  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1    bouyer  *    notice, this list of conditions and the following disclaimer in the
     14   1.1    bouyer  *    documentation and/or other materials provided with the distribution.
     15  1.20       agc  * 3. Neither the name of the University nor the names of its contributors
     16  1.20       agc  *    may be used to endorse or promote products derived from this software
     17  1.20       agc  *    without specific prior written permission.
     18  1.20       agc  *
     19  1.20       agc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  1.20       agc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  1.20       agc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  1.20       agc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  1.20       agc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  1.20       agc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  1.20       agc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  1.20       agc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  1.20       agc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  1.20       agc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  1.20       agc  * SUCH DAMAGE.
     30  1.20       agc  *
     31  1.20       agc  *	@(#)ffs_alloc.c	8.11 (Berkeley) 10/27/94
     32  1.20       agc  *  Modified for ext2fs by Manuel Bouyer.
     33  1.20       agc  */
     34  1.20       agc 
     35  1.20       agc /*
     36  1.20       agc  * Copyright (c) 1997 Manuel Bouyer.
     37  1.20       agc  *
     38  1.20       agc  * Redistribution and use in source and binary forms, with or without
     39  1.20       agc  * modification, are permitted provided that the following conditions
     40  1.20       agc  * are met:
     41  1.20       agc  * 1. Redistributions of source code must retain the above copyright
     42  1.20       agc  *    notice, this list of conditions and the following disclaimer.
     43  1.20       agc  * 2. Redistributions in binary form must reproduce the above copyright
     44  1.20       agc  *    notice, this list of conditions and the following disclaimer in the
     45  1.20       agc  *    documentation and/or other materials provided with the distribution.
     46   1.1    bouyer  *
     47  1.22    bouyer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     48  1.22    bouyer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     49  1.22    bouyer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     50  1.22    bouyer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     51  1.22    bouyer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     52  1.22    bouyer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     53  1.22    bouyer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     54  1.22    bouyer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     55  1.22    bouyer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     56  1.22    bouyer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     57   1.1    bouyer  *
     58   1.1    bouyer  *	@(#)ffs_alloc.c	8.11 (Berkeley) 10/27/94
     59   1.1    bouyer  *  Modified for ext2fs by Manuel Bouyer.
     60   1.1    bouyer  */
     61  1.13     lukem 
     62  1.13     lukem #include <sys/cdefs.h>
     63  1.57   msaitoh __KERNEL_RCSID(0, "$NetBSD: ext2fs_alloc.c,v 1.57 2024/05/13 00:24:19 msaitoh Exp $");
     64   1.1    bouyer 
     65   1.1    bouyer #include <sys/param.h>
     66   1.1    bouyer #include <sys/systm.h>
     67   1.1    bouyer #include <sys/buf.h>
     68   1.1    bouyer #include <sys/proc.h>
     69   1.1    bouyer #include <sys/vnode.h>
     70   1.1    bouyer #include <sys/mount.h>
     71   1.1    bouyer #include <sys/kernel.h>
     72   1.1    bouyer #include <sys/syslog.h>
     73  1.29      elad #include <sys/kauth.h>
     74   1.1    bouyer 
     75  1.49  jdolecek #include <lib/libkern/crc16.h>
     76  1.49  jdolecek 
     77   1.1    bouyer #include <ufs/ufs/inode.h>
     78   1.1    bouyer #include <ufs/ufs/ufs_extern.h>
     79  1.27      yamt #include <ufs/ufs/ufsmount.h>
     80   1.1    bouyer 
     81   1.1    bouyer #include <ufs/ext2fs/ext2fs.h>
     82   1.1    bouyer #include <ufs/ext2fs/ext2fs_extern.h>
     83   1.1    bouyer 
     84   1.1    bouyer u_long ext2gennumber;
     85   1.1    bouyer 
     86  1.26   xtraeme static daddr_t	ext2fs_alloccg(struct inode *, int, daddr_t, int);
     87  1.26   xtraeme static u_long	ext2fs_dirpref(struct m_ext2fs *);
     88  1.26   xtraeme static void	ext2fs_fserr(struct m_ext2fs *, u_int, const char *);
     89  1.26   xtraeme static u_long	ext2fs_hashalloc(struct inode *, int, long, int,
     90  1.40   tsutsui 		    daddr_t (*)(struct inode *, int, daddr_t, int));
     91  1.26   xtraeme static daddr_t	ext2fs_nodealloccg(struct inode *, int, daddr_t, int);
     92  1.26   xtraeme static daddr_t	ext2fs_mapsearch(struct m_ext2fs *, char *, daddr_t);
     93  1.53  christos static __inline void	ext2fs_cg_update(struct m_ext2fs *, int,
     94  1.53  christos     struct ext2_gd *, int, int, int, daddr_t);
     95  1.53  christos static uint16_t ext2fs_cg_get_csum(struct m_ext2fs *, int, struct ext2_gd *);
     96  1.53  christos static void	ext2fs_init_bb(struct m_ext2fs *, int, struct ext2_gd *,
     97  1.53  christos     char *);
     98   1.1    bouyer 
     99   1.1    bouyer /*
    100   1.1    bouyer  * Allocate a block in the file system.
    101  1.23     perry  *
    102   1.1    bouyer  * A preference may be optionally specified. If a preference is given
    103   1.1    bouyer  * the following hierarchy is used to allocate a block:
    104   1.1    bouyer  *   1) allocate the requested block.
    105   1.1    bouyer  *   2) allocate a rotationally optimal block in the same cylinder.
    106   1.1    bouyer  *   3) allocate a block in the same cylinder group.
    107   1.1    bouyer  *   4) quadradically rehash into other cylinder groups, until an
    108   1.1    bouyer  *	  available block is located.
    109  1.11       wiz  * If no block preference is given the following hierarchy is used
    110   1.1    bouyer  * to allocate a block:
    111   1.1    bouyer  *   1) allocate a block in the cylinder group that contains the
    112   1.1    bouyer  *	  inode for the file.
    113   1.1    bouyer  *   2) quadradically rehash into other cylinder groups, until an
    114   1.1    bouyer  *	  available block is located.
    115   1.1    bouyer  */
    116   1.1    bouyer int
    117  1.32  christos ext2fs_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref,
    118  1.31  christos     kauth_cred_t cred, daddr_t *bnp)
    119   1.1    bouyer {
    120   1.7  augustss 	struct m_ext2fs *fs;
    121  1.15      fvdl 	daddr_t bno;
    122   1.1    bouyer 	int cg;
    123  1.23     perry 
    124   1.1    bouyer 	*bnp = 0;
    125   1.1    bouyer 	fs = ip->i_e2fs;
    126   1.1    bouyer #ifdef DIAGNOSTIC
    127   1.1    bouyer 	if (cred == NOCRED)
    128  1.14    provos 		panic("ext2fs_alloc: missing credential");
    129   1.1    bouyer #endif /* DIAGNOSTIC */
    130   1.1    bouyer 	if (fs->e2fs.e2fs_fbcount == 0)
    131   1.1    bouyer 		goto nospace;
    132  1.39      elad 	if (kauth_authorize_system(cred, KAUTH_SYSTEM_FS_RESERVEDSPACE, 0, NULL,
    133  1.39      elad 	    NULL, NULL) != 0 &&
    134  1.34      elad 	    freespace(fs) <= 0)
    135   1.1    bouyer 		goto nospace;
    136   1.1    bouyer 	if (bpref >= fs->e2fs.e2fs_bcount)
    137   1.1    bouyer 		bpref = 0;
    138   1.1    bouyer 	if (bpref == 0)
    139   1.1    bouyer 		cg = ino_to_cg(fs, ip->i_number);
    140   1.1    bouyer 	else
    141   1.1    bouyer 		cg = dtog(fs, bpref);
    142  1.15      fvdl 	bno = (daddr_t)ext2fs_hashalloc(ip, cg, bpref, fs->e2fs_bsize,
    143  1.40   tsutsui 	    ext2fs_alloccg);
    144   1.1    bouyer 	if (bno > 0) {
    145  1.43  jakllsch 		ext2fs_setnblock(ip, ext2fs_nblock(ip) + btodb(fs->e2fs_bsize));
    146   1.1    bouyer 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
    147   1.1    bouyer 		*bnp = bno;
    148  1.48  christos 		return 0;
    149   1.1    bouyer 	}
    150   1.1    bouyer nospace:
    151  1.29      elad 	ext2fs_fserr(fs, kauth_cred_geteuid(cred), "file system full");
    152   1.1    bouyer 	uprintf("\n%s: write failed, file system is full\n", fs->e2fs_fsmnt);
    153  1.48  christos 	return ENOSPC;
    154   1.1    bouyer }
    155   1.1    bouyer 
    156   1.1    bouyer /*
    157   1.1    bouyer  * Allocate an inode in the file system.
    158  1.23     perry  *
    159   1.1    bouyer  * If allocating a directory, use ext2fs_dirpref to select the inode.
    160   1.1    bouyer  * If allocating in a directory, the following hierarchy is followed:
    161   1.1    bouyer  *   1) allocate the preferred inode.
    162   1.1    bouyer  *   2) allocate an inode in the same cylinder group.
    163   1.1    bouyer  *   3) quadradically rehash into other cylinder groups, until an
    164   1.1    bouyer  *	  available inode is located.
    165  1.11       wiz  * If no inode preference is given the following hierarchy is used
    166   1.1    bouyer  * to allocate an inode:
    167   1.1    bouyer  *   1) allocate an inode in cylinder group 0.
    168   1.1    bouyer  *   2) quadradically rehash into other cylinder groups, until an
    169   1.1    bouyer  *	  available inode is located.
    170   1.1    bouyer  */
    171   1.1    bouyer int
    172  1.52   hannken ext2fs_valloc(struct vnode *pvp, int mode, kauth_cred_t cred, ino_t *inop)
    173   1.1    bouyer {
    174   1.7  augustss 	struct inode *pip;
    175   1.7  augustss 	struct m_ext2fs *fs;
    176   1.1    bouyer 	ino_t ino, ipref;
    177  1.52   hannken 	int cg;
    178  1.23     perry 
    179   1.1    bouyer 	pip = VTOI(pvp);
    180   1.1    bouyer 	fs = pip->i_e2fs;
    181   1.1    bouyer 	if (fs->e2fs.e2fs_ficount == 0)
    182   1.1    bouyer 		goto noinodes;
    183   1.1    bouyer 
    184   1.1    bouyer 	if ((mode & IFMT) == IFDIR)
    185   1.1    bouyer 		cg = ext2fs_dirpref(fs);
    186   1.1    bouyer 	else
    187   1.1    bouyer 		cg = ino_to_cg(fs, pip->i_number);
    188   1.1    bouyer 	ipref = cg * fs->e2fs.e2fs_ipg + 1;
    189   1.1    bouyer 	ino = (ino_t)ext2fs_hashalloc(pip, cg, (long)ipref, mode, ext2fs_nodealloccg);
    190   1.1    bouyer 	if (ino == 0)
    191   1.1    bouyer 		goto noinodes;
    192  1.49  jdolecek 
    193  1.52   hannken 	*inop = ino;
    194  1.52   hannken 	return 0;
    195   1.1    bouyer 
    196   1.1    bouyer noinodes:
    197  1.29      elad 	ext2fs_fserr(fs, kauth_cred_geteuid(cred), "out of inodes");
    198   1.1    bouyer 	uprintf("\n%s: create/symlink failed, no inodes free\n", fs->e2fs_fsmnt);
    199  1.48  christos 	return ENOSPC;
    200   1.1    bouyer }
    201   1.1    bouyer 
    202   1.1    bouyer /*
    203   1.1    bouyer  * Find a cylinder to place a directory.
    204   1.1    bouyer  *
    205   1.1    bouyer  * The policy implemented by this algorithm is to select from
    206   1.1    bouyer  * among those cylinder groups with above the average number of
    207   1.1    bouyer  * free inodes, the one with the smallest number of directories.
    208   1.1    bouyer  */
    209   1.1    bouyer static u_long
    210  1.26   xtraeme ext2fs_dirpref(struct m_ext2fs *fs)
    211   1.1    bouyer {
    212   1.1    bouyer 	int cg, maxspace, mincg, avgifree;
    213   1.1    bouyer 
    214   1.1    bouyer 	avgifree = fs->e2fs.e2fs_ficount / fs->e2fs_ncg;
    215   1.1    bouyer 	maxspace = 0;
    216   1.1    bouyer 	mincg = -1;
    217  1.53  christos 	for (cg = 0; cg < fs->e2fs_ncg; cg++) {
    218  1.53  christos 		uint32_t nifree =
    219  1.53  christos 		    (fs2h16(fs->e2fs_gd[cg].ext2bgd_nifree_hi) << 16)
    220  1.53  christos 		    | fs2h16(fs->e2fs_gd[cg].ext2bgd_nifree);
    221  1.53  christos 		if (nifree < avgifree) {
    222  1.53  christos 			continue;
    223  1.53  christos 		}
    224  1.53  christos 		uint32_t nbfree =
    225  1.53  christos 		    (fs2h16(fs->e2fs_gd[cg].ext2bgd_nbfree_hi) << 16)
    226  1.53  christos 		    | fs2h16(fs->e2fs_gd[cg].ext2bgd_nbfree);
    227  1.53  christos 		if (mincg == -1 || nbfree > maxspace) {
    228  1.53  christos 			mincg = cg;
    229  1.53  christos 			maxspace = nbfree;
    230   1.1    bouyer 		}
    231  1.53  christos 	}
    232   1.1    bouyer 	return mincg;
    233   1.1    bouyer }
    234   1.1    bouyer 
    235   1.1    bouyer /*
    236   1.1    bouyer  * Select the desired position for the next block in a file.  The file is
    237   1.1    bouyer  * logically divided into sections. The first section is composed of the
    238   1.1    bouyer  * direct blocks. Each additional section contains fs_maxbpg blocks.
    239  1.23     perry  *
    240   1.1    bouyer  * If no blocks have been allocated in the first section, the policy is to
    241   1.1    bouyer  * request a block in the same cylinder group as the inode that describes
    242   1.1    bouyer  * the file. Otherwise, the policy is to try to allocate the blocks
    243  1.57   msaitoh  * contiguously. The two fields of the ext2 inode extension (see
    244   1.1    bouyer  * ufs/ufs/inode.h) help this.
    245   1.1    bouyer  */
    246  1.15      fvdl daddr_t
    247  1.26   xtraeme ext2fs_blkpref(struct inode *ip, daddr_t lbn, int indx,
    248  1.26   xtraeme 		int32_t *bap /* XXX ondisk32 */)
    249   1.1    bouyer {
    250   1.7  augustss 	struct m_ext2fs *fs;
    251   1.7  augustss 	int cg, i;
    252   1.1    bouyer 
    253   1.1    bouyer 	fs = ip->i_e2fs;
    254   1.1    bouyer 	/*
    255   1.1    bouyer 	 * if we are doing contigous lbn allocation, try to alloc blocks
    256   1.1    bouyer 	 * contigously on disk
    257   1.1    bouyer 	 */
    258   1.1    bouyer 
    259   1.1    bouyer 	if ( ip->i_e2fs_last_blk && lbn == ip->i_e2fs_last_lblk + 1) {
    260   1.1    bouyer 		return ip->i_e2fs_last_blk + 1;
    261   1.1    bouyer 	}
    262   1.1    bouyer 
    263   1.1    bouyer 	/*
    264   1.1    bouyer 	 * bap, if provided, gives us a list of blocks to which we want to
    265   1.1    bouyer 	 * stay close
    266   1.1    bouyer 	 */
    267   1.1    bouyer 
    268   1.1    bouyer 	if (bap) {
    269   1.1    bouyer 		for (i = indx; i >= 0 ; i--) {
    270   1.1    bouyer 			if (bap[i]) {
    271   1.2    bouyer 				return fs2h32(bap[i]) + 1;
    272   1.1    bouyer 			}
    273   1.1    bouyer 		}
    274   1.1    bouyer 	}
    275   1.1    bouyer 
    276   1.1    bouyer 	/* fall back to the first block of the cylinder containing the inode */
    277   1.1    bouyer 
    278   1.1    bouyer 	cg = ino_to_cg(fs, ip->i_number);
    279   1.1    bouyer 	return fs->e2fs.e2fs_bpg * cg + fs->e2fs.e2fs_first_dblock + 1;
    280   1.1    bouyer }
    281   1.1    bouyer 
    282   1.1    bouyer /*
    283   1.1    bouyer  * Implement the cylinder overflow algorithm.
    284   1.1    bouyer  *
    285   1.1    bouyer  * The policy implemented by this algorithm is:
    286   1.1    bouyer  *   1) allocate the block in its requested cylinder group.
    287   1.1    bouyer  *   2) quadradically rehash on the cylinder group number.
    288   1.1    bouyer  *   3) brute force search for a free block.
    289   1.1    bouyer  */
    290   1.1    bouyer static u_long
    291  1.26   xtraeme ext2fs_hashalloc(struct inode *ip, int cg, long pref, int size,
    292  1.26   xtraeme 		daddr_t (*allocator)(struct inode *, int, daddr_t, int))
    293   1.1    bouyer {
    294   1.7  augustss 	struct m_ext2fs *fs;
    295   1.1    bouyer 	long result;
    296   1.1    bouyer 	int i, icg = cg;
    297   1.1    bouyer 
    298   1.1    bouyer 	fs = ip->i_e2fs;
    299   1.1    bouyer 	/*
    300   1.1    bouyer 	 * 1: preferred cylinder group
    301   1.1    bouyer 	 */
    302   1.1    bouyer 	result = (*allocator)(ip, cg, pref, size);
    303   1.1    bouyer 	if (result)
    304  1.48  christos 		return result;
    305   1.1    bouyer 	/*
    306   1.1    bouyer 	 * 2: quadratic rehash
    307   1.1    bouyer 	 */
    308   1.1    bouyer 	for (i = 1; i < fs->e2fs_ncg; i *= 2) {
    309   1.1    bouyer 		cg += i;
    310   1.1    bouyer 		if (cg >= fs->e2fs_ncg)
    311   1.1    bouyer 			cg -= fs->e2fs_ncg;
    312   1.1    bouyer 		result = (*allocator)(ip, cg, 0, size);
    313   1.1    bouyer 		if (result)
    314  1.48  christos 			return result;
    315   1.1    bouyer 	}
    316   1.1    bouyer 	/*
    317   1.1    bouyer 	 * 3: brute force search
    318   1.1    bouyer 	 * Note that we start at i == 2, since 0 was checked initially,
    319   1.1    bouyer 	 * and 1 is always checked in the quadratic rehash.
    320   1.1    bouyer 	 */
    321   1.1    bouyer 	cg = (icg + 2) % fs->e2fs_ncg;
    322   1.1    bouyer 	for (i = 2; i < fs->e2fs_ncg; i++) {
    323   1.1    bouyer 		result = (*allocator)(ip, cg, 0, size);
    324   1.1    bouyer 		if (result)
    325  1.48  christos 			return result;
    326   1.1    bouyer 		cg++;
    327   1.1    bouyer 		if (cg == fs->e2fs_ncg)
    328   1.1    bouyer 			cg = 0;
    329   1.1    bouyer 	}
    330  1.48  christos 	return 0;
    331   1.1    bouyer }
    332   1.1    bouyer 
    333   1.1    bouyer /*
    334   1.1    bouyer  * Determine whether a block can be allocated.
    335   1.1    bouyer  *
    336   1.1    bouyer  * Check to see if a block of the appropriate size is available,
    337   1.1    bouyer  * and if it is, allocate it.
    338   1.1    bouyer  */
    339   1.1    bouyer 
    340  1.15      fvdl static daddr_t
    341  1.32  christos ext2fs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size)
    342   1.1    bouyer {
    343   1.7  augustss 	struct m_ext2fs *fs;
    344   1.7  augustss 	char *bbp;
    345   1.1    bouyer 	struct buf *bp;
    346   1.1    bouyer 	int error, bno, start, end, loc;
    347   1.1    bouyer 
    348   1.1    bouyer 	fs = ip->i_e2fs;
    349  1.53  christos 	if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0 &&
    350  1.53  christos 	    fs->e2fs_gd[cg].ext2bgd_nbfree_hi == 0)
    351  1.48  christos 		return 0;
    352  1.53  christos 	error = bread(ip->i_devvp, EXT2_FSBTODB64(fs,
    353  1.53  christos 		fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap),
    354  1.53  christos 		fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap_hi)),
    355  1.46      maxv 		(int)fs->e2fs_bsize, B_MODIFY, &bp);
    356   1.1    bouyer 	if (error) {
    357  1.48  christos 		return 0;
    358   1.1    bouyer 	}
    359   1.1    bouyer 	bbp = (char *)bp->b_data;
    360   1.1    bouyer 
    361   1.1    bouyer 	if (dtog(fs, bpref) != cg)
    362   1.1    bouyer 		bpref = 0;
    363  1.49  jdolecek 
    364  1.49  jdolecek 	/* initialize block bitmap now if uninit */
    365  1.49  jdolecek 	if (__predict_false(E2FS_HAS_GD_CSUM(fs) &&
    366  1.49  jdolecek 	    (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_BLOCK_UNINIT)))) {
    367  1.49  jdolecek 		ext2fs_init_bb(fs, cg, &fs->e2fs_gd[cg], bbp);
    368  1.49  jdolecek 		fs->e2fs_gd[cg].ext2bgd_flags &= h2fs16(~E2FS_BG_BLOCK_UNINIT);
    369  1.49  jdolecek 	}
    370  1.49  jdolecek 
    371   1.1    bouyer 	if (bpref != 0) {
    372   1.1    bouyer 		bpref = dtogd(fs, bpref);
    373   1.1    bouyer 		/*
    374   1.1    bouyer 		 * if the requested block is available, use it
    375   1.1    bouyer 		 */
    376   1.1    bouyer 		if (isclr(bbp, bpref)) {
    377   1.1    bouyer 			bno = bpref;
    378   1.1    bouyer 			goto gotit;
    379   1.1    bouyer 		}
    380   1.1    bouyer 	}
    381   1.1    bouyer 	/*
    382   1.1    bouyer 	 * no blocks in the requested cylinder, so take next
    383   1.1    bouyer 	 * available one in this cylinder group.
    384   1.1    bouyer 	 * first try to get 8 contigous blocks, then fall back to a single
    385   1.1    bouyer 	 * block.
    386   1.1    bouyer 	 */
    387   1.1    bouyer 	if (bpref)
    388   1.1    bouyer 		start = dtogd(fs, bpref) / NBBY;
    389   1.1    bouyer 	else
    390   1.1    bouyer 		start = 0;
    391   1.1    bouyer 	end = howmany(fs->e2fs.e2fs_fpg, NBBY) - start;
    392   1.1    bouyer 	for (loc = start; loc < end; loc++) {
    393   1.1    bouyer 		if (bbp[loc] == 0) {
    394   1.1    bouyer 			bno = loc * NBBY;
    395   1.1    bouyer 			goto gotit;
    396   1.1    bouyer 		}
    397   1.1    bouyer 	}
    398   1.1    bouyer 	for (loc = 0; loc < start; loc++) {
    399   1.1    bouyer 		if (bbp[loc] == 0) {
    400   1.1    bouyer 			bno = loc * NBBY;
    401   1.1    bouyer 			goto gotit;
    402   1.1    bouyer 		}
    403   1.1    bouyer 	}
    404   1.1    bouyer 
    405   1.1    bouyer 	bno = ext2fs_mapsearch(fs, bbp, bpref);
    406  1.50  jdolecek #if 0
    407  1.51  jdolecek 	/*
    408  1.51  jdolecek 	 * XXX jdolecek mapsearch actually never fails, it panics instead.
    409  1.51  jdolecek 	 * If re-enabling, make sure to brele() before returning.
    410  1.51  jdolecek 	 */
    411   1.1    bouyer 	if (bno < 0)
    412  1.48  christos 		return 0;
    413  1.50  jdolecek #endif
    414   1.1    bouyer gotit:
    415   1.1    bouyer #ifdef DIAGNOSTIC
    416  1.15      fvdl 	if (isset(bbp, (daddr_t)bno)) {
    417  1.53  christos 		printf("%s: cg=%d bno=%d fs=%s\n", __func__,
    418  1.53  christos 		    cg, bno, fs->e2fs_fsmnt);
    419   1.2    bouyer 		panic("ext2fs_alloccg: dup alloc");
    420   1.1    bouyer 	}
    421   1.1    bouyer #endif
    422  1.15      fvdl 	setbit(bbp, (daddr_t)bno);
    423   1.1    bouyer 	fs->e2fs.e2fs_fbcount--;
    424  1.49  jdolecek 	ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg], -1, 0, 0, 0);
    425   1.1    bouyer 	fs->e2fs_fmod = 1;
    426   1.1    bouyer 	bdwrite(bp);
    427  1.48  christos 	return cg * fs->e2fs.e2fs_fpg + fs->e2fs.e2fs_first_dblock + bno;
    428   1.1    bouyer }
    429   1.1    bouyer 
    430   1.1    bouyer /*
    431   1.1    bouyer  * Determine whether an inode can be allocated.
    432   1.1    bouyer  *
    433   1.1    bouyer  * Check to see if an inode is available, and if it is,
    434   1.1    bouyer  * allocate it using the following policy:
    435   1.1    bouyer  *   1) allocate the requested inode.
    436   1.1    bouyer  *   2) allocate the next available inode after the requested
    437   1.1    bouyer  *	  inode in the specified cylinder group.
    438   1.1    bouyer  */
    439  1.15      fvdl static daddr_t
    440  1.26   xtraeme ext2fs_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode)
    441   1.1    bouyer {
    442   1.7  augustss 	struct m_ext2fs *fs;
    443   1.7  augustss 	char *ibp;
    444   1.1    bouyer 	struct buf *bp;
    445   1.1    bouyer 	int error, start, len, loc, map, i;
    446   1.1    bouyer 
    447   1.1    bouyer 	ipref--; /* to avoid a lot of (ipref -1) */
    448  1.33       chs 	if (ipref == -1)
    449  1.33       chs 		ipref = 0;
    450   1.1    bouyer 	fs = ip->i_e2fs;
    451  1.56  christos 	if (fs->e2fs_gd[cg].ext2bgd_nifree == 0 &&
    452  1.53  christos 	    fs->e2fs_gd[cg].ext2bgd_nifree_hi == 0)
    453  1.48  christos 		return 0;
    454  1.53  christos 	error = bread(ip->i_devvp, EXT2_FSBTODB64(fs,
    455  1.53  christos 		fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap),
    456  1.53  christos 		fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap_hi)),
    457  1.46      maxv 		(int)fs->e2fs_bsize, B_MODIFY, &bp);
    458   1.1    bouyer 	if (error) {
    459  1.48  christos 		return 0;
    460   1.1    bouyer 	}
    461   1.1    bouyer 	ibp = (char *)bp->b_data;
    462  1.49  jdolecek 
    463  1.49  jdolecek 	KASSERT(!E2FS_HAS_GD_CSUM(fs) || (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_INODE_ZEROED)) != 0);
    464  1.49  jdolecek 
    465  1.49  jdolecek 	/* initialize inode bitmap now if uninit */
    466  1.49  jdolecek 	if (__predict_false(E2FS_HAS_GD_CSUM(fs) &&
    467  1.49  jdolecek 	    (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_INODE_UNINIT)))) {
    468  1.49  jdolecek 		KASSERT(fs2h16(fs->e2fs_gd[cg].ext2bgd_nifree) == fs->e2fs.e2fs_ipg);
    469  1.49  jdolecek 		memset(ibp, 0, fs->e2fs_bsize);
    470  1.49  jdolecek 		fs->e2fs_gd[cg].ext2bgd_flags &= h2fs16(~E2FS_BG_INODE_UNINIT);
    471  1.49  jdolecek 	}
    472  1.49  jdolecek 
    473   1.1    bouyer 	if (ipref) {
    474   1.1    bouyer 		ipref %= fs->e2fs.e2fs_ipg;
    475   1.1    bouyer 		if (isclr(ibp, ipref))
    476   1.1    bouyer 			goto gotit;
    477   1.1    bouyer 	}
    478   1.1    bouyer 	start = ipref / NBBY;
    479   1.1    bouyer 	len = howmany(fs->e2fs.e2fs_ipg - ipref, NBBY);
    480   1.1    bouyer 	loc = skpc(0xff, len, &ibp[start]);
    481   1.1    bouyer 	if (loc == 0) {
    482   1.1    bouyer 		len = start + 1;
    483   1.1    bouyer 		start = 0;
    484   1.1    bouyer 		loc = skpc(0xff, len, &ibp[0]);
    485   1.1    bouyer 		if (loc == 0) {
    486  1.53  christos 			printf("%s: cg = %d, ipref = %lld, fs = %s\n", __func__,
    487  1.53  christos 			    cg, (long long)ipref, fs->e2fs_fsmnt);
    488  1.53  christos 			panic("%s: map corrupted", __func__);
    489   1.1    bouyer 			/* NOTREACHED */
    490   1.1    bouyer 		}
    491   1.1    bouyer 	}
    492   1.1    bouyer 	i = start + len - loc;
    493  1.42     rmind 	map = ibp[i] ^ 0xff;
    494  1.42     rmind 	if (map == 0) {
    495  1.53  christos 		printf("%s: fs = %s\n", __func__, fs->e2fs_fsmnt);
    496  1.53  christos 		panic("%s: inode not in map", __func__);
    497   1.1    bouyer 	}
    498  1.42     rmind 	ipref = i * NBBY + ffs(map) - 1;
    499   1.1    bouyer gotit:
    500   1.1    bouyer 	setbit(ibp, ipref);
    501   1.1    bouyer 	fs->e2fs.e2fs_ficount--;
    502  1.49  jdolecek 	ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg],
    503  1.49  jdolecek 		0, -1, ((mode & IFMT) == IFDIR) ? 1 : 0, ipref);
    504   1.1    bouyer 	fs->e2fs_fmod = 1;
    505   1.1    bouyer 	bdwrite(bp);
    506  1.48  christos 	return cg * fs->e2fs.e2fs_ipg + ipref + 1;
    507   1.1    bouyer }
    508   1.1    bouyer 
    509   1.1    bouyer /*
    510   1.1    bouyer  * Free a block.
    511   1.1    bouyer  *
    512   1.1    bouyer  * The specified block is placed back in the
    513   1.1    bouyer  * free map.
    514   1.1    bouyer  */
    515   1.1    bouyer void
    516  1.26   xtraeme ext2fs_blkfree(struct inode *ip, daddr_t bno)
    517   1.1    bouyer {
    518   1.7  augustss 	struct m_ext2fs *fs;
    519   1.7  augustss 	char *bbp;
    520   1.1    bouyer 	struct buf *bp;
    521   1.1    bouyer 	int error, cg;
    522   1.1    bouyer 
    523   1.1    bouyer 	fs = ip->i_e2fs;
    524   1.1    bouyer 	cg = dtog(fs, bno);
    525  1.49  jdolecek 
    526  1.53  christos 	KASSERT(!E2FS_HAS_GD_CSUM(fs) ||
    527  1.53  christos 	    (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_BLOCK_UNINIT)) == 0);
    528  1.49  jdolecek 
    529   1.1    bouyer 	if ((u_int)bno >= fs->e2fs.e2fs_bcount) {
    530  1.53  christos 		printf("%s: bad block %jd, ino %ju\n",
    531  1.53  christos 		    __func__, (intmax_t)bno, (uintmax_t)ip->i_number);
    532  1.37       mrg 		ext2fs_fserr(fs, ip->i_uid, "bad block");
    533   1.1    bouyer 		return;
    534   1.1    bouyer 	}
    535  1.53  christos 	error = bread(ip->i_devvp, EXT2_FSBTODB64(fs,
    536  1.53  christos 	    fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap),
    537  1.53  christos 	    fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap_hi)),
    538  1.53  christos 	    (int)fs->e2fs_bsize, B_MODIFY, &bp);
    539   1.1    bouyer 	if (error) {
    540   1.1    bouyer 		return;
    541   1.1    bouyer 	}
    542   1.1    bouyer 	bbp = (char *)bp->b_data;
    543   1.1    bouyer 	bno = dtogd(fs, bno);
    544   1.1    bouyer 	if (isclr(bbp, bno)) {
    545  1.53  christos 		printf("%s: dev = %#jx, block = %jd, fs = %s\n", __func__,
    546  1.53  christos 		    (uintmax_t)ip->i_dev, (intmax_t)bno,
    547  1.38  christos 		    fs->e2fs_fsmnt);
    548  1.53  christos 		panic("%s: freeing free block", __func__);
    549   1.1    bouyer 	}
    550   1.1    bouyer 	clrbit(bbp, bno);
    551   1.1    bouyer 	fs->e2fs.e2fs_fbcount++;
    552  1.49  jdolecek 	ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg], 1, 0, 0, 0);
    553   1.1    bouyer 	fs->e2fs_fmod = 1;
    554   1.1    bouyer 	bdwrite(bp);
    555   1.1    bouyer }
    556   1.1    bouyer 
    557   1.1    bouyer /*
    558   1.1    bouyer  * Free an inode.
    559   1.1    bouyer  *
    560   1.1    bouyer  * The specified inode is placed back in the free map.
    561   1.1    bouyer  */
    562   1.1    bouyer int
    563  1.27      yamt ext2fs_vfree(struct vnode *pvp, ino_t ino, int mode)
    564   1.1    bouyer {
    565   1.7  augustss 	struct m_ext2fs *fs;
    566   1.7  augustss 	char *ibp;
    567   1.7  augustss 	struct inode *pip;
    568   1.1    bouyer 	struct buf *bp;
    569   1.1    bouyer 	int error, cg;
    570   1.1    bouyer 
    571  1.27      yamt 	pip = VTOI(pvp);
    572   1.1    bouyer 	fs = pip->i_e2fs;
    573  1.49  jdolecek 
    574  1.33       chs 	if ((u_int)ino > fs->e2fs.e2fs_icount || (u_int)ino < EXT2_FIRSTINO)
    575  1.53  christos 		panic("%s: range: dev = %#jx, ino = %ju, fs = %s",
    576  1.53  christos 		    __func__, (uintmax_t)pip->i_dev, (uintmax_t)ino,
    577  1.38  christos 		    fs->e2fs_fsmnt);
    578  1.49  jdolecek 
    579   1.1    bouyer 	cg = ino_to_cg(fs, ino);
    580  1.49  jdolecek 
    581  1.53  christos 	KASSERT(!E2FS_HAS_GD_CSUM(fs) ||
    582  1.53  christos 	    (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_INODE_UNINIT)) == 0);
    583  1.49  jdolecek 
    584  1.53  christos 	error = bread(pip->i_devvp, EXT2_FSBTODB64(fs,
    585  1.53  christos 	    fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap),
    586  1.53  christos 	    fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap_hi)),
    587  1.53  christos 	    (int)fs->e2fs_bsize, B_MODIFY, &bp);
    588   1.1    bouyer 	if (error) {
    589  1.48  christos 		return 0;
    590   1.1    bouyer 	}
    591   1.1    bouyer 	ibp = (char *)bp->b_data;
    592   1.1    bouyer 	ino = (ino - 1) % fs->e2fs.e2fs_ipg;
    593   1.1    bouyer 	if (isclr(ibp, ino)) {
    594  1.53  christos 		printf("%s: dev = %#jx, ino = %ju, fs = %s\n", __func__,
    595  1.53  christos 		    (uintmax_t)pip->i_dev,
    596  1.53  christos 		    (uintmax_t)ino, fs->e2fs_fsmnt);
    597   1.1    bouyer 		if (fs->e2fs_ronly == 0)
    598  1.53  christos 			panic("%s: freeing free inode", __func__);
    599   1.1    bouyer 	}
    600   1.1    bouyer 	clrbit(ibp, ino);
    601   1.1    bouyer 	fs->e2fs.e2fs_ficount++;
    602  1.49  jdolecek 	ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg],
    603  1.49  jdolecek 		0, 1, ((mode & IFMT) == IFDIR) ? -1 : 0, 0);
    604   1.1    bouyer 	fs->e2fs_fmod = 1;
    605   1.1    bouyer 	bdwrite(bp);
    606  1.48  christos 	return 0;
    607   1.1    bouyer }
    608   1.1    bouyer 
    609   1.1    bouyer /*
    610   1.1    bouyer  * Find a block in the specified cylinder group.
    611   1.1    bouyer  *
    612   1.1    bouyer  * It is a panic if a request is made to find a block if none are
    613   1.1    bouyer  * available.
    614   1.1    bouyer  */
    615   1.1    bouyer 
    616  1.15      fvdl static daddr_t
    617  1.26   xtraeme ext2fs_mapsearch(struct m_ext2fs *fs, char *bbp, daddr_t bpref)
    618   1.1    bouyer {
    619   1.1    bouyer 	int start, len, loc, i, map;
    620   1.1    bouyer 
    621   1.1    bouyer 	/*
    622   1.1    bouyer 	 * find the fragment by searching through the free block
    623   1.1    bouyer 	 * map for an appropriate bit pattern
    624   1.1    bouyer 	 */
    625   1.1    bouyer 	if (bpref)
    626   1.1    bouyer 		start = dtogd(fs, bpref) / NBBY;
    627   1.1    bouyer 	else
    628   1.1    bouyer 		start = 0;
    629   1.1    bouyer 	len = howmany(fs->e2fs.e2fs_fpg, NBBY) - start;
    630   1.1    bouyer 	loc = skpc(0xff, len, &bbp[start]);
    631   1.1    bouyer 	if (loc == 0) {
    632   1.1    bouyer 		len = start + 1;
    633   1.1    bouyer 		start = 0;
    634   1.1    bouyer 		loc = skpc(0xff, len, &bbp[start]);
    635   1.1    bouyer 		if (loc == 0) {
    636  1.53  christos 			printf("%s: start = %d, len = %d, fs = %s\n",
    637  1.53  christos 			    __func__, start, len, fs->e2fs_fsmnt);
    638  1.53  christos 			panic("%s: map corrupted", __func__);
    639   1.1    bouyer 			/* NOTREACHED */
    640   1.1    bouyer 		}
    641   1.1    bouyer 	}
    642   1.1    bouyer 	i = start + len - loc;
    643  1.42     rmind 	map = bbp[i] ^ 0xff;
    644  1.42     rmind 	if (map == 0) {
    645  1.53  christos 		printf("%s: fs = %s\n", __func__, fs->e2fs_fsmnt);
    646  1.53  christos 		panic("%s: block not in map", __func__);
    647  1.42     rmind 	}
    648  1.42     rmind 	return i * NBBY + ffs(map) - 1;
    649   1.1    bouyer }
    650   1.1    bouyer 
    651   1.1    bouyer /*
    652   1.1    bouyer  * Fserr prints the name of a file system with an error diagnostic.
    653  1.23     perry  *
    654   1.1    bouyer  * The form of the error message is:
    655   1.1    bouyer  *	fs: error message
    656   1.1    bouyer  */
    657   1.1    bouyer static void
    658  1.26   xtraeme ext2fs_fserr(struct m_ext2fs *fs, u_int uid, const char *cp)
    659   1.1    bouyer {
    660   1.1    bouyer 
    661   1.1    bouyer 	log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->e2fs_fsmnt, cp);
    662   1.1    bouyer }
    663  1.49  jdolecek 
    664  1.49  jdolecek static __inline void
    665  1.49  jdolecek ext2fs_cg_update(struct m_ext2fs *fs, int cg, struct ext2_gd *gd, int nbfree, int nifree, int ndirs, daddr_t ioff)
    666  1.49  jdolecek {
    667  1.49  jdolecek 	if (nifree) {
    668  1.53  christos 		uint32_t ext2bgd_nifree = fs2h16(gd->ext2bgd_nifree) |
    669  1.53  christos 		    (fs2h16(gd->ext2bgd_nifree_hi) << 16);
    670  1.54  riastrad 		ext2bgd_nifree += nifree;
    671  1.53  christos 		gd->ext2bgd_nifree = h2fs16(ext2bgd_nifree);
    672  1.53  christos 		gd->ext2bgd_nifree_hi = h2fs16(ext2bgd_nifree >> 16);
    673  1.49  jdolecek 		/*
    674  1.49  jdolecek 		 * If we allocated inode on bigger offset than what was
    675  1.49  jdolecek 		 * ever used before, bump the itable_unused count. This
    676  1.49  jdolecek 		 * member only ever grows, and is used only for initialization
    677  1.49  jdolecek 		 * !INODE_ZEROED groups with used inodes. Of course, by the
    678  1.49  jdolecek 		 * time we get here the itables are already zeroed, but
    679  1.49  jdolecek 		 * e2fstools fsck.ext4 still checks this.
    680  1.49  jdolecek 		 */
    681  1.53  christos 		if (E2FS_HAS_GD_CSUM(fs) && nifree < 0 &&
    682  1.53  christos 		    (ioff + 1) >= (fs->e2fs.e2fs_ipg -
    683  1.53  christos 		    fs2h16(gd->ext2bgd_itable_unused_lo))) {
    684  1.53  christos 			gd->ext2bgd_itable_unused_lo =
    685  1.53  christos 			    h2fs16(fs->e2fs.e2fs_ipg - (ioff + 1));
    686  1.49  jdolecek 		}
    687  1.49  jdolecek 
    688  1.53  christos 		KASSERT(!E2FS_HAS_GD_CSUM(fs) ||
    689  1.53  christos 		    gd->ext2bgd_itable_unused_lo <= ext2bgd_nifree);
    690  1.49  jdolecek 	}
    691  1.49  jdolecek 
    692  1.49  jdolecek 
    693  1.53  christos 	if (nbfree) {
    694  1.53  christos 		uint32_t ext2bgd_nbfree = fs2h16(gd->ext2bgd_nbfree)
    695  1.53  christos 		    | (fs2h16(gd->ext2bgd_nbfree_hi) << 16);
    696  1.53  christos 		ext2bgd_nbfree += nbfree;
    697  1.53  christos 		gd->ext2bgd_nbfree = h2fs16(ext2bgd_nbfree);
    698  1.53  christos 		gd->ext2bgd_nbfree_hi = h2fs16(ext2bgd_nbfree >> 16);
    699  1.53  christos 	}
    700  1.53  christos 
    701  1.53  christos 	if (ndirs) {
    702  1.53  christos 		uint32_t ext2bgd_ndirs = fs2h16(gd->ext2bgd_ndirs)
    703  1.53  christos 		    | (fs2h16(gd->ext2bgd_ndirs_hi) << 16);
    704  1.53  christos 		ext2bgd_ndirs += ndirs;
    705  1.53  christos 		gd->ext2bgd_ndirs = h2fs16(ext2bgd_ndirs);
    706  1.53  christos 		gd->ext2bgd_ndirs_hi = h2fs16(ext2bgd_ndirs >> 16);
    707  1.53  christos 	}
    708  1.49  jdolecek 
    709  1.49  jdolecek 	if (E2FS_HAS_GD_CSUM(fs))
    710  1.49  jdolecek 		gd->ext2bgd_checksum = ext2fs_cg_get_csum(fs, cg, gd);
    711  1.49  jdolecek }
    712  1.49  jdolecek 
    713  1.55  christos static const uint32_t ext2fs_crc32c_table[256] = {
    714  1.55  christos 	0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4,
    715  1.55  christos 	0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
    716  1.55  christos 	0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
    717  1.55  christos 	0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
    718  1.55  christos 	0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b,
    719  1.55  christos 	0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
    720  1.55  christos 	0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54,
    721  1.55  christos 	0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
    722  1.55  christos 	0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
    723  1.55  christos 	0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
    724  1.55  christos 	0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5,
    725  1.55  christos 	0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
    726  1.55  christos 	0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45,
    727  1.55  christos 	0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
    728  1.55  christos 	0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
    729  1.55  christos 	0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
    730  1.55  christos 	0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48,
    731  1.55  christos 	0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
    732  1.55  christos 	0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687,
    733  1.55  christos 	0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
    734  1.55  christos 	0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
    735  1.55  christos 	0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
    736  1.55  christos 	0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8,
    737  1.55  christos 	0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
    738  1.55  christos 	0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096,
    739  1.55  christos 	0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
    740  1.55  christos 	0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
    741  1.55  christos 	0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
    742  1.55  christos 	0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9,
    743  1.55  christos 	0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
    744  1.55  christos 	0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36,
    745  1.55  christos 	0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
    746  1.55  christos 	0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
    747  1.55  christos 	0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
    748  1.55  christos 	0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043,
    749  1.55  christos 	0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
    750  1.55  christos 	0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3,
    751  1.55  christos 	0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
    752  1.55  christos 	0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
    753  1.55  christos 	0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
    754  1.55  christos 	0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652,
    755  1.55  christos 	0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
    756  1.55  christos 	0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d,
    757  1.55  christos 	0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
    758  1.55  christos 	0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
    759  1.55  christos 	0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
    760  1.55  christos 	0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2,
    761  1.55  christos 	0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
    762  1.55  christos 	0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530,
    763  1.55  christos 	0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
    764  1.55  christos 	0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
    765  1.55  christos 	0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
    766  1.55  christos 	0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f,
    767  1.55  christos 	0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
    768  1.55  christos 	0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90,
    769  1.55  christos 	0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
    770  1.55  christos 	0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
    771  1.55  christos 	0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
    772  1.55  christos 	0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321,
    773  1.55  christos 	0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
    774  1.55  christos 	0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81,
    775  1.55  christos 	0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
    776  1.55  christos 	0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
    777  1.55  christos 	0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351,
    778  1.55  christos };
    779  1.55  christos 
    780  1.55  christos static uint32_t
    781  1.55  christos ext2fs_crc32c(uint32_t last, const void *vbuf, size_t len)
    782  1.55  christos {
    783  1.55  christos 	uint32_t crc = last;
    784  1.55  christos 	const uint8_t *buf = vbuf;
    785  1.55  christos 
    786  1.55  christos 	while (len--)
    787  1.55  christos 		crc = ext2fs_crc32c_table[(crc ^ *buf++) & 0xff] ^ (crc >> 8);
    788  1.55  christos 
    789  1.55  christos 	return crc;
    790  1.55  christos }
    791  1.55  christos 
    792  1.49  jdolecek /*
    793  1.49  jdolecek  * Compute group description csum. Structure data must be LE (not host).
    794  1.49  jdolecek  * Returned as LE (disk encoding).
    795  1.49  jdolecek  */
    796  1.49  jdolecek static uint16_t
    797  1.49  jdolecek ext2fs_cg_get_csum(struct m_ext2fs *fs, int cg, struct ext2_gd *gd)
    798  1.49  jdolecek {
    799  1.49  jdolecek 	uint16_t crc;
    800  1.53  christos 	size_t cgsize = 1 << fs->e2fs_group_desc_shift;
    801  1.49  jdolecek 	uint32_t cg_bswapped = h2fs32((uint32_t)cg);
    802  1.49  jdolecek 	size_t off;
    803  1.49  jdolecek 
    804  1.55  christos 	if (EXT2F_HAS_ROCOMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
    805  1.55  christos 		uint32_t crc32;
    806  1.55  christos 		uint8_t dummy[2] = {0, 0};
    807  1.55  christos 
    808  1.55  christos 		off = offsetof(struct ext2_gd, ext2bgd_checksum);
    809  1.55  christos 
    810  1.55  christos 		crc32 = ext2fs_crc32c(~0, fs->e2fs.e2fs_uuid,
    811  1.55  christos 		    sizeof(fs->e2fs.e2fs_uuid));
    812  1.55  christos 		crc32 = ext2fs_crc32c(crc32, &cg_bswapped, sizeof(cg_bswapped));
    813  1.55  christos 		crc32 = ext2fs_crc32c(crc32, gd, off);
    814  1.55  christos 		crc32 = ext2fs_crc32c(crc32, dummy, 2);
    815  1.55  christos 		crc32 = ext2fs_crc32c(crc32, gd + off + 2, cgsize - (off + 2));
    816  1.55  christos 
    817  1.55  christos 		return h2fs16(crc32 & 0xffff);
    818  1.55  christos 	}
    819  1.55  christos 
    820  1.49  jdolecek 	if (!EXT2F_HAS_ROCOMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM))
    821  1.49  jdolecek 		return 0;
    822  1.49  jdolecek 
    823  1.49  jdolecek 	off = offsetof(struct ext2_gd, ext2bgd_checksum);
    824  1.49  jdolecek 
    825  1.55  christos 	crc = crc16(~0, (uint8_t *)fs->e2fs.e2fs_uuid,
    826  1.55  christos 	    sizeof(fs->e2fs.e2fs_uuid));
    827  1.49  jdolecek 	crc = crc16(crc, (uint8_t *)&cg_bswapped, sizeof(cg_bswapped));
    828  1.49  jdolecek 	crc = crc16(crc, (uint8_t *)gd, off);
    829  1.53  christos 	crc = crc16(crc, (uint8_t *)gd + off + 2, cgsize - (off + 2));
    830  1.49  jdolecek 
    831  1.49  jdolecek 	return h2fs16(crc);
    832  1.49  jdolecek }
    833  1.49  jdolecek 
    834  1.49  jdolecek static void
    835  1.49  jdolecek ext2fs_init_bb(struct m_ext2fs *fs, int cg, struct ext2_gd *gd, char *bbp)
    836  1.49  jdolecek {
    837  1.49  jdolecek 	int i;
    838  1.49  jdolecek 
    839  1.49  jdolecek 	memset(bbp, 0, fs->e2fs_bsize);
    840  1.49  jdolecek 
    841  1.49  jdolecek 	/*
    842  1.49  jdolecek 	 * No block was ever allocated on this cg before, so the only used
    843  1.49  jdolecek 	 * blocks are metadata blocks on start of the group. We could optimize
    844  1.49  jdolecek 	 * this to set by bytes, but since this is done once per the group
    845  1.49  jdolecek 	 * in lifetime of filesystem, it really is not worth it.
    846  1.49  jdolecek 	 */
    847  1.49  jdolecek 	for(i=0; i < fs->e2fs.e2fs_bpg - fs2h16(gd->ext2bgd_nbfree); i++)
    848  1.49  jdolecek 		setbit(bbp, i);
    849  1.49  jdolecek }
    850  1.49  jdolecek 
    851  1.49  jdolecek /*
    852  1.49  jdolecek  * Verify csum and initialize itable if not done already
    853  1.49  jdolecek  */
    854  1.49  jdolecek int
    855  1.49  jdolecek ext2fs_cg_verify_and_initialize(struct vnode *devvp, struct m_ext2fs *fs, int ronly)
    856  1.49  jdolecek {
    857  1.49  jdolecek 	struct ext2_gd *gd;
    858  1.49  jdolecek 	ino_t ioff;
    859  1.49  jdolecek 	size_t boff;
    860  1.49  jdolecek 	struct buf *bp;
    861  1.49  jdolecek 	int cg, i, error;
    862  1.49  jdolecek 
    863  1.49  jdolecek 	if (!E2FS_HAS_GD_CSUM(fs))
    864  1.49  jdolecek 		return 0;
    865  1.49  jdolecek 
    866  1.53  christos 	for(cg = 0; cg < fs->e2fs_ncg; cg++) {
    867  1.49  jdolecek 		gd = &fs->e2fs_gd[cg];
    868  1.49  jdolecek 
    869  1.49  jdolecek 		/* Verify checksum */
    870  1.53  christos 		uint16_t csum = ext2fs_cg_get_csum(fs, cg, gd);
    871  1.53  christos 		if (gd->ext2bgd_checksum != csum) {
    872  1.53  christos 			printf("%s: group %d invalid csum (%#x != %#x)\n",
    873  1.53  christos 			    __func__, cg, gd->ext2bgd_checksum, csum);
    874  1.49  jdolecek 			return EINVAL;
    875  1.49  jdolecek 		}
    876  1.49  jdolecek 
    877  1.49  jdolecek 		/* if mounting read-write, zero itable if not already done */
    878  1.53  christos 		if (ronly ||
    879  1.53  christos 		    (gd->ext2bgd_flags & h2fs16(E2FS_BG_INODE_ZEROED)) != 0)
    880  1.49  jdolecek 			continue;
    881  1.49  jdolecek 
    882  1.49  jdolecek 		/*
    883  1.49  jdolecek 		 * We are skipping already used inodes, zero rest of itable
    884  1.49  jdolecek 		 * blocks. First block to zero could be only partial wipe, all
    885  1.49  jdolecek 		 * others are wiped completely. This might take a while,
    886  1.49  jdolecek 		 * there could be many inode table blocks. We use
    887  1.49  jdolecek 		 * delayed writes, so this shouldn't block for very
    888  1.49  jdolecek 		 * long.
    889  1.49  jdolecek 		 */
    890  1.49  jdolecek 		ioff = fs->e2fs.e2fs_ipg - fs2h16(gd->ext2bgd_itable_unused_lo);
    891  1.49  jdolecek 		boff = (ioff % fs->e2fs_ipb) * EXT2_DINODE_SIZE(fs);
    892  1.49  jdolecek 
    893  1.49  jdolecek 		for(i = ioff / fs->e2fs_ipb; i < fs->e2fs_itpg; i++) {
    894  1.49  jdolecek 			if (boff) {
    895  1.49  jdolecek 				/* partial wipe, must read old data */
    896  1.53  christos 				error = bread(devvp, EXT2_FSBTODB64OFF(fs,
    897  1.53  christos 				    fs2h32(gd->ext2bgd_i_tables),
    898  1.53  christos 				    fs2h32(gd->ext2bgd_i_tables_hi), i),
    899  1.53  christos 				    (int)fs->e2fs_bsize, B_MODIFY, &bp);
    900  1.49  jdolecek 				if (error) {
    901  1.53  christos 					printf("%s: can't read itable block",
    902  1.53  christos 					    __func__);
    903  1.49  jdolecek 					return error;
    904  1.49  jdolecek 				}
    905  1.53  christos 				memset((char *)bp->b_data + boff, 0,
    906  1.53  christos 				    fs->e2fs_bsize - boff);
    907  1.49  jdolecek 				boff = 0;
    908  1.49  jdolecek 			} else {
    909  1.49  jdolecek 				/*
    910  1.49  jdolecek 				 * Complete wipe, don't need to read data. This
    911  1.49  jdolecek 				 * assumes nothing else is changing the data.
    912  1.49  jdolecek 				 */
    913  1.53  christos 				bp = getblk(devvp, EXT2_FSBTODB64OFF(fs,
    914  1.53  christos 				    fs2h32(gd->ext2bgd_i_tables),
    915  1.53  christos 				    fs2h32(gd->ext2bgd_i_tables_hi), i),
    916  1.53  christos 				    (int)fs->e2fs_bsize, 0, 0);
    917  1.49  jdolecek 				clrbuf(bp);
    918  1.49  jdolecek 			}
    919  1.54  riastrad 
    920  1.49  jdolecek 			bdwrite(bp);
    921  1.49  jdolecek 		}
    922  1.49  jdolecek 
    923  1.49  jdolecek 		gd->ext2bgd_flags |= h2fs16(E2FS_BG_INODE_ZEROED);
    924  1.49  jdolecek 		gd->ext2bgd_checksum = ext2fs_cg_get_csum(fs, cg, gd);
    925  1.49  jdolecek 		fs->e2fs_fmod = 1;
    926  1.49  jdolecek 	}
    927  1.49  jdolecek 
    928  1.49  jdolecek 	return 0;
    929  1.49  jdolecek }
    930