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