xref: /netbsd-src/sys/ufs/ext2fs/ext2fs_alloc.c (revision 5b84b3983f71fd20a534cfa5d1556623a8aaa717)
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