123396Smckusick /* 251494Sbostic * Copyright (c) 1989, 1991 Regents of the University of California. 337736Smckusick * All rights reserved. 423396Smckusick * 544537Sbostic * %sccs.include.redist.c% 637736Smckusick * 7*52994Sbostic * @(#)lfs_balloc.c 7.27 (Berkeley) 03/18/92 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 2651962Sbostic int lfs_getlbns __P((struct vnode *, daddr_t, INDIR *, int *)); 2751855Sbostic 287443Sroot /* 2951486Sbostic * Bmap converts a the logical block number of a file to its physical block 3051486Sbostic * number on the disk. The conversion is done by using the logical block 3151486Sbostic * number to index into the array of block pointers described by the dinode. 3251855Sbostic */ 3351855Sbostic int 3451855Sbostic lfs_bmap(vp, bn, vpp, bnp) 3551855Sbostic struct vnode *vp; 3651855Sbostic register daddr_t bn; 3751855Sbostic struct vnode **vpp; 3851855Sbostic daddr_t *bnp; 3951855Sbostic { 4051855Sbostic #ifdef VERBOSE 4151855Sbostic printf("lfs_bmap\n"); 4251855Sbostic #endif 4351855Sbostic /* 4451855Sbostic * Check for underlying vnode requests and ensure that logical 4551855Sbostic * to physical mapping is requested. 4651855Sbostic */ 4751855Sbostic if (vpp != NULL) 4851855Sbostic *vpp = VTOI(vp)->i_devvp; 4951855Sbostic if (bnp == NULL) 5051855Sbostic return (0); 5151855Sbostic 5251855Sbostic return (lfs_bmaparray(vp, bn, bnp, NULL, NULL)); 5351855Sbostic } 5451855Sbostic 5551855Sbostic /* 5651846Sbostic * LFS has a different version of bmap from FFS because of a naming conflict. 5751846Sbostic * In FFS, meta blocks are given real disk addresses at allocation time, and 5851846Sbostic * are linked into the device vnode, using a logical block number which is 5951846Sbostic * the same as the physical block number. This can't be done by LFS because 6051846Sbostic * blocks aren't given disk addresses until they're written, so there's no 6151846Sbostic * way to distinguish the meta-data blocks for one file from any other file. 6251846Sbostic * This means that meta-data blocks have to be on the vnode for the file so 6351846Sbostic * they can be found, and have to have "names" different from the standard 6451846Sbostic * data blocks. To do this, we divide the name space into positive and 6551846Sbostic * negative block numbers, and give the meta-data blocks negative logical 6651847Sbostic * numbers. Indirect blocks are addressed by the negative address of the 6751847Sbostic * first data block to which they point. Double indirect blocks are addressed 6851847Sbostic * by one less than the address of the first indirect block to which they 6951847Sbostic * point. Triple indirect blocks are addressed by one less than the address 7051847Sbostic * of the first double indirect block to which they point. 717443Sroot */ 7251348Sroot int 7351855Sbostic lfs_bmaparray(vp, bn, bnp, ap, nump) 7451561Smckusick struct vnode *vp; 7537736Smckusick register daddr_t bn; 7651561Smckusick daddr_t *bnp; 7751855Sbostic INDIR *ap; 7851855Sbostic int *nump; 797443Sroot { 8051561Smckusick register struct inode *ip; 8151846Sbostic struct buf *bp; 8251855Sbostic struct lfs *fs; 8351561Smckusick struct vnode *devvp; 8451855Sbostic INDIR a[NIADDR], *xap; 8551855Sbostic daddr_t *bap, daddr; 8651855Sbostic long metalbn; 8751855Sbostic int error, num, off; 8837736Smckusick 8951855Sbostic 9051561Smckusick ip = VTOI(vp); 9151846Sbostic #ifdef VERBOSE 9251855Sbostic printf("lfs_bmap: block number %d, inode %d\n", bn, ip->i_number); 9351846Sbostic #endif 9451855Sbostic #ifdef DIAGNOSTIC 9551855Sbostic if (ap != NULL && nump == NULL || ap == NULL && nump != NULL) 9651855Sbostic panic("lfs_bmaparray: invalid arguments"); 9751855Sbostic #endif 9851847Sbostic 9951855Sbostic xap = ap == NULL ? a : ap; 10051855Sbostic if (error = lfs_getlbns(vp, bn, xap, nump)) 10151855Sbostic return (error); 10251855Sbostic 10351855Sbostic num = *nump; 104*52994Sbostic 10551855Sbostic if (num == 0) { 10651855Sbostic *bnp = ip->i_db[bn]; 10751855Sbostic if (*bnp == 0) 10851348Sroot *bnp = UNASSIGNED; 10937736Smckusick return (0); 11037736Smckusick } 11151486Sbostic 112*52994Sbostic 113*52994Sbostic /* Get disk address out of indirect block array */ 114*52994Sbostic daddr = ip->i_ib[xap->in_off]; 115*52994Sbostic 11651855Sbostic /* Fetch through the indirect blocks. */ 117*52994Sbostic fs = ip->i_lfs; 11851183Sbostic devvp = VFSTOUFS(vp->v_mount)->um_devvp; 119*52994Sbostic 120*52994Sbostic for (bp = NULL, ++xap; daddr && --num; ++xap) { 121*52994Sbostic /* If looking for a meta-block, break out when we find it. */ 12251855Sbostic metalbn = xap->in_lbn; 12351855Sbostic if (metalbn == bn) 12451847Sbostic break; 12551847Sbostic 12651846Sbostic /* 12751846Sbostic * Read in the appropriate indirect block. LFS can't do a 12851846Sbostic * bread because bread knows that FFS will hand it the device 12951846Sbostic * vnode, not the file vnode, so the b_dev and b_blkno would 13051846Sbostic * be wrong. 13151846Sbostic * 13251846Sbostic * XXX 13351846Sbostic * This REALLY needs to be fixed, at the very least it needs 13451855Sbostic * to be rethought when the buffer cache goes away. When it's 13551855Sbostic * fixed, change lfs_bmaparray and lfs_getlbns to take an ip, 13651855Sbostic * not a vp. 13751846Sbostic */ 13851183Sbostic if (bp) 13937736Smckusick brelse(bp); 14051847Sbostic bp = getblk(vp, metalbn, fs->lfs_bsize); 14151183Sbostic if (bp->b_flags & (B_DONE | B_DELWRI)) { 14251847Sbostic trace(TR_BREADHIT, pack(vp, size), metalbn); 14351183Sbostic } else { 14451847Sbostic trace(TR_BREADMISS, pack(vp, size), metalbn); 14551847Sbostic bp->b_blkno = daddr; 14651846Sbostic bp->b_flags |= B_READ; 14751183Sbostic bp->b_dev = devvp->v_rdev; 14851215Sbostic (devvp->v_op->vop_strategy)(bp); 14951183Sbostic curproc->p_stats->p_ru.ru_inblock++; /* XXX */ 15051183Sbostic if (error = biowait(bp)) { 15151183Sbostic brelse(bp); 15251183Sbostic return (error); 15351183Sbostic } 15437736Smckusick } 155*52994Sbostic daddr = bp->b_un.b_daddr[xap->in_off]; 15651183Sbostic } 15751183Sbostic if (bp) 15839679Smckusick brelse(bp); 15951183Sbostic 160*52994Sbostic *bnp = daddr == 0 ? UNASSIGNED : daddr; 16137736Smckusick return (0); 16237736Smckusick } 16351855Sbostic 16451855Sbostic /* 16551855Sbostic * Create an array of logical block number/offset pairs which represent the 16651855Sbostic * path of indirect blocks required to access a data block. The first "pair" 16751855Sbostic * contains the logical block number of the appropriate single, double or 16851855Sbostic * triple indirect block and the offset into the inode indirect block array. 16951855Sbostic * Note, the logical block number of the inode single/double/triple indirect 17051855Sbostic * block appears twice in the array, once with the offset into the i_ib and 17151855Sbostic * once with the offset into the page itself. 17251855Sbostic */ 17351855Sbostic int 17451855Sbostic lfs_getlbns(vp, bn, ap, nump) 17551855Sbostic struct vnode *vp; 17651855Sbostic register daddr_t bn; 17751855Sbostic INDIR *ap; 17851855Sbostic int *nump; 17951855Sbostic { 18051855Sbostic struct lfs *fs; 18151855Sbostic long metalbn, realbn; 18251855Sbostic int j, off, sh; 18351855Sbostic 18451855Sbostic #ifdef VERBOSE 18551855Sbostic printf("lfs_getlbns: bn %d, inode %d\n", bn, VTOI(vp)->i_number); 18651855Sbostic #endif 18751855Sbostic *nump = 0; 18851855Sbostic realbn = bn; 18951855Sbostic if ((long)bn < 0) 19051855Sbostic bn = -(long)bn; 19151855Sbostic 19251855Sbostic /* The first NDADDR blocks are direct blocks. */ 19351855Sbostic if (bn < NDADDR) 194*52994Sbostic return (0); 19551855Sbostic 19651855Sbostic /* 19751855Sbostic * Determine the number of levels of indirection. After this loop 19851855Sbostic * is done, sh indicates the number of data blocks possible at the 19951855Sbostic * given level of indirection, and NIADDR - j is the number of levels 20051855Sbostic * of indirection needed to locate the requested block. 20151855Sbostic */ 20251855Sbostic bn -= NDADDR; 20351855Sbostic fs = VTOI(vp)->i_lfs; 20451855Sbostic sh = 1; 20551855Sbostic for (j = NIADDR; j > 0; j--) { 20651855Sbostic sh *= NINDIR(fs); 20751855Sbostic if (bn < sh) 20851855Sbostic break; 20951855Sbostic bn -= sh; 21051855Sbostic } 21151855Sbostic if (j == 0) 21251855Sbostic return (EFBIG); 21351855Sbostic 21451855Sbostic /* Calculate the address of the first meta-block. */ 21551855Sbostic if (realbn >= 0) 21651855Sbostic metalbn = -(realbn - bn + NIADDR - j); 21751855Sbostic else 21851855Sbostic metalbn = -(-realbn - bn + NIADDR - j); 21951855Sbostic 22051855Sbostic /* 22151855Sbostic * At each iteration, off is the offset into the bap array which is 22251855Sbostic * an array of disk addresses at the current level of indirection. 22351855Sbostic * The logical block number and the offset in that block are stored 22451855Sbostic * into the argument array. 22551855Sbostic */ 22651855Sbostic ++*nump; 22751855Sbostic ap->in_lbn = metalbn; 22851855Sbostic ap->in_off = off = NIADDR - j; 22951855Sbostic ap++; 23051855Sbostic for (; j <= NIADDR; j++) { 23151855Sbostic /* If searching for a meta-data block, quit when found. */ 23251855Sbostic if (metalbn == realbn) 23351855Sbostic break; 23451855Sbostic 23551855Sbostic sh /= NINDIR(fs); 23651855Sbostic off = (bn / sh) % NINDIR(fs); 23751855Sbostic 23851855Sbostic ++*nump; 23951855Sbostic ap->in_lbn = metalbn; 24051855Sbostic ap->in_off = off; 24151855Sbostic ++ap; 24251855Sbostic 24351855Sbostic metalbn -= -1 + off * sh; 24451855Sbostic } 24551855Sbostic return (0); 24651855Sbostic } 24752082Sbostic 24852082Sbostic int 24952082Sbostic lfs_balloc(vp, iosize, lbn, bpp) 25052082Sbostic struct vnode *vp; 25152082Sbostic u_long iosize; 25252082Sbostic daddr_t lbn; 25352082Sbostic struct buf **bpp; 25452082Sbostic { 25552082Sbostic struct buf *bp; 25652082Sbostic struct inode *ip; 25752082Sbostic struct lfs *fs; 25852082Sbostic daddr_t daddr; 25952082Sbostic int error, newblock; 26052082Sbostic 26152082Sbostic ip = VTOI(vp); 26252082Sbostic fs = ip->i_lfs; 26352082Sbostic 26452082Sbostic /* 26552082Sbostic * Three cases: it's a block beyond the end of file, it's a block in 26652082Sbostic * the file that may or may not have been assigned a disk address or 26752082Sbostic * we're writing an entire block. Note, if the daddr is unassigned, 26852082Sbostic * the block might still have existed in the cache. If it did, make 26952082Sbostic * sure we don't count it as a new block or zero out its contents. 27052082Sbostic */ 27152082Sbostic newblock = ip->i_size <= lbn << fs->lfs_bshift; 27252082Sbostic if (!newblock && (error = lfs_bmap(vp, lbn, NULL, &daddr))) 273*52994Sbostic return (error); 27452082Sbostic 27552172Sbostic if (newblock || daddr == UNASSIGNED || iosize == fs->lfs_bsize) { 27652082Sbostic *bpp = bp = getblk(vp, lbn, fs->lfs_bsize); 27752082Sbostic if (newblock || 27852172Sbostic daddr == UNASSIGNED && !(bp->b_flags & B_CACHE)) { 27952082Sbostic ++ip->i_blocks; 28052082Sbostic if (iosize != fs->lfs_bsize) 28152082Sbostic clrbuf(bp); 28252082Sbostic } 283*52994Sbostic return (0); 28452082Sbostic } 285*52994Sbostic return (bread(vp, lbn, fs->lfs_bsize, NOCRED, bpp)); 28652082Sbostic 28752082Sbostic } 288