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*54128Smckusick * @(#)lfs_inode.c 7.68 (Berkeley) 06/20/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 2053477Smckusick #include <vm/vm.h> 2153477Smckusick 2251498Sbostic #include <ufs/ufs/quota.h> 2351498Sbostic #include <ufs/ufs/inode.h> 2451498Sbostic #include <ufs/ufs/ufsmount.h> 2551498Sbostic #include <ufs/ufs/ufs_extern.h> 2647571Skarels 2751498Sbostic #include <ufs/lfs/lfs.h> 2851498Sbostic #include <ufs/lfs/lfs_extern.h> 2924Sbill 3052834Sbostic static struct dinode *lfs_ifind __P((struct lfs *, ino_t, struct dinode *)); 3152834Sbostic 3251346Sbostic int 3351155Sbostic lfs_init() 3424Sbill { 3551857Sbostic #ifdef VERBOSE 3651857Sbostic printf("lfs_init\n"); 3751857Sbostic #endif 3851484Sbostic return (ufs_init()); 3924Sbill } 4024Sbill 4124Sbill /* 4251484Sbostic * Look up an LFS dinode number to find its incore vnode. If not already 4351484Sbostic * in core, read it in from the specified device. Return the inode locked. 4451484Sbostic * Detection and handling of mount points must be done by the calling routine. 4524Sbill */ 4651346Sbostic int 4753529Sheideman lfs_vget (ap) 4853529Sheideman struct vop_vget_args *ap; 4924Sbill { 5051498Sbostic register struct lfs *fs; 5151484Sbostic register struct inode *ip; 5251484Sbostic struct buf *bp; 5352224Sbostic struct ifile *ifp; 5451498Sbostic struct vnode *vp; 5551562Smckusick struct ufsmount *ump; 5652224Sbostic daddr_t daddr; 5751484Sbostic dev_t dev; 5851346Sbostic int error; 5924Sbill 6051857Sbostic #ifdef VERBOSE 6151857Sbostic printf("lfs_vget\n"); 6251857Sbostic #endif 6353592Sheideman ump = VFSTOUFS(ap->a_mp); 6451562Smckusick dev = ump->um_dev; 6553592Sheideman if ((*ap->a_vpp = ufs_ihashget(dev, ap->a_ino)) != NULL) 6651484Sbostic return (0); 6751484Sbostic 6852224Sbostic /* Translate the inode number to a disk address. */ 6952224Sbostic fs = ump->um_lfs; 7053592Sheideman if (ap->a_ino == LFS_IFILE_INUM) 7152224Sbostic daddr = fs->lfs_idaddr; 7252224Sbostic else { 7353592Sheideman LFS_IENTRY(ifp, fs, ap->a_ino, bp); 7452224Sbostic daddr = ifp->if_daddr; 7552224Sbostic brelse(bp); 7652224Sbostic if (daddr == LFS_UNUSED_DADDR) 7752224Sbostic return (ENOENT); 7852224Sbostic } 7952224Sbostic 8051155Sbostic /* Allocate new vnode/inode. */ 8153592Sheideman if (error = lfs_vcreate(ap->a_mp, ap->a_ino, &vp)) { 8253592Sheideman *ap->a_vpp = NULL; 8337736Smckusick return (error); 8437736Smckusick } 8552224Sbostic 8637736Smckusick /* 8739440Smckusick * Put it onto its hash chain and lock it so that other requests for 8839440Smckusick * this inode will block if they arrive while we are sleeping waiting 8939440Smckusick * for old data structures to be purged or for the contents of the 9039440Smckusick * disk portion of this inode to be read. 9139440Smckusick */ 9251562Smckusick ip = VTOI(vp); 9351484Sbostic ufs_ihashins(ip); 9451155Sbostic 9552224Sbostic /* 9652224Sbostic * XXX 9752224Sbostic * This may not need to be here, logically it should go down with 9852224Sbostic * the i_devvp initialization. 9952224Sbostic * Ask Kirk. 10052224Sbostic */ 10152224Sbostic ip->i_lfs = ump->um_lfs; 10252224Sbostic 10351484Sbostic /* Read in the disk contents for the inode, copy into the inode. */ 10452224Sbostic if (error = 10552224Sbostic bread(ump->um_devvp, daddr, (int)fs->lfs_bsize, NOCRED, &bp)) { 10637736Smckusick /* 10751857Sbostic * The inode does not contain anything useful, so it 10851857Sbostic * would be misleading to leave it on its hash chain. 10951857Sbostic * Iput() will return it to the free list. 11041334Smckusick */ 11141334Smckusick remque(ip); 11241334Smckusick ip->i_forw = ip; 11341334Smckusick ip->i_back = ip; 11451484Sbostic 11551484Sbostic /* Unlock and discard unneeded inode. */ 11651484Sbostic ufs_iput(ip); 11737736Smckusick brelse(bp); 11853592Sheideman *ap->a_vpp = NULL; 11939440Smckusick return (error); 12037736Smckusick } 12153592Sheideman ip->i_din = *lfs_ifind(fs, ap->a_ino, bp->b_un.b_dino); 12239440Smckusick brelse(bp); 12351155Sbostic 12451498Sbostic /* 12551498Sbostic * Initialize the vnode from the inode, check for aliases. In all 12651498Sbostic * cases re-init ip, the underlying vnode/inode may have changed. 12751498Sbostic */ 12853592Sheideman if (error = ufs_vinit(ap->a_mp, lfs_specop_p, LFS_FIFOOPS, &vp)) { 12951484Sbostic ufs_iput(ip); 13053592Sheideman *ap->a_vpp = NULL; 13151484Sbostic return (error); 13240289Smckusick } 13351562Smckusick /* 13451562Smckusick * Finish inode initialization now that aliasing has been resolved. 13551562Smckusick */ 13651562Smckusick ip->i_devvp = ump->um_devvp; 13751562Smckusick VREF(ip->i_devvp); 13853592Sheideman *ap->a_vpp = vp; 13937736Smckusick return (0); 14037736Smckusick } 1417334Skre 14252834Sbostic /* Search a block for a specific dinode. */ 14352834Sbostic static struct dinode * 14452834Sbostic lfs_ifind(fs, ino, dip) 14552834Sbostic struct lfs *fs; 14652834Sbostic ino_t ino; 14752834Sbostic register struct dinode *dip; 14852834Sbostic { 14952834Sbostic register int cnt; 15052834Sbostic 15152834Sbostic #ifdef VERBOSE 15252834Sbostic printf("lfs_ifind: inode %d\n", ino); 15352834Sbostic #endif 15452834Sbostic for (cnt = INOPB(fs); cnt--; ++dip) 15552834Sbostic if (dip->di_inum == ino) 15652834Sbostic return (dip); 15752834Sbostic 15852834Sbostic panic("lfs_ifind: dinode %u not found", ino); 15952834Sbostic /* NOTREACHED */ 16052834Sbostic } 16152834Sbostic 16251346Sbostic int 16353529Sheideman lfs_update (ap) 16453529Sheideman struct vop_update_args *ap; 1657118Smckusick { 16653867Sheideman struct vnode *vp = ap->a_vp; 16751562Smckusick struct inode *ip; 16851562Smckusick 16951857Sbostic #ifdef VERBOSE 17051857Sbostic printf("lfs_update\n"); 17151857Sbostic #endif 17253867Sheideman if (vp->v_mount->mnt_flag & MNT_RDONLY) 17351562Smckusick return (0); 17453867Sheideman ip = VTOI(vp); 17551562Smckusick if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) 17651562Smckusick return (0); 17751562Smckusick if (ip->i_flag&IACC) 17854103Smckusick ip->i_atime.ts_sec = ap->a_ta->tv_sec; 17952018Smckusick if (ip->i_flag&IUPD) { 18054103Smckusick ip->i_mtime.ts_sec = ap->a_tm->tv_sec; 181*54128Smckusick (ip)->i_modrev++; 18252018Smckusick } 18351562Smckusick if (ip->i_flag&ICHG) 18454103Smckusick ip->i_ctime.ts_sec = time.tv_sec; 18551562Smckusick ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 18651562Smckusick 18752327Sbostic /* Push back the vnode and any dirty blocks it may have. */ 18853867Sheideman return (ap->a_waitfor ? lfs_vflush(vp) : 0); 18924Sbill } 19024Sbill 19152222Sbostic /* Update segment usage information when removing a block. */ 19252225Sbostic #define UPDATE_SEGUSE \ 19352225Sbostic if (lastseg != -1) { \ 19452225Sbostic LFS_SEGENTRY(sup, fs, lastseg, sup_bp); \ 19552681Sstaelin sup->su_nbytes -= num << fs->lfs_bshift; \ 19652225Sbostic LFS_UBWRITE(sup_bp); \ 19752225Sbostic blocksreleased += num; \ 19852225Sbostic } 19952222Sbostic 20052222Sbostic #define SEGDEC { \ 20152222Sbostic if (daddr != UNASSIGNED) { \ 20252222Sbostic if (lastseg != (seg = datosn(fs, daddr))) { \ 20352222Sbostic UPDATE_SEGUSE; \ 20452222Sbostic num = 1; \ 20552222Sbostic lastseg = seg; \ 20652222Sbostic } else \ 20752222Sbostic ++num; \ 20852222Sbostic } \ 20952222Sbostic } 21052222Sbostic 21124Sbill /* 21252222Sbostic * Truncate the inode ip to at most length size. Update segment usage 21352222Sbostic * table information. 21424Sbill */ 21551484Sbostic /* ARGSUSED */ 21651484Sbostic int 21753529Sheideman lfs_truncate (ap) 21853529Sheideman struct vop_truncate_args *ap; 21924Sbill { 22053529Sheideman USES_VOP_UPDATE; 22153505Sheideman register INDIR *inp; 22252222Sbostic register int i; 22352222Sbostic register daddr_t *daddrp; 22452225Sbostic struct buf *bp, *sup_bp; 22552327Sbostic struct ifile *ifp; 22652222Sbostic struct inode *ip; 22752222Sbostic struct lfs *fs; 22852222Sbostic INDIR a[NIADDR + 2], a_end[NIADDR + 2]; 22952222Sbostic SEGUSE *sup; 23052222Sbostic daddr_t daddr, lastblock, lbn, olastblock; 23153233Smckusick long off, blocksreleased; 23252222Sbostic int error, depth, lastseg, num, offset, seg, size; 2339165Ssam 23451857Sbostic #ifdef VERBOSE 23551857Sbostic printf("lfs_truncate\n"); 23651857Sbostic #endif 23753592Sheideman vnode_pager_setsize(ap->a_vp, (u_long)ap->a_length); 23852327Sbostic 23953592Sheideman ip = VTOI(ap->a_vp); 24052327Sbostic fs = ip->i_lfs; 24152327Sbostic 24252327Sbostic /* If truncating the file to 0, update the version number. */ 24353592Sheideman if (ap->a_length == 0) { 24452327Sbostic LFS_IENTRY(ifp, fs, ip->i_number, bp); 24552327Sbostic ++ifp->if_version; 24652327Sbostic LFS_UBWRITE(bp); 24752327Sbostic } 24852327Sbostic 24953592Sheideman /* If ap->a_length is larger than the file, just update the times. */ 25053592Sheideman if (ip->i_size <= ap->a_length) { 25152222Sbostic ip->i_flag |= ICHG|IUPD; 25253592Sheideman return (VOP_UPDATE(ap->a_vp, &time, &time, 1)); 25313000Ssam } 25452327Sbostic 25552222Sbostic /* 25652222Sbostic * Calculate index into inode's block list of last direct and indirect 25752222Sbostic * blocks (if any) which we want to keep. Lastblock is 0 when the 25852222Sbostic * file is truncated to 0. 25952222Sbostic */ 26053592Sheideman lastblock = lblkno(fs, ap->a_length + fs->lfs_bsize - 1); 26152222Sbostic olastblock = lblkno(fs, ip->i_size + fs->lfs_bsize - 1) - 1; 26251484Sbostic 2631203Sbill /* 26451484Sbostic * Update the size of the file. If the file is not being truncated to 26551484Sbostic * a block boundry, the contents of the partial block following the end 26651484Sbostic * of the file must be zero'ed in case it ever become accessable again 26751484Sbostic * because of subsequent file growth. 2681203Sbill */ 26953592Sheideman offset = blkoff(fs, ap->a_length); 27051484Sbostic if (offset == 0) 27153592Sheideman ip->i_size = ap->a_length; 27251484Sbostic else { 27353592Sheideman lbn = lblkno(fs, ap->a_length); 27441313Smckusick #ifdef QUOTA 27552222Sbostic if (error = getinoquota(ip)) 27641313Smckusick return (error); 27751183Sbostic #endif 27853592Sheideman if (error = bread(ap->a_vp, lbn, fs->lfs_bsize, NOCRED, &bp)) 27937736Smckusick return (error); 28053592Sheideman ip->i_size = ap->a_length; 28151857Sbostic size = blksize(fs); 28253592Sheideman (void)vnode_pager_uncache(ap->a_vp); 28326272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 28445112Smckusick allocbuf(bp, size); 28552078Sbostic LFS_UBWRITE(bp); 28617942Smckusick } 28752078Sbostic /* 28852222Sbostic * Modify sup->su_nbyte counters for each deleted block; keep track 28952222Sbostic * of number of blocks removed for ip->i_blocks. 29052222Sbostic */ 29152222Sbostic blocksreleased = 0; 29252222Sbostic num = 0; 29352222Sbostic lastseg = -1; 29452222Sbostic 29552222Sbostic for (lbn = olastblock; lbn >= lastblock;) { 29653592Sheideman lfs_bmaparray(ap->a_vp, lbn, &daddr, a, &depth); 29752222Sbostic if (lbn == olastblock) 29852222Sbostic for (i = NIADDR + 2; i--;) 29952222Sbostic a_end[i] = a[i]; 30052222Sbostic switch (depth) { 30152222Sbostic case 0: /* Direct block. */ 30252222Sbostic daddr = ip->i_db[lbn]; 30352222Sbostic SEGDEC; 30452222Sbostic ip->i_db[lbn] = 0; 30552222Sbostic --lbn; 30652222Sbostic break; 30752222Sbostic #ifdef DIAGNOSTIC 30852222Sbostic case 1: /* An indirect block. */ 30952222Sbostic panic("lfs_truncate: lfs_bmaparray returned depth 1"); 31052222Sbostic /* NOTREACHED */ 31152222Sbostic #endif 31252222Sbostic default: /* Chain of indirect blocks. */ 31353505Sheideman inp = a + --depth; 31453505Sheideman if (inp->in_off > 0 && lbn != lastblock) { 31553505Sheideman lbn -= inp->in_off < lbn - lastblock ? 31653505Sheideman inp->in_off : lbn - lastblock; 31752222Sbostic break; 31852222Sbostic } 31953505Sheideman for (; depth && (inp->in_off == 0 || lbn == lastblock); 32053505Sheideman --inp, --depth) { 32152222Sbostic /* 32252222Sbostic * XXX 32352222Sbostic * The indirect block may not yet exist, so 32452222Sbostic * bread will create one just so we can free 32552222Sbostic * it. 32652222Sbostic */ 32753592Sheideman if (bread(ap->a_vp, 32853505Sheideman inp->in_lbn, fs->lfs_bsize, NOCRED, &bp)) 32952222Sbostic panic("lfs_truncate: bread bno %d", 33053505Sheideman inp->in_lbn); 33153505Sheideman daddrp = bp->b_un.b_daddr + inp->in_off; 33253505Sheideman for (i = inp->in_off; 33352222Sbostic i++ <= a_end[depth].in_off;) { 33452222Sbostic daddr = *daddrp++; 33552222Sbostic SEGDEC; 33652222Sbostic } 33753144Sstaelin a_end[depth].in_off = NINDIR(fs) - 1; 33853505Sheideman if (inp->in_off == 0) 33953144Sstaelin brelse (bp); 34053144Sstaelin else { 34153505Sheideman bzero(bp->b_un.b_daddr + inp->in_off, 34252222Sbostic fs->lfs_bsize - 34353505Sheideman inp->in_off * sizeof(daddr_t)); 34452222Sbostic LFS_UBWRITE(bp); 34553144Sstaelin } 34652222Sbostic } 34753144Sstaelin if (depth == 0 && a[1].in_off == 0) { 34852222Sbostic off = a[0].in_off; 34952222Sbostic daddr = ip->i_ib[off]; 35052222Sbostic SEGDEC; 35152222Sbostic ip->i_ib[off] = 0; 35252222Sbostic } 35352681Sstaelin if (lbn == lastblock || lbn <= NDADDR) 35452222Sbostic --lbn; 35552222Sbostic else { 35652222Sbostic lbn -= NINDIR(fs); 35752222Sbostic if (lbn < lastblock) 35852222Sbostic lbn = lastblock; 35952222Sbostic } 36052222Sbostic } 36152222Sbostic } 36252225Sbostic UPDATE_SEGUSE; 36352222Sbostic ip->i_blocks -= blocksreleased; 36452222Sbostic /* 36552078Sbostic * XXX 36652222Sbostic * Currently, we don't know when we allocate an indirect block, so 36752222Sbostic * ip->i_blocks isn't getting incremented appropriately. As a result, 36852222Sbostic * when we delete any indirect blocks, we get a bad number here. 36952078Sbostic */ 37052222Sbostic if (ip->i_blocks < 0) 37152222Sbostic ip->i_blocks = 0; 37252222Sbostic ip->i_flag |= ICHG|IUPD; 37353592Sheideman (void)vinvalbuf(ap->a_vp, ap->a_length > 0); 37453592Sheideman error = VOP_UPDATE(ap->a_vp, &time, &time, MNT_WAIT); 37551857Sbostic return (0); 37624Sbill } 377