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