xref: /csrg-svn/sys/ufs/lfs/lfs_balloc.c (revision 49450)
123396Smckusick /*
237736Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337736Smckusick  * All rights reserved.
423396Smckusick  *
544537Sbostic  * %sccs.include.redist.c%
637736Smckusick  *
7*49450Smckusick  *	@(#)lfs_balloc.c	7.13 (Berkeley) 05/08/91
823396Smckusick  */
97443Sroot 
1017099Sbloom #include "param.h"
1117099Sbloom #include "systm.h"
1217099Sbloom #include "buf.h"
1317099Sbloom #include "proc.h"
1437736Smckusick #include "file.h"
1537736Smckusick #include "vnode.h"
167443Sroot 
1747571Skarels #include "quota.h"
1847571Skarels #include "inode.h"
1947571Skarels #include "fs.h"
2047571Skarels 
217443Sroot /*
22*49450Smckusick  * Bmap converts a the logical block number of a file
23*49450Smckusick  * to its physical block number on the disk. The conversion
24*49450Smckusick  * is done by using the logical block number to index into
25*49450Smckusick  * the array of block pointers described by the dinode.
267443Sroot  */
2739679Smckusick bmap(ip, bn, bnp)
287443Sroot 	register struct inode *ip;
2937736Smckusick 	register daddr_t bn;
3037736Smckusick 	daddr_t	*bnp;
317443Sroot {
3237736Smckusick 	register struct fs *fs;
3337736Smckusick 	register daddr_t nb;
3437736Smckusick 	struct buf *bp;
3537736Smckusick 	daddr_t *bap;
3637736Smckusick 	int i, j, sh;
3737736Smckusick 	int error;
3837736Smckusick 
3937736Smckusick 	if (bn < 0)
4037736Smckusick 		return (EFBIG);
4137736Smckusick 	fs = ip->i_fs;
4237736Smckusick 
4337736Smckusick 	/*
4437736Smckusick 	 * The first NDADDR blocks are direct blocks
4537736Smckusick 	 */
4637736Smckusick 	if (bn < NDADDR) {
4737736Smckusick 		nb = ip->i_db[bn];
4837736Smckusick 		if (nb == 0) {
4937736Smckusick 			*bnp = (daddr_t)-1;
5037736Smckusick 			return (0);
5137736Smckusick 		}
5237736Smckusick 		*bnp = fsbtodb(fs, nb);
5337736Smckusick 		return (0);
5437736Smckusick 	}
5537736Smckusick 	/*
5639679Smckusick 	 * Determine the number of levels of indirection.
5737736Smckusick 	 */
5837736Smckusick 	sh = 1;
5937736Smckusick 	bn -= NDADDR;
6037736Smckusick 	for (j = NIADDR; j > 0; j--) {
6137736Smckusick 		sh *= NINDIR(fs);
6237736Smckusick 		if (bn < sh)
6337736Smckusick 			break;
6437736Smckusick 		bn -= sh;
6537736Smckusick 	}
6637736Smckusick 	if (j == 0)
6737736Smckusick 		return (EFBIG);
6837736Smckusick 	/*
6939679Smckusick 	 * Fetch through the indirect blocks.
7037736Smckusick 	 */
7137736Smckusick 	nb = ip->i_ib[NIADDR - j];
7237736Smckusick 	if (nb == 0) {
7337736Smckusick 		*bnp = (daddr_t)-1;
7437736Smckusick 		return (0);
7537736Smckusick 	}
7637736Smckusick 	for (; j <= NIADDR; j++) {
7737736Smckusick 		if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
7838776Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp)) {
7937736Smckusick 			brelse(bp);
8037736Smckusick 			return (error);
8137736Smckusick 		}
8237736Smckusick 		bap = bp->b_un.b_daddr;
8337736Smckusick 		sh /= NINDIR(fs);
8437736Smckusick 		i = (bn / sh) % NINDIR(fs);
8537736Smckusick 		nb = bap[i];
8637736Smckusick 		if (nb == 0) {
8737736Smckusick 			*bnp = (daddr_t)-1;
8837736Smckusick 			brelse(bp);
8937736Smckusick 			return (0);
9037736Smckusick 		}
9139679Smckusick 		brelse(bp);
9237736Smckusick 	}
9337736Smckusick 	*bnp = fsbtodb(fs, nb);
9437736Smckusick 	return (0);
9537736Smckusick }
9637736Smckusick 
9737736Smckusick /*
9837736Smckusick  * Balloc defines the structure of file system storage
9939679Smckusick  * by allocating the physical blocks on a device given
10039679Smckusick  * the inode and the logical block number in a file.
10137736Smckusick  */
10239679Smckusick balloc(ip, bn, size, bpp, flags)
10337736Smckusick 	register struct inode *ip;
10437736Smckusick 	register daddr_t bn;
10537736Smckusick 	int size;
10639679Smckusick 	struct buf **bpp;
10737736Smckusick 	int flags;
10837736Smckusick {
10937736Smckusick 	register struct fs *fs;
11037736Smckusick 	register daddr_t nb;
1117443Sroot 	struct buf *bp, *nbp;
11239679Smckusick 	struct vnode *vp = ITOV(ip);
11337736Smckusick 	int osize, nsize, i, j, sh, error;
11439679Smckusick 	daddr_t newb, lbn, *bap, pref, blkpref();
1157443Sroot 
11639679Smckusick 	*bpp = (struct buf *)0;
11737736Smckusick 	if (bn < 0)
11837736Smckusick 		return (EFBIG);
1197443Sroot 	fs = ip->i_fs;
1207443Sroot 
1217443Sroot 	/*
1227443Sroot 	 * If the next write will extend the file into a new block,
1237443Sroot 	 * and the file is currently composed of a fragment
1247443Sroot 	 * this fragment has to be extended to be a full block.
1257443Sroot 	 */
1267443Sroot 	nb = lblkno(fs, ip->i_size);
12737736Smckusick 	if (nb < NDADDR && nb < bn) {
1287443Sroot 		osize = blksize(fs, ip, nb);
1297443Sroot 		if (osize < fs->fs_bsize && osize > 0) {
13039679Smckusick 			error = realloccg(ip, nb,
1319165Ssam 				blkpref(ip, nb, (int)nb, &ip->i_db[0]),
13237736Smckusick 				osize, (int)fs->fs_bsize, &bp);
13339679Smckusick 			if (error)
13437736Smckusick 				return (error);
1357443Sroot 			ip->i_size = (nb + 1) * fs->fs_bsize;
13645720Smckusick 			vnode_pager_setsize(ITOV(ip), (u_long)ip->i_size);
1377443Sroot 			ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
1387443Sroot 			ip->i_flag |= IUPD|ICHG;
13939679Smckusick 			if (flags & B_SYNC)
14039679Smckusick 				bwrite(bp);
14139679Smckusick 			else
14239679Smckusick 				bawrite(bp);
1437443Sroot 		}
1447443Sroot 	}
1457443Sroot 	/*
1467443Sroot 	 * The first NDADDR blocks are direct blocks
1477443Sroot 	 */
1487443Sroot 	if (bn < NDADDR) {
1498258Smckusick 		nb = ip->i_db[bn];
15039679Smckusick 		if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) {
15139679Smckusick 			error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp);
15239679Smckusick 			if (error) {
15339679Smckusick 				brelse(bp);
15439679Smckusick 				return (error);
15539679Smckusick 			}
15639679Smckusick 			*bpp = bp;
15739679Smckusick 			return (0);
15839679Smckusick 		}
15939679Smckusick 		if (nb != 0) {
16039679Smckusick 			/*
16139679Smckusick 			 * Consider need to reallocate a fragment.
16239679Smckusick 			 */
16339679Smckusick 			osize = fragroundup(fs, blkoff(fs, ip->i_size));
16439679Smckusick 			nsize = fragroundup(fs, size);
16539679Smckusick 			if (nsize <= osize) {
16639679Smckusick 				error = bread(vp, bn, osize, NOCRED, &bp);
16739679Smckusick 				if (error) {
16839679Smckusick 					brelse(bp);
16939679Smckusick 					return (error);
17039679Smckusick 				}
17139679Smckusick 			} else {
17239679Smckusick 				error = realloccg(ip, bn,
1739165Ssam 					blkpref(ip, bn, (int)bn, &ip->i_db[0]),
17437736Smckusick 					osize, nsize, &bp);
17539679Smckusick 				if (error)
17639679Smckusick 					return (error);
1777443Sroot 			}
17839679Smckusick 		} else {
17939679Smckusick 			if (ip->i_size < (bn + 1) * fs->fs_bsize)
18039679Smckusick 				nsize = fragroundup(fs, size);
18139679Smckusick 			else
18239679Smckusick 				nsize = fs->fs_bsize;
18339679Smckusick 			error = alloc(ip, bn,
18439679Smckusick 				blkpref(ip, bn, (int)bn, &ip->i_db[0]),
18539679Smckusick 				nsize, &newb);
18639679Smckusick 			if (error)
18737736Smckusick 				return (error);
18839679Smckusick 			bp = getblk(vp, bn, nsize);
18939679Smckusick 			bp->b_blkno = fsbtodb(fs, newb);
19039679Smckusick 			if (flags & B_CLRBUF)
19139679Smckusick 				clrbuf(bp);
1927443Sroot 		}
19339679Smckusick 		ip->i_db[bn] = dbtofsb(fs, bp->b_blkno);
19439679Smckusick 		ip->i_flag |= IUPD|ICHG;
19539679Smckusick 		*bpp = bp;
19637736Smckusick 		return (0);
1977443Sroot 	}
1987443Sroot 	/*
19939679Smckusick 	 * Determine the number of levels of indirection.
2007443Sroot 	 */
2018258Smckusick 	pref = 0;
2027443Sroot 	sh = 1;
2038258Smckusick 	lbn = bn;
2047443Sroot 	bn -= NDADDR;
20537736Smckusick 	for (j = NIADDR; j > 0; j--) {
2067443Sroot 		sh *= NINDIR(fs);
2077443Sroot 		if (bn < sh)
2087443Sroot 			break;
2097443Sroot 		bn -= sh;
2107443Sroot 	}
21137736Smckusick 	if (j == 0)
21237736Smckusick 		return (EFBIG);
2137443Sroot 	/*
21439679Smckusick 	 * Fetch the first indirect block allocating if necessary.
2157443Sroot 	 */
2167443Sroot 	nb = ip->i_ib[NIADDR - j];
2177443Sroot 	if (nb == 0) {
2189165Ssam 		pref = blkpref(ip, lbn, 0, (daddr_t *)0);
21939679Smckusick 	        if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb))
22037736Smckusick 			return (error);
22139679Smckusick 		nb = newb;
22239679Smckusick 		bp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
22339679Smckusick 		clrbuf(bp);
2247443Sroot 		/*
2257443Sroot 		 * Write synchronously so that indirect blocks
2267443Sroot 		 * never point at garbage.
2277443Sroot 		 */
22839679Smckusick 		if (error = bwrite(bp)) {
22939679Smckusick 			blkfree(ip, nb, fs->fs_bsize);
23039679Smckusick 			return (error);
23139679Smckusick 		}
2327443Sroot 		ip->i_ib[NIADDR - j] = nb;
2337443Sroot 		ip->i_flag |= IUPD|ICHG;
2347443Sroot 	}
2357443Sroot 	/*
23639679Smckusick 	 * Fetch through the indirect blocks, allocating as necessary.
2377443Sroot 	 */
23839679Smckusick 	for (; ; j++) {
23939679Smckusick 		error = bread(ip->i_devvp, fsbtodb(fs, nb),
24039679Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp);
24139679Smckusick 		if (error) {
2427443Sroot 			brelse(bp);
24337736Smckusick 			return (error);
2447443Sroot 		}
2457443Sroot 		bap = bp->b_un.b_daddr;
2467443Sroot 		sh /= NINDIR(fs);
2477443Sroot 		i = (bn / sh) % NINDIR(fs);
2487443Sroot 		nb = bap[i];
24939679Smckusick 		if (j == NIADDR)
25039679Smckusick 			break;
25139679Smckusick 		if (nb != 0) {
25239679Smckusick 			brelse(bp);
25339679Smckusick 			continue;
25439679Smckusick 		}
25539679Smckusick 		if (pref == 0)
25639679Smckusick 			pref = blkpref(ip, lbn, 0, (daddr_t *)0);
25739679Smckusick 		if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
25839679Smckusick 			brelse(bp);
25939679Smckusick 			return (error);
26039679Smckusick 		}
26139679Smckusick 		nb = newb;
26239679Smckusick 		nbp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
26339679Smckusick 		clrbuf(nbp);
26439679Smckusick 		/*
26539679Smckusick 		 * Write synchronously so that indirect blocks
26639679Smckusick 		 * never point at garbage.
26739679Smckusick 		 */
26839679Smckusick 		if (error = bwrite(nbp)) {
26939679Smckusick 			blkfree(ip, nb, fs->fs_bsize);
27039679Smckusick 			brelse(bp);
27139679Smckusick 			return (error);
27239679Smckusick 		}
27339679Smckusick 		bap[i] = nb;
27439878Smckusick 		/*
27539878Smckusick 		 * If required, write synchronously, otherwise use
27639878Smckusick 		 * delayed write. If this is the first instance of
27739878Smckusick 		 * the delayed write, reassociate the buffer with the
27839878Smckusick 		 * file so it will be written if the file is sync'ed.
27939878Smckusick 		 */
28039878Smckusick 		if (flags & B_SYNC) {
28139679Smckusick 			bwrite(bp);
28239878Smckusick 		} else if (bp->b_flags & B_DELWRI) {
2837443Sroot 			bdwrite(bp);
28439878Smckusick 		} else {
28539878Smckusick 			bdwrite(bp);
28639878Smckusick 			reassignbuf(bp, vp);
28739878Smckusick 		}
28839679Smckusick 	}
28939679Smckusick 	/*
29039679Smckusick 	 * Get the data block, allocating if necessary.
29139679Smckusick 	 */
29239679Smckusick 	if (nb == 0) {
29339679Smckusick 		pref = blkpref(ip, lbn, i, &bap[0]);
29439679Smckusick 		if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
2957443Sroot 			brelse(bp);
29639679Smckusick 			return (error);
29739679Smckusick 		}
29839679Smckusick 		nb = newb;
29939679Smckusick 		nbp = getblk(vp, lbn, fs->fs_bsize);
30039679Smckusick 		nbp->b_blkno = fsbtodb(fs, nb);
30139679Smckusick 		if (flags & B_CLRBUF)
30239679Smckusick 			clrbuf(nbp);
30339679Smckusick 		bap[i] = nb;
30439878Smckusick 		/*
30539878Smckusick 		 * If required, write synchronously, otherwise use
30639878Smckusick 		 * delayed write. If this is the first instance of
30739878Smckusick 		 * the delayed write, reassociate the buffer with the
30839878Smckusick 		 * file so it will be written if the file is sync'ed.
30939878Smckusick 		 */
31039878Smckusick 		if (flags & B_SYNC) {
31139679Smckusick 			bwrite(bp);
31239878Smckusick 		} else if (bp->b_flags & B_DELWRI) {
31339679Smckusick 			bdwrite(bp);
31439878Smckusick 		} else {
31539878Smckusick 			bdwrite(bp);
31639878Smckusick 			reassignbuf(bp, vp);
31739878Smckusick 		}
31839679Smckusick 		*bpp = nbp;
31939679Smckusick 		return (0);
3207443Sroot 	}
32139679Smckusick 	brelse(bp);
32241333Smckusick 	if (flags & B_CLRBUF) {
32339679Smckusick 		error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
32439679Smckusick 		if (error) {
32539679Smckusick 			brelse(nbp);
32639679Smckusick 			return (error);
32739679Smckusick 		}
32841333Smckusick 	} else {
32941333Smckusick 		nbp = getblk(vp, lbn, fs->fs_bsize);
33041333Smckusick 		nbp->b_blkno = fsbtodb(fs, nb);
33139679Smckusick 	}
33239679Smckusick 	*bpp = nbp;
33337736Smckusick 	return (0);
3347443Sroot }
335