123399Smckusick /* 237736Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337736Smckusick * All rights reserved. 423399Smckusick * 537736Smckusick * Redistribution and use in source and binary forms are permitted 637736Smckusick * provided that the above copyright notice and this paragraph are 737736Smckusick * duplicated in all such forms and that any documentation, 837736Smckusick * advertising materials, and other materials related to such 937736Smckusick * distribution and use acknowledge that the software was developed 1037736Smckusick * by the University of California, Berkeley. The name of the 1137736Smckusick * University may not be used to endorse or promote products derived 1237736Smckusick * from this software without specific prior written permission. 1337736Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437736Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537736Smckusick * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637736Smckusick * 17*39440Smckusick * @(#)lfs_inode.c 7.16 (Berkeley) 10/29/89 1823399Smckusick */ 1924Sbill 2017099Sbloom #include "param.h" 2117099Sbloom #include "systm.h" 2217099Sbloom #include "mount.h" 2317099Sbloom #include "user.h" 2437736Smckusick #include "file.h" 2517099Sbloom #include "buf.h" 2624525Sbloom #include "cmap.h" 2737736Smckusick #include "vnode.h" 2837736Smckusick #include "../ufs/inode.h" 2937736Smckusick #include "../ufs/fs.h" 3037736Smckusick #include "../ufs/ufsmount.h" 317651Ssam #ifdef QUOTA 3237736Smckusick #include "../ufs/quota.h" 337504Sroot #endif 3417099Sbloom #include "kernel.h" 3531661Smckusick #include "malloc.h" 3624Sbill 3716840Smckusick #define INOHSZ 512 387334Skre #if ((INOHSZ&(INOHSZ-1)) == 0) 397334Skre #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 407334Skre #else 4110852Ssam #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ) 427334Skre #endif 4324Sbill 4439392Smckusick union ihead { 457334Skre union ihead *ih_head[2]; 467334Skre struct inode *ih_chain[2]; 477334Skre } ihead[INOHSZ]; 487334Skre 4924Sbill /* 5039392Smckusick * Initialize hash links for inodes. 5124Sbill */ 52*39440Smckusick ufs_init() 5324Sbill { 5424Sbill register int i; 5539392Smckusick register union ihead *ih = ihead; 5624Sbill 5739392Smckusick if (VN_MAXPRIVATE < sizeof(struct inode)) 5839392Smckusick panic("ihinit: too small"); 597334Skre for (i = INOHSZ; --i >= 0; ih++) { 607334Skre ih->ih_head[0] = ih; 617334Skre ih->ih_head[1] = ih; 627334Skre } 6324Sbill } 6424Sbill 6524Sbill /* 6637736Smckusick * Look up an vnode/inode by device,inumber. 6724Sbill * If it is in core (in the inode structure), 6824Sbill * honor the locking protocol. 6924Sbill * If it is not in core, read it in from the 7024Sbill * specified device. 7137736Smckusick * Callers must check for mount points!! 7224Sbill * In all cases, a pointer to a locked 7324Sbill * inode structure is returned. 7424Sbill */ 7537736Smckusick iget(xp, ino, ipp) 7637736Smckusick struct inode *xp; 774818Swnj ino_t ino; 7837736Smckusick struct inode **ipp; 7924Sbill { 8037736Smckusick dev_t dev = xp->i_dev; 8137736Smckusick struct mount *mntp = ITOV(xp)->v_mount; 8237736Smckusick register struct fs *fs = VFSTOUFS(mntp)->um_fs; 83*39440Smckusick extern struct vnodeops ufs_vnodeops, spec_inodeops; 8437736Smckusick register struct inode *ip, *iq; 8537736Smckusick register struct vnode *vp; 86*39440Smckusick struct vnode *nvp; 8737736Smckusick struct buf *bp; 88*39440Smckusick struct dinode *dp; 8937736Smckusick union ihead *ih; 9037736Smckusick int error; 9124Sbill 92*39440Smckusick ih = &ihead[INOHASH(dev, ino)]; 9324Sbill loop: 9439392Smckusick for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) { 9539392Smckusick if (ino != ip->i_number || dev != ip->i_dev) 9639392Smckusick continue; 9739392Smckusick if ((ip->i_flag&ILOCKED) != 0) { 9839392Smckusick ip->i_flag |= IWANT; 9939392Smckusick sleep((caddr_t)ip, PINOD); 10039392Smckusick goto loop; 10139392Smckusick } 102*39440Smckusick if (vget(ITOV(ip))) 103*39440Smckusick goto loop; 10439392Smckusick *ipp = ip; 10539392Smckusick return(0); 10639392Smckusick } 107*39440Smckusick /* 108*39440Smckusick * Allocate a new inode. 109*39440Smckusick */ 110*39440Smckusick if (error = getnewvnode(VT_UFS, mntp, &ufs_vnodeops, &nvp)) { 11137736Smckusick *ipp = 0; 11237736Smckusick return (error); 11337736Smckusick } 114*39440Smckusick ip = VTOI(nvp); 115*39440Smckusick ip->i_vnode = nvp; 116*39440Smckusick ip->i_flag = 0; 117*39440Smckusick ip->i_devvp = 0; 118*39440Smckusick ip->i_lastr = 0; 119*39440Smckusick ip->i_mode = 0; 120*39440Smckusick ip->i_flags = 0; 121*39440Smckusick #ifdef QUOTA 122*39440Smckusick ip->i_dquot = NODQUOT; 123*39440Smckusick #endif 12437736Smckusick /* 125*39440Smckusick * Put it onto its hash chain and lock it so that other requests for 126*39440Smckusick * this inode will block if they arrive while we are sleeping waiting 127*39440Smckusick * for old data structures to be purged or for the contents of the 128*39440Smckusick * disk portion of this inode to be read. 129*39440Smckusick */ 130*39440Smckusick ip->i_dev = dev; 131*39440Smckusick ip->i_number = ino; 132*39440Smckusick insque(ip, ih); 133*39440Smckusick ILOCK(ip); 134*39440Smckusick /* 13537736Smckusick * Read in the disk contents for the inode. 13637736Smckusick */ 13737736Smckusick if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)), 13838776Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 13937736Smckusick /* 14039392Smckusick * Unlock and discard unneeded inode. 14137736Smckusick */ 142*39440Smckusick iput(ip); 14337736Smckusick brelse(bp); 14437736Smckusick *ipp = 0; 145*39440Smckusick return (error); 14637736Smckusick } 147*39440Smckusick dp = bp->b_un.b_dino; 148*39440Smckusick dp += itoo(fs, ino); 149*39440Smckusick ip->i_din = *dp; 150*39440Smckusick brelse(bp); 15137736Smckusick /* 152*39440Smckusick * Initialize the associated vnode 15337736Smckusick */ 154*39440Smckusick vp = ITOV(ip); 155*39440Smckusick vp->v_type = IFTOVT(ip->i_mode); 156*39440Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 157*39440Smckusick vp->v_rdev = ip->i_rdev; 158*39440Smckusick vp->v_op = &spec_inodeops; 159*39440Smckusick if (nvp = checkalias(vp, mntp)) { 16037736Smckusick /* 161*39440Smckusick * Reinitialize aliased inode. 16237736Smckusick */ 163*39440Smckusick vp = nvp; 164*39440Smckusick iq = VTOI(vp); 165*39440Smckusick iq->i_vnode = vp; 166*39440Smckusick iq->i_lastr = 0; 167*39440Smckusick iq->i_flags = 0; 168*39440Smckusick ILOCK(iq); 169*39440Smckusick iq->i_din = ip->i_din; 170*39440Smckusick iq->i_dev = dev; 171*39440Smckusick iq->i_number = ino; 172*39440Smckusick insque(iq, ih); 17337736Smckusick /* 174*39440Smckusick * Discard unneeded vnode 17537736Smckusick */ 176*39440Smckusick ip->i_mode = 0; 177*39440Smckusick iput(ip); 17837736Smckusick ip = iq; 17937736Smckusick } 18037736Smckusick } 181*39440Smckusick if (ino == ROOTINO) 182*39440Smckusick vp->v_flag |= VROOT; 18337736Smckusick /* 18437736Smckusick * Finish inode initialization. 18537736Smckusick */ 18637736Smckusick ip->i_fs = fs; 18737736Smckusick ip->i_devvp = VFSTOUFS(mntp)->um_devvp; 18838345Smckusick VREF(ip->i_devvp); 18937736Smckusick #ifdef QUOTA 19037736Smckusick if (ip->i_mode != 0) 19137736Smckusick ip->i_dquot = inoquota(ip); 19237736Smckusick #endif 19338256Smckusick /* 19438256Smckusick * Set up a generation number for this inode if it does not 19538256Smckusick * already have one. This should only happen on old filesystems. 19638256Smckusick */ 19738256Smckusick if (ip->i_gen == 0) { 19838256Smckusick if (++nextgennumber < (u_long)time.tv_sec) 19938256Smckusick nextgennumber = time.tv_sec; 20038256Smckusick ip->i_gen = nextgennumber; 20138256Smckusick if ((vp->v_mount->m_flag & M_RDONLY) == 0) 20238256Smckusick ip->i_flag |= IMOD; 20338256Smckusick } 20437736Smckusick *ipp = ip; 20537736Smckusick return (0); 20637736Smckusick } 2077334Skre 20837736Smckusick /* 20939392Smckusick * Unlock and decrement the reference count of an inode structure. 21024Sbill */ 21124Sbill iput(ip) 2124818Swnj register struct inode *ip; 21324Sbill { 2147118Smckusick 2158452Sroot if ((ip->i_flag & ILOCKED) == 0) 2167118Smckusick panic("iput"); 21716665Smckusick IUNLOCK(ip); 21837736Smckusick vrele(ITOV(ip)); 2197118Smckusick } 2207118Smckusick 22139392Smckusick /* 22239392Smckusick * Last reference to an inode, write the inode out and if necessary, 22339392Smckusick * truncate and deallocate the file. 22439392Smckusick */ 22537736Smckusick ufs_inactive(vp) 22637736Smckusick struct vnode *vp; 2277118Smckusick { 22837736Smckusick register struct inode *ip = VTOI(vp); 22939392Smckusick int mode, error = 0; 23024Sbill 23139364Smckusick if (vp->v_count != 0) 232*39440Smckusick printf("ufs_inactive: pushing active ino %d dev 0x%x\n", 233*39440Smckusick ip->i_number, ip->i_dev); 23438452Smckusick /* 23538452Smckusick * Get rid of inodes related to stale file handles. 23638452Smckusick */ 237*39440Smckusick if (ip->i_mode == 0) { 238*39440Smckusick vgone(vp); 239*39440Smckusick return (0); 240*39440Smckusick } 24138226Smckusick ILOCK(ip); 24239364Smckusick if (ip->i_nlink <= 0 && (vp->v_mount->m_flag & M_RDONLY) == 0) { 24337736Smckusick error = itrunc(ip, (u_long)0); 24437736Smckusick mode = ip->i_mode; 24537736Smckusick ip->i_mode = 0; 24637736Smckusick ip->i_rdev = 0; 24737736Smckusick ip->i_flag |= IUPD|ICHG; 24837736Smckusick ifree(ip, ip->i_number, mode); 2497651Ssam #ifdef QUOTA 25037736Smckusick (void) chkiq(ip->i_dev, ip, ip->i_uid, 0); 25137736Smckusick dqrele(ip->i_dquot); 25237736Smckusick ip->i_dquot = NODQUOT; 2537492Skre #endif 25437736Smckusick } 25537736Smckusick IUPDAT(ip, &time, &time, 0); 25637736Smckusick IUNLOCK(ip); 25737736Smckusick ip->i_flag = 0; 25837736Smckusick /* 25939392Smckusick * If we are done with the inode, reclaim it 26039392Smckusick * so that it can be reused immediately. 26137736Smckusick */ 262*39440Smckusick if (vp->v_count == 0 && ip->i_mode == 0) 263*39440Smckusick vgone(vp); 26437736Smckusick return (error); 26524Sbill } 26624Sbill 26724Sbill /* 26839392Smckusick * Reclaim an inode so that it can be used for other purposes. 26924Sbill */ 27039392Smckusick ufs_reclaim(vp) 27139392Smckusick register struct vnode *vp; 27239392Smckusick { 27339392Smckusick register struct inode *iq, *ip = VTOI(vp); 27439392Smckusick 27539392Smckusick if (vp->v_count != 0) 276*39440Smckusick printf("ufs_reclaim: pushing active ino %d dev 0x%x\n", 277*39440Smckusick ip->i_number, ip->i_dev); 27839392Smckusick /* 27939392Smckusick * Remove the inode from its hash chain. 28039392Smckusick */ 28139392Smckusick remque(ip); 28239392Smckusick ip->i_forw = ip; 28339392Smckusick ip->i_back = ip; 28439392Smckusick /* 28539392Smckusick * Purge old data structures associated with the inode. 28639392Smckusick */ 28739392Smckusick cache_purge(vp); 28839392Smckusick if (ip->i_devvp) { 28939392Smckusick vrele(ip->i_devvp); 29039392Smckusick ip->i_devvp = 0; 29139392Smckusick } 29239392Smckusick #ifdef QUOTA 29339392Smckusick dqrele(ip->i_dquot); 29439392Smckusick ip->i_dquot = NODQUOT; 29539392Smckusick #endif 29639392Smckusick ip->i_flag = 0; 29739392Smckusick return (0); 29839392Smckusick } 29939392Smckusick 30039392Smckusick /* 30139392Smckusick * Check accessed and update flags on an inode structure. 30239392Smckusick * If any is on, update the inode with the current time. 30339392Smckusick * If waitfor is given, then must ensure I/O order, 30439392Smckusick * so wait for write to complete. 30539392Smckusick */ 3061203Sbill iupdat(ip, ta, tm, waitfor) 3074818Swnj register struct inode *ip; 3088630Sroot struct timeval *ta, *tm; 3094818Swnj int waitfor; 31024Sbill { 31137736Smckusick struct buf *bp; 31237736Smckusick struct vnode *vp = ITOV(ip); 31324Sbill struct dinode *dp; 31430749Skarels register struct fs *fs; 31537736Smckusick int error; 31624Sbill 31730749Skarels fs = ip->i_fs; 31837736Smckusick if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) 31937736Smckusick return (0); 32037736Smckusick if (vp->v_mount->m_flag & M_RDONLY) 32137736Smckusick return (0); 32237736Smckusick error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)), 32338776Smckusick (int)fs->fs_bsize, NOCRED, &bp); 32437736Smckusick if (error) { 32537736Smckusick brelse(bp); 32637736Smckusick return (error); 32724Sbill } 32837736Smckusick if (ip->i_flag&IACC) 32937736Smckusick ip->i_atime = ta->tv_sec; 33037736Smckusick if (ip->i_flag&IUPD) 33137736Smckusick ip->i_mtime = tm->tv_sec; 33237736Smckusick if (ip->i_flag&ICHG) 33337736Smckusick ip->i_ctime = time.tv_sec; 33437736Smckusick ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 33537736Smckusick dp = bp->b_un.b_dino + itoo(fs, ip->i_number); 33639392Smckusick *dp = ip->i_din; 33737736Smckusick if (waitfor) { 33837736Smckusick return (bwrite(bp)); 33937736Smckusick } else { 34037736Smckusick bdwrite(bp); 34137736Smckusick return (0); 34237736Smckusick } 34324Sbill } 34424Sbill 34510736Ssam #define SINGLE 0 /* index of single indirect block */ 34610736Ssam #define DOUBLE 1 /* index of double indirect block */ 34710736Ssam #define TRIPLE 2 /* index of triple indirect block */ 34824Sbill /* 34939392Smckusick * Truncate the inode ip to at most length size. Free affected disk 35039392Smckusick * blocks -- the blocks of the file are removed in reverse order. 35110736Ssam * 35210736Ssam * NB: triple indirect blocks are untested. 35324Sbill */ 35410736Ssam itrunc(oip, length) 35517942Smckusick register struct inode *oip; 3569165Ssam u_long length; 35724Sbill { 3589165Ssam register daddr_t lastblock; 35926272Skarels daddr_t bn, lbn, lastiblock[NIADDR]; 3606569Smckusic register struct fs *fs; 36110736Ssam register struct inode *ip; 36217942Smckusick struct buf *bp; 36337736Smckusick int offset, osize, size, level; 36437736Smckusick long count, nblocks, blocksreleased = 0; 36517942Smckusick register int i; 36637736Smckusick int error, allerror = 0; 36710736Ssam struct inode tip; 3689165Ssam 36913000Ssam if (oip->i_size <= length) { 37013000Ssam oip->i_flag |= ICHG|IUPD; 37137736Smckusick error = iupdat(oip, &time, &time, 1); 37237736Smckusick return (error); 37313000Ssam } 3741203Sbill /* 37510736Ssam * Calculate index into inode's block list of 37610736Ssam * last direct and indirect blocks (if any) 37710736Ssam * which we want to keep. Lastblock is -1 when 37810736Ssam * the file is truncated to 0. 3791203Sbill */ 38010736Ssam fs = oip->i_fs; 3819165Ssam lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 38210736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 38310736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 38410736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 38512645Ssam nblocks = btodb(fs->fs_bsize); 3866569Smckusic /* 38717942Smckusick * Update the size of the file. If the file is not being 38817942Smckusick * truncated to a block boundry, the contents of the 38917942Smckusick * partial block following the end of the file must be 39017942Smckusick * zero'ed in case it ever become accessable again because 39117942Smckusick * of subsequent file growth. 39217942Smckusick */ 39317942Smckusick osize = oip->i_size; 39417942Smckusick offset = blkoff(fs, length); 39517942Smckusick if (offset == 0) { 39617942Smckusick oip->i_size = length; 39717942Smckusick } else { 39817942Smckusick lbn = lblkno(fs, length); 39937736Smckusick error = balloc(oip, lbn, offset, &bn, B_CLRBUF); 40037736Smckusick if (error) 40137736Smckusick return (error); 40237736Smckusick if ((long)bn < 0) 40337736Smckusick panic("itrunc: hole"); 40417942Smckusick oip->i_size = length; 40517942Smckusick size = blksize(fs, oip, lbn); 40630749Skarels count = howmany(size, CLBYTES); 40730749Skarels for (i = 0; i < count; i++) 40837736Smckusick munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE); 40938776Smckusick error = bread(oip->i_devvp, bn, size, NOCRED, &bp); 41037736Smckusick if (error) { 41117942Smckusick oip->i_size = osize; 41217942Smckusick brelse(bp); 41337736Smckusick return (error); 41417942Smckusick } 41526272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 41617942Smckusick bdwrite(bp); 41717942Smckusick } 41817942Smckusick /* 41917942Smckusick * Update file and block pointers 42010736Ssam * on disk before we start freeing blocks. 42110736Ssam * If we crash before free'ing blocks below, 42210736Ssam * the blocks will be returned to the free list. 42310736Ssam * lastiblock values are also normalized to -1 42410736Ssam * for calls to indirtrunc below. 4256569Smckusic */ 42610736Ssam tip = *oip; 42717942Smckusick tip.i_size = osize; 42810736Ssam for (level = TRIPLE; level >= SINGLE; level--) 42910736Ssam if (lastiblock[level] < 0) { 43010736Ssam oip->i_ib[level] = 0; 43110736Ssam lastiblock[level] = -1; 4329165Ssam } 43310736Ssam for (i = NDADDR - 1; i > lastblock; i--) 43410736Ssam oip->i_db[i] = 0; 43510736Ssam oip->i_flag |= ICHG|IUPD; 43637736Smckusick allerror = syncip(oip); 43710736Ssam 4386569Smckusic /* 43910736Ssam * Indirect blocks first. 4406569Smckusic */ 44117942Smckusick ip = &tip; 44210736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 44310736Ssam bn = ip->i_ib[level]; 4449165Ssam if (bn != 0) { 44537736Smckusick error = indirtrunc(ip, bn, lastiblock[level], level, 44637736Smckusick &count); 44737736Smckusick if (error) 44837736Smckusick allerror = error; 44937736Smckusick blocksreleased += count; 45010736Ssam if (lastiblock[level] < 0) { 45110736Ssam ip->i_ib[level] = 0; 45231402Smckusick blkfree(ip, bn, (off_t)fs->fs_bsize); 45310736Ssam blocksreleased += nblocks; 45410736Ssam } 45510736Ssam } 45610736Ssam if (lastiblock[level] >= 0) 45710736Ssam goto done; 4589165Ssam } 45910736Ssam 4606569Smckusic /* 46110736Ssam * All whole direct blocks or frags. 4626569Smckusic */ 4639165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 46426359Skarels register off_t bsize; 4659165Ssam 4666569Smckusic bn = ip->i_db[i]; 4679165Ssam if (bn == 0) 46824Sbill continue; 4699165Ssam ip->i_db[i] = 0; 47024525Sbloom bsize = (off_t)blksize(fs, ip, i); 47131402Smckusick blkfree(ip, bn, bsize); 47224525Sbloom blocksreleased += btodb(bsize); 47324Sbill } 47410736Ssam if (lastblock < 0) 47510736Ssam goto done; 47610736Ssam 4771203Sbill /* 4789165Ssam * Finally, look for a change in size of the 4799165Ssam * last direct block; release any frags. 4801203Sbill */ 48110736Ssam bn = ip->i_db[lastblock]; 48210736Ssam if (bn != 0) { 48326359Skarels off_t oldspace, newspace; 48410736Ssam 4859165Ssam /* 4869165Ssam * Calculate amount of space we're giving 4879165Ssam * back as old block size minus new block size. 4889165Ssam */ 48910736Ssam oldspace = blksize(fs, ip, lastblock); 4909165Ssam ip->i_size = length; 49110736Ssam newspace = blksize(fs, ip, lastblock); 49210736Ssam if (newspace == 0) 49310736Ssam panic("itrunc: newspace"); 49410736Ssam if (oldspace - newspace > 0) { 4959165Ssam /* 4969165Ssam * Block number of space to be free'd is 4979165Ssam * the old block # plus the number of frags 4989165Ssam * required for the storage we're keeping. 4999165Ssam */ 50010736Ssam bn += numfrags(fs, newspace); 50131402Smckusick blkfree(ip, bn, oldspace - newspace); 50212645Ssam blocksreleased += btodb(oldspace - newspace); 5039165Ssam } 5049165Ssam } 5059165Ssam done: 50610736Ssam /* BEGIN PARANOIA */ 50710736Ssam for (level = SINGLE; level <= TRIPLE; level++) 50810736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 50910736Ssam panic("itrunc1"); 51010736Ssam for (i = 0; i < NDADDR; i++) 51110736Ssam if (ip->i_db[i] != oip->i_db[i]) 51210736Ssam panic("itrunc2"); 51310736Ssam /* END PARANOIA */ 51412645Ssam oip->i_blocks -= blocksreleased; 51512645Ssam if (oip->i_blocks < 0) /* sanity */ 51612645Ssam oip->i_blocks = 0; 51712645Ssam oip->i_flag |= ICHG; 5189165Ssam #ifdef QUOTA 51912645Ssam (void) chkdq(oip, -blocksreleased, 0); 5209165Ssam #endif 52137736Smckusick return (allerror); 52224Sbill } 52324Sbill 5249165Ssam /* 5259165Ssam * Release blocks associated with the inode ip and 5269165Ssam * stored in the indirect block bn. Blocks are free'd 5279165Ssam * in LIFO order up to (but not including) lastbn. If 52810736Ssam * level is greater than SINGLE, the block is an indirect 52910736Ssam * block and recursive calls to indirtrunc must be used to 53010736Ssam * cleanse other indirect blocks. 53110736Ssam * 53210736Ssam * NB: triple indirect blocks are untested. 5339165Ssam */ 53437736Smckusick indirtrunc(ip, bn, lastbn, level, countp) 5356569Smckusic register struct inode *ip; 5369165Ssam daddr_t bn, lastbn; 53710736Ssam int level; 53837736Smckusick long *countp; 53924Sbill { 5409165Ssam register int i; 54131661Smckusick struct buf *bp; 54231661Smckusick register struct fs *fs = ip->i_fs; 54324Sbill register daddr_t *bap; 54431661Smckusick daddr_t *copy, nb, last; 54537736Smckusick long blkcount, factor; 54637736Smckusick int nblocks, blocksreleased = 0; 54737736Smckusick int error, allerror = 0; 54824Sbill 54910736Ssam /* 55010736Ssam * Calculate index in current block of last 55110736Ssam * block to be kept. -1 indicates the entire 55210736Ssam * block so we need not calculate the index. 55310736Ssam */ 55410736Ssam factor = 1; 55510736Ssam for (i = SINGLE; i < level; i++) 55610736Ssam factor *= NINDIR(fs); 5579165Ssam last = lastbn; 55810736Ssam if (lastbn > 0) 55910736Ssam last /= factor; 56012645Ssam nblocks = btodb(fs->fs_bsize); 56110736Ssam /* 56210736Ssam * Get buffer of block pointers, zero those 56310736Ssam * entries corresponding to blocks to be free'd, 56410736Ssam * and update on disk copy first. 56510736Ssam */ 56638776Smckusick error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, 56738776Smckusick NOCRED, &bp); 56837736Smckusick if (error) { 56910736Ssam brelse(bp); 57037736Smckusick *countp = 0; 57137736Smckusick return (error); 57210736Ssam } 57310736Ssam bap = bp->b_un.b_daddr; 57431661Smckusick MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); 57531661Smckusick bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); 57610736Ssam bzero((caddr_t)&bap[last + 1], 57710736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 57837736Smckusick error = bwrite(bp); 57937736Smckusick if (error) 58037736Smckusick allerror = error; 58131661Smckusick bap = copy; 58210736Ssam 58310736Ssam /* 58410736Ssam * Recursively free totally unused blocks. 58510736Ssam */ 5869165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 58724Sbill nb = bap[i]; 5889165Ssam if (nb == 0) 58924Sbill continue; 59037736Smckusick if (level > SINGLE) { 59137736Smckusick error = indirtrunc(ip, nb, (daddr_t)-1, level - 1, 59237736Smckusick &blkcount); 59337736Smckusick if (error) 59437736Smckusick allerror = error; 59537736Smckusick blocksreleased += blkcount; 59637736Smckusick } 59731402Smckusick blkfree(ip, nb, (off_t)fs->fs_bsize); 5989165Ssam blocksreleased += nblocks; 59924Sbill } 60010736Ssam 60110736Ssam /* 60210736Ssam * Recursively free last partial block. 60310736Ssam */ 60410736Ssam if (level > SINGLE && lastbn >= 0) { 60510736Ssam last = lastbn % factor; 6069165Ssam nb = bap[i]; 60737736Smckusick if (nb != 0) { 60837736Smckusick error = indirtrunc(ip, nb, last, level - 1, &blkcount); 60937736Smckusick if (error) 61037736Smckusick allerror = error; 61137736Smckusick blocksreleased += blkcount; 61237736Smckusick } 6139165Ssam } 61431661Smckusick FREE(copy, M_TEMP); 61537736Smckusick *countp = blocksreleased; 61637736Smckusick return (allerror); 61724Sbill } 61824Sbill 61924Sbill /* 62030749Skarels * Remove any inodes in the inode cache belonging to dev. 6217334Skre * 6227334Skre * There should not be any active ones, return error if any are found 62330749Skarels * (nb: this is a user error, not a system err). 6247334Skre */ 62539363Smckusick int busyprt = 0; /* patch to print out busy inodes */ 62639363Smckusick 6277651Ssam #ifdef QUOTA 62839392Smckusick iflush(mp, iq) 62939392Smckusick struct mount *mp; 6307504Sroot struct inode *iq; 6317492Skre #else 63239392Smckusick iflush(mp) 63339392Smckusick struct mount *mp; 6347492Skre #endif 6357334Skre { 636*39440Smckusick register struct vnode *vp, *nvp; 6377335Skre register struct inode *ip; 63839363Smckusick int busy = 0; 6397334Skre 640*39440Smckusick for (vp = mp->m_mounth; vp; vp = nvp) { 641*39440Smckusick nvp = vp->v_mountf; 64239392Smckusick ip = VTOI(vp); 6437651Ssam #ifdef QUOTA 64439392Smckusick if (ip == iq) 64539363Smckusick continue; 6467492Skre #endif 64739392Smckusick if (vp->v_count) { 64839363Smckusick busy++; 64939363Smckusick if (!busyprt) 65039363Smckusick continue; 65139363Smckusick printf("%s %d on dev 0x%x count %d type %d\n", 65239363Smckusick "iflush: busy inode ", ip->i_number, ip->i_dev, 65339392Smckusick vp->v_count, vp->v_type); 65439363Smckusick continue; 65539363Smckusick } 65639363Smckusick /* 657*39440Smckusick * With v_count == 0, all we need to do is clear out the 658*39440Smckusick * vnode data structures and we are done. 65939363Smckusick */ 660*39440Smckusick vgone(vp); 6617334Skre } 66239363Smckusick if (busy) 66339363Smckusick return (EBUSY); 66430749Skarels return (0); 6657334Skre } 6667334Skre 6673617Sroot /* 6684818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6693617Sroot */ 6704818Swnj ilock(ip) 6714818Swnj register struct inode *ip; 6723617Sroot { 6733617Sroot 67437736Smckusick while (ip->i_flag & ILOCKED) { 67537736Smckusick ip->i_flag |= IWANT; 67637736Smckusick (void) sleep((caddr_t)ip, PINOD); 67737736Smckusick } 67837736Smckusick ip->i_flag |= ILOCKED; 6793617Sroot } 6803617Sroot 6813617Sroot /* 6824818Swnj * Unlock an inode. If WANT bit is on, wakeup. 6833617Sroot */ 6847118Smckusick iunlock(ip) 6854818Swnj register struct inode *ip; 6863617Sroot { 6873617Sroot 68837736Smckusick if ((ip->i_flag & ILOCKED) == 0) 68937736Smckusick printf("unlocking unlocked inode %d on dev 0x%x\n", 69037736Smckusick ip->i_number, ip->i_dev); 69137736Smckusick ip->i_flag &= ~ILOCKED; 69237736Smckusick if (ip->i_flag&IWANT) { 69337736Smckusick ip->i_flag &= ~IWANT; 69437736Smckusick wakeup((caddr_t)ip); 69537736Smckusick } 6963617Sroot } 69737736Smckusick 69837736Smckusick /* 69937736Smckusick * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 70037736Smckusick * The mode is shifted to select the owner/group/other fields. The 70137736Smckusick * super user is granted all permissions. 70237736Smckusick * 70337736Smckusick * NB: Called from vnode op table. It seems this could all be done 70437736Smckusick * using vattr's but... 70537736Smckusick */ 70637736Smckusick iaccess(ip, mode, cred) 70737736Smckusick register struct inode *ip; 70837736Smckusick register int mode; 70937736Smckusick struct ucred *cred; 71037736Smckusick { 71137736Smckusick register gid_t *gp; 71237736Smckusick int i; 71337736Smckusick 71437736Smckusick /* 71539392Smckusick * If you're the super-user, you always get access. 71637736Smckusick */ 71737736Smckusick if (cred->cr_uid == 0) 71837736Smckusick return (0); 71937736Smckusick /* 72037736Smckusick * Access check is based on only one of owner, group, public. 72137736Smckusick * If not owner, then check group. If not a member of the 72237736Smckusick * group, then check public access. 72337736Smckusick */ 72437736Smckusick if (cred->cr_uid != ip->i_uid) { 72537736Smckusick mode >>= 3; 72637736Smckusick gp = cred->cr_groups; 72737736Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 72837736Smckusick if (ip->i_gid == *gp) 72937736Smckusick goto found; 73037736Smckusick mode >>= 3; 73137736Smckusick found: 73237736Smckusick ; 73337736Smckusick } 73437736Smckusick if ((ip->i_mode & mode) != 0) 73537736Smckusick return (0); 73637736Smckusick return (EACCES); 73737736Smckusick } 738