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