xref: /csrg-svn/sys/ufs/ffs/ffs_balloc.c (revision 69910)
123396Smckusick /*
263371Sbostic  * Copyright (c) 1982, 1986, 1989, 1993
363371Sbostic  *	The Regents of the University of California.  All rights reserved.
423396Smckusick  *
544537Sbostic  * %sccs.include.redist.c%
637736Smckusick  *
7*69910Smckusick  *	@(#)ffs_balloc.c	8.8 (Berkeley) 06/16/95
823396Smckusick  */
97443Sroot 
1051470Sbostic #include <sys/param.h>
1151470Sbostic #include <sys/systm.h>
1251470Sbostic #include <sys/buf.h>
1351470Sbostic #include <sys/proc.h>
1451470Sbostic #include <sys/file.h>
1551470Sbostic #include <sys/vnode.h>
167443Sroot 
1753318Smckusick #include <vm/vm.h>
1853318Smckusick 
1951470Sbostic #include <ufs/ufs/quota.h>
2051470Sbostic #include <ufs/ufs/inode.h>
2156444Smargo #include <ufs/ufs/ufs_extern.h>
2247571Skarels 
2351470Sbostic #include <ufs/ffs/fs.h>
2451470Sbostic #include <ufs/ffs/ffs_extern.h>
2551470Sbostic 
267443Sroot /*
2737736Smckusick  * Balloc defines the structure of file system storage
2839679Smckusick  * by allocating the physical blocks on a device given
2939679Smckusick  * the inode and the logical block number in a file.
3037736Smckusick  */
ffs_balloc(ip,lbn,size,cred,bpp,flags)3168153Smckusick ffs_balloc(ip, lbn, size, cred, bpp, flags)
3237736Smckusick 	register struct inode *ip;
3368554Smckusick 	register ufs_daddr_t lbn;
3437736Smckusick 	int size;
3553244Smckusick 	struct ucred *cred;
3639679Smckusick 	struct buf **bpp;
3737736Smckusick 	int flags;
3837736Smckusick {
3937736Smckusick 	register struct fs *fs;
4068554Smckusick 	register ufs_daddr_t nb;
417443Sroot 	struct buf *bp, *nbp;
4239679Smckusick 	struct vnode *vp = ITOV(ip);
4356444Smargo 	struct indir indirs[NIADDR + 2];
4468554Smckusick 	ufs_daddr_t newb, *bap, pref;
4569514Smckusick 	int deallocated, osize, nsize, num, i, error;
46*69910Smckusick 	ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
477443Sroot 
4864420Sbostic 	*bpp = NULL;
4968153Smckusick 	if (lbn < 0)
5037736Smckusick 		return (EFBIG);
517443Sroot 	fs = ip->i_fs;
527443Sroot 
537443Sroot 	/*
547443Sroot 	 * If the next write will extend the file into a new block,
557443Sroot 	 * and the file is currently composed of a fragment
567443Sroot 	 * this fragment has to be extended to be a full block.
577443Sroot 	 */
587443Sroot 	nb = lblkno(fs, ip->i_size);
5968153Smckusick 	if (nb < NDADDR && nb < lbn) {
607443Sroot 		osize = blksize(fs, ip, nb);
617443Sroot 		if (osize < fs->fs_bsize && osize > 0) {
6251470Sbostic 			error = ffs_realloccg(ip, nb,
6351470Sbostic 				ffs_blkpref(ip, nb, (int)nb, &ip->i_db[0]),
6453244Smckusick 				osize, (int)fs->fs_bsize, cred, &bp);
6539679Smckusick 			if (error)
6637736Smckusick 				return (error);
677443Sroot 			ip->i_size = (nb + 1) * fs->fs_bsize;
6853047Sralph 			vnode_pager_setsize(vp, (u_long)ip->i_size);
697443Sroot 			ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
7064606Sbostic 			ip->i_flag |= IN_CHANGE | IN_UPDATE;
7139679Smckusick 			if (flags & B_SYNC)
7239679Smckusick 				bwrite(bp);
7339679Smckusick 			else
7439679Smckusick 				bawrite(bp);
757443Sroot 		}
767443Sroot 	}
777443Sroot 	/*
787443Sroot 	 * The first NDADDR blocks are direct blocks
797443Sroot 	 */
8068153Smckusick 	if (lbn < NDADDR) {
8168153Smckusick 		nb = ip->i_db[lbn];
8268153Smckusick 		if (nb != 0 && ip->i_size >= (lbn + 1) * fs->fs_bsize) {
8368153Smckusick 			error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp);
8439679Smckusick 			if (error) {
8539679Smckusick 				brelse(bp);
8639679Smckusick 				return (error);
8739679Smckusick 			}
8839679Smckusick 			*bpp = bp;
8939679Smckusick 			return (0);
9039679Smckusick 		}
9139679Smckusick 		if (nb != 0) {
9239679Smckusick 			/*
9339679Smckusick 			 * Consider need to reallocate a fragment.
9439679Smckusick 			 */
9539679Smckusick 			osize = fragroundup(fs, blkoff(fs, ip->i_size));
9639679Smckusick 			nsize = fragroundup(fs, size);
9739679Smckusick 			if (nsize <= osize) {
9868153Smckusick 				error = bread(vp, lbn, osize, NOCRED, &bp);
9939679Smckusick 				if (error) {
10039679Smckusick 					brelse(bp);
10139679Smckusick 					return (error);
10239679Smckusick 				}
10339679Smckusick 			} else {
10468153Smckusick 				error = ffs_realloccg(ip, lbn,
10568153Smckusick 				    ffs_blkpref(ip, lbn, (int)lbn,
10668153Smckusick 					&ip->i_db[0]), osize, nsize, cred, &bp);
10739679Smckusick 				if (error)
10839679Smckusick 					return (error);
1097443Sroot 			}
11039679Smckusick 		} else {
11168153Smckusick 			if (ip->i_size < (lbn + 1) * fs->fs_bsize)
11239679Smckusick 				nsize = fragroundup(fs, size);
11339679Smckusick 			else
11439679Smckusick 				nsize = fs->fs_bsize;
11568153Smckusick 			error = ffs_alloc(ip, lbn,
11668153Smckusick 			    ffs_blkpref(ip, lbn, (int)lbn, &ip->i_db[0]),
11753244Smckusick 			    nsize, cred, &newb);
11839679Smckusick 			if (error)
11937736Smckusick 				return (error);
12068153Smckusick 			bp = getblk(vp, lbn, nsize, 0, 0);
12139679Smckusick 			bp->b_blkno = fsbtodb(fs, newb);
12239679Smckusick 			if (flags & B_CLRBUF)
12339679Smckusick 				clrbuf(bp);
1247443Sroot 		}
12568153Smckusick 		ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno);
12664606Sbostic 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
12739679Smckusick 		*bpp = bp;
12837736Smckusick 		return (0);
1297443Sroot 	}
1307443Sroot 	/*
13139679Smckusick 	 * Determine the number of levels of indirection.
1327443Sroot 	 */
1338258Smckusick 	pref = 0;
13468153Smckusick 	if (error = ufs_getlbns(vp, lbn, indirs, &num))
13556444Smargo 		return(error);
13656444Smargo #ifdef DIAGNOSTIC
13756444Smargo 	if (num < 1)
13856444Smargo 		panic ("ffs_balloc: ufs_bmaparray returned indirect block\n");
13956444Smargo #endif
1407443Sroot 	/*
14139679Smckusick 	 * Fetch the first indirect block allocating if necessary.
1427443Sroot 	 */
14356444Smargo 	--num;
14456444Smargo 	nb = ip->i_ib[indirs[0].in_off];
145*69910Smckusick 	allocib = NULL;
14669514Smckusick 	allocblk = allociblk;
1477443Sroot 	if (nb == 0) {
14868554Smckusick 		pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
14953244Smckusick 	        if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
15053244Smckusick 		    cred, &newb))
15137736Smckusick 			return (error);
15239679Smckusick 		nb = newb;
153*69910Smckusick 		*allocblk++ = nb;
15457802Smckusick 		bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
155*69910Smckusick 		bp->b_blkno = fsbtodb(fs, nb);
15639679Smckusick 		clrbuf(bp);
1577443Sroot 		/*
1587443Sroot 		 * Write synchronously so that indirect blocks
1597443Sroot 		 * never point at garbage.
1607443Sroot 		 */
161*69910Smckusick 		if (error = bwrite(bp))
162*69910Smckusick 			goto fail;
16369514Smckusick 		allocib = &ip->i_ib[indirs[0].in_off];
164*69910Smckusick 		*allocib = nb;
16564606Sbostic 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
1667443Sroot 	}
1677443Sroot 	/*
16839679Smckusick 	 * Fetch through the indirect blocks, allocating as necessary.
1697443Sroot 	 */
17064420Sbostic 	for (i = 1;;) {
17164420Sbostic 		error = bread(vp,
17264420Sbostic 		    indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp);
17339679Smckusick 		if (error) {
1747443Sroot 			brelse(bp);
17569514Smckusick 			goto fail;
1767443Sroot 		}
17768554Smckusick 		bap = (ufs_daddr_t *)bp->b_data;
17864420Sbostic 		nb = bap[indirs[i].in_off];
17964420Sbostic 		if (i == num)
18039679Smckusick 			break;
18164420Sbostic 		i += 1;
18239679Smckusick 		if (nb != 0) {
18339679Smckusick 			brelse(bp);
18439679Smckusick 			continue;
18539679Smckusick 		}
18639679Smckusick 		if (pref == 0)
18768554Smckusick 			pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
18851470Sbostic 		if (error =
18953244Smckusick 		    ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) {
19039679Smckusick 			brelse(bp);
19169514Smckusick 			goto fail;
19239679Smckusick 		}
19339679Smckusick 		nb = newb;
194*69910Smckusick 		*allocblk++ = nb;
19564420Sbostic 		nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
19656444Smargo 		nbp->b_blkno = fsbtodb(fs, nb);
19739679Smckusick 		clrbuf(nbp);
19839679Smckusick 		/*
19939679Smckusick 		 * Write synchronously so that indirect blocks
20039679Smckusick 		 * never point at garbage.
20139679Smckusick 		 */
20239679Smckusick 		if (error = bwrite(nbp)) {
20339679Smckusick 			brelse(bp);
20469514Smckusick 			goto fail;
20539679Smckusick 		}
20664420Sbostic 		bap[indirs[i - 1].in_off] = nb;
20739878Smckusick 		/*
20839878Smckusick 		 * If required, write synchronously, otherwise use
20956444Smargo 		 * delayed write.
21039878Smckusick 		 */
21139878Smckusick 		if (flags & B_SYNC) {
21239679Smckusick 			bwrite(bp);
21339878Smckusick 		} else {
21439878Smckusick 			bdwrite(bp);
21539878Smckusick 		}
21639679Smckusick 	}
21739679Smckusick 	/*
21839679Smckusick 	 * Get the data block, allocating if necessary.
21939679Smckusick 	 */
22039679Smckusick 	if (nb == 0) {
22164420Sbostic 		pref = ffs_blkpref(ip, lbn, indirs[i].in_off, &bap[0]);
22264420Sbostic 		if (error = ffs_alloc(ip,
22364420Sbostic 		    lbn, pref, (int)fs->fs_bsize, cred, &newb)) {
2247443Sroot 			brelse(bp);
22569514Smckusick 			goto fail;
22639679Smckusick 		}
22739679Smckusick 		nb = newb;
228*69910Smckusick 		*allocblk++ = nb;
22957802Smckusick 		nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
23039679Smckusick 		nbp->b_blkno = fsbtodb(fs, nb);
23139679Smckusick 		if (flags & B_CLRBUF)
23239679Smckusick 			clrbuf(nbp);
23364420Sbostic 		bap[indirs[i].in_off] = nb;
23439878Smckusick 		/*
23539878Smckusick 		 * If required, write synchronously, otherwise use
23656444Smargo 		 * delayed write.
23739878Smckusick 		 */
23839878Smckusick 		if (flags & B_SYNC) {
23939679Smckusick 			bwrite(bp);
24039878Smckusick 		} else {
24139878Smckusick 			bdwrite(bp);
24239878Smckusick 		}
24339679Smckusick 		*bpp = nbp;
24439679Smckusick 		return (0);
2457443Sroot 	}
24639679Smckusick 	brelse(bp);
24741333Smckusick 	if (flags & B_CLRBUF) {
24839679Smckusick 		error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
24939679Smckusick 		if (error) {
25039679Smckusick 			brelse(nbp);
25169514Smckusick 			goto fail;
25239679Smckusick 		}
25341333Smckusick 	} else {
25457802Smckusick 		nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
25541333Smckusick 		nbp->b_blkno = fsbtodb(fs, nb);
25639679Smckusick 	}
25739679Smckusick 	*bpp = nbp;
25837736Smckusick 	return (0);
25969514Smckusick fail:
26069514Smckusick 	/*
26169514Smckusick 	 * If we have failed part way through block allocation, we
26269514Smckusick 	 * have to deallocate any indirect blocks that we have allocated.
26369514Smckusick 	 */
264*69910Smckusick 	for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
26569514Smckusick 		ffs_blkfree(ip, *blkp, fs->fs_bsize);
26669514Smckusick 		deallocated += fs->fs_bsize;
26769514Smckusick 	}
268*69910Smckusick 	if (allocib != NULL)
269*69910Smckusick 		*allocib = 0;
27069514Smckusick 	if (deallocated) {
27169514Smckusick #ifdef QUOTA
27269514Smckusick 		/*
27369514Smckusick 		 * Restore user's disk quota because allocation failed.
27469514Smckusick 		 */
27569514Smckusick 		(void) chkdq(ip, (long)-btodb(deallocated), cred, FORCE);
27669514Smckusick #endif
27769514Smckusick 		ip->i_blocks -= btodb(deallocated);
27869514Smckusick 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
27969514Smckusick 	}
28069514Smckusick 	return (error);
2817443Sroot }
282