ffs_balloc.c revision 1.22 1 /* $NetBSD: ffs_balloc.c,v 1.22 2022/11/17 06:40:41 chs 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.22 2022/11/17 06:40:41 chs 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 ip->i_fs->fs_magic == FS_UFS2EA_MAGIC)
79 return ffs_balloc_ufs2(ip, offset, bufsize, bpp);
80 else
81 return ffs_balloc_ufs1(ip, offset, bufsize, bpp);
82 }
83
84 static int
85 ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
86 {
87 daddr_t lbn, lastlbn;
88 int size;
89 int32_t nb;
90 struct buf *bp, *nbp;
91 struct fs *fs = ip->i_fs;
92 struct indir indirs[UFS_NIADDR + 2];
93 daddr_t newb, pref;
94 int32_t *bap;
95 int osize, nsize, num, i, error;
96 int32_t *allocblk, allociblk[UFS_NIADDR + 1];
97 int32_t *allocib;
98 const int needswap = UFS_FSNEEDSWAP(fs);
99
100 lbn = ffs_lblkno(fs, offset);
101 size = ffs_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 = ffs_lblkno(fs, ip->i_ffs1_size);
117 if (lastlbn < UFS_NDADDR && lastlbn < lbn) {
118 nb = lastlbn;
119 osize = ffs_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 >= ffs_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(ip->i_devvp, lbn, fs->fs_bsize,
143 0, 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 = ffs_fragroundup(fs, ffs_blkoff(fs, ip->i_ffs1_size));
158 nsize = ffs_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(ip->i_devvp, lbn, osize,
169 0, 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 < ffs_lblktosize(fs, lbn + 1))
188 nsize = ffs_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(ip->i_devvp, lbn, nsize, 0, 0);
199 bp->b_blkno = FFS_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(ip->i_devvp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
237 bp->b_blkno = FFS_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(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize,
255 0, &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(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
279 nbp->b_blkno = FFS_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(ip->i_devvp, lbn, fs->fs_bsize, 0, 0);
310 nbp->b_blkno = FFS_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(ip->i_devvp, lbn, (int)fs->fs_bsize, 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
350 lbn = ffs_lblkno(fs, offset);
351 size = ffs_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 = ffs_lblkno(fs, ip->i_ffs2_size);
367 if (lastlbn < UFS_NDADDR && lastlbn < lbn) {
368 nb = lastlbn;
369 osize = ffs_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 UFS_NDADDR blocks are direct blocks
378 */
379
380 if (lbn < UFS_NDADDR) {
381 nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
382 if (nb != 0 && ip->i_ffs2_size >= ffs_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_devvp, lbn, fs->fs_bsize,
393 0, bpp);
394 if (error) {
395 brelse(*bpp, 0);
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 = ffs_fragroundup(fs, ffs_blkoff(fs, ip->i_ffs2_size));
408 nsize = ffs_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_devvp, lbn, osize,
419 0, bpp);
420 if (error) {
421 brelse(*bpp, 0);
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 < ffs_lblktosize(fs, lbn + 1))
438 nsize = ffs_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_devvp, lbn, nsize, 0, 0);
449 bp->b_blkno = FFS_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_devvp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
487 bp->b_blkno = FFS_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_devvp, indirs[i].in_lbn, fs->fs_bsize,
505 0, &bp);
506 if (error) {
507 brelse(bp, 0);
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, 0);
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, 0);
524 return error;
525 }
526 nb = newb;
527 *allocblk++ = nb;
528 nbp = getblk(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
529 nbp->b_blkno = FFS_FSBTODB(fs, nb);
530 clrbuf(nbp);
531 /*
532 * Write synchronously so that indirect blocks
533 * never point at garbage.
534 */
535
536 if ((error = bwrite(nbp)) != 0) {
537 brelse(bp, 0);
538 return error;
539 }
540 bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap);
541
542 bwrite(bp);
543 }
544
545 /*
546 * Get the data block, allocating if necessary.
547 */
548
549 if (nb == 0) {
550 pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]);
551 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
552 if (error) {
553 brelse(bp, 0);
554 return error;
555 }
556 nb = newb;
557 *allocblk++ = nb;
558 if (bpp != NULL) {
559 nbp = getblk(ip->i_devvp, lbn, fs->fs_bsize, 0, 0);
560 nbp->b_blkno = FFS_FSBTODB(fs, nb);
561 clrbuf(nbp);
562 *bpp = nbp;
563 }
564 bap[indirs[num].in_off] = ufs_rw64(nb, needswap);
565
566 /*
567 * If required, write synchronously, otherwise use
568 * delayed write.
569 */
570 bwrite(bp);
571 return (0);
572 }
573 brelse(bp, 0);
574 if (bpp != NULL) {
575 error = bread(ip->i_devvp, lbn, (int)fs->fs_bsize, 0,
576 &nbp);
577 if (error) {
578 brelse(nbp, 0);
579 return error;
580 }
581 *bpp = nbp;
582 }
583 return (0);
584 }
585