123396Smckusick /* 263375Sbostic * Copyright (c) 1989, 1991, 1993 363375Sbostic * The Regents of the University of California. All rights reserved. 423396Smckusick * 544537Sbostic * %sccs.include.redist.c% 637736Smckusick * 7*69286Smckusick * @(#)lfs_balloc.c 8.3 (Berkeley) 05/08/95 823396Smckusick */ 951486Sbostic #include <sys/param.h> 1051486Sbostic #include <sys/buf.h> 1151486Sbostic #include <sys/proc.h> 1251486Sbostic #include <sys/vnode.h> 1351486Sbostic #include <sys/mount.h> 1451486Sbostic #include <sys/resourcevar.h> 1551486Sbostic #include <sys/trace.h> 167443Sroot 1755048Smckusick #include <miscfs/specfs/specdev.h> 1855048Smckusick 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 2651855Sbostic int 27*69286Smckusick lfs_balloc(vp, offset, iosize, lbn, bpp) 2852082Sbostic struct vnode *vp; 29*69286Smckusick int offset; 3052082Sbostic u_long iosize; 3168550Smckusick ufs_daddr_t lbn; 3252082Sbostic struct buf **bpp; 3352082Sbostic { 3456609Smargo struct buf *ibp, *bp; 3552082Sbostic struct inode *ip; 3652082Sbostic struct lfs *fs; 3756609Smargo struct indir indirs[NIADDR+2]; 38*69286Smckusick ufs_daddr_t lastblock; 39*69286Smckusick int bb; /* number of disk blocks in a block disk blocks */ 40*69286Smckusick int error, frags, i, nsize, osize, num; 4152082Sbostic 4252082Sbostic ip = VTOI(vp); 4352082Sbostic fs = ip->i_lfs; 4452082Sbostic 4552082Sbostic /* 4652082Sbostic * Three cases: it's a block beyond the end of file, it's a block in 4752082Sbostic * the file that may or may not have been assigned a disk address or 4852082Sbostic * we're writing an entire block. Note, if the daddr is unassigned, 4956609Smargo * the block might still have existed in the cache (if it was read 5056609Smargo * or written earlier). If it did, make sure we don't count it as a 5156609Smargo * new block or zero out its contents. If it did not, make sure 5256609Smargo * we allocate any necessary indirect blocks. 53*69286Smckusick * If we are writing a block beyond the end of the file, we need to 54*69286Smckusick * check if the old last block was a fragment. If it was, we need 55*69286Smckusick * to rewrite it. 5652082Sbostic */ 5755942Sbostic 5855942Sbostic *bpp = NULL; 5956609Smargo if (error = ufs_bmaparray(vp, lbn, &daddr, &indirs[0], &num, NULL )) 6052994Sbostic return (error); 6152082Sbostic 62*69286Smckusick /* Check for block beyond end of file and fragment extension needed. */ 63*69286Smckusick lastblock = lblkno(fs, ip->i_size); 64*69286Smckusick if (lastblock < NDADDR && lastblock < lbn) { 65*69286Smckusick osize = blksize(fs, ip, lastblock); 66*69286Smckusick if (osize < fs->lfs_bsize && osize > 0) { 67*69286Smckusick if (error = lfs_fragextend(vp, osize, fs->lfs_bsize, 68*69286Smckusick lastblock, &bp)) 69*69286Smckusick return(error); 70*69286Smckusick ip->i_size = (lastblock + 1) * fs->lfs_bsize; 71*69286Smckusick vnode_pager_setsize(vp, (u_long)ip->i_size); 72*69286Smckusick ip->i_flag |= IN_CHANGE | IN_UPDATE; 73*69286Smckusick VOP_BWRITE(bp); 74*69286Smckusick } 75*69286Smckusick } 76*69286Smckusick 7756609Smargo bb = VFSTOUFS(vp->v_mount)->um_seqinc; 7856609Smargo if (daddr == UNASSIGNED) 7956609Smargo /* May need to allocate indirect blocks */ 8056609Smargo for (i = 1; i < num; ++i) 8156609Smargo if (!indirs[i].in_exists) { 82*69286Smckusick ibp = getblk(vp, indirs[i].in_lbn, fs->lfs_bsize, 83*69286Smckusick 0, 0); 84*69286Smckusick if ((ibp->b_flags & (B_DONE | B_DELWRI))) 8556609Smargo panic ("Indirect block should not exist"); 86*69286Smckusick 87*69286Smckusick if (!ISSPACE(fs, bb, curproc->p_ucred)){ 88*69286Smckusick ibp->b_flags |= B_INVAL; 89*69286Smckusick brelse(ibp); 90*69286Smckusick return(ENOSPC); 91*69286Smckusick } else { 92*69286Smckusick ip->i_blocks += bb; 93*69286Smckusick ip->i_lfs->lfs_bfree -= bb; 94*69286Smckusick clrbuf(ibp); 95*69286Smckusick if(error = VOP_BWRITE(ibp)) 96*69286Smckusick return(error); 97*69286Smckusick } 9856609Smargo } 99*69286Smckusick 100*69286Smckusick /* 101*69286Smckusick * If the block we are writing is a direct block, it's the last 102*69286Smckusick * block in the file, and offset + iosize is less than a full 103*69286Smckusick * block, we can write one or more fragments. There are two cases: 104*69286Smckusick * the block is brand new and we should allocate it the correct 105*69286Smckusick * size or it already exists and contains some fragments and 106*69286Smckusick * may need to extend it. 107*69286Smckusick */ 108*69286Smckusick if (lbn < NDADDR && lblkno(fs, ip->i_size) == lbn) { 109*69286Smckusick nsize = fragroundup(fs, offset + iosize); 110*69286Smckusick frags = numfrags(fs, nsize); 111*69286Smckusick bb = fragstodb(fs, frags); 112*69286Smckusick if (lblktosize(fs, lbn) == ip->i_size) 113*69286Smckusick /* Brand new block or fragment */ 114*69286Smckusick *bpp = bp = getblk(vp, lbn, nsize, 0, 0); 115*69286Smckusick else { 116*69286Smckusick /* Extend existing block */ 117*69286Smckusick if (error = lfs_fragextend(vp, (int)blksize(fs, ip, lbn), 118*69286Smckusick nsize, lbn, &bp)) 119*69286Smckusick return(error); 120*69286Smckusick *bpp = bp; 121*69286Smckusick } 122*69286Smckusick } else { 123*69286Smckusick /* 124*69286Smckusick * Get the existing block from the cache either because the 125*69286Smckusick * block is 1) not a direct block or because it's not the last 126*69286Smckusick * block in the file. 127*69286Smckusick */ 128*69286Smckusick frags = dbtofrags(fs, bb); 129*69286Smckusick *bpp = bp = getblk(vp, lbn, blksize(fs, ip, lbn), 0, 0); 13056609Smargo } 13156609Smargo 132*69286Smckusick /* 133*69286Smckusick * The block we are writing may be a brand new block 134*69286Smckusick * in which case we need to do accounting (i.e. check 135*69286Smckusick * for free space and update the inode number of blocks. 136*69286Smckusick */ 13756609Smargo if (!(bp->b_flags & (B_CACHE | B_DONE | B_DELWRI))) { 13856609Smargo if (daddr == UNASSIGNED) 13956609Smargo if (!ISSPACE(fs, bb, curproc->p_ucred)) { 14056160Smargo bp->b_flags |= B_INVAL; 14156160Smargo brelse(bp); 14256609Smargo return(ENOSPC); 14356609Smargo } else { 14456609Smargo ip->i_blocks += bb; 14556609Smargo ip->i_lfs->lfs_bfree -= bb; 14656609Smargo if (iosize != fs->lfs_bsize) 14756609Smargo clrbuf(bp); 14856160Smargo } 14956609Smargo else if (iosize == fs->lfs_bsize) 150*69286Smckusick /* Optimization: I/O is unnecessary. */ 151*69286Smckusick bp->b_blkno = daddr; 15256609Smargo else { 153*69286Smckusick /* 154*69286Smckusick * We need to read the block to preserve the 155*69286Smckusick * existing bytes. 156*69286Smckusick */ 15756609Smargo bp->b_blkno = daddr; 15857063Smargo bp->b_flags |= B_READ; 15956609Smargo VOP_STRATEGY(bp); 16056864Smargo return(biowait(bp)); 16152082Sbostic } 16252082Sbostic } 163*69286Smckusick return (0); 16452082Sbostic } 165*69286Smckusick 166*69286Smckusick lfs_fragextend(vp, osize, nsize, lbn, bpp) 167*69286Smckusick struct vnode *vp; 168*69286Smckusick int osize; 169*69286Smckusick int nsize; 170*69286Smckusick daddr_t lbn; 171*69286Smckusick struct buf **bpp; 172*69286Smckusick { 173*69286Smckusick struct inode *ip; 174*69286Smckusick struct lfs *fs; 175*69286Smckusick long bb; 176*69286Smckusick int error; 177*69286Smckusick 178*69286Smckusick ip = VTOI(vp); 179*69286Smckusick fs = ip->i_lfs; 180*69286Smckusick bb = (long)fragstodb(fs, numfrags(fs, nsize - osize)); 181*69286Smckusick if (!ISSPACE(fs, bb, curproc->p_ucred)) { 182*69286Smckusick return(ENOSPC); 183*69286Smckusick } 184*69286Smckusick 185*69286Smckusick if (error = bread(vp, lbn, osize, NOCRED, bpp)) { 186*69286Smckusick brelse(*bpp); 187*69286Smckusick return(error); 188*69286Smckusick } 189*69286Smckusick #ifdef QUOTA 190*69286Smckusick if (error = chkdq(ip, bb, curproc->p_ucred, 0)) { 191*69286Smckusick brelse(*bpp); 192*69286Smckusick return (error); 193*69286Smckusick } 194*69286Smckusick #endif 195*69286Smckusick ip->i_blocks += bb; 196*69286Smckusick ip->i_flag |= IN_CHANGE | IN_UPDATE; 197*69286Smckusick fs->lfs_bfree -= fragstodb(fs, numfrags(fs, (nsize - osize))); 198*69286Smckusick allocbuf(*bpp, nsize); 199*69286Smckusick bzero((char *)((*bpp)->b_data) + osize, (u_int)(nsize - osize)); 200*69286Smckusick return(0); 201*69286Smckusick } 202