123399Smckusick /* 251498Sbostic * Copyright (c) 1986, 1989, 1991 Regents of the University of California. 337736Smckusick * All rights reserved. 423399Smckusick * 544537Sbostic * %sccs.include.redist.c% 637736Smckusick * 7*52681Sstaelin * @(#)lfs_inode.c 7.57 (Berkeley) 02/27/92 823399Smckusick */ 924Sbill 1051484Sbostic #include <sys/param.h> 1151484Sbostic #include <sys/systm.h> 1251484Sbostic #include <sys/mount.h> 1351484Sbostic #include <sys/proc.h> 1451484Sbostic #include <sys/file.h> 1551484Sbostic #include <sys/buf.h> 1651484Sbostic #include <sys/vnode.h> 1751484Sbostic #include <sys/kernel.h> 1851484Sbostic #include <sys/malloc.h> 1924Sbill 2051498Sbostic #include <ufs/ufs/quota.h> 2151498Sbostic #include <ufs/ufs/inode.h> 2251498Sbostic #include <ufs/ufs/ufsmount.h> 2351498Sbostic #include <ufs/ufs/ufs_extern.h> 2447571Skarels 2551498Sbostic #include <ufs/lfs/lfs.h> 2651498Sbostic #include <ufs/lfs/lfs_extern.h> 2724Sbill 2851346Sbostic int 2951155Sbostic lfs_init() 3024Sbill { 3151857Sbostic #ifdef VERBOSE 3251857Sbostic printf("lfs_init\n"); 3351857Sbostic #endif 3451484Sbostic return (ufs_init()); 3524Sbill } 3624Sbill 3724Sbill /* 3851484Sbostic * Look up an LFS dinode number to find its incore vnode. If not already 3951484Sbostic * in core, read it in from the specified device. Return the inode locked. 4051484Sbostic * Detection and handling of mount points must be done by the calling routine. 4124Sbill */ 4251346Sbostic int 4351562Smckusick lfs_vget(mntp, ino, vpp) 4451562Smckusick struct mount *mntp; 454818Swnj ino_t ino; 4651562Smckusick struct vnode **vpp; 4724Sbill { 4851498Sbostic register struct lfs *fs; 4951484Sbostic register struct inode *ip; 5051484Sbostic struct buf *bp; 5152224Sbostic struct ifile *ifp; 5251498Sbostic struct vnode *vp; 5351562Smckusick struct ufsmount *ump; 5452224Sbostic daddr_t daddr; 5551484Sbostic dev_t dev; 5651346Sbostic int error; 5724Sbill 5851857Sbostic #ifdef VERBOSE 5951857Sbostic printf("lfs_vget\n"); 6051857Sbostic #endif 6151562Smckusick ump = VFSTOUFS(mntp); 6251562Smckusick dev = ump->um_dev; 6351562Smckusick if ((*vpp = ufs_ihashget(dev, ino)) != NULL) 6451484Sbostic return (0); 6551484Sbostic 6652224Sbostic /* Translate the inode number to a disk address. */ 6752224Sbostic fs = ump->um_lfs; 6852224Sbostic if (ino == LFS_IFILE_INUM) 6952224Sbostic daddr = fs->lfs_idaddr; 7052224Sbostic else { 7152224Sbostic LFS_IENTRY(ifp, fs, ino, bp); 7252224Sbostic daddr = ifp->if_daddr; 7352224Sbostic brelse(bp); 7452224Sbostic if (daddr == LFS_UNUSED_DADDR) 7552224Sbostic return (ENOENT); 7652224Sbostic } 7752224Sbostic 7851155Sbostic /* Allocate new vnode/inode. */ 7951498Sbostic if (error = lfs_vcreate(mntp, ino, &vp)) { 8051562Smckusick *vpp = NULL; 8137736Smckusick return (error); 8237736Smckusick } 8352224Sbostic 8437736Smckusick /* 8539440Smckusick * Put it onto its hash chain and lock it so that other requests for 8639440Smckusick * this inode will block if they arrive while we are sleeping waiting 8739440Smckusick * for old data structures to be purged or for the contents of the 8839440Smckusick * disk portion of this inode to be read. 8939440Smckusick */ 9051562Smckusick ip = VTOI(vp); 9151484Sbostic ufs_ihashins(ip); 9251155Sbostic 9352224Sbostic /* 9452224Sbostic * XXX 9552224Sbostic * This may not need to be here, logically it should go down with 9652224Sbostic * the i_devvp initialization. 9752224Sbostic * Ask Kirk. 9852224Sbostic */ 9952224Sbostic ip->i_lfs = ump->um_lfs; 10052224Sbostic 10151484Sbostic /* Read in the disk contents for the inode, copy into the inode. */ 10252224Sbostic if (error = 10352224Sbostic bread(ump->um_devvp, daddr, (int)fs->lfs_bsize, NOCRED, &bp)) { 10437736Smckusick /* 10551857Sbostic * The inode does not contain anything useful, so it 10651857Sbostic * would be misleading to leave it on its hash chain. 10751857Sbostic * Iput() will return it to the free list. 10841334Smckusick */ 10941334Smckusick remque(ip); 11041334Smckusick ip->i_forw = ip; 11141334Smckusick ip->i_back = ip; 11251484Sbostic 11351484Sbostic /* Unlock and discard unneeded inode. */ 11451484Sbostic ufs_iput(ip); 11537736Smckusick brelse(bp); 11651562Smckusick *vpp = NULL; 11739440Smckusick return (error); 11837736Smckusick } 11951155Sbostic ip->i_din = *lfs_ifind(fs, ino, bp->b_un.b_dino); 12039440Smckusick brelse(bp); 12151155Sbostic 12251498Sbostic /* 12351498Sbostic * Initialize the vnode from the inode, check for aliases. In all 12451498Sbostic * cases re-init ip, the underlying vnode/inode may have changed. 12551498Sbostic */ 12651595Smckusick if (error = ufs_vinit(mntp, &lfs_specops, LFS_FIFOOPS, &vp)) { 12751484Sbostic ufs_iput(ip); 12851562Smckusick *vpp = NULL; 12951484Sbostic return (error); 13040289Smckusick } 13151562Smckusick /* 13251562Smckusick * Finish inode initialization now that aliasing has been resolved. 13351562Smckusick */ 13451562Smckusick ip->i_devvp = ump->um_devvp; 13551562Smckusick VREF(ip->i_devvp); 13651562Smckusick *vpp = vp; 13737736Smckusick return (0); 13837736Smckusick } 1397334Skre 14051346Sbostic int 14151562Smckusick lfs_update(vp, ta, tm, waitfor) 14251562Smckusick register struct vnode *vp; 14351484Sbostic struct timeval *ta, *tm; 14451484Sbostic int waitfor; 1457118Smckusick { 14651562Smckusick struct inode *ip; 14751562Smckusick 14851857Sbostic #ifdef VERBOSE 14951857Sbostic printf("lfs_update\n"); 15051857Sbostic #endif 15151562Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) 15251562Smckusick return (0); 15351562Smckusick ip = VTOI(vp); 15451562Smckusick if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) 15551562Smckusick return (0); 15651562Smckusick if (ip->i_flag&IACC) 15751562Smckusick ip->i_atime = ta->tv_sec; 15852018Smckusick if (ip->i_flag&IUPD) { 15951562Smckusick ip->i_mtime = tm->tv_sec; 16052018Smckusick INCRQUAD((ip)->i_modrev); 16152018Smckusick } 16251562Smckusick if (ip->i_flag&ICHG) 16351562Smckusick ip->i_ctime = time.tv_sec; 16451562Smckusick ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 16551562Smckusick 16652327Sbostic /* Push back the vnode and any dirty blocks it may have. */ 16752327Sbostic return (waitfor ? lfs_vflush(vp) : 0); 16824Sbill } 16924Sbill 17052222Sbostic /* Update segment usage information when removing a block. */ 17152225Sbostic #define UPDATE_SEGUSE \ 17252225Sbostic if (lastseg != -1) { \ 17352225Sbostic LFS_SEGENTRY(sup, fs, lastseg, sup_bp); \ 174*52681Sstaelin sup->su_nbytes -= num << fs->lfs_bshift; \ 17552225Sbostic LFS_UBWRITE(sup_bp); \ 17652225Sbostic blocksreleased += num; \ 17752225Sbostic } 17852222Sbostic 17952222Sbostic #define SEGDEC { \ 18052222Sbostic if (daddr != UNASSIGNED) { \ 18152222Sbostic if (lastseg != (seg = datosn(fs, daddr))) { \ 18252222Sbostic UPDATE_SEGUSE; \ 18352222Sbostic num = 1; \ 18452222Sbostic lastseg = seg; \ 18552222Sbostic } else \ 18652222Sbostic ++num; \ 18752222Sbostic } \ 18852222Sbostic } 18952222Sbostic 19024Sbill /* 19152222Sbostic * Truncate the inode ip to at most length size. Update segment usage 19252222Sbostic * table information. 19324Sbill */ 19451484Sbostic /* ARGSUSED */ 19551484Sbostic int 19652222Sbostic lfs_truncate(vp, length, flags) 19752222Sbostic struct vnode *vp; 1989165Ssam u_long length; 19939676Smckusick int flags; 20024Sbill { 20152222Sbostic register INDIR *ap; 20252222Sbostic register int i; 20352222Sbostic register daddr_t *daddrp; 20452225Sbostic struct buf *bp, *sup_bp; 20552327Sbostic struct ifile *ifp; 20652222Sbostic struct inode *ip; 20752222Sbostic struct lfs *fs; 20852222Sbostic INDIR a[NIADDR + 2], a_end[NIADDR + 2]; 20952222Sbostic SEGUSE *sup; 21052222Sbostic daddr_t daddr, lastblock, lbn, olastblock; 21152222Sbostic off_t off; 21252222Sbostic long blocksreleased; 21352222Sbostic int error, depth, lastseg, num, offset, seg, size; 2149165Ssam 21551857Sbostic #ifdef VERBOSE 21651857Sbostic printf("lfs_truncate\n"); 21751857Sbostic #endif 21852222Sbostic vnode_pager_setsize(vp, length); 21952327Sbostic 22052222Sbostic ip = VTOI(vp); 22152327Sbostic fs = ip->i_lfs; 22252327Sbostic 22352327Sbostic /* If truncating the file to 0, update the version number. */ 22452327Sbostic if (length == 0) { 22552327Sbostic LFS_IENTRY(ifp, fs, ip->i_number, bp); 22652327Sbostic ++ifp->if_version; 22752327Sbostic LFS_UBWRITE(bp); 22852327Sbostic } 22952327Sbostic 23051484Sbostic /* If length is larger than the file, just update the times. */ 23152222Sbostic if (ip->i_size <= length) { 23252222Sbostic ip->i_flag |= ICHG|IUPD; 23352222Sbostic return (lfs_update(vp, &time, &time, 1)); 23413000Ssam } 23552327Sbostic 23652222Sbostic /* 23752222Sbostic * Calculate index into inode's block list of last direct and indirect 23852222Sbostic * blocks (if any) which we want to keep. Lastblock is 0 when the 23952222Sbostic * file is truncated to 0. 24052222Sbostic */ 24152222Sbostic lastblock = lblkno(fs, length + fs->lfs_bsize - 1); 24252222Sbostic olastblock = lblkno(fs, ip->i_size + fs->lfs_bsize - 1) - 1; 24351484Sbostic 2441203Sbill /* 24551484Sbostic * Update the size of the file. If the file is not being truncated to 24651484Sbostic * a block boundry, the contents of the partial block following the end 24751484Sbostic * of the file must be zero'ed in case it ever become accessable again 24851484Sbostic * because of subsequent file growth. 2491203Sbill */ 25017942Smckusick offset = blkoff(fs, length); 25151484Sbostic if (offset == 0) 25252222Sbostic ip->i_size = length; 25351484Sbostic else { 25417942Smckusick lbn = lblkno(fs, length); 25541313Smckusick #ifdef QUOTA 25652222Sbostic if (error = getinoquota(ip)) 25741313Smckusick return (error); 25851183Sbostic #endif 25952222Sbostic if (error = bread(vp, lbn, fs->lfs_bsize, NOCRED, &bp)) 26037736Smckusick return (error); 26152222Sbostic ip->i_size = length; 26251857Sbostic size = blksize(fs); 26352222Sbostic (void)vnode_pager_uncache(vp); 26426272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 26545112Smckusick allocbuf(bp, size); 26652078Sbostic LFS_UBWRITE(bp); 26717942Smckusick } 26852078Sbostic /* 26952222Sbostic * Modify sup->su_nbyte counters for each deleted block; keep track 27052222Sbostic * of number of blocks removed for ip->i_blocks. 27152222Sbostic */ 27252222Sbostic blocksreleased = 0; 27352222Sbostic num = 0; 27452222Sbostic lastseg = -1; 27552222Sbostic 27652222Sbostic for (lbn = olastblock; lbn >= lastblock;) { 27752222Sbostic lfs_bmaparray(vp, lbn, &daddr, a, &depth); 27852222Sbostic if (lbn == olastblock) 27952222Sbostic for (i = NIADDR + 2; i--;) 28052222Sbostic a_end[i] = a[i]; 28152222Sbostic switch (depth) { 28252222Sbostic case 0: /* Direct block. */ 28352222Sbostic daddr = ip->i_db[lbn]; 28452222Sbostic SEGDEC; 28552222Sbostic ip->i_db[lbn] = 0; 28652222Sbostic --lbn; 28752222Sbostic break; 28852222Sbostic #ifdef DIAGNOSTIC 28952222Sbostic case 1: /* An indirect block. */ 29052222Sbostic panic("lfs_truncate: lfs_bmaparray returned depth 1"); 29152222Sbostic /* NOTREACHED */ 29252222Sbostic #endif 29352222Sbostic default: /* Chain of indirect blocks. */ 29452222Sbostic ap = a + --depth; 29552222Sbostic if (ap->in_off > 0 && lbn != lastblock) { 29652222Sbostic lbn -= ap->in_off < lbn - lastblock ? 29752222Sbostic ap->in_off : lbn - lastblock; 29852222Sbostic break; 29952222Sbostic } 30052222Sbostic for (; depth && (ap->in_off == 0 || lbn == lastblock); 30152222Sbostic --ap, --depth) { 30252222Sbostic /* 30352222Sbostic * XXX 30452222Sbostic * The indirect block may not yet exist, so 30552222Sbostic * bread will create one just so we can free 30652222Sbostic * it. 30752222Sbostic */ 30852222Sbostic if (bread(vp, 30952222Sbostic ap->in_lbn, fs->lfs_bsize, NOCRED, &bp)) 31052222Sbostic panic("lfs_truncate: bread bno %d", 31152222Sbostic ap->in_lbn); 31252222Sbostic daddrp = bp->b_un.b_daddr + ap->in_off; 31352222Sbostic for (i = ap->in_off; 31452222Sbostic i++ <= a_end[depth].in_off;) { 31552222Sbostic daddr = *daddrp++; 31652222Sbostic SEGDEC; 31752222Sbostic } 31852222Sbostic a_end[depth].in_off=NINDIR(fs)-1; 31952222Sbostic if (ap->in_off > 0 && lbn == lastblock) { 32052222Sbostic bzero(bp->b_un.b_daddr + ap->in_off, 32152222Sbostic fs->lfs_bsize - 32252222Sbostic ap->in_off * sizeof(daddr_t)); 32352222Sbostic LFS_UBWRITE(bp); 32452222Sbostic } else 32552222Sbostic brelse (bp); 32652222Sbostic } 32752222Sbostic if (a[1].in_off == 0) { 32852222Sbostic off = a[0].in_off; 32952222Sbostic daddr = ip->i_ib[off]; 33052222Sbostic SEGDEC; 33152222Sbostic ip->i_ib[off] = 0; 33252222Sbostic } 333*52681Sstaelin if (lbn == lastblock || lbn <= NDADDR) 33452222Sbostic --lbn; 33552222Sbostic else { 33652222Sbostic lbn -= NINDIR(fs); 33752222Sbostic if (lbn < lastblock) 33852222Sbostic lbn = lastblock; 33952222Sbostic } 34052222Sbostic } 34152222Sbostic } 34252225Sbostic UPDATE_SEGUSE; 34352222Sbostic ip->i_blocks -= blocksreleased; 34452222Sbostic /* 34552078Sbostic * XXX 34652222Sbostic * Currently, we don't know when we allocate an indirect block, so 34752222Sbostic * ip->i_blocks isn't getting incremented appropriately. As a result, 34852222Sbostic * when we delete any indirect blocks, we get a bad number here. 34952078Sbostic */ 35052222Sbostic if (ip->i_blocks < 0) 35152222Sbostic ip->i_blocks = 0; 35252222Sbostic ip->i_flag |= ICHG|IUPD; 35352222Sbostic (void)vinvalbuf(vp, length > 0); 35452222Sbostic error = lfs_update(vp, &time, &time, MNT_WAIT); 35551857Sbostic return (0); 35624Sbill } 357