xref: /csrg-svn/sys/ufs/lfs/lfs_balloc.c (revision 38776)
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*38776Smckusick  *	@(#)lfs_balloc.c	7.5 (Berkeley) 08/26/89
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
327443Sroot  * by returning the physical block number on a device given the
337443Sroot  * inode and the logical block number in a file.
347443Sroot  * When convenient, it also leaves the physical
357443Sroot  * block number of the next block of the file in rablock
367443Sroot  * for use in read-ahead.
377443Sroot  */
3837736Smckusick bmap(ip, bn, bnp, rablockp, rasizep)
397443Sroot 	register struct inode *ip;
4037736Smckusick 	register daddr_t bn;
4137736Smckusick 	daddr_t	*bnp;
4237736Smckusick 	daddr_t	*rablockp;
4337736Smckusick 	int *rasizep;
447443Sroot {
4537736Smckusick 	register struct fs *fs;
4637736Smckusick 	register daddr_t nb;
4737736Smckusick 	struct buf *bp;
4837736Smckusick 	daddr_t *bap;
4937736Smckusick 	int i, j, sh;
5037736Smckusick 	int error;
5137736Smckusick 
5237736Smckusick 	if (bn < 0)
5337736Smckusick 		return (EFBIG);
5437736Smckusick 	fs = ip->i_fs;
5537736Smckusick 
5637736Smckusick 	/*
5737736Smckusick 	 * The first NDADDR blocks are direct blocks
5837736Smckusick 	 */
5937736Smckusick 	if (bn < NDADDR) {
6037736Smckusick 		nb = ip->i_db[bn];
6137736Smckusick 		if (nb == 0) {
6237736Smckusick 			*bnp = (daddr_t)-1;
6337736Smckusick 			return (0);
6437736Smckusick 		}
6537736Smckusick 		if (rablockp && rasizep) {
6637736Smckusick 			if (bn < NDADDR - 1) {
6737736Smckusick 				*rablockp = fsbtodb(fs, ip->i_db[bn + 1]);
6837736Smckusick 				*rasizep = blksize(fs, ip, bn + 1);
6937736Smckusick 			} else {
7037736Smckusick 				*rablockp = 0;
7137736Smckusick 				*rasizep = 0;
7237736Smckusick 			}
7337736Smckusick 		}
7437736Smckusick 		*bnp = fsbtodb(fs, nb);
7537736Smckusick 		return (0);
7637736Smckusick 	}
7737736Smckusick 
7837736Smckusick 	/*
7937736Smckusick 	 * Determine how many levels of indirection.
8037736Smckusick 	 */
8137736Smckusick 	sh = 1;
8237736Smckusick 	bn -= NDADDR;
8337736Smckusick 	for (j = NIADDR; j > 0; j--) {
8437736Smckusick 		sh *= NINDIR(fs);
8537736Smckusick 		if (bn < sh)
8637736Smckusick 			break;
8737736Smckusick 		bn -= sh;
8837736Smckusick 	}
8937736Smckusick 	if (j == 0)
9037736Smckusick 		return (EFBIG);
9137736Smckusick 
9237736Smckusick 	/*
9337736Smckusick 	 * fetch the first indirect block
9437736Smckusick 	 */
9537736Smckusick 	nb = ip->i_ib[NIADDR - j];
9637736Smckusick 	if (nb == 0) {
9737736Smckusick 		*bnp = (daddr_t)-1;
9837736Smckusick 		return (0);
9937736Smckusick 	}
10037736Smckusick 
10137736Smckusick 	/*
10237736Smckusick 	 * fetch through the indirect blocks
10337736Smckusick 	 */
10437736Smckusick 	for (; j <= NIADDR; j++) {
10537736Smckusick 		if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
106*38776Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp)) {
10737736Smckusick 			brelse(bp);
10837736Smckusick 			return (error);
10937736Smckusick 		}
11037736Smckusick 		bap = bp->b_un.b_daddr;
11137736Smckusick 		sh /= NINDIR(fs);
11237736Smckusick 		i = (bn / sh) % NINDIR(fs);
11337736Smckusick 		nb = bap[i];
11437736Smckusick 		if (nb == 0) {
11537736Smckusick 			*bnp = (daddr_t)-1;
11637736Smckusick 			brelse(bp);
11737736Smckusick 			return (0);
11837736Smckusick 		}
11938448Smckusick 		if (j < NIADDR)
12038448Smckusick 			brelse(bp);
12137736Smckusick 	}
12237736Smckusick 
12337736Smckusick 	/*
12437736Smckusick 	 * calculate read-ahead.
12537736Smckusick 	 */
12637736Smckusick 	if (rablockp && rasizep) {
12737736Smckusick 		if (i < NINDIR(fs) - 1) {
12837736Smckusick 			*rablockp = fsbtodb(fs, bap[i + 1]);
12937736Smckusick 			*rasizep = fs->fs_bsize;
13037736Smckusick 		} else {
13137736Smckusick 			*rablockp = 0;
13237736Smckusick 			*rasizep = 0;
13337736Smckusick 		}
13437736Smckusick 	}
13537736Smckusick 	*bnp = fsbtodb(fs, nb);
13637736Smckusick 	brelse(bp);
13737736Smckusick 	return (0);
13837736Smckusick }
13937736Smckusick 
14037736Smckusick /*
14137736Smckusick  * Balloc defines the structure of file system storage
14237736Smckusick  * by returning the physical block number on a device given the
14337736Smckusick  * inode and the logical block number in a file.
14437736Smckusick  * When unallocated entries are found, new physical blocks
14537736Smckusick  * are allocated.
14637736Smckusick  */
14737736Smckusick balloc(ip, bn, size, bnp, flags)
14837736Smckusick 	register struct inode *ip;
14937736Smckusick 	register daddr_t bn;
15037736Smckusick 	int size;
15137736Smckusick 	daddr_t	*bnp;
15237736Smckusick 	int flags;
15337736Smckusick {
15437736Smckusick 	register struct fs *fs;
15537736Smckusick 	register daddr_t nb;
1567443Sroot 	struct buf *bp, *nbp;
15737736Smckusick 	int osize, nsize, i, j, sh, error;
15837736Smckusick 	daddr_t lbn, *bap, pref, blkpref();
1597443Sroot 
16037736Smckusick 	if (bn < 0)
16137736Smckusick 		return (EFBIG);
1627443Sroot 	fs = ip->i_fs;
1637443Sroot 
1647443Sroot 	/*
1657443Sroot 	 * If the next write will extend the file into a new block,
1667443Sroot 	 * and the file is currently composed of a fragment
1677443Sroot 	 * this fragment has to be extended to be a full block.
1687443Sroot 	 */
1697443Sroot 	nb = lblkno(fs, ip->i_size);
17037736Smckusick 	if (nb < NDADDR && nb < bn) {
1717443Sroot 		osize = blksize(fs, ip, nb);
1727443Sroot 		if (osize < fs->fs_bsize && osize > 0) {
17337736Smckusick 			error = realloccg(ip, ip->i_db[nb],
1749165Ssam 				blkpref(ip, nb, (int)nb, &ip->i_db[0]),
17537736Smckusick 				osize, (int)fs->fs_bsize, &bp);
17637736Smckusick 			if (error) {
17737736Smckusick 				*bnp = (daddr_t)-1;
17837736Smckusick 				return (error);
17937736Smckusick 			}
1807443Sroot 			ip->i_size = (nb + 1) * fs->fs_bsize;
1817443Sroot 			ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
1827443Sroot 			ip->i_flag |= IUPD|ICHG;
1837443Sroot 			bdwrite(bp);
1847443Sroot 		}
1857443Sroot 	}
1867443Sroot 	/*
1877443Sroot 	 * The first NDADDR blocks are direct blocks
1887443Sroot 	 */
1897443Sroot 	if (bn < NDADDR) {
1908258Smckusick 		nb = ip->i_db[bn];
1918258Smckusick 		if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) {
1927443Sroot 			if (nb != 0) {
1937443Sroot 				/* consider need to reallocate a frag */
1947443Sroot 				osize = fragroundup(fs, blkoff(fs, ip->i_size));
1957443Sroot 				nsize = fragroundup(fs, size);
1967443Sroot 				if (nsize <= osize)
1977443Sroot 					goto gotit;
19837736Smckusick 				error = realloccg(ip, nb,
1999165Ssam 					blkpref(ip, bn, (int)bn, &ip->i_db[0]),
20037736Smckusick 					osize, nsize, &bp);
2017443Sroot 			} else {
2028258Smckusick 				if (ip->i_size < (bn + 1) * fs->fs_bsize)
2037443Sroot 					nsize = fragroundup(fs, size);
2047443Sroot 				else
2057443Sroot 					nsize = fs->fs_bsize;
20637736Smckusick 				error = alloc(ip,
2079165Ssam 					blkpref(ip, bn, (int)bn, &ip->i_db[0]),
20837736Smckusick 					nsize, &bp, flags);
2097443Sroot 			}
21037736Smckusick 			if (error) {
21137736Smckusick 				*bnp = (daddr_t)-1;
21237736Smckusick 				return (error);
21337736Smckusick 			}
2147443Sroot 			nb = dbtofsb(fs, bp->b_blkno);
21537736Smckusick 			if ((ip->i_mode & IFMT) == IFDIR)
2167443Sroot 				/*
2177443Sroot 				 * Write directory blocks synchronously
2187443Sroot 				 * so they never appear with garbage in
2197443Sroot 				 * them on the disk.
22037736Smckusick 				 *
22137736Smckusick 				 * NB: Should free space and return error
22237736Smckusick 				 * if bwrite returns an error.
2237443Sroot 				 */
22437736Smckusick 				error = bwrite(bp);
2257443Sroot 			else
2267443Sroot 				bdwrite(bp);
2278258Smckusick 			ip->i_db[bn] = nb;
2287443Sroot 			ip->i_flag |= IUPD|ICHG;
2297443Sroot 		}
2307443Sroot gotit:
23137736Smckusick 		*bnp = fsbtodb(fs, nb);
23237736Smckusick 		return (0);
2337443Sroot 	}
2347443Sroot 
2357443Sroot 	/*
2367443Sroot 	 * Determine how many levels of indirection.
2377443Sroot 	 */
2388258Smckusick 	pref = 0;
2397443Sroot 	sh = 1;
2408258Smckusick 	lbn = bn;
2417443Sroot 	bn -= NDADDR;
24237736Smckusick 	for (j = NIADDR; j > 0; j--) {
2437443Sroot 		sh *= NINDIR(fs);
2447443Sroot 		if (bn < sh)
2457443Sroot 			break;
2467443Sroot 		bn -= sh;
2477443Sroot 	}
24837736Smckusick 	if (j == 0)
24937736Smckusick 		return (EFBIG);
2507443Sroot 
2517443Sroot 	/*
2527443Sroot 	 * fetch the first indirect block
2537443Sroot 	 */
2547443Sroot 	nb = ip->i_ib[NIADDR - j];
2557443Sroot 	if (nb == 0) {
2569165Ssam 		pref = blkpref(ip, lbn, 0, (daddr_t *)0);
25737736Smckusick 	        error = alloc(ip, pref, (int)fs->fs_bsize, &bp, B_CLRBUF);
25837736Smckusick 		if (error) {
25937736Smckusick 			*bnp = (daddr_t)-1;
26037736Smckusick 			return (error);
26137736Smckusick 		}
2627443Sroot 		nb = dbtofsb(fs, bp->b_blkno);
2637443Sroot 		/*
2647443Sroot 		 * Write synchronously so that indirect blocks
2657443Sroot 		 * never point at garbage.
26637736Smckusick 		 *
26737736Smckusick 		 * NB: Should free space and return error
26837736Smckusick 		 * if bwrite returns an error.
2697443Sroot 		 */
27037736Smckusick 		error = bwrite(bp);
2717443Sroot 		ip->i_ib[NIADDR - j] = nb;
2727443Sroot 		ip->i_flag |= IUPD|ICHG;
2737443Sroot 	}
2747443Sroot 
2757443Sroot 	/*
2767443Sroot 	 * fetch through the indirect blocks
2777443Sroot 	 */
2787443Sroot 	for (; j <= NIADDR; j++) {
27937736Smckusick 		if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
280*38776Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp)) {
2817443Sroot 			brelse(bp);
28237736Smckusick 			return (error);
2837443Sroot 		}
2847443Sroot 		bap = bp->b_un.b_daddr;
2857443Sroot 		sh /= NINDIR(fs);
2867443Sroot 		i = (bn / sh) % NINDIR(fs);
2877443Sroot 		nb = bap[i];
2887443Sroot 		if (nb == 0) {
2898258Smckusick 			if (pref == 0)
2908258Smckusick 				if (j < NIADDR)
2919165Ssam 					pref = blkpref(ip, lbn, 0,
2929165Ssam 						(daddr_t *)0);
2938258Smckusick 				else
2948258Smckusick 					pref = blkpref(ip, lbn, i, &bap[0]);
29537736Smckusick 		        error = alloc(ip, pref, (int)fs->fs_bsize, &nbp,
29637736Smckusick 				(j < NIADDR) ? B_CLRBUF : flags);
29737736Smckusick 			if (error) {
2987443Sroot 				brelse(bp);
29937736Smckusick 				*bnp = (daddr_t)-1;
30037736Smckusick 				return (error);
3017443Sroot 			}
3027443Sroot 			nb = dbtofsb(fs, nbp->b_blkno);
30337736Smckusick 			if (j < NIADDR || (ip->i_mode & IFMT) == IFDIR)
3047443Sroot 				/*
3057443Sroot 				 * Write synchronously so indirect blocks
3067443Sroot 				 * never point at garbage and blocks
3077443Sroot 				 * in directories never contain garbage.
30837736Smckusick 				 *
30937736Smckusick 				 * NB: Should free space and return error
31037736Smckusick 				 * if bwrite returns an error.
3117443Sroot 				 */
31237736Smckusick 				error = bwrite(nbp);
3137443Sroot 			else
3147443Sroot 				bdwrite(nbp);
3157443Sroot 			bap[i] = nb;
3167443Sroot 			bdwrite(bp);
3177443Sroot 		} else
3187443Sroot 			brelse(bp);
3197443Sroot 	}
3207443Sroot 
32137736Smckusick 	*bnp = fsbtodb(fs, nb);
32237736Smckusick 	return (0);
3237443Sroot }
324