ffs_balloc.c revision 1.15 1 /* $NetBSD: ffs_balloc.c,v 1.15 2013/01/26 00:19:39 christos 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.15 2013/01/26 00:19:39 christos 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[UFS_NIADDR + 2];
92 daddr_t newb, pref;
93 int32_t *bap;
94 int osize, nsize, num, i, error;
95 int32_t *allocblk, allociblk[UFS_NIADDR + 1];
96 int32_t *allocib;
97 const int needswap = UFS_FSNEEDSWAP(fs);
98 struct vnode vp = { ip->i_fd, ip->i_fs, NULL, 0 };
99
100 lbn = lblkno(fs, offset);
101 size = blkoff(fs, offset) + bufsize;
102 if (bpp != NULL) {
103 *bpp = NULL;
104 }
105
106 assert(size <= fs->fs_bsize);
107 if (lbn < 0)
108 return (EFBIG);
109
110 /*
111 * If the next write will extend the file into a new block,
112 * and the file is currently composed of a fragment
113 * this fragment has to be extended to be a full block.
114 */
115
116 lastlbn = lblkno(fs, ip->i_ffs1_size);
117 if (lastlbn < UFS_NDADDR && lastlbn < lbn) {
118 nb = lastlbn;
119 osize = blksize(fs, ip, nb);
120 if (osize < fs->fs_bsize && osize > 0) {
121 warnx("need to ffs_realloccg; not supported!");
122 abort();
123 }
124 }
125
126 /*
127 * The first UFS_NDADDR blocks are direct blocks
128 */
129
130 if (lbn < UFS_NDADDR) {
131 nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap);
132 if (nb != 0 && ip->i_ffs1_size >= lblktosize(fs, lbn + 1)) {
133
134 /*
135 * The block is an already-allocated direct block
136 * and the file already extends past this block,
137 * thus this must be a whole block.
138 * Just read the block (if requested).
139 */
140
141 if (bpp != NULL) {
142 error = bread(&vp, lbn, fs->fs_bsize, NULL, 0,
143 bpp);
144 if (error) {
145 brelse(*bpp, 0);
146 return (error);
147 }
148 }
149 return (0);
150 }
151 if (nb != 0) {
152
153 /*
154 * Consider need to reallocate a fragment.
155 */
156
157 osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size));
158 nsize = fragroundup(fs, size);
159 if (nsize <= osize) {
160
161 /*
162 * The existing block is already
163 * at least as big as we want.
164 * Just read the block (if requested).
165 */
166
167 if (bpp != NULL) {
168 error = bread(&vp, lbn, osize, NULL, 0,
169 bpp);
170 if (error) {
171 brelse(*bpp, 0);
172 return (error);
173 }
174 }
175 return 0;
176 } else {
177 warnx("need to ffs_realloccg; not supported!");
178 abort();
179 }
180 } else {
181
182 /*
183 * the block was not previously allocated,
184 * allocate a new block or fragment.
185 */
186
187 if (ip->i_ffs1_size < lblktosize(fs, lbn + 1))
188 nsize = fragroundup(fs, size);
189 else
190 nsize = fs->fs_bsize;
191 error = ffs_alloc(ip, lbn,
192 ffs_blkpref_ufs1(ip, lbn, (int)lbn,
193 &ip->i_ffs1_db[0]),
194 nsize, &newb);
195 if (error)
196 return (error);
197 if (bpp != NULL) {
198 bp = getblk(&vp, lbn, nsize, 0, 0);
199 bp->b_blkno = fsbtodb(fs, newb);
200 clrbuf(bp);
201 *bpp = bp;
202 }
203 }
204 ip->i_ffs1_db[lbn] = ufs_rw32((int32_t)newb, needswap);
205 return (0);
206 }
207
208 /*
209 * Determine the number of levels of indirection.
210 */
211
212 pref = 0;
213 if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
214 return (error);
215
216 if (num < 1) {
217 warnx("ffs_balloc: ufs_getlbns returned indirect block");
218 abort();
219 }
220
221 /*
222 * Fetch the first indirect block allocating if necessary.
223 */
224
225 --num;
226 nb = ufs_rw32(ip->i_ffs1_ib[indirs[0].in_off], needswap);
227 allocib = NULL;
228 allocblk = allociblk;
229 if (nb == 0) {
230 pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
231 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
232 if (error)
233 return error;
234 nb = newb;
235 *allocblk++ = nb;
236 bp = getblk(&vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
237 bp->b_blkno = fsbtodb(fs, nb);
238 clrbuf(bp);
239 /*
240 * Write synchronously so that indirect blocks
241 * never point at garbage.
242 */
243 if ((error = bwrite(bp)) != 0)
244 return error;
245 allocib = &ip->i_ffs1_ib[indirs[0].in_off];
246 *allocib = ufs_rw32((int32_t)nb, needswap);
247 }
248
249 /*
250 * Fetch through the indirect blocks, allocating as necessary.
251 */
252
253 for (i = 1;;) {
254 error = bread(&vp, indirs[i].in_lbn, fs->fs_bsize, NULL, 0,
255 &bp);
256 if (error) {
257 brelse(bp, 0);
258 return error;
259 }
260 bap = (int32_t *)bp->b_data;
261 nb = ufs_rw32(bap[indirs[i].in_off], needswap);
262 if (i == num)
263 break;
264 i++;
265 if (nb != 0) {
266 brelse(bp, 0);
267 continue;
268 }
269 if (pref == 0)
270 pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
271 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
272 if (error) {
273 brelse(bp, 0);
274 return error;
275 }
276 nb = newb;
277 *allocblk++ = nb;
278 nbp = getblk(&vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
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, 0);
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, 0);
304 return error;
305 }
306 nb = newb;
307 *allocblk++ = nb;
308 if (bpp != NULL) {
309 nbp = getblk(&vp, lbn, fs->fs_bsize, 0, 0);
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, 0);
324 if (bpp != NULL) {
325 error = bread(&vp, lbn, (int)fs->fs_bsize, NULL, 0, &nbp);
326 if (error) {
327 brelse(nbp, 0);
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[UFS_NIADDR + 2];
343 daddr_t newb, pref, nb;
344 int64_t *bap;
345 int osize, nsize, num, i, error;
346 int64_t *allocblk, allociblk[UFS_NIADDR + 1];
347 int64_t *allocib;
348 const int needswap = UFS_FSNEEDSWAP(fs);
349 struct vnode vp = { ip->i_fd, ip->i_fs, NULL, 0 };
350
351 lbn = lblkno(fs, offset);
352 size = blkoff(fs, offset) + bufsize;
353 if (bpp != NULL) {
354 *bpp = NULL;
355 }
356
357 assert(size <= fs->fs_bsize);
358 if (lbn < 0)
359 return (EFBIG);
360
361 /*
362 * If the next write will extend the file into a new block,
363 * and the file is currently composed of a fragment
364 * this fragment has to be extended to be a full block.
365 */
366
367 lastlbn = lblkno(fs, ip->i_ffs2_size);
368 if (lastlbn < UFS_NDADDR && lastlbn < lbn) {
369 nb = lastlbn;
370 osize = blksize(fs, ip, nb);
371 if (osize < fs->fs_bsize && osize > 0) {
372 warnx("need to ffs_realloccg; not supported!");
373 abort();
374 }
375 }
376
377 /*
378 * The first UFS_NDADDR blocks are direct blocks
379 */
380
381 if (lbn < UFS_NDADDR) {
382 nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
383 if (nb != 0 && ip->i_ffs2_size >= lblktosize(fs, lbn + 1)) {
384
385 /*
386 * The block is an already-allocated direct block
387 * and the file already extends past this block,
388 * thus this must be a whole block.
389 * Just read the block (if requested).
390 */
391
392 if (bpp != NULL) {
393 error = bread(&vp, lbn, fs->fs_bsize, NULL, 0,
394 bpp);
395 if (error) {
396 brelse(*bpp, 0);
397 return (error);
398 }
399 }
400 return (0);
401 }
402 if (nb != 0) {
403
404 /*
405 * Consider need to reallocate a fragment.
406 */
407
408 osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size));
409 nsize = fragroundup(fs, size);
410 if (nsize <= osize) {
411
412 /*
413 * The existing block is already
414 * at least as big as we want.
415 * Just read the block (if requested).
416 */
417
418 if (bpp != NULL) {
419 error = bread(&vp, lbn, osize, NULL, 0,
420 bpp);
421 if (error) {
422 brelse(*bpp, 0);
423 return (error);
424 }
425 }
426 return 0;
427 } else {
428 warnx("need to ffs_realloccg; not supported!");
429 abort();
430 }
431 } else {
432
433 /*
434 * the block was not previously allocated,
435 * allocate a new block or fragment.
436 */
437
438 if (ip->i_ffs2_size < lblktosize(fs, lbn + 1))
439 nsize = fragroundup(fs, size);
440 else
441 nsize = fs->fs_bsize;
442 error = ffs_alloc(ip, lbn,
443 ffs_blkpref_ufs2(ip, lbn, (int)lbn,
444 &ip->i_ffs2_db[0]),
445 nsize, &newb);
446 if (error)
447 return (error);
448 if (bpp != NULL) {
449 bp = getblk(&vp, lbn, nsize, 0, 0);
450 bp->b_blkno = fsbtodb(fs, newb);
451 clrbuf(bp);
452 *bpp = bp;
453 }
454 }
455 ip->i_ffs2_db[lbn] = ufs_rw64(newb, needswap);
456 return (0);
457 }
458
459 /*
460 * Determine the number of levels of indirection.
461 */
462
463 pref = 0;
464 if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
465 return (error);
466
467 if (num < 1) {
468 warnx("ffs_balloc: ufs_getlbns returned indirect block");
469 abort();
470 }
471
472 /*
473 * Fetch the first indirect block allocating if necessary.
474 */
475
476 --num;
477 nb = ufs_rw64(ip->i_ffs2_ib[indirs[0].in_off], needswap);
478 allocib = NULL;
479 allocblk = allociblk;
480 if (nb == 0) {
481 pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
482 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
483 if (error)
484 return error;
485 nb = newb;
486 *allocblk++ = nb;
487 bp = getblk(&vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
488 bp->b_blkno = fsbtodb(fs, nb);
489 clrbuf(bp);
490 /*
491 * Write synchronously so that indirect blocks
492 * never point at garbage.
493 */
494 if ((error = bwrite(bp)) != 0)
495 return error;
496 allocib = &ip->i_ffs2_ib[indirs[0].in_off];
497 *allocib = ufs_rw64(nb, needswap);
498 }
499
500 /*
501 * Fetch through the indirect blocks, allocating as necessary.
502 */
503
504 for (i = 1;;) {
505 error = bread(&vp, indirs[i].in_lbn, fs->fs_bsize, NULL, 0,
506 &bp);
507 if (error) {
508 brelse(bp, 0);
509 return error;
510 }
511 bap = (int64_t *)bp->b_data;
512 nb = ufs_rw64(bap[indirs[i].in_off], needswap);
513 if (i == num)
514 break;
515 i++;
516 if (nb != 0) {
517 brelse(bp, 0);
518 continue;
519 }
520 if (pref == 0)
521 pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
522 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
523 if (error) {
524 brelse(bp, 0);
525 return error;
526 }
527 nb = newb;
528 *allocblk++ = nb;
529 nbp = getblk(&vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
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, 0);
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, 0);
555 return error;
556 }
557 nb = newb;
558 *allocblk++ = nb;
559 if (bpp != NULL) {
560 nbp = getblk(&vp, lbn, fs->fs_bsize, 0, 0);
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, 0);
575 if (bpp != NULL) {
576 error = bread(&vp, lbn, (int)fs->fs_bsize, NULL, 0, &nbp);
577 if (error) {
578 brelse(nbp, 0);
579 return error;
580 }
581 *bpp = nbp;
582 }
583 return (0);
584 }
585