xref: /csrg-svn/sys/ufs/lfs/lfs_balloc.c (revision 44537)
123396Smckusick /*
237736Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337736Smckusick  * All rights reserved.
423396Smckusick  *
5*44537Sbostic  * %sccs.include.redist.c%
637736Smckusick  *
7*44537Sbostic  *	@(#)lfs_balloc.c	7.10 (Berkeley) 06/28/90
823396Smckusick  */
97443Sroot 
1017099Sbloom #include "param.h"
1117099Sbloom #include "systm.h"
1217099Sbloom #include "user.h"
1317099Sbloom #include "buf.h"
1417099Sbloom #include "proc.h"
1537736Smckusick #include "file.h"
1637736Smckusick #include "vnode.h"
1741310Smckusick #include "../ufs/quota.h"
1837736Smckusick #include "../ufs/inode.h"
1937736Smckusick #include "../ufs/fs.h"
207443Sroot 
217443Sroot /*
227443Sroot  * Bmap defines the structure of file system storage
2339679Smckusick  * by returning the physical block number on a device
2439679Smckusick  * given the inode and the logical block number in a file.
257443Sroot  */
2639679Smckusick bmap(ip, bn, bnp)
277443Sroot 	register struct inode *ip;
2837736Smckusick 	register daddr_t bn;
2937736Smckusick 	daddr_t	*bnp;
307443Sroot {
3137736Smckusick 	register struct fs *fs;
3237736Smckusick 	register daddr_t nb;
3337736Smckusick 	struct buf *bp;
3437736Smckusick 	daddr_t *bap;
3537736Smckusick 	int i, j, sh;
3637736Smckusick 	int error;
3737736Smckusick 
3837736Smckusick 	if (bn < 0)
3937736Smckusick 		return (EFBIG);
4037736Smckusick 	fs = ip->i_fs;
4137736Smckusick 
4237736Smckusick 	/*
4337736Smckusick 	 * The first NDADDR blocks are direct blocks
4437736Smckusick 	 */
4537736Smckusick 	if (bn < NDADDR) {
4637736Smckusick 		nb = ip->i_db[bn];
4737736Smckusick 		if (nb == 0) {
4837736Smckusick 			*bnp = (daddr_t)-1;
4937736Smckusick 			return (0);
5037736Smckusick 		}
5137736Smckusick 		*bnp = fsbtodb(fs, nb);
5237736Smckusick 		return (0);
5337736Smckusick 	}
5437736Smckusick 	/*
5539679Smckusick 	 * Determine the number of levels of indirection.
5637736Smckusick 	 */
5737736Smckusick 	sh = 1;
5837736Smckusick 	bn -= NDADDR;
5937736Smckusick 	for (j = NIADDR; j > 0; j--) {
6037736Smckusick 		sh *= NINDIR(fs);
6137736Smckusick 		if (bn < sh)
6237736Smckusick 			break;
6337736Smckusick 		bn -= sh;
6437736Smckusick 	}
6537736Smckusick 	if (j == 0)
6637736Smckusick 		return (EFBIG);
6737736Smckusick 	/*
6839679Smckusick 	 * Fetch through the indirect blocks.
6937736Smckusick 	 */
7037736Smckusick 	nb = ip->i_ib[NIADDR - j];
7137736Smckusick 	if (nb == 0) {
7237736Smckusick 		*bnp = (daddr_t)-1;
7337736Smckusick 		return (0);
7437736Smckusick 	}
7537736Smckusick 	for (; j <= NIADDR; j++) {
7637736Smckusick 		if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
7738776Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp)) {
7837736Smckusick 			brelse(bp);
7937736Smckusick 			return (error);
8037736Smckusick 		}
8137736Smckusick 		bap = bp->b_un.b_daddr;
8237736Smckusick 		sh /= NINDIR(fs);
8337736Smckusick 		i = (bn / sh) % NINDIR(fs);
8437736Smckusick 		nb = bap[i];
8537736Smckusick 		if (nb == 0) {
8637736Smckusick 			*bnp = (daddr_t)-1;
8737736Smckusick 			brelse(bp);
8837736Smckusick 			return (0);
8937736Smckusick 		}
9039679Smckusick 		brelse(bp);
9137736Smckusick 	}
9237736Smckusick 	*bnp = fsbtodb(fs, nb);
9337736Smckusick 	return (0);
9437736Smckusick }
9537736Smckusick 
9637736Smckusick /*
9737736Smckusick  * Balloc defines the structure of file system storage
9839679Smckusick  * by allocating the physical blocks on a device given
9939679Smckusick  * the inode and the logical block number in a file.
10037736Smckusick  */
10139679Smckusick balloc(ip, bn, size, bpp, flags)
10237736Smckusick 	register struct inode *ip;
10337736Smckusick 	register daddr_t bn;
10437736Smckusick 	int size;
10539679Smckusick 	struct buf **bpp;
10637736Smckusick 	int flags;
10737736Smckusick {
10837736Smckusick 	register struct fs *fs;
10937736Smckusick 	register daddr_t nb;
1107443Sroot 	struct buf *bp, *nbp;
11139679Smckusick 	struct vnode *vp = ITOV(ip);
11237736Smckusick 	int osize, nsize, i, j, sh, error;
11339679Smckusick 	daddr_t newb, lbn, *bap, pref, blkpref();
1147443Sroot 
11539679Smckusick 	*bpp = (struct buf *)0;
11637736Smckusick 	if (bn < 0)
11737736Smckusick 		return (EFBIG);
1187443Sroot 	fs = ip->i_fs;
1197443Sroot 
1207443Sroot 	/*
1217443Sroot 	 * If the next write will extend the file into a new block,
1227443Sroot 	 * and the file is currently composed of a fragment
1237443Sroot 	 * this fragment has to be extended to be a full block.
1247443Sroot 	 */
1257443Sroot 	nb = lblkno(fs, ip->i_size);
12637736Smckusick 	if (nb < NDADDR && nb < bn) {
1277443Sroot 		osize = blksize(fs, ip, nb);
1287443Sroot 		if (osize < fs->fs_bsize && osize > 0) {
12939679Smckusick 			error = realloccg(ip, nb,
1309165Ssam 				blkpref(ip, nb, (int)nb, &ip->i_db[0]),
13137736Smckusick 				osize, (int)fs->fs_bsize, &bp);
13239679Smckusick 			if (error)
13337736Smckusick 				return (error);
1347443Sroot 			ip->i_size = (nb + 1) * fs->fs_bsize;
1357443Sroot 			ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
1367443Sroot 			ip->i_flag |= IUPD|ICHG;
13739679Smckusick 			if (flags & B_SYNC)
13839679Smckusick 				bwrite(bp);
13939679Smckusick 			else
14039679Smckusick 				bawrite(bp);
1417443Sroot 		}
1427443Sroot 	}
1437443Sroot 	/*
1447443Sroot 	 * The first NDADDR blocks are direct blocks
1457443Sroot 	 */
1467443Sroot 	if (bn < NDADDR) {
1478258Smckusick 		nb = ip->i_db[bn];
14839679Smckusick 		if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) {
14939679Smckusick 			error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp);
15039679Smckusick 			if (error) {
15139679Smckusick 				brelse(bp);
15239679Smckusick 				return (error);
15339679Smckusick 			}
15439679Smckusick 			*bpp = bp;
15539679Smckusick 			return (0);
15639679Smckusick 		}
15739679Smckusick 		if (nb != 0) {
15839679Smckusick 			/*
15939679Smckusick 			 * Consider need to reallocate a fragment.
16039679Smckusick 			 */
16139679Smckusick 			osize = fragroundup(fs, blkoff(fs, ip->i_size));
16239679Smckusick 			nsize = fragroundup(fs, size);
16339679Smckusick 			if (nsize <= osize) {
16439679Smckusick 				error = bread(vp, bn, osize, NOCRED, &bp);
16539679Smckusick 				if (error) {
16639679Smckusick 					brelse(bp);
16739679Smckusick 					return (error);
16839679Smckusick 				}
16939679Smckusick 			} else {
17039679Smckusick 				error = realloccg(ip, bn,
1719165Ssam 					blkpref(ip, bn, (int)bn, &ip->i_db[0]),
17237736Smckusick 					osize, nsize, &bp);
17339679Smckusick 				if (error)
17439679Smckusick 					return (error);
1757443Sroot 			}
17639679Smckusick 		} else {
17739679Smckusick 			if (ip->i_size < (bn + 1) * fs->fs_bsize)
17839679Smckusick 				nsize = fragroundup(fs, size);
17939679Smckusick 			else
18039679Smckusick 				nsize = fs->fs_bsize;
18139679Smckusick 			error = alloc(ip, bn,
18239679Smckusick 				blkpref(ip, bn, (int)bn, &ip->i_db[0]),
18339679Smckusick 				nsize, &newb);
18439679Smckusick 			if (error)
18537736Smckusick 				return (error);
18639679Smckusick 			bp = getblk(vp, bn, nsize);
18739679Smckusick 			bp->b_blkno = fsbtodb(fs, newb);
18839679Smckusick 			if (flags & B_CLRBUF)
18939679Smckusick 				clrbuf(bp);
1907443Sroot 		}
19139679Smckusick 		ip->i_db[bn] = dbtofsb(fs, bp->b_blkno);
19239679Smckusick 		ip->i_flag |= IUPD|ICHG;
19339679Smckusick 		*bpp = bp;
19437736Smckusick 		return (0);
1957443Sroot 	}
1967443Sroot 	/*
19739679Smckusick 	 * Determine the number of levels of indirection.
1987443Sroot 	 */
1998258Smckusick 	pref = 0;
2007443Sroot 	sh = 1;
2018258Smckusick 	lbn = bn;
2027443Sroot 	bn -= NDADDR;
20337736Smckusick 	for (j = NIADDR; j > 0; j--) {
2047443Sroot 		sh *= NINDIR(fs);
2057443Sroot 		if (bn < sh)
2067443Sroot 			break;
2077443Sroot 		bn -= sh;
2087443Sroot 	}
20937736Smckusick 	if (j == 0)
21037736Smckusick 		return (EFBIG);
2117443Sroot 	/*
21239679Smckusick 	 * Fetch the first indirect block allocating if necessary.
2137443Sroot 	 */
2147443Sroot 	nb = ip->i_ib[NIADDR - j];
2157443Sroot 	if (nb == 0) {
2169165Ssam 		pref = blkpref(ip, lbn, 0, (daddr_t *)0);
21739679Smckusick 	        if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb))
21837736Smckusick 			return (error);
21939679Smckusick 		nb = newb;
22039679Smckusick 		bp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
22139679Smckusick 		clrbuf(bp);
2227443Sroot 		/*
2237443Sroot 		 * Write synchronously so that indirect blocks
2247443Sroot 		 * never point at garbage.
2257443Sroot 		 */
22639679Smckusick 		if (error = bwrite(bp)) {
22739679Smckusick 			blkfree(ip, nb, fs->fs_bsize);
22839679Smckusick 			return (error);
22939679Smckusick 		}
2307443Sroot 		ip->i_ib[NIADDR - j] = nb;
2317443Sroot 		ip->i_flag |= IUPD|ICHG;
2327443Sroot 	}
2337443Sroot 	/*
23439679Smckusick 	 * Fetch through the indirect blocks, allocating as necessary.
2357443Sroot 	 */
23639679Smckusick 	for (; ; j++) {
23739679Smckusick 		error = bread(ip->i_devvp, fsbtodb(fs, nb),
23839679Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp);
23939679Smckusick 		if (error) {
2407443Sroot 			brelse(bp);
24137736Smckusick 			return (error);
2427443Sroot 		}
2437443Sroot 		bap = bp->b_un.b_daddr;
2447443Sroot 		sh /= NINDIR(fs);
2457443Sroot 		i = (bn / sh) % NINDIR(fs);
2467443Sroot 		nb = bap[i];
24739679Smckusick 		if (j == NIADDR)
24839679Smckusick 			break;
24939679Smckusick 		if (nb != 0) {
25039679Smckusick 			brelse(bp);
25139679Smckusick 			continue;
25239679Smckusick 		}
25339679Smckusick 		if (pref == 0)
25439679Smckusick 			pref = blkpref(ip, lbn, 0, (daddr_t *)0);
25539679Smckusick 		if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
25639679Smckusick 			brelse(bp);
25739679Smckusick 			return (error);
25839679Smckusick 		}
25939679Smckusick 		nb = newb;
26039679Smckusick 		nbp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
26139679Smckusick 		clrbuf(nbp);
26239679Smckusick 		/*
26339679Smckusick 		 * Write synchronously so that indirect blocks
26439679Smckusick 		 * never point at garbage.
26539679Smckusick 		 */
26639679Smckusick 		if (error = bwrite(nbp)) {
26739679Smckusick 			blkfree(ip, nb, fs->fs_bsize);
26839679Smckusick 			brelse(bp);
26939679Smckusick 			return (error);
27039679Smckusick 		}
27139679Smckusick 		bap[i] = nb;
27239878Smckusick 		/*
27339878Smckusick 		 * If required, write synchronously, otherwise use
27439878Smckusick 		 * delayed write. If this is the first instance of
27539878Smckusick 		 * the delayed write, reassociate the buffer with the
27639878Smckusick 		 * file so it will be written if the file is sync'ed.
27739878Smckusick 		 */
27839878Smckusick 		if (flags & B_SYNC) {
27939679Smckusick 			bwrite(bp);
28039878Smckusick 		} else if (bp->b_flags & B_DELWRI) {
2817443Sroot 			bdwrite(bp);
28239878Smckusick 		} else {
28339878Smckusick 			bdwrite(bp);
28439878Smckusick 			reassignbuf(bp, vp);
28539878Smckusick 		}
28639679Smckusick 	}
28739679Smckusick 	/*
28839679Smckusick 	 * Get the data block, allocating if necessary.
28939679Smckusick 	 */
29039679Smckusick 	if (nb == 0) {
29139679Smckusick 		pref = blkpref(ip, lbn, i, &bap[0]);
29239679Smckusick 		if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
2937443Sroot 			brelse(bp);
29439679Smckusick 			return (error);
29539679Smckusick 		}
29639679Smckusick 		nb = newb;
29739679Smckusick 		nbp = getblk(vp, lbn, fs->fs_bsize);
29839679Smckusick 		nbp->b_blkno = fsbtodb(fs, nb);
29939679Smckusick 		if (flags & B_CLRBUF)
30039679Smckusick 			clrbuf(nbp);
30139679Smckusick 		bap[i] = nb;
30239878Smckusick 		/*
30339878Smckusick 		 * If required, write synchronously, otherwise use
30439878Smckusick 		 * delayed write. If this is the first instance of
30539878Smckusick 		 * the delayed write, reassociate the buffer with the
30639878Smckusick 		 * file so it will be written if the file is sync'ed.
30739878Smckusick 		 */
30839878Smckusick 		if (flags & B_SYNC) {
30939679Smckusick 			bwrite(bp);
31039878Smckusick 		} else if (bp->b_flags & B_DELWRI) {
31139679Smckusick 			bdwrite(bp);
31239878Smckusick 		} else {
31339878Smckusick 			bdwrite(bp);
31439878Smckusick 			reassignbuf(bp, vp);
31539878Smckusick 		}
31639679Smckusick 		*bpp = nbp;
31739679Smckusick 		return (0);
3187443Sroot 	}
31939679Smckusick 	brelse(bp);
32041333Smckusick 	if (flags & B_CLRBUF) {
32139679Smckusick 		error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
32239679Smckusick 		if (error) {
32339679Smckusick 			brelse(nbp);
32439679Smckusick 			return (error);
32539679Smckusick 		}
32641333Smckusick 	} else {
32741333Smckusick 		nbp = getblk(vp, lbn, fs->fs_bsize);
32841333Smckusick 		nbp->b_blkno = fsbtodb(fs, nb);
32939679Smckusick 	}
33039679Smckusick 	*bpp = nbp;
33137736Smckusick 	return (0);
3327443Sroot }
333