Home | History | Annotate | Line # | Download | only in ext2fs
ext2fs_alloc.c revision 1.26
      1 /*	$NetBSD: ext2fs_alloc.c,v 1.26 2005/08/30 22:01:12 xtraeme Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1982, 1986, 1989, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  *
     31  *	@(#)ffs_alloc.c	8.11 (Berkeley) 10/27/94
     32  *  Modified for ext2fs by Manuel Bouyer.
     33  */
     34 
     35 /*
     36  * Copyright (c) 1997 Manuel Bouyer.
     37  *
     38  * Redistribution and use in source and binary forms, with or without
     39  * modification, are permitted provided that the following conditions
     40  * are met:
     41  * 1. Redistributions of source code must retain the above copyright
     42  *    notice, this list of conditions and the following disclaimer.
     43  * 2. Redistributions in binary form must reproduce the above copyright
     44  *    notice, this list of conditions and the following disclaimer in the
     45  *    documentation and/or other materials provided with the distribution.
     46  * 3. All advertising materials mentioning features or use of this software
     47  *    must display the following acknowledgement:
     48  *	This product includes software developed by Manuel Bouyer.
     49  * 4. The name of the author may not be used to endorse or promote products
     50  *    derived from this software without specific prior written permission.
     51  *
     52  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     53  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     54  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     55  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     56  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     57  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     58  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     59  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     60  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     61  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     62  *
     63  *	@(#)ffs_alloc.c	8.11 (Berkeley) 10/27/94
     64  *  Modified for ext2fs by Manuel Bouyer.
     65  */
     66 
     67 #include <sys/cdefs.h>
     68 __KERNEL_RCSID(0, "$NetBSD: ext2fs_alloc.c,v 1.26 2005/08/30 22:01:12 xtraeme Exp $");
     69 
     70 #include <sys/param.h>
     71 #include <sys/systm.h>
     72 #include <sys/buf.h>
     73 #include <sys/proc.h>
     74 #include <sys/vnode.h>
     75 #include <sys/mount.h>
     76 #include <sys/kernel.h>
     77 #include <sys/syslog.h>
     78 
     79 #include <ufs/ufs/inode.h>
     80 #include <ufs/ufs/ufs_extern.h>
     81 
     82 #include <ufs/ext2fs/ext2fs.h>
     83 #include <ufs/ext2fs/ext2fs_extern.h>
     84 
     85 u_long ext2gennumber;
     86 
     87 static daddr_t	ext2fs_alloccg(struct inode *, int, daddr_t, int);
     88 static u_long	ext2fs_dirpref(struct m_ext2fs *);
     89 static void	ext2fs_fserr(struct m_ext2fs *, u_int, const char *);
     90 static u_long	ext2fs_hashalloc(struct inode *, int, long, int,
     91 				   daddr_t (*)(struct inode *, int, daddr_t,
     92 						   int));
     93 static daddr_t	ext2fs_nodealloccg(struct inode *, int, daddr_t, int);
     94 static daddr_t	ext2fs_mapsearch(struct m_ext2fs *, char *, daddr_t);
     95 
     96 /*
     97  * Allocate a block in the file system.
     98  *
     99  * A preference may be optionally specified. If a preference is given
    100  * the following hierarchy is used to allocate a block:
    101  *   1) allocate the requested block.
    102  *   2) allocate a rotationally optimal block in the same cylinder.
    103  *   3) allocate a block in the same cylinder group.
    104  *   4) quadradically rehash into other cylinder groups, until an
    105  *	  available block is located.
    106  * If no block preference is given the following hierarchy is used
    107  * to allocate a block:
    108  *   1) allocate a block in the cylinder group that contains the
    109  *	  inode for the file.
    110  *   2) quadradically rehash into other cylinder groups, until an
    111  *	  available block is located.
    112  */
    113 int
    114 ext2fs_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref, struct ucred *cred,
    115 		daddr_t *bnp)
    116 {
    117 	struct m_ext2fs *fs;
    118 	daddr_t bno;
    119 	int cg;
    120 
    121 	*bnp = 0;
    122 	fs = ip->i_e2fs;
    123 #ifdef DIAGNOSTIC
    124 	if (cred == NOCRED)
    125 		panic("ext2fs_alloc: missing credential");
    126 #endif /* DIAGNOSTIC */
    127 	if (fs->e2fs.e2fs_fbcount == 0)
    128 		goto nospace;
    129 	if (cred->cr_uid != 0 && freespace(fs) <= 0)
    130 		goto nospace;
    131 	if (bpref >= fs->e2fs.e2fs_bcount)
    132 		bpref = 0;
    133 	if (bpref == 0)
    134 		cg = ino_to_cg(fs, ip->i_number);
    135 	else
    136 		cg = dtog(fs, bpref);
    137 	bno = (daddr_t)ext2fs_hashalloc(ip, cg, bpref, fs->e2fs_bsize,
    138 						 ext2fs_alloccg);
    139 	if (bno > 0) {
    140 		ip->i_e2fs_nblock += btodb(fs->e2fs_bsize);
    141 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
    142 		*bnp = bno;
    143 		return (0);
    144 	}
    145 nospace:
    146 	ext2fs_fserr(fs, cred->cr_uid, "file system full");
    147 	uprintf("\n%s: write failed, file system is full\n", fs->e2fs_fsmnt);
    148 	return (ENOSPC);
    149 }
    150 
    151 /*
    152  * Allocate an inode in the file system.
    153  *
    154  * If allocating a directory, use ext2fs_dirpref to select the inode.
    155  * If allocating in a directory, the following hierarchy is followed:
    156  *   1) allocate the preferred inode.
    157  *   2) allocate an inode in the same cylinder group.
    158  *   3) quadradically rehash into other cylinder groups, until an
    159  *	  available inode is located.
    160  * If no inode preference is given the following hierarchy is used
    161  * to allocate an inode:
    162  *   1) allocate an inode in cylinder group 0.
    163  *   2) quadradically rehash into other cylinder groups, until an
    164  *	  available inode is located.
    165  */
    166 int
    167 ext2fs_valloc(void *v)
    168 {
    169 	struct vop_valloc_args /* {
    170 		struct vnode *a_pvp;
    171 		int a_mode;
    172 		struct ucred *a_cred;
    173 		struct vnode **a_vpp;
    174 	} */ *ap = v;
    175 	struct vnode *pvp = ap->a_pvp;
    176 	struct inode *pip;
    177 	struct m_ext2fs *fs;
    178 	struct inode *ip;
    179 	mode_t mode = ap->a_mode;
    180 	ino_t ino, ipref;
    181 	int cg, error;
    182 
    183 	*ap->a_vpp = NULL;
    184 	pip = VTOI(pvp);
    185 	fs = pip->i_e2fs;
    186 	if (fs->e2fs.e2fs_ficount == 0)
    187 		goto noinodes;
    188 
    189 	if ((mode & IFMT) == IFDIR)
    190 		cg = ext2fs_dirpref(fs);
    191 	else
    192 		cg = ino_to_cg(fs, pip->i_number);
    193 	ipref = cg * fs->e2fs.e2fs_ipg + 1;
    194 	ino = (ino_t)ext2fs_hashalloc(pip, cg, (long)ipref, mode, ext2fs_nodealloccg);
    195 	if (ino == 0)
    196 		goto noinodes;
    197 	error = VFS_VGET(pvp->v_mount, ino, ap->a_vpp);
    198 	if (error) {
    199 		VOP_VFREE(pvp, ino, mode);
    200 		return (error);
    201 	}
    202 	ip = VTOI(*ap->a_vpp);
    203 	if (ip->i_e2fs_mode && ip->i_e2fs_nlink != 0) {
    204 		printf("mode = 0%o, nlinks %d, inum = %llu, fs = %s\n",
    205 		    ip->i_e2fs_mode, ip->i_e2fs_nlink,
    206 		    (unsigned long long)ip->i_number, fs->e2fs_fsmnt);
    207 		panic("ext2fs_valloc: dup alloc");
    208 	}
    209 
    210 	memset(ip->i_din.e2fs_din, 0, sizeof(struct ext2fs_dinode));
    211 
    212 	/*
    213 	 * Set up a new generation number for this inode.
    214 	 */
    215 	if (++ext2gennumber < (u_long)time.tv_sec)
    216 		ext2gennumber = time.tv_sec;
    217 	ip->i_e2fs_gen = ext2gennumber;
    218 	return (0);
    219 noinodes:
    220 	ext2fs_fserr(fs, ap->a_cred->cr_uid, "out of inodes");
    221 	uprintf("\n%s: create/symlink failed, no inodes free\n", fs->e2fs_fsmnt);
    222 	return (ENOSPC);
    223 }
    224 
    225 /*
    226  * Find a cylinder to place a directory.
    227  *
    228  * The policy implemented by this algorithm is to select from
    229  * among those cylinder groups with above the average number of
    230  * free inodes, the one with the smallest number of directories.
    231  */
    232 static u_long
    233 ext2fs_dirpref(struct m_ext2fs *fs)
    234 {
    235 	int cg, maxspace, mincg, avgifree;
    236 
    237 	avgifree = fs->e2fs.e2fs_ficount / fs->e2fs_ncg;
    238 	maxspace = 0;
    239 	mincg = -1;
    240 	for (cg = 0; cg < fs->e2fs_ncg; cg++)
    241 		if ( fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree) {
    242 			if (mincg == -1 || fs->e2fs_gd[cg].ext2bgd_nbfree > maxspace) {
    243 				mincg = cg;
    244 				maxspace = fs->e2fs_gd[cg].ext2bgd_nbfree;
    245 			}
    246 		}
    247 	return mincg;
    248 }
    249 
    250 /*
    251  * Select the desired position for the next block in a file.  The file is
    252  * logically divided into sections. The first section is composed of the
    253  * direct blocks. Each additional section contains fs_maxbpg blocks.
    254  *
    255  * If no blocks have been allocated in the first section, the policy is to
    256  * request a block in the same cylinder group as the inode that describes
    257  * the file. Otherwise, the policy is to try to allocate the blocks
    258  * contigously. The two fields of the ext2 inode extension (see
    259  * ufs/ufs/inode.h) help this.
    260  */
    261 daddr_t
    262 ext2fs_blkpref(struct inode *ip, daddr_t lbn, int indx,
    263 		int32_t *bap /* XXX ondisk32 */)
    264 {
    265 	struct m_ext2fs *fs;
    266 	int cg, i;
    267 
    268 	fs = ip->i_e2fs;
    269 	/*
    270 	 * if we are doing contigous lbn allocation, try to alloc blocks
    271 	 * contigously on disk
    272 	 */
    273 
    274 	if ( ip->i_e2fs_last_blk && lbn == ip->i_e2fs_last_lblk + 1) {
    275 		return ip->i_e2fs_last_blk + 1;
    276 	}
    277 
    278 	/*
    279 	 * bap, if provided, gives us a list of blocks to which we want to
    280 	 * stay close
    281 	 */
    282 
    283 	if (bap) {
    284 		for (i = indx; i >= 0 ; i--) {
    285 			if (bap[i]) {
    286 				return fs2h32(bap[i]) + 1;
    287 			}
    288 		}
    289 	}
    290 
    291 	/* fall back to the first block of the cylinder containing the inode */
    292 
    293 	cg = ino_to_cg(fs, ip->i_number);
    294 	return fs->e2fs.e2fs_bpg * cg + fs->e2fs.e2fs_first_dblock + 1;
    295 }
    296 
    297 /*
    298  * Implement the cylinder overflow algorithm.
    299  *
    300  * The policy implemented by this algorithm is:
    301  *   1) allocate the block in its requested cylinder group.
    302  *   2) quadradically rehash on the cylinder group number.
    303  *   3) brute force search for a free block.
    304  */
    305 static u_long
    306 ext2fs_hashalloc(struct inode *ip, int cg, long pref, int size,
    307 		daddr_t (*allocator)(struct inode *, int, daddr_t, int))
    308 {
    309 	struct m_ext2fs *fs;
    310 	long result;
    311 	int i, icg = cg;
    312 
    313 	fs = ip->i_e2fs;
    314 	/*
    315 	 * 1: preferred cylinder group
    316 	 */
    317 	result = (*allocator)(ip, cg, pref, size);
    318 	if (result)
    319 		return (result);
    320 	/*
    321 	 * 2: quadratic rehash
    322 	 */
    323 	for (i = 1; i < fs->e2fs_ncg; i *= 2) {
    324 		cg += i;
    325 		if (cg >= fs->e2fs_ncg)
    326 			cg -= fs->e2fs_ncg;
    327 		result = (*allocator)(ip, cg, 0, size);
    328 		if (result)
    329 			return (result);
    330 	}
    331 	/*
    332 	 * 3: brute force search
    333 	 * Note that we start at i == 2, since 0 was checked initially,
    334 	 * and 1 is always checked in the quadratic rehash.
    335 	 */
    336 	cg = (icg + 2) % fs->e2fs_ncg;
    337 	for (i = 2; i < fs->e2fs_ncg; i++) {
    338 		result = (*allocator)(ip, cg, 0, size);
    339 		if (result)
    340 			return (result);
    341 		cg++;
    342 		if (cg == fs->e2fs_ncg)
    343 			cg = 0;
    344 	}
    345 	return (0);
    346 }
    347 
    348 /*
    349  * Determine whether a block can be allocated.
    350  *
    351  * Check to see if a block of the appropriate size is available,
    352  * and if it is, allocate it.
    353  */
    354 
    355 static daddr_t
    356 ext2fs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size)
    357 {
    358 	struct m_ext2fs *fs;
    359 	char *bbp;
    360 	struct buf *bp;
    361 	/* XXX ondisk32 */
    362 	int error, bno, start, end, loc;
    363 
    364 	fs = ip->i_e2fs;
    365 	if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0)
    366 		return (0);
    367 	error = bread(ip->i_devvp, fsbtodb(fs,
    368 		fs->e2fs_gd[cg].ext2bgd_b_bitmap),
    369 		(int)fs->e2fs_bsize, NOCRED, &bp);
    370 	if (error) {
    371 		brelse(bp);
    372 		return (0);
    373 	}
    374 	bbp = (char *)bp->b_data;
    375 
    376 	if (dtog(fs, bpref) != cg)
    377 		bpref = 0;
    378 	if (bpref != 0) {
    379 		bpref = dtogd(fs, bpref);
    380 		/*
    381 		 * if the requested block is available, use it
    382 		 */
    383 		if (isclr(bbp, bpref)) {
    384 			bno = bpref;
    385 			goto gotit;
    386 		}
    387 	}
    388 	/*
    389 	 * no blocks in the requested cylinder, so take next
    390 	 * available one in this cylinder group.
    391 	 * first try to get 8 contigous blocks, then fall back to a single
    392 	 * block.
    393 	 */
    394 	if (bpref)
    395 		start = dtogd(fs, bpref) / NBBY;
    396 	else
    397 		start = 0;
    398 	end = howmany(fs->e2fs.e2fs_fpg, NBBY) - start;
    399 	for (loc = start; loc < end; loc++) {
    400 		if (bbp[loc] == 0) {
    401 			bno = loc * NBBY;
    402 			goto gotit;
    403 		}
    404 	}
    405 	for (loc = 0; loc < start; loc++) {
    406 		if (bbp[loc] == 0) {
    407 			bno = loc * NBBY;
    408 			goto gotit;
    409 		}
    410 	}
    411 
    412 	bno = ext2fs_mapsearch(fs, bbp, bpref);
    413 	if (bno < 0)
    414 		return (0);
    415 gotit:
    416 #ifdef DIAGNOSTIC
    417 	if (isset(bbp, (daddr_t)bno)) {
    418 		printf("ext2fs_alloccgblk: cg=%d bno=%d fs=%s\n",
    419 			cg, bno, fs->e2fs_fsmnt);
    420 		panic("ext2fs_alloccg: dup alloc");
    421 	}
    422 #endif
    423 	setbit(bbp, (daddr_t)bno);
    424 	fs->e2fs.e2fs_fbcount--;
    425 	fs->e2fs_gd[cg].ext2bgd_nbfree--;
    426 	fs->e2fs_fmod = 1;
    427 	bdwrite(bp);
    428 	return (cg * fs->e2fs.e2fs_fpg + fs->e2fs.e2fs_first_dblock + bno);
    429 }
    430 
    431 /*
    432  * Determine whether an inode can be allocated.
    433  *
    434  * Check to see if an inode is available, and if it is,
    435  * allocate it using the following policy:
    436  *   1) allocate the requested inode.
    437  *   2) allocate the next available inode after the requested
    438  *	  inode in the specified cylinder group.
    439  */
    440 static daddr_t
    441 ext2fs_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode)
    442 {
    443 	struct m_ext2fs *fs;
    444 	char *ibp;
    445 	struct buf *bp;
    446 	int error, start, len, loc, map, i;
    447 
    448 	ipref--; /* to avoid a lot of (ipref -1) */
    449 	fs = ip->i_e2fs;
    450 	if (fs->e2fs_gd[cg].ext2bgd_nifree == 0)
    451 		return (0);
    452 	error = bread(ip->i_devvp, fsbtodb(fs,
    453 		fs->e2fs_gd[cg].ext2bgd_i_bitmap),
    454 		(int)fs->e2fs_bsize, NOCRED, &bp);
    455 	if (error) {
    456 		brelse(bp);
    457 		return (0);
    458 	}
    459 	ibp = (char *)bp->b_data;
    460 	if (ipref) {
    461 		ipref %= fs->e2fs.e2fs_ipg;
    462 		if (isclr(ibp, ipref))
    463 			goto gotit;
    464 	}
    465 	start = ipref / NBBY;
    466 	len = howmany(fs->e2fs.e2fs_ipg - ipref, NBBY);
    467 	loc = skpc(0xff, len, &ibp[start]);
    468 	if (loc == 0) {
    469 		len = start + 1;
    470 		start = 0;
    471 		loc = skpc(0xff, len, &ibp[0]);
    472 		if (loc == 0) {
    473 			printf("cg = %d, ipref = %lld, fs = %s\n",
    474 				cg, (long long)ipref, fs->e2fs_fsmnt);
    475 			panic("ext2fs_nodealloccg: map corrupted");
    476 			/* NOTREACHED */
    477 		}
    478 	}
    479 	i = start + len - loc;
    480 	map = ibp[i];
    481 	ipref = i * NBBY;
    482 	for (i = 1; i < (1 << NBBY); i <<= 1, ipref++) {
    483 		if ((map & i) == 0) {
    484 			goto gotit;
    485 		}
    486 	}
    487 	printf("fs = %s\n", fs->e2fs_fsmnt);
    488 	panic("ext2fs_nodealloccg: block not in map");
    489 	/* NOTREACHED */
    490 gotit:
    491 	setbit(ibp, ipref);
    492 	fs->e2fs.e2fs_ficount--;
    493 	fs->e2fs_gd[cg].ext2bgd_nifree--;
    494 	fs->e2fs_fmod = 1;
    495 	if ((mode & IFMT) == IFDIR) {
    496 		fs->e2fs_gd[cg].ext2bgd_ndirs++;
    497 	}
    498 	bdwrite(bp);
    499 	return (cg * fs->e2fs.e2fs_ipg + ipref +1);
    500 }
    501 
    502 /*
    503  * Free a block.
    504  *
    505  * The specified block is placed back in the
    506  * free map.
    507  */
    508 void
    509 ext2fs_blkfree(struct inode *ip, daddr_t bno)
    510 {
    511 	struct m_ext2fs *fs;
    512 	char *bbp;
    513 	struct buf *bp;
    514 	int error, cg;
    515 
    516 	fs = ip->i_e2fs;
    517 	cg = dtog(fs, bno);
    518 	if ((u_int)bno >= fs->e2fs.e2fs_bcount) {
    519 		printf("bad block %lld, ino %llu\n", (long long)bno,
    520 		    (unsigned long long)ip->i_number);
    521 		ext2fs_fserr(fs, ip->i_e2fs_uid, "bad block");
    522 		return;
    523 	}
    524 	error = bread(ip->i_devvp,
    525 		fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
    526 		(int)fs->e2fs_bsize, NOCRED, &bp);
    527 	if (error) {
    528 		brelse(bp);
    529 		return;
    530 	}
    531 	bbp = (char *)bp->b_data;
    532 	bno = dtogd(fs, bno);
    533 	if (isclr(bbp, bno)) {
    534 		printf("dev = 0x%x, block = %lld, fs = %s\n",
    535 			ip->i_dev, (long long)bno, fs->e2fs_fsmnt);
    536 		panic("blkfree: freeing free block");
    537 	}
    538 	clrbit(bbp, bno);
    539 	fs->e2fs.e2fs_fbcount++;
    540 	fs->e2fs_gd[cg].ext2bgd_nbfree++;
    541 
    542 	fs->e2fs_fmod = 1;
    543 	bdwrite(bp);
    544 }
    545 
    546 /*
    547  * Free an inode.
    548  *
    549  * The specified inode is placed back in the free map.
    550  */
    551 int
    552 ext2fs_vfree(void *v)
    553 {
    554 	struct vop_vfree_args /* {
    555 		struct vnode *a_pvp;
    556 		ino_t a_ino;
    557 		int a_mode;
    558 	} */ *ap = v;
    559 	struct m_ext2fs *fs;
    560 	char *ibp;
    561 	struct inode *pip;
    562 	ino_t ino = ap->a_ino;
    563 	struct buf *bp;
    564 	int error, cg;
    565 
    566 	pip = VTOI(ap->a_pvp);
    567 	fs = pip->i_e2fs;
    568 	if ((u_int)ino >= fs->e2fs.e2fs_icount || (u_int)ino < EXT2_FIRSTINO)
    569 		panic("ifree: range: dev = 0x%x, ino = %llu, fs = %s",
    570 			pip->i_dev, (unsigned long long)ino, fs->e2fs_fsmnt);
    571 	cg = ino_to_cg(fs, ino);
    572 	error = bread(pip->i_devvp,
    573 		fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
    574 		(int)fs->e2fs_bsize, NOCRED, &bp);
    575 	if (error) {
    576 		brelse(bp);
    577 		return (0);
    578 	}
    579 	ibp = (char *)bp->b_data;
    580 	ino = (ino - 1) % fs->e2fs.e2fs_ipg;
    581 	if (isclr(ibp, ino)) {
    582 		printf("dev = 0x%x, ino = %llu, fs = %s\n",
    583 		    pip->i_dev, (unsigned long long)ino, fs->e2fs_fsmnt);
    584 		if (fs->e2fs_ronly == 0)
    585 			panic("ifree: freeing free inode");
    586 	}
    587 	clrbit(ibp, ino);
    588 	fs->e2fs.e2fs_ficount++;
    589 	fs->e2fs_gd[cg].ext2bgd_nifree++;
    590 	if ((ap->a_mode & IFMT) == IFDIR) {
    591 		fs->e2fs_gd[cg].ext2bgd_ndirs--;
    592 	}
    593 	fs->e2fs_fmod = 1;
    594 	bdwrite(bp);
    595 	return (0);
    596 }
    597 
    598 /*
    599  * Find a block in the specified cylinder group.
    600  *
    601  * It is a panic if a request is made to find a block if none are
    602  * available.
    603  */
    604 
    605 static daddr_t
    606 ext2fs_mapsearch(struct m_ext2fs *fs, char *bbp, daddr_t bpref)
    607 {
    608 	daddr_t bno;
    609 	int start, len, loc, i, map;
    610 
    611 	/*
    612 	 * find the fragment by searching through the free block
    613 	 * map for an appropriate bit pattern
    614 	 */
    615 	if (bpref)
    616 		start = dtogd(fs, bpref) / NBBY;
    617 	else
    618 		start = 0;
    619 	len = howmany(fs->e2fs.e2fs_fpg, NBBY) - start;
    620 	loc = skpc(0xff, len, &bbp[start]);
    621 	if (loc == 0) {
    622 		len = start + 1;
    623 		start = 0;
    624 		loc = skpc(0xff, len, &bbp[start]);
    625 		if (loc == 0) {
    626 			printf("start = %d, len = %d, fs = %s\n",
    627 				start, len, fs->e2fs_fsmnt);
    628 			panic("ext2fs_alloccg: map corrupted");
    629 			/* NOTREACHED */
    630 		}
    631 	}
    632 	i = start + len - loc;
    633 	map = bbp[i];
    634 	bno = i * NBBY;
    635 	for (i = 1; i < (1 << NBBY); i <<= 1, bno++) {
    636 		if ((map & i) == 0)
    637 			return (bno);
    638 	}
    639 	printf("fs = %s\n", fs->e2fs_fsmnt);
    640 	panic("ext2fs_mapsearch: block not in map");
    641 	/* NOTREACHED */
    642 }
    643 
    644 /*
    645  * Fserr prints the name of a file system with an error diagnostic.
    646  *
    647  * The form of the error message is:
    648  *	fs: error message
    649  */
    650 static void
    651 ext2fs_fserr(struct m_ext2fs *fs, u_int uid, const char *cp)
    652 {
    653 
    654 	log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->e2fs_fsmnt, cp);
    655 }
    656