xref: /csrg-svn/sys/ufs/lfs/lfs_balloc.c (revision 41310)
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*41310Smckusick  *	@(#)lfs_balloc.c	7.8 (Berkeley) 05/02/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"
27*41310Smckusick #include "../ufs/quota.h"
2837736Smckusick #include "../ufs/inode.h"
2937736Smckusick #include "../ufs/fs.h"
307443Sroot 
317443Sroot /*
327443Sroot  * Bmap defines the structure of file system storage
3339679Smckusick  * by returning the physical block number on a device
3439679Smckusick  * given the inode and the logical block number in a file.
357443Sroot  */
3639679Smckusick bmap(ip, bn, bnp)
377443Sroot 	register struct inode *ip;
3837736Smckusick 	register daddr_t bn;
3937736Smckusick 	daddr_t	*bnp;
407443Sroot {
4137736Smckusick 	register struct fs *fs;
4237736Smckusick 	register daddr_t nb;
4337736Smckusick 	struct buf *bp;
4437736Smckusick 	daddr_t *bap;
4537736Smckusick 	int i, j, sh;
4637736Smckusick 	int error;
4737736Smckusick 
4837736Smckusick 	if (bn < 0)
4937736Smckusick 		return (EFBIG);
5037736Smckusick 	fs = ip->i_fs;
5137736Smckusick 
5237736Smckusick 	/*
5337736Smckusick 	 * The first NDADDR blocks are direct blocks
5437736Smckusick 	 */
5537736Smckusick 	if (bn < NDADDR) {
5637736Smckusick 		nb = ip->i_db[bn];
5737736Smckusick 		if (nb == 0) {
5837736Smckusick 			*bnp = (daddr_t)-1;
5937736Smckusick 			return (0);
6037736Smckusick 		}
6137736Smckusick 		*bnp = fsbtodb(fs, nb);
6237736Smckusick 		return (0);
6337736Smckusick 	}
6437736Smckusick 	/*
6539679Smckusick 	 * Determine the number of levels of indirection.
6637736Smckusick 	 */
6737736Smckusick 	sh = 1;
6837736Smckusick 	bn -= NDADDR;
6937736Smckusick 	for (j = NIADDR; j > 0; j--) {
7037736Smckusick 		sh *= NINDIR(fs);
7137736Smckusick 		if (bn < sh)
7237736Smckusick 			break;
7337736Smckusick 		bn -= sh;
7437736Smckusick 	}
7537736Smckusick 	if (j == 0)
7637736Smckusick 		return (EFBIG);
7737736Smckusick 	/*
7839679Smckusick 	 * Fetch through the indirect blocks.
7937736Smckusick 	 */
8037736Smckusick 	nb = ip->i_ib[NIADDR - j];
8137736Smckusick 	if (nb == 0) {
8237736Smckusick 		*bnp = (daddr_t)-1;
8337736Smckusick 		return (0);
8437736Smckusick 	}
8537736Smckusick 	for (; j <= NIADDR; j++) {
8637736Smckusick 		if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
8738776Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp)) {
8837736Smckusick 			brelse(bp);
8937736Smckusick 			return (error);
9037736Smckusick 		}
9137736Smckusick 		bap = bp->b_un.b_daddr;
9237736Smckusick 		sh /= NINDIR(fs);
9337736Smckusick 		i = (bn / sh) % NINDIR(fs);
9437736Smckusick 		nb = bap[i];
9537736Smckusick 		if (nb == 0) {
9637736Smckusick 			*bnp = (daddr_t)-1;
9737736Smckusick 			brelse(bp);
9837736Smckusick 			return (0);
9937736Smckusick 		}
10039679Smckusick 		brelse(bp);
10137736Smckusick 	}
10237736Smckusick 	*bnp = fsbtodb(fs, nb);
10337736Smckusick 	return (0);
10437736Smckusick }
10537736Smckusick 
10637736Smckusick /*
10737736Smckusick  * Balloc defines the structure of file system storage
10839679Smckusick  * by allocating the physical blocks on a device given
10939679Smckusick  * the inode and the logical block number in a file.
11037736Smckusick  */
11139679Smckusick balloc(ip, bn, size, bpp, flags)
11237736Smckusick 	register struct inode *ip;
11337736Smckusick 	register daddr_t bn;
11437736Smckusick 	int size;
11539679Smckusick 	struct buf **bpp;
11637736Smckusick 	int flags;
11737736Smckusick {
11837736Smckusick 	register struct fs *fs;
11937736Smckusick 	register daddr_t nb;
1207443Sroot 	struct buf *bp, *nbp;
12139679Smckusick 	struct vnode *vp = ITOV(ip);
12237736Smckusick 	int osize, nsize, i, j, sh, error;
12339679Smckusick 	daddr_t newb, lbn, *bap, pref, blkpref();
1247443Sroot 
12539679Smckusick 	*bpp = (struct buf *)0;
12637736Smckusick 	if (bn < 0)
12737736Smckusick 		return (EFBIG);
1287443Sroot 	fs = ip->i_fs;
1297443Sroot 
1307443Sroot 	/*
1317443Sroot 	 * If the next write will extend the file into a new block,
1327443Sroot 	 * and the file is currently composed of a fragment
1337443Sroot 	 * this fragment has to be extended to be a full block.
1347443Sroot 	 */
1357443Sroot 	nb = lblkno(fs, ip->i_size);
13637736Smckusick 	if (nb < NDADDR && nb < bn) {
1377443Sroot 		osize = blksize(fs, ip, nb);
1387443Sroot 		if (osize < fs->fs_bsize && osize > 0) {
13939679Smckusick 			error = realloccg(ip, nb,
1409165Ssam 				blkpref(ip, nb, (int)nb, &ip->i_db[0]),
14137736Smckusick 				osize, (int)fs->fs_bsize, &bp);
14239679Smckusick 			if (error)
14337736Smckusick 				return (error);
1447443Sroot 			ip->i_size = (nb + 1) * fs->fs_bsize;
1457443Sroot 			ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
1467443Sroot 			ip->i_flag |= IUPD|ICHG;
14739679Smckusick 			if (flags & B_SYNC)
14839679Smckusick 				bwrite(bp);
14939679Smckusick 			else
15039679Smckusick 				bawrite(bp);
1517443Sroot 		}
1527443Sroot 	}
1537443Sroot 	/*
1547443Sroot 	 * The first NDADDR blocks are direct blocks
1557443Sroot 	 */
1567443Sroot 	if (bn < NDADDR) {
1578258Smckusick 		nb = ip->i_db[bn];
15839679Smckusick 		if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) {
15939679Smckusick 			error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp);
16039679Smckusick 			if (error) {
16139679Smckusick 				brelse(bp);
16239679Smckusick 				return (error);
16339679Smckusick 			}
16439679Smckusick 			*bpp = bp;
16539679Smckusick 			return (0);
16639679Smckusick 		}
16739679Smckusick 		if (nb != 0) {
16839679Smckusick 			/*
16939679Smckusick 			 * Consider need to reallocate a fragment.
17039679Smckusick 			 */
17139679Smckusick 			osize = fragroundup(fs, blkoff(fs, ip->i_size));
17239679Smckusick 			nsize = fragroundup(fs, size);
17339679Smckusick 			if (nsize <= osize) {
17439679Smckusick 				error = bread(vp, bn, osize, NOCRED, &bp);
17539679Smckusick 				if (error) {
17639679Smckusick 					brelse(bp);
17739679Smckusick 					return (error);
17839679Smckusick 				}
17939679Smckusick 			} else {
18039679Smckusick 				error = realloccg(ip, bn,
1819165Ssam 					blkpref(ip, bn, (int)bn, &ip->i_db[0]),
18237736Smckusick 					osize, nsize, &bp);
18339679Smckusick 				if (error)
18439679Smckusick 					return (error);
1857443Sroot 			}
18639679Smckusick 		} else {
18739679Smckusick 			if (ip->i_size < (bn + 1) * fs->fs_bsize)
18839679Smckusick 				nsize = fragroundup(fs, size);
18939679Smckusick 			else
19039679Smckusick 				nsize = fs->fs_bsize;
19139679Smckusick 			error = alloc(ip, bn,
19239679Smckusick 				blkpref(ip, bn, (int)bn, &ip->i_db[0]),
19339679Smckusick 				nsize, &newb);
19439679Smckusick 			if (error)
19537736Smckusick 				return (error);
19639679Smckusick 			bp = getblk(vp, bn, nsize);
19739679Smckusick 			bp->b_blkno = fsbtodb(fs, newb);
19839679Smckusick 			if (flags & B_CLRBUF)
19939679Smckusick 				clrbuf(bp);
2007443Sroot 		}
20139679Smckusick 		ip->i_db[bn] = dbtofsb(fs, bp->b_blkno);
20239679Smckusick 		ip->i_flag |= IUPD|ICHG;
20339679Smckusick 		*bpp = bp;
20437736Smckusick 		return (0);
2057443Sroot 	}
2067443Sroot 	/*
20739679Smckusick 	 * Determine the number of levels of indirection.
2087443Sroot 	 */
2098258Smckusick 	pref = 0;
2107443Sroot 	sh = 1;
2118258Smckusick 	lbn = bn;
2127443Sroot 	bn -= NDADDR;
21337736Smckusick 	for (j = NIADDR; j > 0; j--) {
2147443Sroot 		sh *= NINDIR(fs);
2157443Sroot 		if (bn < sh)
2167443Sroot 			break;
2177443Sroot 		bn -= sh;
2187443Sroot 	}
21937736Smckusick 	if (j == 0)
22037736Smckusick 		return (EFBIG);
2217443Sroot 	/*
22239679Smckusick 	 * Fetch the first indirect block allocating if necessary.
2237443Sroot 	 */
2247443Sroot 	nb = ip->i_ib[NIADDR - j];
2257443Sroot 	if (nb == 0) {
2269165Ssam 		pref = blkpref(ip, lbn, 0, (daddr_t *)0);
22739679Smckusick 	        if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb))
22837736Smckusick 			return (error);
22939679Smckusick 		nb = newb;
23039679Smckusick 		bp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
23139679Smckusick 		clrbuf(bp);
2327443Sroot 		/*
2337443Sroot 		 * Write synchronously so that indirect blocks
2347443Sroot 		 * never point at garbage.
2357443Sroot 		 */
23639679Smckusick 		if (error = bwrite(bp)) {
23739679Smckusick 			blkfree(ip, nb, fs->fs_bsize);
23839679Smckusick 			return (error);
23939679Smckusick 		}
2407443Sroot 		ip->i_ib[NIADDR - j] = nb;
2417443Sroot 		ip->i_flag |= IUPD|ICHG;
2427443Sroot 	}
2437443Sroot 	/*
24439679Smckusick 	 * Fetch through the indirect blocks, allocating as necessary.
2457443Sroot 	 */
24639679Smckusick 	for (; ; j++) {
24739679Smckusick 		error = bread(ip->i_devvp, fsbtodb(fs, nb),
24839679Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp);
24939679Smckusick 		if (error) {
2507443Sroot 			brelse(bp);
25137736Smckusick 			return (error);
2527443Sroot 		}
2537443Sroot 		bap = bp->b_un.b_daddr;
2547443Sroot 		sh /= NINDIR(fs);
2557443Sroot 		i = (bn / sh) % NINDIR(fs);
2567443Sroot 		nb = bap[i];
25739679Smckusick 		if (j == NIADDR)
25839679Smckusick 			break;
25939679Smckusick 		if (nb != 0) {
26039679Smckusick 			brelse(bp);
26139679Smckusick 			continue;
26239679Smckusick 		}
26339679Smckusick 		if (pref == 0)
26439679Smckusick 			pref = blkpref(ip, lbn, 0, (daddr_t *)0);
26539679Smckusick 		if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
26639679Smckusick 			brelse(bp);
26739679Smckusick 			return (error);
26839679Smckusick 		}
26939679Smckusick 		nb = newb;
27039679Smckusick 		nbp = getblk(ip->i_devvp, fsbtodb(fs, nb), fs->fs_bsize);
27139679Smckusick 		clrbuf(nbp);
27239679Smckusick 		/*
27339679Smckusick 		 * Write synchronously so that indirect blocks
27439679Smckusick 		 * never point at garbage.
27539679Smckusick 		 */
27639679Smckusick 		if (error = bwrite(nbp)) {
27739679Smckusick 			blkfree(ip, nb, fs->fs_bsize);
27839679Smckusick 			brelse(bp);
27939679Smckusick 			return (error);
28039679Smckusick 		}
28139679Smckusick 		bap[i] = nb;
28239878Smckusick 		/*
28339878Smckusick 		 * If required, write synchronously, otherwise use
28439878Smckusick 		 * delayed write. If this is the first instance of
28539878Smckusick 		 * the delayed write, reassociate the buffer with the
28639878Smckusick 		 * file so it will be written if the file is sync'ed.
28739878Smckusick 		 */
28839878Smckusick 		if (flags & B_SYNC) {
28939679Smckusick 			bwrite(bp);
29039878Smckusick 		} else if (bp->b_flags & B_DELWRI) {
2917443Sroot 			bdwrite(bp);
29239878Smckusick 		} else {
29339878Smckusick 			bdwrite(bp);
29439878Smckusick 			reassignbuf(bp, vp);
29539878Smckusick 		}
29639679Smckusick 	}
29739679Smckusick 	/*
29839679Smckusick 	 * Get the data block, allocating if necessary.
29939679Smckusick 	 */
30039679Smckusick 	if (nb == 0) {
30139679Smckusick 		pref = blkpref(ip, lbn, i, &bap[0]);
30239679Smckusick 		if (error = alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb)) {
3037443Sroot 			brelse(bp);
30439679Smckusick 			return (error);
30539679Smckusick 		}
30639679Smckusick 		nb = newb;
30739679Smckusick 		nbp = getblk(vp, lbn, fs->fs_bsize);
30839679Smckusick 		nbp->b_blkno = fsbtodb(fs, nb);
30939679Smckusick 		if (flags & B_CLRBUF)
31039679Smckusick 			clrbuf(nbp);
31139679Smckusick 		bap[i] = nb;
31239878Smckusick 		/*
31339878Smckusick 		 * If required, write synchronously, otherwise use
31439878Smckusick 		 * delayed write. If this is the first instance of
31539878Smckusick 		 * the delayed write, reassociate the buffer with the
31639878Smckusick 		 * file so it will be written if the file is sync'ed.
31739878Smckusick 		 */
31839878Smckusick 		if (flags & B_SYNC) {
31939679Smckusick 			bwrite(bp);
32039878Smckusick 		} else if (bp->b_flags & B_DELWRI) {
32139679Smckusick 			bdwrite(bp);
32239878Smckusick 		} else {
32339878Smckusick 			bdwrite(bp);
32439878Smckusick 			reassignbuf(bp, vp);
32539878Smckusick 		}
32639679Smckusick 		*bpp = nbp;
32739679Smckusick 		return (0);
3287443Sroot 	}
32939679Smckusick 	brelse(bp);
33039679Smckusick 	nbp = getblk(vp, lbn, fs->fs_bsize);
33139679Smckusick 	nbp->b_blkno = fsbtodb(fs, nb);
33239679Smckusick 	if ((flags & B_CLRBUF) && (nbp->b_flags & (B_DONE|B_DELWRI)) == 0) {
33339679Smckusick 		brelse(nbp);
33439679Smckusick 		error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
33539679Smckusick 		if (error) {
33639679Smckusick 			brelse(nbp);
33739679Smckusick 			return (error);
33839679Smckusick 		}
33939679Smckusick 	}
34039679Smckusick 	*bpp = nbp;
34137736Smckusick 	return (0);
3427443Sroot }
343