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*39795Smckusick * @(#)lfs_inode.c 7.25 (Berkeley) 12/29/89 1823399Smckusick */ 1924Sbill 2017099Sbloom #include "param.h" 2117099Sbloom #include "systm.h" 2217099Sbloom #include "mount.h" 2317099Sbloom #include "user.h" 24*39795Smckusick #include "proc.h" 2537736Smckusick #include "file.h" 2617099Sbloom #include "buf.h" 2724525Sbloom #include "cmap.h" 2837736Smckusick #include "vnode.h" 2937736Smckusick #include "../ufs/inode.h" 3037736Smckusick #include "../ufs/fs.h" 3137736Smckusick #include "../ufs/ufsmount.h" 327651Ssam #ifdef QUOTA 3337736Smckusick #include "../ufs/quota.h" 347504Sroot #endif 3517099Sbloom #include "kernel.h" 3631661Smckusick #include "malloc.h" 3724Sbill 3816840Smckusick #define INOHSZ 512 397334Skre #if ((INOHSZ&(INOHSZ-1)) == 0) 407334Skre #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 417334Skre #else 4210852Ssam #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ) 437334Skre #endif 4424Sbill 4539392Smckusick union ihead { 467334Skre union ihead *ih_head[2]; 477334Skre struct inode *ih_chain[2]; 487334Skre } ihead[INOHSZ]; 497334Skre 5039574Smckusick int prtactive; /* 1 => print out reclaim of active vnodes */ 5139574Smckusick 5224Sbill /* 5339392Smckusick * Initialize hash links for inodes. 5424Sbill */ 5539440Smckusick ufs_init() 5624Sbill { 5724Sbill register int i; 5839392Smckusick register union ihead *ih = ihead; 5924Sbill 6039492Smckusick #ifndef lint 6139392Smckusick if (VN_MAXPRIVATE < sizeof(struct inode)) 6239392Smckusick panic("ihinit: too small"); 6339492Smckusick #endif /* not lint */ 647334Skre for (i = INOHSZ; --i >= 0; ih++) { 657334Skre ih->ih_head[0] = ih; 667334Skre ih->ih_head[1] = ih; 677334Skre } 6824Sbill } 6924Sbill 7024Sbill /* 7137736Smckusick * Look up an vnode/inode by device,inumber. 7224Sbill * If it is in core (in the inode structure), 7324Sbill * honor the locking protocol. 7424Sbill * If it is not in core, read it in from the 7524Sbill * specified device. 7637736Smckusick * Callers must check for mount points!! 7724Sbill * In all cases, a pointer to a locked 7824Sbill * inode structure is returned. 7924Sbill */ 8037736Smckusick iget(xp, ino, ipp) 8137736Smckusick struct inode *xp; 824818Swnj ino_t ino; 8337736Smckusick struct inode **ipp; 8424Sbill { 8537736Smckusick dev_t dev = xp->i_dev; 8637736Smckusick struct mount *mntp = ITOV(xp)->v_mount; 8737736Smckusick register struct fs *fs = VFSTOUFS(mntp)->um_fs; 8839440Smckusick extern struct vnodeops ufs_vnodeops, spec_inodeops; 8937736Smckusick register struct inode *ip, *iq; 9037736Smckusick register struct vnode *vp; 9139440Smckusick struct vnode *nvp; 9237736Smckusick struct buf *bp; 9339440Smckusick struct dinode *dp; 9437736Smckusick union ihead *ih; 9537736Smckusick int error; 9624Sbill 9739440Smckusick ih = &ihead[INOHASH(dev, ino)]; 9824Sbill loop: 9939392Smckusick for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) { 10039392Smckusick if (ino != ip->i_number || dev != ip->i_dev) 10139392Smckusick continue; 10239392Smckusick if ((ip->i_flag&ILOCKED) != 0) { 10339392Smckusick ip->i_flag |= IWANT; 10439392Smckusick sleep((caddr_t)ip, PINOD); 10539392Smckusick goto loop; 10639392Smckusick } 10739440Smckusick if (vget(ITOV(ip))) 10839440Smckusick goto loop; 10939392Smckusick *ipp = ip; 11039392Smckusick return(0); 11139392Smckusick } 11239440Smckusick /* 11339440Smckusick * Allocate a new inode. 11439440Smckusick */ 11539440Smckusick if (error = getnewvnode(VT_UFS, mntp, &ufs_vnodeops, &nvp)) { 11637736Smckusick *ipp = 0; 11737736Smckusick return (error); 11837736Smckusick } 11939440Smckusick ip = VTOI(nvp); 12039440Smckusick ip->i_vnode = nvp; 12139440Smckusick ip->i_flag = 0; 12239440Smckusick ip->i_devvp = 0; 12339440Smckusick ip->i_lastr = 0; 12439440Smckusick ip->i_mode = 0; 12539440Smckusick #ifdef QUOTA 12639440Smckusick ip->i_dquot = NODQUOT; 12739440Smckusick #endif 12837736Smckusick /* 12939440Smckusick * Put it onto its hash chain and lock it so that other requests for 13039440Smckusick * this inode will block if they arrive while we are sleeping waiting 13139440Smckusick * for old data structures to be purged or for the contents of the 13239440Smckusick * disk portion of this inode to be read. 13339440Smckusick */ 13439440Smckusick ip->i_dev = dev; 13539440Smckusick ip->i_number = ino; 13639440Smckusick insque(ip, ih); 13739440Smckusick ILOCK(ip); 13839440Smckusick /* 13937736Smckusick * Read in the disk contents for the inode. 14037736Smckusick */ 14137736Smckusick if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)), 14238776Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 14337736Smckusick /* 14439392Smckusick * Unlock and discard unneeded inode. 14537736Smckusick */ 14639440Smckusick iput(ip); 14737736Smckusick brelse(bp); 14837736Smckusick *ipp = 0; 14939440Smckusick return (error); 15037736Smckusick } 15139440Smckusick dp = bp->b_un.b_dino; 15239440Smckusick dp += itoo(fs, ino); 15339440Smckusick ip->i_din = *dp; 15439440Smckusick brelse(bp); 15537736Smckusick /* 15639440Smckusick * Initialize the associated vnode 15737736Smckusick */ 15839440Smckusick vp = ITOV(ip); 15939440Smckusick vp->v_type = IFTOVT(ip->i_mode); 16039440Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 16139440Smckusick vp->v_op = &spec_inodeops; 16239617Smckusick if (nvp = checkalias(vp, ip->i_rdev, mntp)) { 16337736Smckusick /* 16439440Smckusick * Reinitialize aliased inode. 16537736Smckusick */ 16639440Smckusick vp = nvp; 16739440Smckusick iq = VTOI(vp); 16839440Smckusick iq->i_vnode = vp; 16939440Smckusick iq->i_lastr = 0; 17039517Smckusick iq->i_flag = 0; 17139440Smckusick ILOCK(iq); 17239440Smckusick iq->i_din = ip->i_din; 17339440Smckusick iq->i_dev = dev; 17439440Smckusick iq->i_number = ino; 17539440Smckusick insque(iq, ih); 17637736Smckusick /* 17739440Smckusick * Discard unneeded vnode 17837736Smckusick */ 17939440Smckusick ip->i_mode = 0; 18039440Smckusick iput(ip); 18137736Smckusick ip = iq; 18237736Smckusick } 18337736Smckusick } 18439440Smckusick if (ino == ROOTINO) 18539440Smckusick vp->v_flag |= VROOT; 18637736Smckusick /* 18737736Smckusick * Finish inode initialization. 18837736Smckusick */ 18937736Smckusick ip->i_fs = fs; 19037736Smckusick ip->i_devvp = VFSTOUFS(mntp)->um_devvp; 19138345Smckusick VREF(ip->i_devvp); 19237736Smckusick #ifdef QUOTA 19337736Smckusick if (ip->i_mode != 0) 19437736Smckusick ip->i_dquot = inoquota(ip); 19537736Smckusick #endif 19638256Smckusick /* 19738256Smckusick * Set up a generation number for this inode if it does not 19838256Smckusick * already have one. This should only happen on old filesystems. 19938256Smckusick */ 20038256Smckusick if (ip->i_gen == 0) { 20138256Smckusick if (++nextgennumber < (u_long)time.tv_sec) 20238256Smckusick nextgennumber = time.tv_sec; 20338256Smckusick ip->i_gen = nextgennumber; 20438256Smckusick if ((vp->v_mount->m_flag & M_RDONLY) == 0) 20538256Smckusick ip->i_flag |= IMOD; 20638256Smckusick } 20737736Smckusick *ipp = ip; 20837736Smckusick return (0); 20937736Smckusick } 2107334Skre 21137736Smckusick /* 21239392Smckusick * Unlock and decrement the reference count of an inode structure. 21324Sbill */ 21424Sbill iput(ip) 2154818Swnj register struct inode *ip; 21624Sbill { 2177118Smckusick 2188452Sroot if ((ip->i_flag & ILOCKED) == 0) 2197118Smckusick panic("iput"); 22016665Smckusick IUNLOCK(ip); 22137736Smckusick vrele(ITOV(ip)); 2227118Smckusick } 2237118Smckusick 22439392Smckusick /* 22539392Smckusick * Last reference to an inode, write the inode out and if necessary, 22639392Smckusick * truncate and deallocate the file. 22739392Smckusick */ 22837736Smckusick ufs_inactive(vp) 22937736Smckusick struct vnode *vp; 2307118Smckusick { 23137736Smckusick register struct inode *ip = VTOI(vp); 23239392Smckusick int mode, error = 0; 23324Sbill 23439574Smckusick if (prtactive && vp->v_count != 0) 23539676Smckusick vprint("ufs_inactive: pushing active", vp); 23638452Smckusick /* 23738452Smckusick * Get rid of inodes related to stale file handles. 23838452Smckusick */ 23939440Smckusick if (ip->i_mode == 0) { 24039676Smckusick if ((vp->v_flag & VXLOCK) == 0) 24139676Smckusick vgone(vp); 24239440Smckusick return (0); 24339440Smckusick } 24438226Smckusick ILOCK(ip); 24539364Smckusick if (ip->i_nlink <= 0 && (vp->v_mount->m_flag & M_RDONLY) == 0) { 24639676Smckusick error = itrunc(ip, (u_long)0, 0); 24737736Smckusick mode = ip->i_mode; 24837736Smckusick ip->i_mode = 0; 24937736Smckusick ip->i_rdev = 0; 25037736Smckusick ip->i_flag |= IUPD|ICHG; 25137736Smckusick ifree(ip, ip->i_number, mode); 2527651Ssam #ifdef QUOTA 25337736Smckusick (void) chkiq(ip->i_dev, ip, ip->i_uid, 0); 25437736Smckusick dqrele(ip->i_dquot); 25537736Smckusick ip->i_dquot = NODQUOT; 2567492Skre #endif 25737736Smckusick } 25837736Smckusick IUPDAT(ip, &time, &time, 0); 25937736Smckusick /* 26039392Smckusick * If we are done with the inode, reclaim it 26139392Smckusick * so that it can be reused immediately. 26237736Smckusick */ 26339676Smckusick if (vp->v_count == 0 && ip->i_mode == 0) { 26439676Smckusick vinvalbuf(vp, 0); 26539676Smckusick IUNLOCK(ip); 26639676Smckusick ip->i_flag = 0; 26739676Smckusick if ((vp->v_flag & VXLOCK) == 0) 26839676Smckusick vgone(vp); 26939676Smckusick return (error); 27039676Smckusick } 27139676Smckusick IUNLOCK(ip); 27239676Smckusick ip->i_flag = 0; 27337736Smckusick return (error); 27424Sbill } 27524Sbill 27624Sbill /* 27739392Smckusick * Reclaim an inode so that it can be used for other purposes. 27824Sbill */ 27939392Smckusick ufs_reclaim(vp) 28039392Smckusick register struct vnode *vp; 28139392Smckusick { 28239492Smckusick register struct inode *ip = VTOI(vp); 28339392Smckusick 28439574Smckusick if (prtactive && vp->v_count != 0) 28539676Smckusick vprint("ufs_reclaim: pushing active", vp); 28639392Smckusick /* 28739392Smckusick * Remove the inode from its hash chain. 28839392Smckusick */ 28939392Smckusick remque(ip); 29039392Smckusick ip->i_forw = ip; 29139392Smckusick ip->i_back = ip; 29239392Smckusick /* 29339392Smckusick * Purge old data structures associated with the inode. 29439392Smckusick */ 29539392Smckusick cache_purge(vp); 29639392Smckusick if (ip->i_devvp) { 29739392Smckusick vrele(ip->i_devvp); 29839392Smckusick ip->i_devvp = 0; 29939392Smckusick } 30039392Smckusick #ifdef QUOTA 30139392Smckusick dqrele(ip->i_dquot); 30239392Smckusick ip->i_dquot = NODQUOT; 30339392Smckusick #endif 30439392Smckusick ip->i_flag = 0; 30539392Smckusick return (0); 30639392Smckusick } 30739392Smckusick 30839392Smckusick /* 30939392Smckusick * Check accessed and update flags on an inode structure. 31039392Smckusick * If any is on, update the inode with the current time. 31139392Smckusick * If waitfor is given, then must ensure I/O order, 31239392Smckusick * so wait for write to complete. 31339392Smckusick */ 3141203Sbill iupdat(ip, ta, tm, waitfor) 3154818Swnj register struct inode *ip; 3168630Sroot struct timeval *ta, *tm; 3174818Swnj int waitfor; 31824Sbill { 31937736Smckusick struct buf *bp; 32037736Smckusick struct vnode *vp = ITOV(ip); 32124Sbill struct dinode *dp; 32230749Skarels register struct fs *fs; 32337736Smckusick int error; 32424Sbill 32530749Skarels fs = ip->i_fs; 32637736Smckusick if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) 32737736Smckusick return (0); 32837736Smckusick if (vp->v_mount->m_flag & M_RDONLY) 32937736Smckusick return (0); 33037736Smckusick error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)), 33138776Smckusick (int)fs->fs_bsize, NOCRED, &bp); 33237736Smckusick if (error) { 33337736Smckusick brelse(bp); 33437736Smckusick return (error); 33524Sbill } 33637736Smckusick if (ip->i_flag&IACC) 33737736Smckusick ip->i_atime = ta->tv_sec; 33837736Smckusick if (ip->i_flag&IUPD) 33937736Smckusick ip->i_mtime = tm->tv_sec; 34037736Smckusick if (ip->i_flag&ICHG) 34137736Smckusick ip->i_ctime = time.tv_sec; 34237736Smckusick ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 34337736Smckusick dp = bp->b_un.b_dino + itoo(fs, ip->i_number); 34439392Smckusick *dp = ip->i_din; 34537736Smckusick if (waitfor) { 34637736Smckusick return (bwrite(bp)); 34737736Smckusick } else { 34837736Smckusick bdwrite(bp); 34937736Smckusick return (0); 35037736Smckusick } 35124Sbill } 35224Sbill 35310736Ssam #define SINGLE 0 /* index of single indirect block */ 35410736Ssam #define DOUBLE 1 /* index of double indirect block */ 35510736Ssam #define TRIPLE 2 /* index of triple indirect block */ 35624Sbill /* 35739392Smckusick * Truncate the inode ip to at most length size. Free affected disk 35839392Smckusick * blocks -- the blocks of the file are removed in reverse order. 35910736Ssam * 36010736Ssam * NB: triple indirect blocks are untested. 36124Sbill */ 36239676Smckusick itrunc(oip, length, flags) 36317942Smckusick register struct inode *oip; 3649165Ssam u_long length; 36539676Smckusick int flags; 36624Sbill { 3679165Ssam register daddr_t lastblock; 36826272Skarels daddr_t bn, lbn, lastiblock[NIADDR]; 3696569Smckusic register struct fs *fs; 37010736Ssam register struct inode *ip; 37117942Smckusick struct buf *bp; 37237736Smckusick int offset, osize, size, level; 37337736Smckusick long count, nblocks, blocksreleased = 0; 37417942Smckusick register int i; 37539676Smckusick int aflags, error, allerror; 37610736Ssam struct inode tip; 3779165Ssam 37813000Ssam if (oip->i_size <= length) { 37913000Ssam oip->i_flag |= ICHG|IUPD; 38037736Smckusick error = iupdat(oip, &time, &time, 1); 38137736Smckusick return (error); 38213000Ssam } 3831203Sbill /* 38410736Ssam * Calculate index into inode's block list of 38510736Ssam * last direct and indirect blocks (if any) 38610736Ssam * which we want to keep. Lastblock is -1 when 38710736Ssam * the file is truncated to 0. 3881203Sbill */ 38910736Ssam fs = oip->i_fs; 3909165Ssam lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 39110736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 39210736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 39310736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 39412645Ssam nblocks = btodb(fs->fs_bsize); 3956569Smckusic /* 39617942Smckusick * Update the size of the file. If the file is not being 39717942Smckusick * truncated to a block boundry, the contents of the 39817942Smckusick * partial block following the end of the file must be 39917942Smckusick * zero'ed in case it ever become accessable again because 40017942Smckusick * of subsequent file growth. 40117942Smckusick */ 40217942Smckusick osize = oip->i_size; 40317942Smckusick offset = blkoff(fs, length); 40417942Smckusick if (offset == 0) { 40517942Smckusick oip->i_size = length; 40617942Smckusick } else { 40717942Smckusick lbn = lblkno(fs, length); 40839676Smckusick aflags = B_CLRBUF; 40939676Smckusick if (flags & IO_SYNC) 41039676Smckusick aflags |= B_SYNC; 41139676Smckusick if (error = balloc(oip, lbn, offset, &bp, aflags)) 41237736Smckusick return (error); 41317942Smckusick oip->i_size = length; 41417942Smckusick size = blksize(fs, oip, lbn); 41539676Smckusick bn = bp->b_blkno; 41630749Skarels count = howmany(size, CLBYTES); 41730749Skarels for (i = 0; i < count; i++) 41837736Smckusick munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE); 41926272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 42039676Smckusick brealloc(bp, size); 42139676Smckusick if (flags & IO_SYNC) 42239676Smckusick bwrite(bp); 42339676Smckusick else 42439676Smckusick bdwrite(bp); 42517942Smckusick } 42617942Smckusick /* 42717942Smckusick * Update file and block pointers 42810736Ssam * on disk before we start freeing blocks. 42910736Ssam * If we crash before free'ing blocks below, 43010736Ssam * the blocks will be returned to the free list. 43110736Ssam * lastiblock values are also normalized to -1 43210736Ssam * for calls to indirtrunc below. 4336569Smckusic */ 43410736Ssam tip = *oip; 43517942Smckusick tip.i_size = osize; 43610736Ssam for (level = TRIPLE; level >= SINGLE; level--) 43710736Ssam if (lastiblock[level] < 0) { 43810736Ssam oip->i_ib[level] = 0; 43910736Ssam lastiblock[level] = -1; 4409165Ssam } 44110736Ssam for (i = NDADDR - 1; i > lastblock; i--) 44210736Ssam oip->i_db[i] = 0; 44310736Ssam oip->i_flag |= ICHG|IUPD; 44439676Smckusick vinvalbuf(ITOV(oip), (length > 0)); 44539740Smckusick allerror = iupdat(oip, &time, &time, MNT_WAIT); 44610736Ssam 4476569Smckusic /* 44810736Ssam * Indirect blocks first. 4496569Smckusic */ 45017942Smckusick ip = &tip; 45110736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 45210736Ssam bn = ip->i_ib[level]; 4539165Ssam if (bn != 0) { 45437736Smckusick error = indirtrunc(ip, bn, lastiblock[level], level, 45537736Smckusick &count); 45637736Smckusick if (error) 45737736Smckusick allerror = error; 45837736Smckusick blocksreleased += count; 45910736Ssam if (lastiblock[level] < 0) { 46010736Ssam ip->i_ib[level] = 0; 46131402Smckusick blkfree(ip, bn, (off_t)fs->fs_bsize); 46210736Ssam blocksreleased += nblocks; 46310736Ssam } 46410736Ssam } 46510736Ssam if (lastiblock[level] >= 0) 46610736Ssam goto done; 4679165Ssam } 46810736Ssam 4696569Smckusic /* 47010736Ssam * All whole direct blocks or frags. 4716569Smckusic */ 4729165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 47326359Skarels register off_t bsize; 4749165Ssam 4756569Smckusic bn = ip->i_db[i]; 4769165Ssam if (bn == 0) 47724Sbill continue; 4789165Ssam ip->i_db[i] = 0; 47924525Sbloom bsize = (off_t)blksize(fs, ip, i); 48031402Smckusick blkfree(ip, bn, bsize); 48124525Sbloom blocksreleased += btodb(bsize); 48224Sbill } 48310736Ssam if (lastblock < 0) 48410736Ssam goto done; 48510736Ssam 4861203Sbill /* 4879165Ssam * Finally, look for a change in size of the 4889165Ssam * last direct block; release any frags. 4891203Sbill */ 49010736Ssam bn = ip->i_db[lastblock]; 49110736Ssam if (bn != 0) { 49226359Skarels off_t oldspace, newspace; 49310736Ssam 4949165Ssam /* 4959165Ssam * Calculate amount of space we're giving 4969165Ssam * back as old block size minus new block size. 4979165Ssam */ 49810736Ssam oldspace = blksize(fs, ip, lastblock); 4999165Ssam ip->i_size = length; 50010736Ssam newspace = blksize(fs, ip, lastblock); 50110736Ssam if (newspace == 0) 50210736Ssam panic("itrunc: newspace"); 50310736Ssam if (oldspace - newspace > 0) { 5049165Ssam /* 5059165Ssam * Block number of space to be free'd is 5069165Ssam * the old block # plus the number of frags 5079165Ssam * required for the storage we're keeping. 5089165Ssam */ 50910736Ssam bn += numfrags(fs, newspace); 51031402Smckusick blkfree(ip, bn, oldspace - newspace); 51112645Ssam blocksreleased += btodb(oldspace - newspace); 5129165Ssam } 5139165Ssam } 5149165Ssam done: 51510736Ssam /* BEGIN PARANOIA */ 51610736Ssam for (level = SINGLE; level <= TRIPLE; level++) 51710736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 51810736Ssam panic("itrunc1"); 51910736Ssam for (i = 0; i < NDADDR; i++) 52010736Ssam if (ip->i_db[i] != oip->i_db[i]) 52110736Ssam panic("itrunc2"); 52210736Ssam /* END PARANOIA */ 52312645Ssam oip->i_blocks -= blocksreleased; 52412645Ssam if (oip->i_blocks < 0) /* sanity */ 52512645Ssam oip->i_blocks = 0; 52612645Ssam oip->i_flag |= ICHG; 5279165Ssam #ifdef QUOTA 52812645Ssam (void) chkdq(oip, -blocksreleased, 0); 5299165Ssam #endif 53037736Smckusick return (allerror); 53124Sbill } 53224Sbill 5339165Ssam /* 5349165Ssam * Release blocks associated with the inode ip and 5359165Ssam * stored in the indirect block bn. Blocks are free'd 5369165Ssam * in LIFO order up to (but not including) lastbn. If 53710736Ssam * level is greater than SINGLE, the block is an indirect 53810736Ssam * block and recursive calls to indirtrunc must be used to 53910736Ssam * cleanse other indirect blocks. 54010736Ssam * 54110736Ssam * NB: triple indirect blocks are untested. 5429165Ssam */ 54337736Smckusick indirtrunc(ip, bn, lastbn, level, countp) 5446569Smckusic register struct inode *ip; 5459165Ssam daddr_t bn, lastbn; 54610736Ssam int level; 54737736Smckusick long *countp; 54824Sbill { 5499165Ssam register int i; 55031661Smckusick struct buf *bp; 55131661Smckusick register struct fs *fs = ip->i_fs; 55224Sbill register daddr_t *bap; 55331661Smckusick daddr_t *copy, nb, last; 55437736Smckusick long blkcount, factor; 55537736Smckusick int nblocks, blocksreleased = 0; 55637736Smckusick int error, allerror = 0; 55724Sbill 55810736Ssam /* 55910736Ssam * Calculate index in current block of last 56010736Ssam * block to be kept. -1 indicates the entire 56110736Ssam * block so we need not calculate the index. 56210736Ssam */ 56310736Ssam factor = 1; 56410736Ssam for (i = SINGLE; i < level; i++) 56510736Ssam factor *= NINDIR(fs); 5669165Ssam last = lastbn; 56710736Ssam if (lastbn > 0) 56810736Ssam last /= factor; 56912645Ssam nblocks = btodb(fs->fs_bsize); 57010736Ssam /* 57110736Ssam * Get buffer of block pointers, zero those 57210736Ssam * entries corresponding to blocks to be free'd, 57310736Ssam * and update on disk copy first. 57410736Ssam */ 57538776Smckusick error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, 57638776Smckusick NOCRED, &bp); 57737736Smckusick if (error) { 57810736Ssam brelse(bp); 57937736Smckusick *countp = 0; 58037736Smckusick return (error); 58110736Ssam } 58239676Smckusick if ((bp->b_flags & B_CACHE) == 0) 58339676Smckusick reassignbuf(bp, ITOV(ip)); 58410736Ssam bap = bp->b_un.b_daddr; 58531661Smckusick MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); 58631661Smckusick bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); 58710736Ssam bzero((caddr_t)&bap[last + 1], 58810736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 58939676Smckusick if (last == -1) 59039676Smckusick bp->b_flags |= B_INVAL; 59137736Smckusick error = bwrite(bp); 59237736Smckusick if (error) 59337736Smckusick allerror = error; 59431661Smckusick bap = copy; 59510736Ssam 59610736Ssam /* 59710736Ssam * Recursively free totally unused blocks. 59810736Ssam */ 5999165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 60024Sbill nb = bap[i]; 6019165Ssam if (nb == 0) 60224Sbill continue; 60337736Smckusick if (level > SINGLE) { 60437736Smckusick error = indirtrunc(ip, nb, (daddr_t)-1, level - 1, 60537736Smckusick &blkcount); 60637736Smckusick if (error) 60737736Smckusick allerror = error; 60837736Smckusick blocksreleased += blkcount; 60937736Smckusick } 61031402Smckusick blkfree(ip, nb, (off_t)fs->fs_bsize); 6119165Ssam blocksreleased += nblocks; 61224Sbill } 61310736Ssam 61410736Ssam /* 61510736Ssam * Recursively free last partial block. 61610736Ssam */ 61710736Ssam if (level > SINGLE && lastbn >= 0) { 61810736Ssam last = lastbn % factor; 6199165Ssam nb = bap[i]; 62037736Smckusick if (nb != 0) { 62137736Smckusick error = indirtrunc(ip, nb, last, level - 1, &blkcount); 62237736Smckusick if (error) 62337736Smckusick allerror = error; 62437736Smckusick blocksreleased += blkcount; 62537736Smckusick } 6269165Ssam } 62731661Smckusick FREE(copy, M_TEMP); 62837736Smckusick *countp = blocksreleased; 62937736Smckusick return (allerror); 63024Sbill } 63124Sbill 63224Sbill /* 6334818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6343617Sroot */ 6354818Swnj ilock(ip) 6364818Swnj register struct inode *ip; 6373617Sroot { 6383617Sroot 63937736Smckusick while (ip->i_flag & ILOCKED) { 64037736Smckusick ip->i_flag |= IWANT; 641*39795Smckusick if (ip->i_spare0 == u.u_procp->p_pid) 642*39795Smckusick panic("locking against myself"); 643*39795Smckusick ip->i_spare1 = u.u_procp->p_pid; 64437736Smckusick (void) sleep((caddr_t)ip, PINOD); 64537736Smckusick } 646*39795Smckusick ip->i_spare1 = 0; 647*39795Smckusick ip->i_spare0 = u.u_procp->p_pid; 648*39795Smckusick u.u_spare[0]++; 64937736Smckusick ip->i_flag |= ILOCKED; 6503617Sroot } 6513617Sroot 6523617Sroot /* 6534818Swnj * Unlock an inode. If WANT bit is on, wakeup. 6543617Sroot */ 6557118Smckusick iunlock(ip) 6564818Swnj register struct inode *ip; 6573617Sroot { 6583617Sroot 65937736Smckusick if ((ip->i_flag & ILOCKED) == 0) 66039676Smckusick vprint("iunlock: unlocked inode", ITOV(ip)); 661*39795Smckusick ip->i_spare0 = 0; 662*39795Smckusick u.u_spare[0]--; 66337736Smckusick ip->i_flag &= ~ILOCKED; 66437736Smckusick if (ip->i_flag&IWANT) { 66537736Smckusick ip->i_flag &= ~IWANT; 66637736Smckusick wakeup((caddr_t)ip); 66737736Smckusick } 6683617Sroot } 66937736Smckusick 67037736Smckusick /* 67137736Smckusick * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 67237736Smckusick * The mode is shifted to select the owner/group/other fields. The 67337736Smckusick * super user is granted all permissions. 67437736Smckusick * 67537736Smckusick * NB: Called from vnode op table. It seems this could all be done 67637736Smckusick * using vattr's but... 67737736Smckusick */ 67837736Smckusick iaccess(ip, mode, cred) 67937736Smckusick register struct inode *ip; 68037736Smckusick register int mode; 68137736Smckusick struct ucred *cred; 68237736Smckusick { 68337736Smckusick register gid_t *gp; 68437736Smckusick int i; 68537736Smckusick 68637736Smckusick /* 68739392Smckusick * If you're the super-user, you always get access. 68837736Smckusick */ 68937736Smckusick if (cred->cr_uid == 0) 69037736Smckusick return (0); 69137736Smckusick /* 69237736Smckusick * Access check is based on only one of owner, group, public. 69337736Smckusick * If not owner, then check group. If not a member of the 69437736Smckusick * group, then check public access. 69537736Smckusick */ 69637736Smckusick if (cred->cr_uid != ip->i_uid) { 69737736Smckusick mode >>= 3; 69837736Smckusick gp = cred->cr_groups; 69937736Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 70037736Smckusick if (ip->i_gid == *gp) 70137736Smckusick goto found; 70237736Smckusick mode >>= 3; 70337736Smckusick found: 70437736Smckusick ; 70537736Smckusick } 70637736Smckusick if ((ip->i_mode & mode) != 0) 70737736Smckusick return (0); 70837736Smckusick return (EACCES); 70937736Smckusick } 710