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 * SPDX-License-Identifier: BSD-3-Clause 6 * 7 * Copyright (c) 1982, 1986, 1989, 1993 8 * The Regents of the University of California. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95 35 */ 36 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 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 59 static int ffs_balloc_ufs1(struct inode *, off_t, int, struct buf **); 60 static 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 70 int 71 ffs_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 79 static int 80 ffs_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[UFS_NIADDR + 2]; 88 daddr_t newb, pref; 89 int32_t *bap; 90 int osize, nsize, num, i, error; 91 int32_t *allocblk, allociblk[UFS_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 < UFS_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 UFS_NDADDR blocks are direct blocks 123 */ 124 125 if (lbn < UFS_NDADDR) { 126 nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap); 127 if (nb != 0 && ip->i_ffs1_size >= 128 (uint64_t)lblktosize(fs, lbn + 1)) { 129 130 /* 131 * The block is an already-allocated direct block 132 * and the file already extends past this block, 133 * thus this must be a whole block. 134 * Just read the block (if requested). 135 */ 136 137 if (bpp != NULL) { 138 error = bread(ip->i_devvp, lbn, fs->fs_bsize, 139 NULL, bpp); 140 if (error) { 141 brelse(*bpp); 142 return (error); 143 } 144 } 145 return (0); 146 } 147 if (nb != 0) { 148 149 /* 150 * Consider need to reallocate a fragment. 151 */ 152 153 osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size)); 154 nsize = fragroundup(fs, size); 155 if (nsize <= osize) { 156 157 /* 158 * The existing block is already 159 * at least as big as we want. 160 * Just read the block (if requested). 161 */ 162 163 if (bpp != NULL) { 164 error = bread(ip->i_devvp, lbn, osize, 165 NULL, bpp); 166 if (error) { 167 brelse(*bpp); 168 return (error); 169 } 170 } 171 return 0; 172 } else { 173 warnx("need to ffs_realloccg; not supported!"); 174 abort(); 175 } 176 } else { 177 178 /* 179 * the block was not previously allocated, 180 * allocate a new block or fragment. 181 */ 182 183 if (ip->i_ffs1_size < (uint64_t)lblktosize(fs, lbn + 1)) 184 nsize = fragroundup(fs, size); 185 else 186 nsize = fs->fs_bsize; 187 error = ffs_alloc(ip, lbn, 188 ffs_blkpref_ufs1(ip, lbn, (int)lbn, 189 &ip->i_ffs1_db[0]), 190 nsize, &newb); 191 if (error) 192 return (error); 193 if (bpp != NULL) { 194 bp = getblk(ip->i_devvp, lbn, nsize, 0, 0, 0); 195 bp->b_blkno = fsbtodb(fs, newb); 196 clrbuf(bp); 197 *bpp = bp; 198 } 199 } 200 ip->i_ffs1_db[lbn] = ufs_rw32((int32_t)newb, needswap); 201 return (0); 202 } 203 204 /* 205 * Determine the number of levels of indirection. 206 */ 207 208 pref = 0; 209 if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0) 210 return (error); 211 212 if (num < 1) { 213 warnx("ffs_balloc: ufs_getlbns returned indirect block"); 214 abort(); 215 } 216 217 /* 218 * Fetch the first indirect block allocating if necessary. 219 */ 220 221 --num; 222 nb = ufs_rw32(ip->i_ffs1_ib[indirs[0].in_off], needswap); 223 allocib = NULL; 224 allocblk = allociblk; 225 if (nb == 0) { 226 pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0); 227 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); 228 if (error) 229 return error; 230 nb = newb; 231 *allocblk++ = nb; 232 bp = getblk(ip->i_devvp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0); 233 bp->b_blkno = fsbtodb(fs, nb); 234 clrbuf(bp); 235 /* 236 * Write synchronously so that indirect blocks 237 * never point at garbage. 238 */ 239 if ((error = bwrite(bp)) != 0) 240 return error; 241 allocib = &ip->i_ffs1_ib[indirs[0].in_off]; 242 *allocib = ufs_rw32((int32_t)nb, needswap); 243 } 244 245 /* 246 * Fetch through the indirect blocks, allocating as necessary. 247 */ 248 249 for (i = 1;;) { 250 error = bread(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize, 251 NULL, &bp); 252 if (error) { 253 brelse(bp); 254 return error; 255 } 256 bap = (int32_t *)bp->b_data; 257 nb = ufs_rw32(bap[indirs[i].in_off], needswap); 258 if (i == num) 259 break; 260 i++; 261 if (nb != 0) { 262 brelse(bp); 263 continue; 264 } 265 if (pref == 0) 266 pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0); 267 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); 268 if (error) { 269 brelse(bp); 270 return error; 271 } 272 nb = newb; 273 *allocblk++ = nb; 274 nbp = getblk(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0); 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_devvp, lbn, fs->fs_bsize, 0, 0, 0); 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_devvp, lbn, (int)fs->fs_bsize, NULL, &nbp); 322 if (error) { 323 brelse(nbp); 324 return error; 325 } 326 *bpp = nbp; 327 } 328 return (0); 329 } 330 331 static int 332 ffs_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[UFS_NIADDR + 2]; 339 daddr_t newb, pref, nb; 340 int64_t *bap; 341 int osize, nsize, num, i, error; 342 int64_t *allocblk, allociblk[UFS_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 < UFS_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 UFS_NDADDR blocks are direct blocks 374 */ 375 376 if (lbn < UFS_NDADDR) { 377 nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap); 378 if (nb != 0 && ip->i_ffs2_size >= 379 (uint64_t)lblktosize(fs, lbn + 1)) { 380 381 /* 382 * The block is an already-allocated direct block 383 * and the file already extends past this block, 384 * thus this must be a whole block. 385 * Just read the block (if requested). 386 */ 387 388 if (bpp != NULL) { 389 error = bread(ip->i_devvp, lbn, fs->fs_bsize, 390 NULL, bpp); 391 if (error) { 392 brelse(*bpp); 393 return (error); 394 } 395 } 396 return (0); 397 } 398 if (nb != 0) { 399 400 /* 401 * Consider need to reallocate a fragment. 402 */ 403 404 osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size)); 405 nsize = fragroundup(fs, size); 406 if (nsize <= osize) { 407 408 /* 409 * The existing block is already 410 * at least as big as we want. 411 * Just read the block (if requested). 412 */ 413 414 if (bpp != NULL) { 415 error = bread(ip->i_devvp, lbn, osize, 416 NULL, bpp); 417 if (error) { 418 brelse(*bpp); 419 return (error); 420 } 421 } 422 return 0; 423 } else { 424 warnx("need to ffs_realloccg; not supported!"); 425 abort(); 426 } 427 } else { 428 429 /* 430 * the block was not previously allocated, 431 * allocate a new block or fragment. 432 */ 433 434 if (ip->i_ffs2_size < (uint64_t)lblktosize(fs, lbn + 1)) 435 nsize = fragroundup(fs, size); 436 else 437 nsize = fs->fs_bsize; 438 error = ffs_alloc(ip, lbn, 439 ffs_blkpref_ufs2(ip, lbn, (int)lbn, 440 &ip->i_ffs2_db[0]), 441 nsize, &newb); 442 if (error) 443 return (error); 444 if (bpp != NULL) { 445 bp = getblk(ip->i_devvp, lbn, nsize, 0, 0, 0); 446 bp->b_blkno = fsbtodb(fs, newb); 447 clrbuf(bp); 448 *bpp = bp; 449 } 450 } 451 ip->i_ffs2_db[lbn] = ufs_rw64(newb, needswap); 452 return (0); 453 } 454 455 /* 456 * Determine the number of levels of indirection. 457 */ 458 459 pref = 0; 460 if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0) 461 return (error); 462 463 if (num < 1) { 464 warnx("ffs_balloc: ufs_getlbns returned indirect block"); 465 abort(); 466 } 467 468 /* 469 * Fetch the first indirect block allocating if necessary. 470 */ 471 472 --num; 473 nb = ufs_rw64(ip->i_ffs2_ib[indirs[0].in_off], needswap); 474 allocib = NULL; 475 allocblk = allociblk; 476 if (nb == 0) { 477 pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0); 478 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); 479 if (error) 480 return error; 481 nb = newb; 482 *allocblk++ = nb; 483 bp = getblk(ip->i_devvp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0); 484 bp->b_blkno = fsbtodb(fs, nb); 485 clrbuf(bp); 486 /* 487 * Write synchronously so that indirect blocks 488 * never point at garbage. 489 */ 490 if ((error = bwrite(bp)) != 0) 491 return error; 492 allocib = &ip->i_ffs2_ib[indirs[0].in_off]; 493 *allocib = ufs_rw64(nb, needswap); 494 } 495 496 /* 497 * Fetch through the indirect blocks, allocating as necessary. 498 */ 499 500 for (i = 1;;) { 501 error = bread(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize, 502 NULL, &bp); 503 if (error) { 504 brelse(bp); 505 return error; 506 } 507 bap = (int64_t *)bp->b_data; 508 nb = ufs_rw64(bap[indirs[i].in_off], needswap); 509 if (i == num) 510 break; 511 i++; 512 if (nb != 0) { 513 brelse(bp); 514 continue; 515 } 516 if (pref == 0) 517 pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0); 518 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb); 519 if (error) { 520 brelse(bp); 521 return error; 522 } 523 nb = newb; 524 *allocblk++ = nb; 525 nbp = getblk(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0); 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_devvp, lbn, fs->fs_bsize, 0, 0, 0); 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_devvp, lbn, (int)fs->fs_bsize, NULL, &nbp); 573 if (error) { 574 brelse(nbp); 575 return error; 576 } 577 *bpp = nbp; 578 } 579 return (0); 580 } 581