xref: /csrg-svn/sys/ufs/lfs/lfs_balloc.c (revision 51846)
123396Smckusick /*
251494Sbostic  * Copyright (c) 1989, 1991 Regents of the University of California.
337736Smckusick  * All rights reserved.
423396Smckusick  *
544537Sbostic  * %sccs.include.redist.c%
637736Smckusick  *
7*51846Sbostic  *	@(#)lfs_balloc.c	7.21 (Berkeley) 12/06/91
823396Smckusick  */
97443Sroot 
1051486Sbostic #include <sys/param.h>
1151486Sbostic #include <sys/buf.h>
1251486Sbostic #include <sys/proc.h>
1351486Sbostic #include <sys/vnode.h>
1451486Sbostic #include <sys/mount.h>
1551486Sbostic #include <sys/resourcevar.h>
1651486Sbostic #include <sys/specdev.h>
1751486Sbostic #include <sys/trace.h>
187443Sroot 
1951494Sbostic #include <ufs/ufs/quota.h>
2051494Sbostic #include <ufs/ufs/inode.h>
2151494Sbostic #include <ufs/ufs/ufsmount.h>
2247571Skarels 
2351494Sbostic #include <ufs/lfs/lfs.h>
2451494Sbostic #include <ufs/lfs/lfs_extern.h>
2551486Sbostic 
267443Sroot /*
2751486Sbostic  * Bmap converts a the logical block number of a file to its physical block
2851486Sbostic  * number on the disk. The conversion is done by using the logical block
2951486Sbostic  * number to index into the array of block pointers described by the dinode.
30*51846Sbostic  *
31*51846Sbostic  * LFS has a different version of bmap from FFS because of a naming conflict.
32*51846Sbostic  * In FFS, meta blocks are given real disk addresses at allocation time, and
33*51846Sbostic  * are linked into the device vnode, using a logical block number which is
34*51846Sbostic  * the same as the physical block number.  This can't be done by LFS because
35*51846Sbostic  * blocks aren't given disk addresses until they're written, so there's no
36*51846Sbostic  * way to distinguish the meta-data blocks for one file from any other file.
37*51846Sbostic  * This means that meta-data blocks have to be on the vnode for the file so
38*51846Sbostic  * they can be found, and have to have "names" different from the standard
39*51846Sbostic  * data blocks.  To do this, we divide the name space into positive and
40*51846Sbostic  * negative block numbers, and give the meta-data blocks negative logical
41*51846Sbostic  * numbers.
42*51846Sbostic  *
43*51846Sbostic  * The mapping for meta-data blocks is as follows (assuming a 4K block size):
44*51846Sbostic  *
45*51846Sbostic  * -1 -- single indirect
46*51846Sbostic  * -2 -- double indirect:
47*51846Sbostic  *		single indirect blocks -4, -1027
48*51846Sbostic  * -3 -- triple indirect:
49*51846Sbostic  *		double indirect blocks -1028, -2051
50*51846Sbostic  *		single indirect blocks -2052, -(1M + 2052 - 1)
517443Sroot  */
5251348Sroot int
5351561Smckusick lfs_bmap(vp, bn, vpp, bnp)
5451561Smckusick 	struct vnode *vp;
5537736Smckusick 	register daddr_t bn;
5651561Smckusick 	struct vnode **vpp;
5751561Smckusick 	daddr_t *bnp;
587443Sroot {
5951561Smckusick 	register struct inode *ip;
6051494Sbostic 	register struct lfs *fs;
6137736Smckusick 	register daddr_t nb;
62*51846Sbostic 	struct buf *bp;
6351561Smckusick 	struct vnode *devvp;
64*51846Sbostic 	daddr_t *bap, daddr, lbn_ind, doing_a_triple;
65*51846Sbostic 	int error, j, off, sh, sh_ind;
6637736Smckusick 
6751561Smckusick 	/*
6851561Smckusick 	 * Check for underlying vnode requests and ensure that logical
6951561Smckusick 	 * to physical mapping is requested.
7051561Smckusick 	 */
7151561Smckusick 	ip = VTOI(vp);
7251561Smckusick 	if (vpp != NULL)
7351561Smckusick 		*vpp = ip->i_devvp;
7451561Smckusick 	if (bnp == NULL)
7551561Smckusick 		return (0);
76*51846Sbostic 
77*51846Sbostic #ifdef VERBOSE
7851155Sbostic printf("lfs_bmap: block number %d, inode %d\n", bn, ip->i_number);
79*51846Sbostic #endif
8051486Sbostic 	/* The first NDADDR blocks are direct blocks. */
8137736Smckusick 	if (bn < NDADDR) {
8237736Smckusick 		nb = ip->i_db[bn];
83*51846Sbostic 		if (nb == LFS_UNUSED_DADDR)
8451348Sroot 			*bnp = UNASSIGNED;
85*51846Sbostic 		else
86*51846Sbostic 			*bnp = nb;
8737736Smckusick 		return (0);
8837736Smckusick 	}
8951486Sbostic 
90*51846Sbostic 	/*
91*51846Sbostic 	 * The first NIADDR negative blocks are the indirect block pointers.
92*51846Sbostic 	 * Determine the number of levels of indirection.  After this loop
93*51846Sbostic 	 * is done, sh indicates the number of data blocks possible at the
94*51846Sbostic 	 * given level of indirection, lbn_ind is the logical block number
95*51846Sbostic 	 * of the next indirect block to retrieve, and NIADDR - j is the
96*51846Sbostic 	 * number of levels of indirection needed to locate the requested
97*51846Sbostic 	 * block.
98*51846Sbostic 	 */
99*51846Sbostic 	fs = ip->i_lfs;
10037736Smckusick 	sh = 1;
10137736Smckusick 	bn -= NDADDR;
10251183Sbostic 	lbn_ind = 0;
10337736Smckusick 	for (j = NIADDR; j > 0; j--) {
104*51846Sbostic 		--lbn_ind;
10537736Smckusick 		sh *= NINDIR(fs);
10637736Smckusick 		if (bn < sh)
10737736Smckusick 			break;
10837736Smckusick 		bn -= sh;
10937736Smckusick 	}
11037736Smckusick 	if (j == 0)
11137736Smckusick 		return (EFBIG);
11251183Sbostic 
113*51846Sbostic 	/*
114*51846Sbostic 	 * Fetch through the indirect blocks.  At each iteration, off is the
115*51846Sbostic 	 * offset into the bap array which is an array of disk addresses at
116*51846Sbostic 	 * the current level of indirection.
117*51846Sbostic 	 */
118*51846Sbostic 	bap = ip->i_ib;
119*51846Sbostic 	bp = NULL;
12051183Sbostic 	devvp = VFSTOUFS(vp->v_mount)->um_devvp;
121*51846Sbostic 	off = NIADDR - j;
122*51846Sbostic 	doing_a_triple = 0;
123*51846Sbostic 	for (; j <= NIADDR; j++) {
124*51846Sbostic 		/*
125*51846Sbostic 		 * In LFS, it's possible to have a block appended to a file
126*51846Sbostic 		 * for which the meta-blocks have not yet been allocated.
127*51846Sbostic 		 * This is a win if the file never gets written or if the
128*51846Sbostic 		 * file's growing.
129*51846Sbostic 		 */
130*51846Sbostic 		if ((daddr = bap[off]) == 0) {
13151348Sroot 			daddr = UNASSIGNED;
13251183Sbostic 			break;
13351183Sbostic 		}
134*51846Sbostic 		/*
135*51846Sbostic 		 * Read in the appropriate indirect block.  LFS can't do a
136*51846Sbostic 		 * bread because bread knows that FFS will hand it the device
137*51846Sbostic 		 * vnode, not the file vnode, so the b_dev and b_blkno would
138*51846Sbostic 		 * be wrong.
139*51846Sbostic 		 *
140*51846Sbostic 		 * XXX
141*51846Sbostic 		 * This REALLY needs to be fixed, at the very least it needs
142*51846Sbostic 		 * to be rethought when the buffer cache goes away.
143*51846Sbostic 		 */
14451183Sbostic 		if (bp)
14537736Smckusick 			brelse(bp);
14651183Sbostic 		bp = getblk(vp, lbn_ind, fs->lfs_bsize);
14751183Sbostic 		if (bp->b_flags & (B_DONE | B_DELWRI)) {
14851183Sbostic 			trace(TR_BREADHIT, pack(vp, size), lbn_ind);
14951183Sbostic 		} else {
150*51846Sbostic 			bp->b_flags |= B_READ;
15151183Sbostic 			bp->b_blkno = daddr;
15251183Sbostic 			bp->b_dev = devvp->v_rdev;
15351215Sbostic 			(devvp->v_op->vop_strategy)(bp);
154*51846Sbostic 			trace(TR_BREADMISS, pack(vp, size), lbn_ind);
15551183Sbostic 			curproc->p_stats->p_ru.ru_inblock++;	/* XXX */
15651183Sbostic 			if (error = biowait(bp)) {
15751183Sbostic 				brelse(bp);
15851183Sbostic 				return (error);
15951183Sbostic 			}
16037736Smckusick 		}
16137736Smckusick 		bap = bp->b_un.b_daddr;
16237736Smckusick 		sh /= NINDIR(fs);
16351183Sbostic 		off = (bn / sh) % NINDIR(fs);
164*51846Sbostic 
165*51846Sbostic 		/*
166*51846Sbostic 		 * Ahem.  Now the disgusting part.  We have to figure out
167*51846Sbostic 		 * the logical block number for the next meta-data block.
168*51846Sbostic 		 * There are really three equations...  Note the clever
169*51846Sbostic 		 * use of the doing_a_triple variable to hold the last
170*51846Sbostic 		 * offset into the block of pointers.
171*51846Sbostic 		 */
172*51846Sbostic 		switch(j) {
173*51846Sbostic 		case 1:
174*51846Sbostic 			/* The triple indirect block found in the inode. */
175*51846Sbostic 			doing_a_triple = off;
176*51846Sbostic 			lbn_ind = -(NIADDR + 1 + off + NINDIR(fs));
177*51846Sbostic 			break;
178*51846Sbostic 		case 2:
179*51846Sbostic 			/*
180*51846Sbostic 			 * The double indirect block found after indirecting
181*51846Sbostic 			 * through a triple indirect block.
182*51846Sbostic 			 */
183*51846Sbostic 			if (doing_a_triple)
184*51846Sbostic 				lbn_ind = -((doing_a_triple + 2) * NINDIR(fs) +
185*51846Sbostic 				    NIADDR + 1);
186*51846Sbostic 
187*51846Sbostic 			/* The double indirect block found in the inode. */
188*51846Sbostic 			else
189*51846Sbostic 				lbn_ind = -(NIADDR + 1 + off);
190*51846Sbostic 			break;
191*51846Sbostic 		case 3:
192*51846Sbostic 			/*
193*51846Sbostic 			 * A single indirect block; lbn_ind isn't used again,
194*51846Sbostic 			 * so don't do anything.
195*51846Sbostic 			 */
196*51846Sbostic 			break;
197*51846Sbostic 		}
19851183Sbostic 	}
19951183Sbostic 	if (bp)
20039679Smckusick 		brelse(bp);
20151183Sbostic 
20251183Sbostic 	*bnp = daddr;
20337736Smckusick 	return (0);
20437736Smckusick }
205