1*7247f83aSnatano /* $OpenBSD: ffs_balloc.c,v 1.8 2016/10/22 19:43:50 natano Exp $ */
26163fc9cSnatano /* $NetBSD: ffs_balloc.c,v 1.21 2015/03/29 05:52:59 agc Exp $ */
36163fc9cSnatano /* From NetBSD: ffs_balloc.c,v 1.25 2001/08/08 08:36:36 lukem Exp */
46163fc9cSnatano
56163fc9cSnatano /*
66163fc9cSnatano * Copyright (c) 1982, 1986, 1989, 1993
76163fc9cSnatano * The Regents of the University of California. All rights reserved.
86163fc9cSnatano *
96163fc9cSnatano * Redistribution and use in source and binary forms, with or without
106163fc9cSnatano * modification, are permitted provided that the following conditions
116163fc9cSnatano * are met:
126163fc9cSnatano * 1. Redistributions of source code must retain the above copyright
136163fc9cSnatano * notice, this list of conditions and the following disclaimer.
146163fc9cSnatano * 2. Redistributions in binary form must reproduce the above copyright
156163fc9cSnatano * notice, this list of conditions and the following disclaimer in the
166163fc9cSnatano * documentation and/or other materials provided with the distribution.
176163fc9cSnatano * 3. Neither the name of the University nor the names of its contributors
186163fc9cSnatano * may be used to endorse or promote products derived from this software
196163fc9cSnatano * without specific prior written permission.
206163fc9cSnatano *
216163fc9cSnatano * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
226163fc9cSnatano * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
236163fc9cSnatano * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
246163fc9cSnatano * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
256163fc9cSnatano * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
266163fc9cSnatano * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
276163fc9cSnatano * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
286163fc9cSnatano * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
296163fc9cSnatano * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
306163fc9cSnatano * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
316163fc9cSnatano * SUCH DAMAGE.
326163fc9cSnatano *
336163fc9cSnatano * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95
346163fc9cSnatano */
356163fc9cSnatano
366163fc9cSnatano #include <assert.h>
376163fc9cSnatano #include <errno.h>
386163fc9cSnatano #include <stdio.h>
396163fc9cSnatano #include <stdlib.h>
406163fc9cSnatano
416c4d9c1cSnatano #include <ufs/ufs/dinode.h>
426c4d9c1cSnatano #include <ufs/ffs/fs.h>
436163fc9cSnatano
446163fc9cSnatano #include "ffs/buf.h"
456163fc9cSnatano #include "ffs/ufs_inode.h"
466163fc9cSnatano #include "ffs/ffs_extern.h"
476163fc9cSnatano
484af638d7Stedu static int ffs_balloc_ufs1(struct inode *, off_t, int, struct mkfsbuf **);
494af638d7Stedu static int ffs_balloc_ufs2(struct inode *, off_t, int, struct mkfsbuf **);
506163fc9cSnatano
516163fc9cSnatano /*
526163fc9cSnatano * Balloc defines the structure of file system storage
536163fc9cSnatano * by allocating the physical blocks on a device given
546163fc9cSnatano * the inode and the logical block number in a file.
556163fc9cSnatano *
566163fc9cSnatano * Assume: flags == B_SYNC | B_CLRBUF
576163fc9cSnatano */
586163fc9cSnatano
596163fc9cSnatano int
ffs_balloc(struct inode * ip,off_t offset,int bufsize,struct mkfsbuf ** bpp)604af638d7Stedu ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct mkfsbuf **bpp)
616163fc9cSnatano {
626163fc9cSnatano if (ip->i_fs->fs_magic == FS_UFS2_MAGIC)
636163fc9cSnatano return ffs_balloc_ufs2(ip, offset, bufsize, bpp);
646163fc9cSnatano else
656163fc9cSnatano return ffs_balloc_ufs1(ip, offset, bufsize, bpp);
666163fc9cSnatano }
676163fc9cSnatano
686163fc9cSnatano static int
ffs_balloc_ufs1(struct inode * ip,off_t offset,int bufsize,struct mkfsbuf ** bpp)694af638d7Stedu ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct mkfsbuf **bpp)
706163fc9cSnatano {
716163fc9cSnatano daddr_t lbn, lastlbn;
726163fc9cSnatano int size;
736163fc9cSnatano int32_t nb;
744af638d7Stedu struct mkfsbuf *bp, *nbp;
756163fc9cSnatano struct fs *fs = ip->i_fs;
766c4d9c1cSnatano struct indir indirs[NIADDR + 2];
776163fc9cSnatano daddr_t newb, pref;
786163fc9cSnatano int32_t *bap;
796163fc9cSnatano int osize, nsize, num, i, error;
806c4d9c1cSnatano int32_t *allocblk, allociblk[NIADDR + 1];
816163fc9cSnatano int32_t *allocib;
826163fc9cSnatano
836c4d9c1cSnatano lbn = lblkno(fs, offset);
846c4d9c1cSnatano size = blkoff(fs, offset) + bufsize;
856163fc9cSnatano if (bpp != NULL) {
866163fc9cSnatano *bpp = NULL;
876163fc9cSnatano }
886163fc9cSnatano
896163fc9cSnatano assert(size <= fs->fs_bsize);
906163fc9cSnatano if (lbn < 0)
916163fc9cSnatano return (EFBIG);
926163fc9cSnatano
936163fc9cSnatano /*
946163fc9cSnatano * If the next write will extend the file into a new block,
956163fc9cSnatano * and the file is currently composed of a fragment
966163fc9cSnatano * this fragment has to be extended to be a full block.
976163fc9cSnatano */
986163fc9cSnatano
996c4d9c1cSnatano lastlbn = lblkno(fs, ip->i_ffs1_size);
1006c4d9c1cSnatano if (lastlbn < NDADDR && lastlbn < lbn) {
1016163fc9cSnatano nb = lastlbn;
1026c4d9c1cSnatano osize = blksize(fs, ip, nb);
1036163fc9cSnatano if (osize < fs->fs_bsize && osize > 0) {
1046163fc9cSnatano warnx("need to ffs_realloccg; not supported!");
1056163fc9cSnatano abort();
1066163fc9cSnatano }
1076163fc9cSnatano }
1086163fc9cSnatano
1096163fc9cSnatano /*
1106c4d9c1cSnatano * The first NDADDR blocks are direct blocks
1116163fc9cSnatano */
1126163fc9cSnatano
1136c4d9c1cSnatano if (lbn < NDADDR) {
114*7247f83aSnatano nb = ip->i_ffs1_db[lbn];
1156c4d9c1cSnatano if (nb != 0 && ip->i_ffs1_size >= lblktosize(fs, lbn + 1)) {
1166163fc9cSnatano
1176163fc9cSnatano /*
1186163fc9cSnatano * The block is an already-allocated direct block
1196163fc9cSnatano * and the file already extends past this block,
1206163fc9cSnatano * thus this must be a whole block.
1216163fc9cSnatano * Just read the block (if requested).
1226163fc9cSnatano */
1236163fc9cSnatano
1246163fc9cSnatano if (bpp != NULL) {
1256163fc9cSnatano error = bread(ip->i_devvp, lbn, fs->fs_bsize,
1266163fc9cSnatano 0, bpp);
1276163fc9cSnatano if (error) {
1286163fc9cSnatano brelse(*bpp, 0);
1296163fc9cSnatano return (error);
1306163fc9cSnatano }
1316163fc9cSnatano }
1326163fc9cSnatano return (0);
1336163fc9cSnatano }
1346163fc9cSnatano if (nb != 0) {
1356163fc9cSnatano
1366163fc9cSnatano /*
1376163fc9cSnatano * Consider need to reallocate a fragment.
1386163fc9cSnatano */
1396163fc9cSnatano
1406c4d9c1cSnatano osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size));
1416c4d9c1cSnatano nsize = fragroundup(fs, size);
1426163fc9cSnatano if (nsize <= osize) {
1436163fc9cSnatano
1446163fc9cSnatano /*
1456163fc9cSnatano * The existing block is already
1466163fc9cSnatano * at least as big as we want.
1476163fc9cSnatano * Just read the block (if requested).
1486163fc9cSnatano */
1496163fc9cSnatano
1506163fc9cSnatano if (bpp != NULL) {
1516163fc9cSnatano error = bread(ip->i_devvp, lbn, osize,
1526163fc9cSnatano 0, bpp);
1536163fc9cSnatano if (error) {
1546163fc9cSnatano brelse(*bpp, 0);
1556163fc9cSnatano return (error);
1566163fc9cSnatano }
1576163fc9cSnatano }
1586163fc9cSnatano return 0;
1596163fc9cSnatano } else {
1606163fc9cSnatano warnx("need to ffs_realloccg; not supported!");
1616163fc9cSnatano abort();
1626163fc9cSnatano }
1636163fc9cSnatano } else {
1646163fc9cSnatano
1656163fc9cSnatano /*
1666163fc9cSnatano * the block was not previously allocated,
1676163fc9cSnatano * allocate a new block or fragment.
1686163fc9cSnatano */
1696163fc9cSnatano
1706c4d9c1cSnatano if (ip->i_ffs1_size < lblktosize(fs, lbn + 1))
1716c4d9c1cSnatano nsize = fragroundup(fs, size);
1726163fc9cSnatano else
1736163fc9cSnatano nsize = fs->fs_bsize;
1746163fc9cSnatano error = ffs_alloc(ip, lbn,
1756163fc9cSnatano ffs_blkpref_ufs1(ip, lbn, (int)lbn,
1766163fc9cSnatano &ip->i_ffs1_db[0]),
1776163fc9cSnatano nsize, &newb);
1786163fc9cSnatano if (error)
1796163fc9cSnatano return (error);
1806163fc9cSnatano if (bpp != NULL) {
1816163fc9cSnatano bp = getblk(ip->i_devvp, lbn, nsize, 0, 0);
1826c4d9c1cSnatano bp->b_blkno = fsbtodb(fs, newb);
1836163fc9cSnatano clrbuf(bp);
1846163fc9cSnatano *bpp = bp;
1856163fc9cSnatano }
1866163fc9cSnatano }
187*7247f83aSnatano ip->i_ffs1_db[lbn] = newb;
1886163fc9cSnatano return (0);
1896163fc9cSnatano }
1906163fc9cSnatano
1916163fc9cSnatano /*
1926163fc9cSnatano * Determine the number of levels of indirection.
1936163fc9cSnatano */
1946163fc9cSnatano
1956163fc9cSnatano pref = 0;
1966163fc9cSnatano if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
1976163fc9cSnatano return (error);
1986163fc9cSnatano
1996163fc9cSnatano if (num < 1) {
2006163fc9cSnatano warnx("ffs_balloc: ufs_getlbns returned indirect block");
2016163fc9cSnatano abort();
2026163fc9cSnatano }
2036163fc9cSnatano
2046163fc9cSnatano /*
2056163fc9cSnatano * Fetch the first indirect block allocating if necessary.
2066163fc9cSnatano */
2076163fc9cSnatano
2086163fc9cSnatano --num;
209*7247f83aSnatano nb = ip->i_ffs1_ib[indirs[0].in_off];
2106163fc9cSnatano allocib = NULL;
2116163fc9cSnatano allocblk = allociblk;
2126163fc9cSnatano if (nb == 0) {
2136163fc9cSnatano pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
2146163fc9cSnatano error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
2156163fc9cSnatano if (error)
2166163fc9cSnatano return error;
2176163fc9cSnatano nb = newb;
2186163fc9cSnatano *allocblk++ = nb;
2196163fc9cSnatano bp = getblk(ip->i_devvp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
2206c4d9c1cSnatano bp->b_blkno = fsbtodb(fs, nb);
2216163fc9cSnatano clrbuf(bp);
2226163fc9cSnatano /*
2236163fc9cSnatano * Write synchronously so that indirect blocks
2246163fc9cSnatano * never point at garbage.
2256163fc9cSnatano */
2266163fc9cSnatano if ((error = bwrite(bp)) != 0)
2276163fc9cSnatano return error;
2286163fc9cSnatano allocib = &ip->i_ffs1_ib[indirs[0].in_off];
229*7247f83aSnatano *allocib = nb;
2306163fc9cSnatano }
2316163fc9cSnatano
2326163fc9cSnatano /*
2336163fc9cSnatano * Fetch through the indirect blocks, allocating as necessary.
2346163fc9cSnatano */
2356163fc9cSnatano
2366163fc9cSnatano for (i = 1;;) {
2376163fc9cSnatano error = bread(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize,
2386163fc9cSnatano 0, &bp);
2396163fc9cSnatano if (error) {
2406163fc9cSnatano brelse(bp, 0);
2416163fc9cSnatano return error;
2426163fc9cSnatano }
2436163fc9cSnatano bap = (int32_t *)bp->b_data;
244*7247f83aSnatano nb = bap[indirs[i].in_off];
2456163fc9cSnatano if (i == num)
2466163fc9cSnatano break;
2476163fc9cSnatano i++;
2486163fc9cSnatano if (nb != 0) {
2496163fc9cSnatano brelse(bp, 0);
2506163fc9cSnatano continue;
2516163fc9cSnatano }
2526163fc9cSnatano if (pref == 0)
2536163fc9cSnatano pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
2546163fc9cSnatano error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
2556163fc9cSnatano if (error) {
2566163fc9cSnatano brelse(bp, 0);
2576163fc9cSnatano return error;
2586163fc9cSnatano }
2596163fc9cSnatano nb = newb;
2606163fc9cSnatano *allocblk++ = nb;
2616163fc9cSnatano nbp = getblk(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
2626c4d9c1cSnatano nbp->b_blkno = fsbtodb(fs, nb);
2636163fc9cSnatano clrbuf(nbp);
2646163fc9cSnatano /*
2656163fc9cSnatano * Write synchronously so that indirect blocks
2666163fc9cSnatano * never point at garbage.
2676163fc9cSnatano */
2686163fc9cSnatano
2696163fc9cSnatano if ((error = bwrite(nbp)) != 0) {
2706163fc9cSnatano brelse(bp, 0);
2716163fc9cSnatano return error;
2726163fc9cSnatano }
273*7247f83aSnatano bap[indirs[i - 1].in_off] = nb;
2746163fc9cSnatano
2756163fc9cSnatano bwrite(bp);
2766163fc9cSnatano }
2776163fc9cSnatano
2786163fc9cSnatano /*
2796163fc9cSnatano * Get the data block, allocating if necessary.
2806163fc9cSnatano */
2816163fc9cSnatano
2826163fc9cSnatano if (nb == 0) {
2836163fc9cSnatano pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]);
2846163fc9cSnatano error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
2856163fc9cSnatano if (error) {
2866163fc9cSnatano brelse(bp, 0);
2876163fc9cSnatano return error;
2886163fc9cSnatano }
2896163fc9cSnatano nb = newb;
2906163fc9cSnatano *allocblk++ = nb;
2916163fc9cSnatano if (bpp != NULL) {
2926163fc9cSnatano nbp = getblk(ip->i_devvp, lbn, fs->fs_bsize, 0, 0);
2936c4d9c1cSnatano nbp->b_blkno = fsbtodb(fs, nb);
2946163fc9cSnatano clrbuf(nbp);
2956163fc9cSnatano *bpp = nbp;
2966163fc9cSnatano }
297*7247f83aSnatano bap[indirs[num].in_off] = nb;
2986163fc9cSnatano
2996163fc9cSnatano /*
3006163fc9cSnatano * If required, write synchronously, otherwise use
3016163fc9cSnatano * delayed write.
3026163fc9cSnatano */
3036163fc9cSnatano bwrite(bp);
3046163fc9cSnatano return (0);
3056163fc9cSnatano }
3066163fc9cSnatano brelse(bp, 0);
3076163fc9cSnatano if (bpp != NULL) {
3086163fc9cSnatano error = bread(ip->i_devvp, lbn, (int)fs->fs_bsize, 0, &nbp);
3096163fc9cSnatano if (error) {
3106163fc9cSnatano brelse(nbp, 0);
3116163fc9cSnatano return error;
3126163fc9cSnatano }
3136163fc9cSnatano *bpp = nbp;
3146163fc9cSnatano }
3156163fc9cSnatano return (0);
3166163fc9cSnatano }
3176163fc9cSnatano
3186163fc9cSnatano static int
ffs_balloc_ufs2(struct inode * ip,off_t offset,int bufsize,struct mkfsbuf ** bpp)3194af638d7Stedu ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct mkfsbuf **bpp)
3206163fc9cSnatano {
3216163fc9cSnatano daddr_t lbn, lastlbn;
3226163fc9cSnatano int size;
3234af638d7Stedu struct mkfsbuf *bp, *nbp;
3246163fc9cSnatano struct fs *fs = ip->i_fs;
3256c4d9c1cSnatano struct indir indirs[NIADDR + 2];
3266163fc9cSnatano daddr_t newb, pref, nb;
3276163fc9cSnatano int64_t *bap;
3286163fc9cSnatano int osize, nsize, num, i, error;
3296c4d9c1cSnatano int64_t *allocblk, allociblk[NIADDR + 1];
3306163fc9cSnatano int64_t *allocib;
3316163fc9cSnatano
3326c4d9c1cSnatano lbn = lblkno(fs, offset);
3336c4d9c1cSnatano size = blkoff(fs, offset) + bufsize;
3346163fc9cSnatano if (bpp != NULL) {
3356163fc9cSnatano *bpp = NULL;
3366163fc9cSnatano }
3376163fc9cSnatano
3386163fc9cSnatano assert(size <= fs->fs_bsize);
3396163fc9cSnatano if (lbn < 0)
3406163fc9cSnatano return (EFBIG);
3416163fc9cSnatano
3426163fc9cSnatano /*
3436163fc9cSnatano * If the next write will extend the file into a new block,
3446163fc9cSnatano * and the file is currently composed of a fragment
3456163fc9cSnatano * this fragment has to be extended to be a full block.
3466163fc9cSnatano */
3476163fc9cSnatano
3486c4d9c1cSnatano lastlbn = lblkno(fs, ip->i_ffs2_size);
3496c4d9c1cSnatano if (lastlbn < NDADDR && lastlbn < lbn) {
3506163fc9cSnatano nb = lastlbn;
3516c4d9c1cSnatano osize = blksize(fs, ip, nb);
3526163fc9cSnatano if (osize < fs->fs_bsize && osize > 0) {
3536163fc9cSnatano warnx("need to ffs_realloccg; not supported!");
3546163fc9cSnatano abort();
3556163fc9cSnatano }
3566163fc9cSnatano }
3576163fc9cSnatano
3586163fc9cSnatano /*
3596c4d9c1cSnatano * The first NDADDR blocks are direct blocks
3606163fc9cSnatano */
3616163fc9cSnatano
3626c4d9c1cSnatano if (lbn < NDADDR) {
363*7247f83aSnatano nb = ip->i_ffs2_db[lbn];
3646c4d9c1cSnatano if (nb != 0 && ip->i_ffs2_size >= lblktosize(fs, lbn + 1)) {
3656163fc9cSnatano
3666163fc9cSnatano /*
3676163fc9cSnatano * The block is an already-allocated direct block
3686163fc9cSnatano * and the file already extends past this block,
3696163fc9cSnatano * thus this must be a whole block.
3706163fc9cSnatano * Just read the block (if requested).
3716163fc9cSnatano */
3726163fc9cSnatano
3736163fc9cSnatano if (bpp != NULL) {
3746163fc9cSnatano error = bread(ip->i_devvp, lbn, fs->fs_bsize,
3756163fc9cSnatano 0, bpp);
3766163fc9cSnatano if (error) {
3776163fc9cSnatano brelse(*bpp, 0);
3786163fc9cSnatano return (error);
3796163fc9cSnatano }
3806163fc9cSnatano }
3816163fc9cSnatano return (0);
3826163fc9cSnatano }
3836163fc9cSnatano if (nb != 0) {
3846163fc9cSnatano
3856163fc9cSnatano /*
3866163fc9cSnatano * Consider need to reallocate a fragment.
3876163fc9cSnatano */
3886163fc9cSnatano
3896c4d9c1cSnatano osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size));
3906c4d9c1cSnatano nsize = fragroundup(fs, size);
3916163fc9cSnatano if (nsize <= osize) {
3926163fc9cSnatano
3936163fc9cSnatano /*
3946163fc9cSnatano * The existing block is already
3956163fc9cSnatano * at least as big as we want.
3966163fc9cSnatano * Just read the block (if requested).
3976163fc9cSnatano */
3986163fc9cSnatano
3996163fc9cSnatano if (bpp != NULL) {
4006163fc9cSnatano error = bread(ip->i_devvp, lbn, osize,
4016163fc9cSnatano 0, bpp);
4026163fc9cSnatano if (error) {
4036163fc9cSnatano brelse(*bpp, 0);
4046163fc9cSnatano return (error);
4056163fc9cSnatano }
4066163fc9cSnatano }
4076163fc9cSnatano return 0;
4086163fc9cSnatano } else {
4096163fc9cSnatano warnx("need to ffs_realloccg; not supported!");
4106163fc9cSnatano abort();
4116163fc9cSnatano }
4126163fc9cSnatano } else {
4136163fc9cSnatano
4146163fc9cSnatano /*
4156163fc9cSnatano * the block was not previously allocated,
4166163fc9cSnatano * allocate a new block or fragment.
4176163fc9cSnatano */
4186163fc9cSnatano
4196c4d9c1cSnatano if (ip->i_ffs2_size < lblktosize(fs, lbn + 1))
4206c4d9c1cSnatano nsize = fragroundup(fs, size);
4216163fc9cSnatano else
4226163fc9cSnatano nsize = fs->fs_bsize;
4236163fc9cSnatano error = ffs_alloc(ip, lbn,
4246163fc9cSnatano ffs_blkpref_ufs2(ip, lbn, (int)lbn,
4256163fc9cSnatano &ip->i_ffs2_db[0]),
4266163fc9cSnatano nsize, &newb);
4276163fc9cSnatano if (error)
4286163fc9cSnatano return (error);
4296163fc9cSnatano if (bpp != NULL) {
4306163fc9cSnatano bp = getblk(ip->i_devvp, lbn, nsize, 0, 0);
4316c4d9c1cSnatano bp->b_blkno = fsbtodb(fs, newb);
4326163fc9cSnatano clrbuf(bp);
4336163fc9cSnatano *bpp = bp;
4346163fc9cSnatano }
4356163fc9cSnatano }
436*7247f83aSnatano ip->i_ffs2_db[lbn] = newb;
4376163fc9cSnatano return (0);
4386163fc9cSnatano }
4396163fc9cSnatano
4406163fc9cSnatano /*
4416163fc9cSnatano * Determine the number of levels of indirection.
4426163fc9cSnatano */
4436163fc9cSnatano
4446163fc9cSnatano pref = 0;
4456163fc9cSnatano if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
4466163fc9cSnatano return (error);
4476163fc9cSnatano
4486163fc9cSnatano if (num < 1) {
4496163fc9cSnatano warnx("ffs_balloc: ufs_getlbns returned indirect block");
4506163fc9cSnatano abort();
4516163fc9cSnatano }
4526163fc9cSnatano
4536163fc9cSnatano /*
4546163fc9cSnatano * Fetch the first indirect block allocating if necessary.
4556163fc9cSnatano */
4566163fc9cSnatano
4576163fc9cSnatano --num;
458*7247f83aSnatano nb = ip->i_ffs2_ib[indirs[0].in_off];
4596163fc9cSnatano allocib = NULL;
4606163fc9cSnatano allocblk = allociblk;
4616163fc9cSnatano if (nb == 0) {
4626163fc9cSnatano pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
4636163fc9cSnatano error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
4646163fc9cSnatano if (error)
4656163fc9cSnatano return error;
4666163fc9cSnatano nb = newb;
4676163fc9cSnatano *allocblk++ = nb;
4686163fc9cSnatano bp = getblk(ip->i_devvp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
4696c4d9c1cSnatano bp->b_blkno = fsbtodb(fs, nb);
4706163fc9cSnatano clrbuf(bp);
4716163fc9cSnatano /*
4726163fc9cSnatano * Write synchronously so that indirect blocks
4736163fc9cSnatano * never point at garbage.
4746163fc9cSnatano */
4756163fc9cSnatano if ((error = bwrite(bp)) != 0)
4766163fc9cSnatano return error;
4776163fc9cSnatano allocib = &ip->i_ffs2_ib[indirs[0].in_off];
478*7247f83aSnatano *allocib = nb;
4796163fc9cSnatano }
4806163fc9cSnatano
4816163fc9cSnatano /*
4826163fc9cSnatano * Fetch through the indirect blocks, allocating as necessary.
4836163fc9cSnatano */
4846163fc9cSnatano
4856163fc9cSnatano for (i = 1;;) {
4866163fc9cSnatano error = bread(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize,
4876163fc9cSnatano 0, &bp);
4886163fc9cSnatano if (error) {
4896163fc9cSnatano brelse(bp, 0);
4906163fc9cSnatano return error;
4916163fc9cSnatano }
4926163fc9cSnatano bap = (int64_t *)bp->b_data;
493*7247f83aSnatano nb = bap[indirs[i].in_off];
4946163fc9cSnatano if (i == num)
4956163fc9cSnatano break;
4966163fc9cSnatano i++;
4976163fc9cSnatano if (nb != 0) {
4986163fc9cSnatano brelse(bp, 0);
4996163fc9cSnatano continue;
5006163fc9cSnatano }
5016163fc9cSnatano if (pref == 0)
5026163fc9cSnatano pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
5036163fc9cSnatano error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
5046163fc9cSnatano if (error) {
5056163fc9cSnatano brelse(bp, 0);
5066163fc9cSnatano return error;
5076163fc9cSnatano }
5086163fc9cSnatano nb = newb;
5096163fc9cSnatano *allocblk++ = nb;
5106163fc9cSnatano nbp = getblk(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
5116c4d9c1cSnatano nbp->b_blkno = fsbtodb(fs, nb);
5126163fc9cSnatano clrbuf(nbp);
5136163fc9cSnatano /*
5146163fc9cSnatano * Write synchronously so that indirect blocks
5156163fc9cSnatano * never point at garbage.
5166163fc9cSnatano */
5176163fc9cSnatano
5186163fc9cSnatano if ((error = bwrite(nbp)) != 0) {
5196163fc9cSnatano brelse(bp, 0);
5206163fc9cSnatano return error;
5216163fc9cSnatano }
522*7247f83aSnatano bap[indirs[i - 1].in_off] = nb;
5236163fc9cSnatano
5246163fc9cSnatano bwrite(bp);
5256163fc9cSnatano }
5266163fc9cSnatano
5276163fc9cSnatano /*
5286163fc9cSnatano * Get the data block, allocating if necessary.
5296163fc9cSnatano */
5306163fc9cSnatano
5316163fc9cSnatano if (nb == 0) {
5326163fc9cSnatano pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]);
5336163fc9cSnatano error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
5346163fc9cSnatano if (error) {
5356163fc9cSnatano brelse(bp, 0);
5366163fc9cSnatano return error;
5376163fc9cSnatano }
5386163fc9cSnatano nb = newb;
5396163fc9cSnatano *allocblk++ = nb;
5406163fc9cSnatano if (bpp != NULL) {
5416163fc9cSnatano nbp = getblk(ip->i_devvp, lbn, fs->fs_bsize, 0, 0);
5426c4d9c1cSnatano nbp->b_blkno = fsbtodb(fs, nb);
5436163fc9cSnatano clrbuf(nbp);
5446163fc9cSnatano *bpp = nbp;
5456163fc9cSnatano }
546*7247f83aSnatano bap[indirs[num].in_off] = nb;
5476163fc9cSnatano
5486163fc9cSnatano /*
5496163fc9cSnatano * If required, write synchronously, otherwise use
5506163fc9cSnatano * delayed write.
5516163fc9cSnatano */
5526163fc9cSnatano bwrite(bp);
5536163fc9cSnatano return (0);
5546163fc9cSnatano }
5556163fc9cSnatano brelse(bp, 0);
5566163fc9cSnatano if (bpp != NULL) {
5576163fc9cSnatano error = bread(ip->i_devvp, lbn, (int)fs->fs_bsize, 0,
5586163fc9cSnatano &nbp);
5596163fc9cSnatano if (error) {
5606163fc9cSnatano brelse(nbp, 0);
5616163fc9cSnatano return error;
5626163fc9cSnatano }
5636163fc9cSnatano *bpp = nbp;
5646163fc9cSnatano }
5656163fc9cSnatano return (0);
5666163fc9cSnatano }
567