xref: /openbsd-src/usr.sbin/makefs/ffs/ffs_balloc.c (revision 7247f83abc859d2f791971d4585dfa4943bf1c01)
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