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