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