xref: /csrg-svn/sys/ufs/lfs/lfs_balloc.c (revision 39878)
123396Smckusick /*
237736Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337736Smckusick  * All rights reserved.
423396Smckusick  *
537736Smckusick  * Redistribution and use in source and binary forms are permitted
637736Smckusick  * provided that the above copyright notice and this paragraph are
737736Smckusick  * duplicated in all such forms and that any documentation,
837736Smckusick  * advertising materials, and other materials related to such
937736Smckusick  * distribution and use acknowledge that the software was developed
1037736Smckusick  * by the University of California, Berkeley.  The name of the
1137736Smckusick  * University may not be used to endorse or promote products derived
1237736Smckusick  * from this software without specific prior written permission.
1337736Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1437736Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1537736Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1637736Smckusick  *
17*39878Smckusick  *	@(#)lfs_balloc.c	7.7 (Berkeley) 01/04/90
1823396Smckusick  */
197443Sroot 
2017099Sbloom #include "param.h"
2117099Sbloom #include "systm.h"
2217099Sbloom #include "user.h"
2317099Sbloom #include "buf.h"
2417099Sbloom #include "proc.h"
2537736Smckusick #include "file.h"
2637736Smckusick #include "vnode.h"
2737736Smckusick #include "../ufs/inode.h"
2837736Smckusick #include "../ufs/fs.h"
297443Sroot 
307443Sroot /*
317443Sroot  * Bmap defines the structure of file system storage
3239679Smckusick  * by returning the physical block number on a device
3339679Smckusick  * given the inode and the logical block number in a file.
347443Sroot  */
3539679Smckusick bmap(ip, bn, bnp)
367443Sroot 	register struct inode *ip;
3737736Smckusick 	register daddr_t bn;
3837736Smckusick 	daddr_t	*bnp;
397443Sroot {
4037736Smckusick 	register struct fs *fs;
4137736Smckusick 	register daddr_t nb;
4237736Smckusick 	struct buf *bp;
4337736Smckusick 	daddr_t *bap;
4437736Smckusick 	int i, j, sh;
4537736Smckusick 	int error;
4637736Smckusick 
4737736Smckusick 	if (bn < 0)
4837736Smckusick 		return (EFBIG);
4937736Smckusick 	fs = ip->i_fs;
5037736Smckusick 
5137736Smckusick 	/*
5237736Smckusick 	 * The first NDADDR blocks are direct blocks
5337736Smckusick 	 */
5437736Smckusick 	if (bn < NDADDR) {
5537736Smckusick 		nb = ip->i_db[bn];
5637736Smckusick 		if (nb == 0) {
5737736Smckusick 			*bnp = (daddr_t)-1;
5837736Smckusick 			return (0);
5937736Smckusick 		}
6037736Smckusick 		*bnp = fsbtodb(fs, nb);
6137736Smckusick 		return (0);
6237736Smckusick 	}
6337736Smckusick 	/*
6439679Smckusick 	 * Determine the number of levels of indirection.
6537736Smckusick 	 */
6637736Smckusick 	sh = 1;
6737736Smckusick 	bn -= NDADDR;
6837736Smckusick 	for (j = NIADDR; j > 0; j--) {
6937736Smckusick 		sh *= NINDIR(fs);
7037736Smckusick 		if (bn < sh)
7137736Smckusick 			break;
7237736Smckusick 		bn -= sh;
7337736Smckusick 	}
7437736Smckusick 	if (j == 0)
7537736Smckusick 		return (EFBIG);
7637736Smckusick 	/*
7739679Smckusick 	 * Fetch through the indirect blocks.
7837736Smckusick 	 */
7937736Smckusick 	nb = ip->i_ib[NIADDR - j];
8037736Smckusick 	if (nb == 0) {
8137736Smckusick 		*bnp = (daddr_t)-1;
8237736Smckusick 		return (0);
8337736Smckusick 	}
8437736Smckusick 	for (; j <= NIADDR; j++) {
8537736Smckusick 		if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
8638776Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp)) {
8737736Smckusick 			brelse(bp);
8837736Smckusick 			return (error);
8937736Smckusick 		}
9037736Smckusick 		bap = bp->b_un.b_daddr;
9137736Smckusick 		sh /= NINDIR(fs);
9237736Smckusick 		i = (bn / sh) % NINDIR(fs);
9337736Smckusick 		nb = bap[i];
9437736Smckusick 		if (nb == 0) {
9537736Smckusick 			*bnp = (daddr_t)-1;
9637736Smckusick 			brelse(bp);
9737736Smckusick 			return (0);
9837736Smckusick 		}
9939679Smckusick 		brelse(bp);
10037736Smckusick 	}
10137736Smckusick 	*bnp = fsbtodb(fs, nb);
10237736Smckusick 	return (0);
10337736Smckusick }
10437736Smckusick 
10537736Smckusick /*
10637736Smckusick  * Balloc defines the structure of file system storage
10739679Smckusick  * by allocating the physical blocks on a device given
10839679Smckusick  * the inode and the logical block number in a file.
10937736Smckusick  */
11039679Smckusick balloc(ip, bn, size, bpp, flags)
11137736Smckusick 	register struct inode *ip;
11237736Smckusick 	register daddr_t bn;
11337736Smckusick 	int size;
11439679Smckusick 	struct buf **bpp;
11537736Smckusick 	int flags;
11637736Smckusick {
11737736Smckusick 	register struct fs *fs;
11837736Smckusick 	register daddr_t nb;
1197443Sroot 	struct buf *bp, *nbp;
12039679Smckusick 	struct vnode *vp = ITOV(ip);
12137736Smckusick 	int osize, nsize, i, j, sh, error;
12239679Smckusick 	daddr_t newb, lbn, *bap, pref, blkpref();
1237443Sroot 
12439679Smckusick 	*bpp = (struct buf *)0;
12537736Smckusick 	if (bn < 0)
12637736Smckusick 		return (EFBIG);
1277443Sroot 	fs = ip->i_fs;
1287443Sroot 
1297443Sroot 	/*
1307443Sroot 	 * If the next write will extend the file into a new block,
1317443Sroot 	 * and the file is currently composed of a fragment
1327443Sroot 	 * this fragment has to be extended to be a full block.
1337443Sroot 	 */
1347443Sroot 	nb = lblkno(fs, ip->i_size);
13537736Smckusick 	if (nb < NDADDR && nb < bn) {
1367443Sroot 		osize = blksize(fs, ip, nb);
1377443Sroot 		if (osize < fs->fs_bsize && osize > 0) {
13839679Smckusick 			error = realloccg(ip, nb,
1399165Ssam 				blkpref(ip, nb, (int)nb, &ip->i_db[0]),
14037736Smckusick 				osize, (int)fs->fs_bsize, &bp);
14139679Smckusick 			if (error)
14237736Smckusick 				return (error);
1437443Sroot 			ip->i_size = (nb + 1) * fs->fs_bsize;
1447443Sroot 			ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
1457443Sroot 			ip->i_flag |= IUPD|ICHG;
14639679Smckusick 			if (flags & B_SYNC)
14739679Smckusick 				bwrite(bp);
14839679Smckusick 			else
14939679Smckusick 				bawrite(bp);
1507443Sroot 		}
1517443Sroot 	}
1527443Sroot 	/*
1537443Sroot 	 * The first NDADDR blocks are direct blocks
1547443Sroot 	 */
1557443Sroot 	if (bn < NDADDR) {
1568258Smckusick 		nb = ip->i_db[bn];
15739679Smckusick 		if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) {
15839679Smckusick 			error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp);
15939679Smckusick 			if (error) {
16039679Smckusick 				brelse(bp);
16139679Smckusick 				return (error);
16239679Smckusick 			}
16339679Smckusick 			*bpp = bp;
16439679Smckusick 			return (0);
16539679Smckusick 		}
16639679Smckusick 		if (nb != 0) {
16739679Smckusick 			/*
16839679Smckusick 			 * Consider need to reallocate a fragment.
16939679Smckusick 			 */
17039679Smckusick 			osize = fragroundup(fs, blkoff(fs, ip->i_size));
17139679Smckusick 			nsize = fragroundup(fs, size);
17239679Smckusick 			if (nsize <= osize) {
17339679Smckusick 				error = bread(vp, bn, osize, NOCRED, &bp);
17439679Smckusick 				if (error) {
17539679Smckusick 					brelse(bp);
17639679Smckusick 					return (error);
17739679Smckusick 				}
17839679Smckusick 			} else {
17939679Smckusick 				error = realloccg(ip, bn,
1809165Ssam 					blkpref(ip, bn, (int)bn, &ip->i_db[0]),
18137736Smckusick 					osize, nsize, &bp);
18239679Smckusick 				if (error)
18339679Smckusick 					return (error);
1847443Sroot 			}
18539679Smckusick 		} else {
18639679Smckusick 			if (ip->i_size < (bn + 1) * fs->fs_bsize)
18739679Smckusick 				nsize = fragroundup(fs, size);
18839679Smckusick 			else
18939679Smckusick 				nsize = fs->fs_bsize;
19039679Smckusick 			error = alloc(ip, bn,
19139679Smckusick 				blkpref(ip, bn, (int)bn, &ip->i_db[0]),
19239679Smckusick 				nsize, &newb);
19339679Smckusick 			if (error)
19437736Smckusick 				return (error);
19539679Smckusick 			bp = getblk(vp, bn, nsize);
19639679Smckusick 			bp->b_blkno = fsbtodb(fs, newb);
19739679Smckusick 			if (flags & B_CLRBUF)
19839679Smckusick 				clrbuf(bp);
1997443Sroot 		}
20039679Smckusick 		ip->i_db[bn] = dbtofsb(fs, bp->b_blkno);
20139679Smckusick 		ip->i_flag |= IUPD|ICHG;
20239679Smckusick 		*bpp = bp;
20337736Smckusick 		return (0);
2047443Sroot 	}
2057443Sroot 	/*
20639679Smckusick 	 * Determine the number of levels of indirection.
2077443Sroot 	 */
2088258Smckusick 	pref = 0;
2097443Sroot 	sh = 1;
2108258Smckusick 	lbn = bn;
2117443Sroot 	bn -= NDADDR;
21237736Smckusick 	for (j = NIADDR; j > 0; j--) {
2137443Sroot 		sh *= NINDIR(fs);
2147443Sroot 		if (bn < sh)
2157443Sroot 			break;
2167443Sroot 		bn -= sh;
2177443Sroot 	}
21837736Smckusick 	if (j == 0)
21937736Smckusick 		return (EFBIG);
2207443Sroot 	/*
22139679Smckusick 	 * Fetch the first indirect block allocating if necessary.
2227443Sroot 	 */
2237443Sroot 	nb = ip->i_ib[NIADDR - j];
2247443Sroot 	if (nb == 0) {
2259165Ssam 		pref = blkpref(ip, lbn, 0, (daddr_t *)0);
22639679Smckusick 	        if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb))
22737736Smckusick 			return (error);
22839679Smckusick 		nb = newb;
22939679Smckusick 		bp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
23039679Smckusick 		clrbuf(bp);
2317443Sroot 		/*
2327443Sroot 		 * Write synchronously so that indirect blocks
2337443Sroot 		 * never point at garbage.
2347443Sroot 		 */
23539679Smckusick 		if (error = bwrite(bp)) {
23639679Smckusick 			blkfree(ip, nb, fs->fs_bsize);
23739679Smckusick 			return (error);
23839679Smckusick 		}
2397443Sroot 		ip->i_ib[NIADDR - j] = nb;
2407443Sroot 		ip->i_flag |= IUPD|ICHG;
2417443Sroot 	}
2427443Sroot 	/*
24339679Smckusick 	 * Fetch through the indirect blocks, allocating as necessary.
2447443Sroot 	 */
24539679Smckusick 	for (; ; j++) {
24639679Smckusick 		error = bread(ip->i_devvp, fsbtodb(fs, nb),
24739679Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp);
24839679Smckusick 		if (error) {
2497443Sroot 			brelse(bp);
25037736Smckusick 			return (error);
2517443Sroot 		}
2527443Sroot 		bap = bp->b_un.b_daddr;
2537443Sroot 		sh /= NINDIR(fs);
2547443Sroot 		i = (bn / sh) % NINDIR(fs);
2557443Sroot 		nb = bap[i];
25639679Smckusick 		if (j == NIADDR)
25739679Smckusick 			break;
25839679Smckusick 		if (nb != 0) {
25939679Smckusick 			brelse(bp);
26039679Smckusick 			continue;
26139679Smckusick 		}
26239679Smckusick 		if (pref == 0)
26339679Smckusick 			pref = blkpref(ip, lbn, 0, (daddr_t *)0);
26439679Smckusick 		if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
26539679Smckusick 			brelse(bp);
26639679Smckusick 			return (error);
26739679Smckusick 		}
26839679Smckusick 		nb = newb;
26939679Smckusick 		nbp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
27039679Smckusick 		clrbuf(nbp);
27139679Smckusick 		/*
27239679Smckusick 		 * Write synchronously so that indirect blocks
27339679Smckusick 		 * never point at garbage.
27439679Smckusick 		 */
27539679Smckusick 		if (error = bwrite(nbp)) {
27639679Smckusick 			blkfree(ip, nb, fs->fs_bsize);
27739679Smckusick 			brelse(bp);
27839679Smckusick 			return (error);
27939679Smckusick 		}
28039679Smckusick 		bap[i] = nb;
281*39878Smckusick 		/*
282*39878Smckusick 		 * If required, write synchronously, otherwise use
283*39878Smckusick 		 * delayed write. If this is the first instance of
284*39878Smckusick 		 * the delayed write, reassociate the buffer with the
285*39878Smckusick 		 * file so it will be written if the file is sync'ed.
286*39878Smckusick 		 */
287*39878Smckusick 		if (flags & B_SYNC) {
28839679Smckusick 			bwrite(bp);
289*39878Smckusick 		} else if (bp->b_flags & B_DELWRI) {
2907443Sroot 			bdwrite(bp);
291*39878Smckusick 		} else {
292*39878Smckusick 			bdwrite(bp);
293*39878Smckusick 			reassignbuf(bp, vp);
294*39878Smckusick 		}
29539679Smckusick 	}
29639679Smckusick 	/*
29739679Smckusick 	 * Get the data block, allocating if necessary.
29839679Smckusick 	 */
29939679Smckusick 	if (nb == 0) {
30039679Smckusick 		pref = blkpref(ip, lbn, i, &bap[0]);
30139679Smckusick 		if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
3027443Sroot 			brelse(bp);
30339679Smckusick 			return (error);
30439679Smckusick 		}
30539679Smckusick 		nb = newb;
30639679Smckusick 		nbp = getblk(vp, lbn, fs->fs_bsize);
30739679Smckusick 		nbp->b_blkno = fsbtodb(fs, nb);
30839679Smckusick 		if (flags & B_CLRBUF)
30939679Smckusick 			clrbuf(nbp);
31039679Smckusick 		bap[i] = nb;
311*39878Smckusick 		/*
312*39878Smckusick 		 * If required, write synchronously, otherwise use
313*39878Smckusick 		 * delayed write. If this is the first instance of
314*39878Smckusick 		 * the delayed write, reassociate the buffer with the
315*39878Smckusick 		 * file so it will be written if the file is sync'ed.
316*39878Smckusick 		 */
317*39878Smckusick 		if (flags & B_SYNC) {
31839679Smckusick 			bwrite(bp);
319*39878Smckusick 		} else if (bp->b_flags & B_DELWRI) {
32039679Smckusick 			bdwrite(bp);
321*39878Smckusick 		} else {
322*39878Smckusick 			bdwrite(bp);
323*39878Smckusick 			reassignbuf(bp, vp);
324*39878Smckusick 		}
32539679Smckusick 		*bpp = nbp;
32639679Smckusick 		return (0);
3277443Sroot 	}
32839679Smckusick 	brelse(bp);
32939679Smckusick 	nbp = getblk(vp, lbn, fs->fs_bsize);
33039679Smckusick 	nbp->b_blkno = fsbtodb(fs, nb);
33139679Smckusick 	if ((flags & B_CLRBUF) && (nbp->b_flags & (B_DONE|B_DELWRI)) == 0) {
33239679Smckusick 		brelse(nbp);
33339679Smckusick 		error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
33439679Smckusick 		if (error) {
33539679Smckusick 			brelse(nbp);
33639679Smckusick 			return (error);
33739679Smckusick 		}
33839679Smckusick 	}
33939679Smckusick 	*bpp = nbp;
34037736Smckusick 	return (0);
3417443Sroot }
342