ffs_balloc.c revision 1.13 1 /* $NetBSD: ffs_balloc.c,v 1.13 2004/06/20 22:20:18 jmc Exp $ */
2 /* From NetBSD: ffs_balloc.c,v 1.25 2001/08/08 08:36:36 lukem Exp */
3
4 /*
5 * Copyright (c) 1982, 1986, 1989, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95
33 */
34
35 #if HAVE_NBTOOL_CONFIG_H
36 #include "nbtool_config.h"
37 #endif
38
39 #include <sys/cdefs.h>
40 #if defined(__RCSID) && !defined(__lint)
41 __RCSID("$NetBSD: ffs_balloc.c,v 1.13 2004/06/20 22:20:18 jmc Exp $");
42 #endif /* !__lint */
43
44 #include <sys/param.h>
45 #include <sys/time.h>
46
47 #include <assert.h>
48 #include <errno.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52
53 #include "makefs.h"
54
55 #include <ufs/ufs/dinode.h>
56 #include <ufs/ufs/ufs_bswap.h>
57 #include <ufs/ffs/fs.h>
58
59 #include "ffs/buf.h"
60 #include "ffs/ufs_inode.h"
61 #include "ffs/ffs_extern.h"
62
63 static int ffs_balloc_ufs1(struct inode *, off_t, int, struct buf **);
64 static int ffs_balloc_ufs2(struct inode *, off_t, int, struct buf **);
65
66 /*
67 * Balloc defines the structure of file system storage
68 * by allocating the physical blocks on a device given
69 * the inode and the logical block number in a file.
70 *
71 * Assume: flags == B_SYNC | B_CLRBUF
72 */
73
74 int
75 ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
76 {
77 if (ip->i_fs->fs_magic == FS_UFS2_MAGIC)
78 return ffs_balloc_ufs2(ip, offset, bufsize, bpp);
79 else
80 return ffs_balloc_ufs1(ip, offset, bufsize, bpp);
81 }
82
83 static int
84 ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
85 {
86 daddr_t lbn, lastlbn;
87 int size;
88 int32_t nb;
89 struct buf *bp, *nbp;
90 struct fs *fs = ip->i_fs;
91 struct indir indirs[NIADDR + 2];
92 daddr_t newb, pref;
93 int32_t *bap;
94 int osize, nsize, num, i, error;
95 int32_t *allocblk, allociblk[NIADDR + 1];
96 int32_t *allocib;
97 const int needswap = UFS_FSNEEDSWAP(fs);
98
99 lbn = lblkno(fs, offset);
100 size = blkoff(fs, offset) + bufsize;
101 if (bpp != NULL) {
102 *bpp = NULL;
103 }
104
105 assert(size <= fs->fs_bsize);
106 if (lbn < 0)
107 return (EFBIG);
108
109 /*
110 * If the next write will extend the file into a new block,
111 * and the file is currently composed of a fragment
112 * this fragment has to be extended to be a full block.
113 */
114
115 lastlbn = lblkno(fs, ip->i_ffs1_size);
116 if (lastlbn < NDADDR && lastlbn < lbn) {
117 nb = lastlbn;
118 osize = blksize(fs, ip, nb);
119 if (osize < fs->fs_bsize && osize > 0) {
120 warnx("need to ffs_realloccg; not supported!");
121 abort();
122 }
123 }
124
125 /*
126 * The first NDADDR blocks are direct blocks
127 */
128
129 if (lbn < NDADDR) {
130 nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap);
131 if (nb != 0 && ip->i_ffs1_size >= lblktosize(fs, lbn + 1)) {
132
133 /*
134 * The block is an already-allocated direct block
135 * and the file already extends past this block,
136 * thus this must be a whole block.
137 * Just read the block (if requested).
138 */
139
140 if (bpp != NULL) {
141 error = bread(ip->i_fd, ip->i_fs, lbn,
142 fs->fs_bsize, bpp);
143 if (error) {
144 brelse(*bpp);
145 return (error);
146 }
147 }
148 return (0);
149 }
150 if (nb != 0) {
151
152 /*
153 * Consider need to reallocate a fragment.
154 */
155
156 osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size));
157 nsize = fragroundup(fs, size);
158 if (nsize <= osize) {
159
160 /*
161 * The existing block is already
162 * at least as big as we want.
163 * Just read the block (if requested).
164 */
165
166 if (bpp != NULL) {
167 error = bread(ip->i_fd, ip->i_fs, lbn,
168 osize, bpp);
169 if (error) {
170 brelse(*bpp);
171 return (error);
172 }
173 }
174 return 0;
175 } else {
176 warnx("need to ffs_realloccg; not supported!");
177 abort();
178 }
179 } else {
180
181 /*
182 * the block was not previously allocated,
183 * allocate a new block or fragment.
184 */
185
186 if (ip->i_ffs1_size < lblktosize(fs, lbn + 1))
187 nsize = fragroundup(fs, size);
188 else
189 nsize = fs->fs_bsize;
190 error = ffs_alloc(ip, lbn,
191 ffs_blkpref_ufs1(ip, lbn, (int)lbn,
192 &ip->i_ffs1_db[0]),
193 nsize, &newb);
194 if (error)
195 return (error);
196 if (bpp != NULL) {
197 bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize);
198 bp->b_blkno = fsbtodb(fs, newb);
199 clrbuf(bp);
200 *bpp = bp;
201 }
202 }
203 ip->i_ffs1_db[lbn] = ufs_rw32((int32_t)newb, needswap);
204 return (0);
205 }
206
207 /*
208 * Determine the number of levels of indirection.
209 */
210
211 pref = 0;
212 if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
213 return (error);
214
215 if (num < 1) {
216 warnx("ffs_balloc: ufs_getlbns returned indirect block");
217 abort();
218 }
219
220 /*
221 * Fetch the first indirect block allocating if necessary.
222 */
223
224 --num;
225 nb = ufs_rw32(ip->i_ffs1_ib[indirs[0].in_off], needswap);
226 allocib = NULL;
227 allocblk = allociblk;
228 if (nb == 0) {
229 pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
230 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
231 if (error)
232 return error;
233 nb = newb;
234 *allocblk++ = nb;
235 bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize);
236 bp->b_blkno = fsbtodb(fs, nb);
237 clrbuf(bp);
238 /*
239 * Write synchronously so that indirect blocks
240 * never point at garbage.
241 */
242 if ((error = bwrite(bp)) != 0)
243 return error;
244 allocib = &ip->i_ffs1_ib[indirs[0].in_off];
245 *allocib = ufs_rw32((int32_t)nb, needswap);
246 }
247
248 /*
249 * Fetch through the indirect blocks, allocating as necessary.
250 */
251
252 for (i = 1;;) {
253 error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
254 fs->fs_bsize, &bp);
255 if (error) {
256 brelse(bp);
257 return error;
258 }
259 bap = (int32_t *)bp->b_data;
260 nb = ufs_rw32(bap[indirs[i].in_off], needswap);
261 if (i == num)
262 break;
263 i++;
264 if (nb != 0) {
265 brelse(bp);
266 continue;
267 }
268 if (pref == 0)
269 pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
270 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
271 if (error) {
272 brelse(bp);
273 return error;
274 }
275 nb = newb;
276 *allocblk++ = nb;
277 nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
278 fs->fs_bsize);
279 nbp->b_blkno = fsbtodb(fs, nb);
280 clrbuf(nbp);
281 /*
282 * Write synchronously so that indirect blocks
283 * never point at garbage.
284 */
285
286 if ((error = bwrite(nbp)) != 0) {
287 brelse(bp);
288 return error;
289 }
290 bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap);
291
292 bwrite(bp);
293 }
294
295 /*
296 * Get the data block, allocating if necessary.
297 */
298
299 if (nb == 0) {
300 pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]);
301 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
302 if (error) {
303 brelse(bp);
304 return error;
305 }
306 nb = newb;
307 *allocblk++ = nb;
308 if (bpp != NULL) {
309 nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize);
310 nbp->b_blkno = fsbtodb(fs, nb);
311 clrbuf(nbp);
312 *bpp = nbp;
313 }
314 bap[indirs[num].in_off] = ufs_rw32(nb, needswap);
315
316 /*
317 * If required, write synchronously, otherwise use
318 * delayed write.
319 */
320 bwrite(bp);
321 return (0);
322 }
323 brelse(bp);
324 if (bpp != NULL) {
325 error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp);
326 if (error) {
327 brelse(nbp);
328 return error;
329 }
330 *bpp = nbp;
331 }
332 return (0);
333 }
334
335 static int
336 ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
337 {
338 daddr_t lbn, lastlbn;
339 int size;
340 struct buf *bp, *nbp;
341 struct fs *fs = ip->i_fs;
342 struct indir indirs[NIADDR + 2];
343 daddr_t newb, pref, nb;
344 int64_t *bap;
345 int osize, nsize, num, i, error;
346 int64_t *allocblk, allociblk[NIADDR + 1];
347 int64_t *allocib;
348 const int needswap = UFS_FSNEEDSWAP(fs);
349
350 lbn = lblkno(fs, offset);
351 size = blkoff(fs, offset) + bufsize;
352 if (bpp != NULL) {
353 *bpp = NULL;
354 }
355
356 assert(size <= fs->fs_bsize);
357 if (lbn < 0)
358 return (EFBIG);
359
360 /*
361 * If the next write will extend the file into a new block,
362 * and the file is currently composed of a fragment
363 * this fragment has to be extended to be a full block.
364 */
365
366 lastlbn = lblkno(fs, ip->i_ffs2_size);
367 if (lastlbn < NDADDR && lastlbn < lbn) {
368 nb = lastlbn;
369 osize = blksize(fs, ip, nb);
370 if (osize < fs->fs_bsize && osize > 0) {
371 warnx("need to ffs_realloccg; not supported!");
372 abort();
373 }
374 }
375
376 /*
377 * The first NDADDR blocks are direct blocks
378 */
379
380 if (lbn < NDADDR) {
381 nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
382 if (nb != 0 && ip->i_ffs2_size >= lblktosize(fs, lbn + 1)) {
383
384 /*
385 * The block is an already-allocated direct block
386 * and the file already extends past this block,
387 * thus this must be a whole block.
388 * Just read the block (if requested).
389 */
390
391 if (bpp != NULL) {
392 error = bread(ip->i_fd, ip->i_fs, lbn,
393 fs->fs_bsize, bpp);
394 if (error) {
395 brelse(*bpp);
396 return (error);
397 }
398 }
399 return (0);
400 }
401 if (nb != 0) {
402
403 /*
404 * Consider need to reallocate a fragment.
405 */
406
407 osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size));
408 nsize = fragroundup(fs, size);
409 if (nsize <= osize) {
410
411 /*
412 * The existing block is already
413 * at least as big as we want.
414 * Just read the block (if requested).
415 */
416
417 if (bpp != NULL) {
418 error = bread(ip->i_fd, ip->i_fs, lbn,
419 osize, bpp);
420 if (error) {
421 brelse(*bpp);
422 return (error);
423 }
424 }
425 return 0;
426 } else {
427 warnx("need to ffs_realloccg; not supported!");
428 abort();
429 }
430 } else {
431
432 /*
433 * the block was not previously allocated,
434 * allocate a new block or fragment.
435 */
436
437 if (ip->i_ffs2_size < lblktosize(fs, lbn + 1))
438 nsize = fragroundup(fs, size);
439 else
440 nsize = fs->fs_bsize;
441 error = ffs_alloc(ip, lbn,
442 ffs_blkpref_ufs2(ip, lbn, (int)lbn,
443 &ip->i_ffs2_db[0]),
444 nsize, &newb);
445 if (error)
446 return (error);
447 if (bpp != NULL) {
448 bp = getblk(ip->i_fd, ip->i_fs, lbn, nsize);
449 bp->b_blkno = fsbtodb(fs, newb);
450 clrbuf(bp);
451 *bpp = bp;
452 }
453 }
454 ip->i_ffs2_db[lbn] = ufs_rw64(newb, needswap);
455 return (0);
456 }
457
458 /*
459 * Determine the number of levels of indirection.
460 */
461
462 pref = 0;
463 if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
464 return (error);
465
466 if (num < 1) {
467 warnx("ffs_balloc: ufs_getlbns returned indirect block");
468 abort();
469 }
470
471 /*
472 * Fetch the first indirect block allocating if necessary.
473 */
474
475 --num;
476 nb = ufs_rw64(ip->i_ffs2_ib[indirs[0].in_off], needswap);
477 allocib = NULL;
478 allocblk = allociblk;
479 if (nb == 0) {
480 pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
481 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
482 if (error)
483 return error;
484 nb = newb;
485 *allocblk++ = nb;
486 bp = getblk(ip->i_fd, ip->i_fs, indirs[1].in_lbn, fs->fs_bsize);
487 bp->b_blkno = fsbtodb(fs, nb);
488 clrbuf(bp);
489 /*
490 * Write synchronously so that indirect blocks
491 * never point at garbage.
492 */
493 if ((error = bwrite(bp)) != 0)
494 return error;
495 allocib = &ip->i_ffs2_ib[indirs[0].in_off];
496 *allocib = ufs_rw64(nb, needswap);
497 }
498
499 /*
500 * Fetch through the indirect blocks, allocating as necessary.
501 */
502
503 for (i = 1;;) {
504 error = bread(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
505 fs->fs_bsize, &bp);
506 if (error) {
507 brelse(bp);
508 return error;
509 }
510 bap = (int64_t *)bp->b_data;
511 nb = ufs_rw64(bap[indirs[i].in_off], needswap);
512 if (i == num)
513 break;
514 i++;
515 if (nb != 0) {
516 brelse(bp);
517 continue;
518 }
519 if (pref == 0)
520 pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
521 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
522 if (error) {
523 brelse(bp);
524 return error;
525 }
526 nb = newb;
527 *allocblk++ = nb;
528 nbp = getblk(ip->i_fd, ip->i_fs, indirs[i].in_lbn,
529 fs->fs_bsize);
530 nbp->b_blkno = fsbtodb(fs, nb);
531 clrbuf(nbp);
532 /*
533 * Write synchronously so that indirect blocks
534 * never point at garbage.
535 */
536
537 if ((error = bwrite(nbp)) != 0) {
538 brelse(bp);
539 return error;
540 }
541 bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap);
542
543 bwrite(bp);
544 }
545
546 /*
547 * Get the data block, allocating if necessary.
548 */
549
550 if (nb == 0) {
551 pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]);
552 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
553 if (error) {
554 brelse(bp);
555 return error;
556 }
557 nb = newb;
558 *allocblk++ = nb;
559 if (bpp != NULL) {
560 nbp = getblk(ip->i_fd, ip->i_fs, lbn, fs->fs_bsize);
561 nbp->b_blkno = fsbtodb(fs, nb);
562 clrbuf(nbp);
563 *bpp = nbp;
564 }
565 bap[indirs[num].in_off] = ufs_rw64(nb, needswap);
566
567 /*
568 * If required, write synchronously, otherwise use
569 * delayed write.
570 */
571 bwrite(bp);
572 return (0);
573 }
574 brelse(bp);
575 if (bpp != NULL) {
576 error = bread(ip->i_fd, ip->i_fs, lbn, (int)fs->fs_bsize, &nbp);
577 if (error) {
578 brelse(nbp);
579 return error;
580 }
581 *bpp = nbp;
582 }
583 return (0);
584 }
585