xref: /csrg-svn/sys/ufs/lfs/lfs_balloc.c (revision 51847)
123396Smckusick /*
251494Sbostic  * Copyright (c) 1989, 1991 Regents of the University of California.
337736Smckusick  * All rights reserved.
423396Smckusick  *
544537Sbostic  * %sccs.include.redist.c%
637736Smckusick  *
7*51847Sbostic  *	@(#)lfs_balloc.c	7.22 (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.
3051846Sbostic  *
3151846Sbostic  * LFS has a different version of bmap from FFS because of a naming conflict.
3251846Sbostic  * In FFS, meta blocks are given real disk addresses at allocation time, and
3351846Sbostic  * are linked into the device vnode, using a logical block number which is
3451846Sbostic  * the same as the physical block number.  This can't be done by LFS because
3551846Sbostic  * blocks aren't given disk addresses until they're written, so there's no
3651846Sbostic  * way to distinguish the meta-data blocks for one file from any other file.
3751846Sbostic  * This means that meta-data blocks have to be on the vnode for the file so
3851846Sbostic  * they can be found, and have to have "names" different from the standard
3951846Sbostic  * data blocks.  To do this, we divide the name space into positive and
4051846Sbostic  * negative block numbers, and give the meta-data blocks negative logical
41*51847Sbostic  * numbers.  Indirect blocks are addressed by the negative address of the
42*51847Sbostic  * first data block to which they point.  Double indirect blocks are addressed
43*51847Sbostic  * by one less than the address of the first indirect block to which they
44*51847Sbostic  * point.  Triple indirect blocks are addressed by one less than the address
45*51847Sbostic  * of the first double indirect block to which they point.
467443Sroot  */
4751348Sroot int
4851561Smckusick lfs_bmap(vp, bn, vpp, bnp)
4951561Smckusick 	struct vnode *vp;
5037736Smckusick 	register daddr_t bn;
5151561Smckusick 	struct vnode **vpp;
5251561Smckusick 	daddr_t *bnp;
537443Sroot {
5451561Smckusick 	register struct inode *ip;
5551494Sbostic 	register struct lfs *fs;
5637736Smckusick 	register daddr_t nb;
5751846Sbostic 	struct buf *bp;
5851561Smckusick 	struct vnode *devvp;
59*51847Sbostic 	daddr_t *bap, daddr, metalbn;
60*51847Sbostic 	long realbn;
61*51847Sbostic 	int error, j, off, sh;
6237736Smckusick 
6351561Smckusick 	/*
6451561Smckusick 	 * Check for underlying vnode requests and ensure that logical
6551561Smckusick 	 * to physical mapping is requested.
6651561Smckusick 	 */
6751561Smckusick 	ip = VTOI(vp);
6851561Smckusick 	if (vpp != NULL)
6951561Smckusick 		*vpp = ip->i_devvp;
7051561Smckusick 	if (bnp == NULL)
7151561Smckusick 		return (0);
7251846Sbostic 
7351846Sbostic #ifdef VERBOSE
7451155Sbostic printf("lfs_bmap: block number %d, inode %d\n", bn, ip->i_number);
7551846Sbostic #endif
76*51847Sbostic 	realbn = bn;
77*51847Sbostic 	if ((long)bn < 0)
78*51847Sbostic 		bn = -(long)bn;
79*51847Sbostic 
8051486Sbostic 	/* The first NDADDR blocks are direct blocks. */
8137736Smckusick 	if (bn < NDADDR) {
8237736Smckusick 		nb = ip->i_db[bn];
83*51847Sbostic 		if (nb == 0) {
8451348Sroot 			*bnp = UNASSIGNED;
85*51847Sbostic 			return (0);
86*51847Sbostic 		}
87*51847Sbostic 		*bnp = nb;
8837736Smckusick 		return (0);
8937736Smckusick 	}
9051486Sbostic 
9151846Sbostic 	/*
9251846Sbostic 	 * Determine the number of levels of indirection.  After this loop
9351846Sbostic 	 * is done, sh indicates the number of data blocks possible at the
94*51847Sbostic 	 * given level of indirection, and NIADDR - j is the number of levels
95*51847Sbostic 	 * of indirection needed to locate the requested block.
9651846Sbostic 	 */
97*51847Sbostic 	bn -= NDADDR;
9851846Sbostic 	fs = ip->i_lfs;
9937736Smckusick 	sh = 1;
10037736Smckusick 	for (j = NIADDR; j > 0; j--) {
10137736Smckusick 		sh *= NINDIR(fs);
10237736Smckusick 		if (bn < sh)
10337736Smckusick 			break;
10437736Smckusick 		bn -= sh;
10537736Smckusick 	}
10637736Smckusick 	if (j == 0)
10737736Smckusick 		return (EFBIG);
10851183Sbostic 
109*51847Sbostic 	/* Calculate the address of the first meta-block. */
110*51847Sbostic 	if (realbn >= 0)
111*51847Sbostic 		metalbn = -(realbn - bn + NIADDR - j);
112*51847Sbostic 	else
113*51847Sbostic 		metalbn = -(-realbn - bn + NIADDR - j);
114*51847Sbostic 
11551846Sbostic 	/*
11651846Sbostic 	 * Fetch through the indirect blocks.  At each iteration, off is the
11751846Sbostic 	 * offset into the bap array which is an array of disk addresses at
11851846Sbostic 	 * the current level of indirection.
11951846Sbostic 	 */
12051846Sbostic 	bp = NULL;
12151183Sbostic 	devvp = VFSTOUFS(vp->v_mount)->um_devvp;
122*51847Sbostic 	for (off = NIADDR - j, bap = ip->i_ib; j <= NIADDR; j++) {
12351846Sbostic 		/*
12451846Sbostic 		 * In LFS, it's possible to have a block appended to a file
12551846Sbostic 		 * for which the meta-blocks have not yet been allocated.
12651846Sbostic 		 * This is a win if the file never gets written or if the
12751846Sbostic 		 * file's growing.
12851846Sbostic 		 */
12951846Sbostic 		if ((daddr = bap[off]) == 0) {
13051348Sroot 			daddr = UNASSIGNED;
13151183Sbostic 			break;
13251183Sbostic 		}
133*51847Sbostic 
134*51847Sbostic 		/* If searching for a meta-data block, quit when found. */
135*51847Sbostic 		if (metalbn == realbn)
136*51847Sbostic 			break;
137*51847Sbostic 
13851846Sbostic 		/*
13951846Sbostic 		 * Read in the appropriate indirect block.  LFS can't do a
14051846Sbostic 		 * bread because bread knows that FFS will hand it the device
14151846Sbostic 		 * vnode, not the file vnode, so the b_dev and b_blkno would
14251846Sbostic 		 * be wrong.
14351846Sbostic 		 *
14451846Sbostic 		 * XXX
14551846Sbostic 		 * This REALLY needs to be fixed, at the very least it needs
14651846Sbostic 		 * to be rethought when the buffer cache goes away.
14751846Sbostic 		 */
14851183Sbostic 		if (bp)
14937736Smckusick 			brelse(bp);
150*51847Sbostic 		bp = getblk(vp, metalbn, fs->lfs_bsize);
15151183Sbostic 		if (bp->b_flags & (B_DONE | B_DELWRI)) {
152*51847Sbostic 			trace(TR_BREADHIT, pack(vp, size), metalbn);
15351183Sbostic 		} else {
154*51847Sbostic 			trace(TR_BREADMISS, pack(vp, size), metalbn);
155*51847Sbostic 			bp->b_blkno = daddr;
15651846Sbostic 			bp->b_flags |= B_READ;
15751183Sbostic 			bp->b_dev = devvp->v_rdev;
15851215Sbostic 			(devvp->v_op->vop_strategy)(bp);
15951183Sbostic 			curproc->p_stats->p_ru.ru_inblock++;	/* XXX */
16051183Sbostic 			if (error = biowait(bp)) {
16151183Sbostic 				brelse(bp);
16251183Sbostic 				return (error);
16351183Sbostic 			}
16437736Smckusick 		}
165*51847Sbostic 
16637736Smckusick 		bap = bp->b_un.b_daddr;
16737736Smckusick 		sh /= NINDIR(fs);
16851183Sbostic 		off = (bn / sh) % NINDIR(fs);
169*51847Sbostic 		metalbn -= -1 + off * sh;
17051183Sbostic 	}
17151183Sbostic 	if (bp)
17239679Smckusick 		brelse(bp);
17351183Sbostic 
17451183Sbostic 	*bnp = daddr;
17537736Smckusick 	return (0);
17637736Smckusick }
177