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*53529Sheideman * @(#)lfs_inode.c 7.64 (Berkeley) 05/14/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 47*53529Sheideman lfs_vget (ap) 48*53529Sheideman struct vop_vget_args *ap; 49*53529Sheideman #define mntp (ap->a_mp) 50*53529Sheideman #define ino (ap->a_ino) 51*53529Sheideman #define vpp (ap->a_vpp) 5224Sbill { 5351498Sbostic register struct lfs *fs; 5451484Sbostic register struct inode *ip; 5551484Sbostic struct buf *bp; 5652224Sbostic struct ifile *ifp; 5751498Sbostic struct vnode *vp; 5851562Smckusick struct ufsmount *ump; 5952224Sbostic daddr_t daddr; 6051484Sbostic dev_t dev; 6151346Sbostic int error; 6224Sbill 6351857Sbostic #ifdef VERBOSE 6451857Sbostic printf("lfs_vget\n"); 6551857Sbostic #endif 6651562Smckusick ump = VFSTOUFS(mntp); 6751562Smckusick dev = ump->um_dev; 6851562Smckusick if ((*vpp = ufs_ihashget(dev, ino)) != NULL) 6951484Sbostic return (0); 7051484Sbostic 7152224Sbostic /* Translate the inode number to a disk address. */ 7252224Sbostic fs = ump->um_lfs; 7352224Sbostic if (ino == LFS_IFILE_INUM) 7452224Sbostic daddr = fs->lfs_idaddr; 7552224Sbostic else { 7652224Sbostic LFS_IENTRY(ifp, fs, ino, bp); 7752224Sbostic daddr = ifp->if_daddr; 7852224Sbostic brelse(bp); 7952224Sbostic if (daddr == LFS_UNUSED_DADDR) 8052224Sbostic return (ENOENT); 8152224Sbostic } 8252224Sbostic 8351155Sbostic /* Allocate new vnode/inode. */ 8451498Sbostic if (error = lfs_vcreate(mntp, ino, &vp)) { 8551562Smckusick *vpp = NULL; 8637736Smckusick return (error); 8737736Smckusick } 8852224Sbostic 8937736Smckusick /* 9039440Smckusick * Put it onto its hash chain and lock it so that other requests for 9139440Smckusick * this inode will block if they arrive while we are sleeping waiting 9239440Smckusick * for old data structures to be purged or for the contents of the 9339440Smckusick * disk portion of this inode to be read. 9439440Smckusick */ 9551562Smckusick ip = VTOI(vp); 9651484Sbostic ufs_ihashins(ip); 9751155Sbostic 9852224Sbostic /* 9952224Sbostic * XXX 10052224Sbostic * This may not need to be here, logically it should go down with 10152224Sbostic * the i_devvp initialization. 10252224Sbostic * Ask Kirk. 10352224Sbostic */ 10452224Sbostic ip->i_lfs = ump->um_lfs; 10552224Sbostic 10651484Sbostic /* Read in the disk contents for the inode, copy into the inode. */ 10752224Sbostic if (error = 10852224Sbostic bread(ump->um_devvp, daddr, (int)fs->lfs_bsize, NOCRED, &bp)) { 10937736Smckusick /* 11051857Sbostic * The inode does not contain anything useful, so it 11151857Sbostic * would be misleading to leave it on its hash chain. 11251857Sbostic * Iput() will return it to the free list. 11341334Smckusick */ 11441334Smckusick remque(ip); 11541334Smckusick ip->i_forw = ip; 11641334Smckusick ip->i_back = ip; 11751484Sbostic 11851484Sbostic /* Unlock and discard unneeded inode. */ 11951484Sbostic ufs_iput(ip); 12037736Smckusick brelse(bp); 12151562Smckusick *vpp = NULL; 12239440Smckusick return (error); 12337736Smckusick } 12451155Sbostic ip->i_din = *lfs_ifind(fs, ino, bp->b_un.b_dino); 12539440Smckusick brelse(bp); 12651155Sbostic 12751498Sbostic /* 12851498Sbostic * Initialize the vnode from the inode, check for aliases. In all 12951498Sbostic * cases re-init ip, the underlying vnode/inode may have changed. 13051498Sbostic */ 131*53529Sheideman if (error = ufs_vinit(mntp, lfs_specop_p, LFS_FIFOOPS, &vp)) { 13251484Sbostic ufs_iput(ip); 13351562Smckusick *vpp = NULL; 13451484Sbostic return (error); 13540289Smckusick } 13651562Smckusick /* 13751562Smckusick * Finish inode initialization now that aliasing has been resolved. 13851562Smckusick */ 13951562Smckusick ip->i_devvp = ump->um_devvp; 14051562Smckusick VREF(ip->i_devvp); 14151562Smckusick *vpp = vp; 14237736Smckusick return (0); 14337736Smckusick } 144*53529Sheideman #undef mntp 145*53529Sheideman #undef ino 146*53529Sheideman #undef vpp 1477334Skre 14852834Sbostic /* Search a block for a specific dinode. */ 14952834Sbostic static struct dinode * 15052834Sbostic lfs_ifind(fs, ino, dip) 15152834Sbostic struct lfs *fs; 15252834Sbostic ino_t ino; 15352834Sbostic register struct dinode *dip; 15452834Sbostic { 15552834Sbostic register int cnt; 15652834Sbostic 15752834Sbostic #ifdef VERBOSE 15852834Sbostic printf("lfs_ifind: inode %d\n", ino); 15952834Sbostic #endif 16052834Sbostic for (cnt = INOPB(fs); cnt--; ++dip) 16152834Sbostic if (dip->di_inum == ino) 16252834Sbostic return (dip); 16352834Sbostic 16452834Sbostic panic("lfs_ifind: dinode %u not found", ino); 16552834Sbostic /* NOTREACHED */ 16652834Sbostic } 16752834Sbostic 16851346Sbostic int 169*53529Sheideman lfs_update (ap) 170*53529Sheideman struct vop_update_args *ap; 171*53529Sheideman #define vp (ap->a_vp) 172*53529Sheideman #define ta (ap->a_ta) 173*53529Sheideman #define tm (ap->a_tm) 174*53529Sheideman #define waitfor (ap->a_waitfor) 1757118Smckusick { 17651562Smckusick struct inode *ip; 17751562Smckusick 17851857Sbostic #ifdef VERBOSE 17951857Sbostic printf("lfs_update\n"); 18051857Sbostic #endif 18151562Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) 18251562Smckusick return (0); 18351562Smckusick ip = VTOI(vp); 18451562Smckusick if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) 18551562Smckusick return (0); 18651562Smckusick if (ip->i_flag&IACC) 18753477Smckusick ip->i_atime.tv_sec = ta->tv_sec; 18852018Smckusick if (ip->i_flag&IUPD) { 18953477Smckusick ip->i_mtime.tv_sec = tm->tv_sec; 19052018Smckusick INCRQUAD((ip)->i_modrev); 19152018Smckusick } 19251562Smckusick if (ip->i_flag&ICHG) 19353477Smckusick ip->i_ctime.tv_sec = time.tv_sec; 19451562Smckusick ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 19551562Smckusick 19652327Sbostic /* Push back the vnode and any dirty blocks it may have. */ 19752327Sbostic return (waitfor ? lfs_vflush(vp) : 0); 19824Sbill } 199*53529Sheideman #undef vp 200*53529Sheideman #undef ta 201*53529Sheideman #undef tm 202*53529Sheideman #undef waitfor 20324Sbill 20452222Sbostic /* Update segment usage information when removing a block. */ 20552225Sbostic #define UPDATE_SEGUSE \ 20652225Sbostic if (lastseg != -1) { \ 20752225Sbostic LFS_SEGENTRY(sup, fs, lastseg, sup_bp); \ 20852681Sstaelin sup->su_nbytes -= num << fs->lfs_bshift; \ 20952225Sbostic LFS_UBWRITE(sup_bp); \ 21052225Sbostic blocksreleased += num; \ 21152225Sbostic } 21252222Sbostic 21352222Sbostic #define SEGDEC { \ 21452222Sbostic if (daddr != UNASSIGNED) { \ 21552222Sbostic if (lastseg != (seg = datosn(fs, daddr))) { \ 21652222Sbostic UPDATE_SEGUSE; \ 21752222Sbostic num = 1; \ 21852222Sbostic lastseg = seg; \ 21952222Sbostic } else \ 22052222Sbostic ++num; \ 22152222Sbostic } \ 22252222Sbostic } 22352222Sbostic 22424Sbill /* 22552222Sbostic * Truncate the inode ip to at most length size. Update segment usage 22652222Sbostic * table information. 22724Sbill */ 22851484Sbostic /* ARGSUSED */ 22951484Sbostic int 230*53529Sheideman lfs_truncate (ap) 231*53529Sheideman struct vop_truncate_args *ap; 232*53529Sheideman #define vp (ap->a_vp) 233*53529Sheideman #define length (ap->a_length) 234*53529Sheideman #define flags (ap->a_flags) 235*53529Sheideman #define cred (ap->a_cred) 23624Sbill { 237*53529Sheideman USES_VOP_UPDATE; 23853505Sheideman register INDIR *inp; 23952222Sbostic register int i; 24052222Sbostic register daddr_t *daddrp; 24152225Sbostic struct buf *bp, *sup_bp; 24252327Sbostic struct ifile *ifp; 24352222Sbostic struct inode *ip; 24452222Sbostic struct lfs *fs; 24552222Sbostic INDIR a[NIADDR + 2], a_end[NIADDR + 2]; 24652222Sbostic SEGUSE *sup; 24752222Sbostic daddr_t daddr, lastblock, lbn, olastblock; 24853233Smckusick long off, blocksreleased; 24952222Sbostic int error, depth, lastseg, num, offset, seg, size; 2509165Ssam 25151857Sbostic #ifdef VERBOSE 25251857Sbostic printf("lfs_truncate\n"); 25351857Sbostic #endif 25453477Smckusick vnode_pager_setsize(vp, (u_long)length); 25552327Sbostic 25652222Sbostic ip = VTOI(vp); 25752327Sbostic fs = ip->i_lfs; 25852327Sbostic 25952327Sbostic /* If truncating the file to 0, update the version number. */ 26052327Sbostic if (length == 0) { 26152327Sbostic LFS_IENTRY(ifp, fs, ip->i_number, bp); 26252327Sbostic ++ifp->if_version; 26352327Sbostic LFS_UBWRITE(bp); 26452327Sbostic } 26552327Sbostic 26651484Sbostic /* If length is larger than the file, just update the times. */ 26752222Sbostic if (ip->i_size <= length) { 26852222Sbostic ip->i_flag |= ICHG|IUPD; 269*53529Sheideman return (VOP_UPDATE(vp, &time, &time, 1)); 27013000Ssam } 27152327Sbostic 27252222Sbostic /* 27352222Sbostic * Calculate index into inode's block list of last direct and indirect 27452222Sbostic * blocks (if any) which we want to keep. Lastblock is 0 when the 27552222Sbostic * file is truncated to 0. 27652222Sbostic */ 27752222Sbostic lastblock = lblkno(fs, length + fs->lfs_bsize - 1); 27852222Sbostic olastblock = lblkno(fs, ip->i_size + fs->lfs_bsize - 1) - 1; 27951484Sbostic 2801203Sbill /* 28151484Sbostic * Update the size of the file. If the file is not being truncated to 28251484Sbostic * a block boundry, the contents of the partial block following the end 28351484Sbostic * of the file must be zero'ed in case it ever become accessable again 28451484Sbostic * because of subsequent file growth. 2851203Sbill */ 28617942Smckusick offset = blkoff(fs, length); 28751484Sbostic if (offset == 0) 28852222Sbostic ip->i_size = length; 28951484Sbostic else { 29017942Smckusick lbn = lblkno(fs, length); 29141313Smckusick #ifdef QUOTA 29252222Sbostic if (error = getinoquota(ip)) 29341313Smckusick return (error); 29451183Sbostic #endif 29552222Sbostic if (error = bread(vp, lbn, fs->lfs_bsize, NOCRED, &bp)) 29637736Smckusick return (error); 29752222Sbostic ip->i_size = length; 29851857Sbostic size = blksize(fs); 29952222Sbostic (void)vnode_pager_uncache(vp); 30026272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 30145112Smckusick allocbuf(bp, size); 30252078Sbostic LFS_UBWRITE(bp); 30317942Smckusick } 30452078Sbostic /* 30552222Sbostic * Modify sup->su_nbyte counters for each deleted block; keep track 30652222Sbostic * of number of blocks removed for ip->i_blocks. 30752222Sbostic */ 30852222Sbostic blocksreleased = 0; 30952222Sbostic num = 0; 31052222Sbostic lastseg = -1; 31152222Sbostic 31252222Sbostic for (lbn = olastblock; lbn >= lastblock;) { 31352222Sbostic lfs_bmaparray(vp, lbn, &daddr, a, &depth); 31452222Sbostic if (lbn == olastblock) 31552222Sbostic for (i = NIADDR + 2; i--;) 31652222Sbostic a_end[i] = a[i]; 31752222Sbostic switch (depth) { 31852222Sbostic case 0: /* Direct block. */ 31952222Sbostic daddr = ip->i_db[lbn]; 32052222Sbostic SEGDEC; 32152222Sbostic ip->i_db[lbn] = 0; 32252222Sbostic --lbn; 32352222Sbostic break; 32452222Sbostic #ifdef DIAGNOSTIC 32552222Sbostic case 1: /* An indirect block. */ 32652222Sbostic panic("lfs_truncate: lfs_bmaparray returned depth 1"); 32752222Sbostic /* NOTREACHED */ 32852222Sbostic #endif 32952222Sbostic default: /* Chain of indirect blocks. */ 33053505Sheideman inp = a + --depth; 33153505Sheideman if (inp->in_off > 0 && lbn != lastblock) { 33253505Sheideman lbn -= inp->in_off < lbn - lastblock ? 33353505Sheideman inp->in_off : lbn - lastblock; 33452222Sbostic break; 33552222Sbostic } 33653505Sheideman for (; depth && (inp->in_off == 0 || lbn == lastblock); 33753505Sheideman --inp, --depth) { 33852222Sbostic /* 33952222Sbostic * XXX 34052222Sbostic * The indirect block may not yet exist, so 34152222Sbostic * bread will create one just so we can free 34252222Sbostic * it. 34352222Sbostic */ 34452222Sbostic if (bread(vp, 34553505Sheideman inp->in_lbn, fs->lfs_bsize, NOCRED, &bp)) 34652222Sbostic panic("lfs_truncate: bread bno %d", 34753505Sheideman inp->in_lbn); 34853505Sheideman daddrp = bp->b_un.b_daddr + inp->in_off; 34953505Sheideman for (i = inp->in_off; 35052222Sbostic i++ <= a_end[depth].in_off;) { 35152222Sbostic daddr = *daddrp++; 35252222Sbostic SEGDEC; 35352222Sbostic } 35453144Sstaelin a_end[depth].in_off = NINDIR(fs) - 1; 35553505Sheideman if (inp->in_off == 0) 35653144Sstaelin brelse (bp); 35753144Sstaelin else { 35853505Sheideman bzero(bp->b_un.b_daddr + inp->in_off, 35952222Sbostic fs->lfs_bsize - 36053505Sheideman inp->in_off * sizeof(daddr_t)); 36152222Sbostic LFS_UBWRITE(bp); 36253144Sstaelin } 36352222Sbostic } 36453144Sstaelin if (depth == 0 && a[1].in_off == 0) { 36552222Sbostic off = a[0].in_off; 36652222Sbostic daddr = ip->i_ib[off]; 36752222Sbostic SEGDEC; 36852222Sbostic ip->i_ib[off] = 0; 36952222Sbostic } 37052681Sstaelin if (lbn == lastblock || lbn <= NDADDR) 37152222Sbostic --lbn; 37252222Sbostic else { 37352222Sbostic lbn -= NINDIR(fs); 37452222Sbostic if (lbn < lastblock) 37552222Sbostic lbn = lastblock; 37652222Sbostic } 37752222Sbostic } 37852222Sbostic } 37952225Sbostic UPDATE_SEGUSE; 38052222Sbostic ip->i_blocks -= blocksreleased; 38152222Sbostic /* 38252078Sbostic * XXX 38352222Sbostic * Currently, we don't know when we allocate an indirect block, so 38452222Sbostic * ip->i_blocks isn't getting incremented appropriately. As a result, 38552222Sbostic * when we delete any indirect blocks, we get a bad number here. 38652078Sbostic */ 38752222Sbostic if (ip->i_blocks < 0) 38852222Sbostic ip->i_blocks = 0; 38952222Sbostic ip->i_flag |= ICHG|IUPD; 39052222Sbostic (void)vinvalbuf(vp, length > 0); 391*53529Sheideman error = VOP_UPDATE(vp, &time, &time, MNT_WAIT); 39251857Sbostic return (0); 39324Sbill } 394*53529Sheideman #undef vp 395*53529Sheideman #undef length 396*53529Sheideman #undef flags 397*53529Sheideman #undef cred 398