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*41334Smckusick * @(#)lfs_inode.c 7.31 (Berkeley) 05/03/90 1823399Smckusick */ 1924Sbill 2017099Sbloom #include "param.h" 2117099Sbloom #include "systm.h" 2217099Sbloom #include "mount.h" 2317099Sbloom #include "user.h" 2439795Smckusick #include "proc.h" 2537736Smckusick #include "file.h" 2617099Sbloom #include "buf.h" 2724525Sbloom #include "cmap.h" 2837736Smckusick #include "vnode.h" 2941313Smckusick #include "../ufs/quota.h" 3037736Smckusick #include "../ufs/inode.h" 3137736Smckusick #include "../ufs/fs.h" 3237736Smckusick #include "../ufs/ufsmount.h" 3317099Sbloom #include "kernel.h" 3431661Smckusick #include "malloc.h" 3524Sbill 3616840Smckusick #define INOHSZ 512 377334Skre #if ((INOHSZ&(INOHSZ-1)) == 0) 387334Skre #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 397334Skre #else 4010852Ssam #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ) 417334Skre #endif 4224Sbill 4339392Smckusick union ihead { 447334Skre union ihead *ih_head[2]; 457334Skre struct inode *ih_chain[2]; 467334Skre } ihead[INOHSZ]; 477334Skre 4839574Smckusick int prtactive; /* 1 => print out reclaim of active vnodes */ 4939574Smckusick 5024Sbill /* 5139392Smckusick * Initialize hash links for inodes. 5224Sbill */ 5339440Smckusick ufs_init() 5424Sbill { 5524Sbill register int i; 5639392Smckusick register union ihead *ih = ihead; 5724Sbill 5839492Smckusick #ifndef lint 5939392Smckusick if (VN_MAXPRIVATE < sizeof(struct inode)) 6039392Smckusick panic("ihinit: too small"); 6139492Smckusick #endif /* not lint */ 627334Skre for (i = INOHSZ; --i >= 0; ih++) { 637334Skre ih->ih_head[0] = ih; 647334Skre ih->ih_head[1] = ih; 657334Skre } 6641313Smckusick #ifdef QUOTA 6741313Smckusick dqinit(); 6841313Smckusick #endif /* QUOTA */ 6924Sbill } 7024Sbill 7124Sbill /* 7237736Smckusick * Look up an vnode/inode by device,inumber. 7324Sbill * If it is in core (in the inode structure), 7424Sbill * honor the locking protocol. 7524Sbill * If it is not in core, read it in from the 7624Sbill * specified device. 7737736Smckusick * Callers must check for mount points!! 7824Sbill * In all cases, a pointer to a locked 7924Sbill * inode structure is returned. 8024Sbill */ 8137736Smckusick iget(xp, ino, ipp) 8237736Smckusick struct inode *xp; 834818Swnj ino_t ino; 8437736Smckusick struct inode **ipp; 8524Sbill { 8637736Smckusick dev_t dev = xp->i_dev; 8737736Smckusick struct mount *mntp = ITOV(xp)->v_mount; 8837736Smckusick register struct fs *fs = VFSTOUFS(mntp)->um_fs; 8939440Smckusick extern struct vnodeops ufs_vnodeops, spec_inodeops; 9037736Smckusick register struct inode *ip, *iq; 9137736Smckusick register struct vnode *vp; 9239440Smckusick struct vnode *nvp; 9337736Smckusick struct buf *bp; 9439440Smckusick struct dinode *dp; 9541313Smckusick union ihead *ih; 9641313Smckusick int i, error; 9724Sbill 9839440Smckusick ih = &ihead[INOHASH(dev, ino)]; 9924Sbill loop: 10039392Smckusick for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) { 10139392Smckusick if (ino != ip->i_number || dev != ip->i_dev) 10239392Smckusick continue; 10339392Smckusick if ((ip->i_flag&ILOCKED) != 0) { 10439392Smckusick ip->i_flag |= IWANT; 10539392Smckusick sleep((caddr_t)ip, PINOD); 10639392Smckusick goto loop; 10739392Smckusick } 10839440Smckusick if (vget(ITOV(ip))) 10939440Smckusick goto loop; 11039392Smckusick *ipp = ip; 11139392Smckusick return(0); 11239392Smckusick } 11339440Smckusick /* 11439440Smckusick * Allocate a new inode. 11539440Smckusick */ 11639440Smckusick if (error = getnewvnode(VT_UFS, mntp, &ufs_vnodeops, &nvp)) { 11737736Smckusick *ipp = 0; 11837736Smckusick return (error); 11937736Smckusick } 12039440Smckusick ip = VTOI(nvp); 12139440Smckusick ip->i_vnode = nvp; 12239440Smckusick ip->i_flag = 0; 12339440Smckusick ip->i_devvp = 0; 12439440Smckusick ip->i_mode = 0; 12539879Smckusick ip->i_diroff = 0; 12639440Smckusick #ifdef QUOTA 12741313Smckusick for (i = 0; i < MAXQUOTAS; i++) 12841313Smckusick ip->i_dquot[i] = NODQUOT; 12939440Smckusick #endif 13037736Smckusick /* 13139440Smckusick * Put it onto its hash chain and lock it so that other requests for 13239440Smckusick * this inode will block if they arrive while we are sleeping waiting 13339440Smckusick * for old data structures to be purged or for the contents of the 13439440Smckusick * disk portion of this inode to be read. 13539440Smckusick */ 13639440Smckusick ip->i_dev = dev; 13739440Smckusick ip->i_number = ino; 13839440Smckusick insque(ip, ih); 13939440Smckusick ILOCK(ip); 14039440Smckusick /* 14137736Smckusick * Read in the disk contents for the inode. 14237736Smckusick */ 14337736Smckusick if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)), 14438776Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 14537736Smckusick /* 146*41334Smckusick * The inode does not contain anything useful, so it would 147*41334Smckusick * be misleading to leave it on its hash chain. 148*41334Smckusick * Iput() will take care of putting it back on the free list. 149*41334Smckusick */ 150*41334Smckusick remque(ip); 151*41334Smckusick ip->i_forw = ip; 152*41334Smckusick ip->i_back = ip; 153*41334Smckusick /* 15439392Smckusick * Unlock and discard unneeded inode. 15537736Smckusick */ 15639440Smckusick iput(ip); 15737736Smckusick brelse(bp); 15837736Smckusick *ipp = 0; 15939440Smckusick return (error); 16037736Smckusick } 16139440Smckusick dp = bp->b_un.b_dino; 16239440Smckusick dp += itoo(fs, ino); 16339440Smckusick ip->i_din = *dp; 16439440Smckusick brelse(bp); 16537736Smckusick /* 16639440Smckusick * Initialize the associated vnode 16737736Smckusick */ 16839440Smckusick vp = ITOV(ip); 16939440Smckusick vp->v_type = IFTOVT(ip->i_mode); 17040289Smckusick if (vp->v_type == VFIFO) { 17140289Smckusick #ifdef FIFO 17240289Smckusick extern struct vnodeops fifo_inodeops; 17340289Smckusick vp->v_op = &fifo_inodeops; 17440289Smckusick #else 17540289Smckusick iput(ip); 17640289Smckusick *ipp = 0; 17740289Smckusick return (EOPNOTSUPP); 17840289Smckusick #endif /* FIFO */ 17940289Smckusick } 18039440Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 18139440Smckusick vp->v_op = &spec_inodeops; 18239617Smckusick if (nvp = checkalias(vp, ip->i_rdev, mntp)) { 18337736Smckusick /* 18439440Smckusick * Reinitialize aliased inode. 18537736Smckusick */ 18639440Smckusick vp = nvp; 18739440Smckusick iq = VTOI(vp); 18839440Smckusick iq->i_vnode = vp; 18939517Smckusick iq->i_flag = 0; 19039440Smckusick ILOCK(iq); 19139440Smckusick iq->i_din = ip->i_din; 19239440Smckusick iq->i_dev = dev; 19339440Smckusick iq->i_number = ino; 19439440Smckusick insque(iq, ih); 19537736Smckusick /* 19639440Smckusick * Discard unneeded vnode 19737736Smckusick */ 19839440Smckusick ip->i_mode = 0; 19939440Smckusick iput(ip); 20037736Smckusick ip = iq; 20137736Smckusick } 20237736Smckusick } 20339440Smckusick if (ino == ROOTINO) 20439440Smckusick vp->v_flag |= VROOT; 20537736Smckusick /* 20637736Smckusick * Finish inode initialization. 20737736Smckusick */ 20837736Smckusick ip->i_fs = fs; 20937736Smckusick ip->i_devvp = VFSTOUFS(mntp)->um_devvp; 21038345Smckusick VREF(ip->i_devvp); 21138256Smckusick /* 21238256Smckusick * Set up a generation number for this inode if it does not 21338256Smckusick * already have one. This should only happen on old filesystems. 21438256Smckusick */ 21538256Smckusick if (ip->i_gen == 0) { 21638256Smckusick if (++nextgennumber < (u_long)time.tv_sec) 21738256Smckusick nextgennumber = time.tv_sec; 21838256Smckusick ip->i_gen = nextgennumber; 21938256Smckusick if ((vp->v_mount->m_flag & M_RDONLY) == 0) 22038256Smckusick ip->i_flag |= IMOD; 22138256Smckusick } 22237736Smckusick *ipp = ip; 22337736Smckusick return (0); 22437736Smckusick } 2257334Skre 22637736Smckusick /* 22739392Smckusick * Unlock and decrement the reference count of an inode structure. 22824Sbill */ 22924Sbill iput(ip) 2304818Swnj register struct inode *ip; 23124Sbill { 2327118Smckusick 2338452Sroot if ((ip->i_flag & ILOCKED) == 0) 2347118Smckusick panic("iput"); 23516665Smckusick IUNLOCK(ip); 23637736Smckusick vrele(ITOV(ip)); 2377118Smckusick } 2387118Smckusick 23939392Smckusick /* 24039392Smckusick * Last reference to an inode, write the inode out and if necessary, 24139392Smckusick * truncate and deallocate the file. 24239392Smckusick */ 24337736Smckusick ufs_inactive(vp) 24437736Smckusick struct vnode *vp; 2457118Smckusick { 24637736Smckusick register struct inode *ip = VTOI(vp); 24739392Smckusick int mode, error = 0; 24824Sbill 24939816Smckusick if (prtactive && vp->v_usecount != 0) 25039676Smckusick vprint("ufs_inactive: pushing active", vp); 25138452Smckusick /* 25238452Smckusick * Get rid of inodes related to stale file handles. 25338452Smckusick */ 25439440Smckusick if (ip->i_mode == 0) { 25539676Smckusick if ((vp->v_flag & VXLOCK) == 0) 25639676Smckusick vgone(vp); 25739440Smckusick return (0); 25839440Smckusick } 25938226Smckusick ILOCK(ip); 26039364Smckusick if (ip->i_nlink <= 0 && (vp->v_mount->m_flag & M_RDONLY) == 0) { 26141313Smckusick #ifdef QUOTA 26241313Smckusick if (!getinoquota(ip)) 26341313Smckusick (void) chkiq(ip, -1, NOCRED, 0); 26441313Smckusick #endif 26539676Smckusick error = itrunc(ip, (u_long)0, 0); 26637736Smckusick mode = ip->i_mode; 26737736Smckusick ip->i_mode = 0; 26837736Smckusick ip->i_flag |= IUPD|ICHG; 26937736Smckusick ifree(ip, ip->i_number, mode); 27037736Smckusick } 27137736Smckusick IUPDAT(ip, &time, &time, 0); 27240033Smckusick IUNLOCK(ip); 27340033Smckusick ip->i_flag = 0; 27437736Smckusick /* 27539392Smckusick * If we are done with the inode, reclaim it 27639392Smckusick * so that it can be reused immediately. 27737736Smckusick */ 27841313Smckusick if (vp->v_usecount == 0 && ip->i_mode == 0) 27940033Smckusick vgone(vp); 28037736Smckusick return (error); 28124Sbill } 28224Sbill 28324Sbill /* 28439392Smckusick * Reclaim an inode so that it can be used for other purposes. 28524Sbill */ 28639392Smckusick ufs_reclaim(vp) 28739392Smckusick register struct vnode *vp; 28839392Smckusick { 28939492Smckusick register struct inode *ip = VTOI(vp); 29041313Smckusick int i; 29139392Smckusick 29239816Smckusick if (prtactive && vp->v_usecount != 0) 29339676Smckusick vprint("ufs_reclaim: pushing active", vp); 29439392Smckusick /* 29539392Smckusick * Remove the inode from its hash chain. 29639392Smckusick */ 29739392Smckusick remque(ip); 29839392Smckusick ip->i_forw = ip; 29939392Smckusick ip->i_back = ip; 30039392Smckusick /* 30139392Smckusick * Purge old data structures associated with the inode. 30239392Smckusick */ 30339392Smckusick cache_purge(vp); 30439392Smckusick if (ip->i_devvp) { 30539392Smckusick vrele(ip->i_devvp); 30639392Smckusick ip->i_devvp = 0; 30739392Smckusick } 30839392Smckusick #ifdef QUOTA 30941313Smckusick for (i = 0; i < MAXQUOTAS; i++) { 31041313Smckusick if (ip->i_dquot[i] != NODQUOT) { 31141313Smckusick dqrele(vp, ip->i_dquot[i]); 31241313Smckusick ip->i_dquot[i] = NODQUOT; 31341313Smckusick } 31441313Smckusick } 31539392Smckusick #endif 31639392Smckusick ip->i_flag = 0; 31739392Smckusick return (0); 31839392Smckusick } 31939392Smckusick 32039392Smckusick /* 32139392Smckusick * Check accessed and update flags on an inode structure. 32239392Smckusick * If any is on, update the inode with the current time. 32339392Smckusick * If waitfor is given, then must ensure I/O order, 32439392Smckusick * so wait for write to complete. 32539392Smckusick */ 3261203Sbill iupdat(ip, ta, tm, waitfor) 3274818Swnj register struct inode *ip; 3288630Sroot struct timeval *ta, *tm; 3294818Swnj int waitfor; 33024Sbill { 33137736Smckusick struct buf *bp; 33237736Smckusick struct vnode *vp = ITOV(ip); 33324Sbill struct dinode *dp; 33430749Skarels register struct fs *fs; 33537736Smckusick int error; 33624Sbill 33730749Skarels fs = ip->i_fs; 33837736Smckusick if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) 33937736Smckusick return (0); 34037736Smckusick if (vp->v_mount->m_flag & M_RDONLY) 34137736Smckusick return (0); 34237736Smckusick error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)), 34338776Smckusick (int)fs->fs_bsize, NOCRED, &bp); 34437736Smckusick if (error) { 34537736Smckusick brelse(bp); 34637736Smckusick return (error); 34724Sbill } 34837736Smckusick if (ip->i_flag&IACC) 34937736Smckusick ip->i_atime = ta->tv_sec; 35037736Smckusick if (ip->i_flag&IUPD) 35137736Smckusick ip->i_mtime = tm->tv_sec; 35237736Smckusick if (ip->i_flag&ICHG) 35337736Smckusick ip->i_ctime = time.tv_sec; 35437736Smckusick ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 35537736Smckusick dp = bp->b_un.b_dino + itoo(fs, ip->i_number); 35639392Smckusick *dp = ip->i_din; 35737736Smckusick if (waitfor) { 35837736Smckusick return (bwrite(bp)); 35937736Smckusick } else { 36037736Smckusick bdwrite(bp); 36137736Smckusick return (0); 36237736Smckusick } 36324Sbill } 36424Sbill 36510736Ssam #define SINGLE 0 /* index of single indirect block */ 36610736Ssam #define DOUBLE 1 /* index of double indirect block */ 36710736Ssam #define TRIPLE 2 /* index of triple indirect block */ 36824Sbill /* 36939392Smckusick * Truncate the inode ip to at most length size. Free affected disk 37039392Smckusick * blocks -- the blocks of the file are removed in reverse order. 37110736Ssam * 37210736Ssam * NB: triple indirect blocks are untested. 37324Sbill */ 37439676Smckusick itrunc(oip, length, flags) 37517942Smckusick register struct inode *oip; 3769165Ssam u_long length; 37739676Smckusick int flags; 37824Sbill { 3799165Ssam register daddr_t lastblock; 38026272Skarels daddr_t bn, lbn, lastiblock[NIADDR]; 3816569Smckusic register struct fs *fs; 38210736Ssam register struct inode *ip; 38317942Smckusick struct buf *bp; 38437736Smckusick int offset, osize, size, level; 38537736Smckusick long count, nblocks, blocksreleased = 0; 38617942Smckusick register int i; 38739676Smckusick int aflags, error, allerror; 38810736Ssam struct inode tip; 3899165Ssam 39013000Ssam if (oip->i_size <= length) { 39113000Ssam oip->i_flag |= ICHG|IUPD; 39237736Smckusick error = iupdat(oip, &time, &time, 1); 39337736Smckusick return (error); 39413000Ssam } 3951203Sbill /* 39610736Ssam * Calculate index into inode's block list of 39710736Ssam * last direct and indirect blocks (if any) 39810736Ssam * which we want to keep. Lastblock is -1 when 39910736Ssam * the file is truncated to 0. 4001203Sbill */ 40110736Ssam fs = oip->i_fs; 4029165Ssam lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 40310736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 40410736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 40510736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 40612645Ssam nblocks = btodb(fs->fs_bsize); 4076569Smckusic /* 40817942Smckusick * Update the size of the file. If the file is not being 40917942Smckusick * truncated to a block boundry, the contents of the 41017942Smckusick * partial block following the end of the file must be 41117942Smckusick * zero'ed in case it ever become accessable again because 41217942Smckusick * of subsequent file growth. 41317942Smckusick */ 41417942Smckusick osize = oip->i_size; 41517942Smckusick offset = blkoff(fs, length); 41617942Smckusick if (offset == 0) { 41717942Smckusick oip->i_size = length; 41817942Smckusick } else { 41917942Smckusick lbn = lblkno(fs, length); 42039676Smckusick aflags = B_CLRBUF; 42139676Smckusick if (flags & IO_SYNC) 42239676Smckusick aflags |= B_SYNC; 42341313Smckusick #ifdef QUOTA 42441313Smckusick if (error = getinoquota(oip)) 42541313Smckusick return (error); 42641313Smckusick #endif 42739676Smckusick if (error = balloc(oip, lbn, offset, &bp, aflags)) 42837736Smckusick return (error); 42917942Smckusick oip->i_size = length; 43017942Smckusick size = blksize(fs, oip, lbn); 43139676Smckusick bn = bp->b_blkno; 43230749Skarels count = howmany(size, CLBYTES); 43330749Skarels for (i = 0; i < count; i++) 43437736Smckusick munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE); 43526272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 43639676Smckusick brealloc(bp, size); 43739676Smckusick if (flags & IO_SYNC) 43839676Smckusick bwrite(bp); 43939676Smckusick else 44039676Smckusick bdwrite(bp); 44117942Smckusick } 44217942Smckusick /* 44317942Smckusick * Update file and block pointers 44410736Ssam * on disk before we start freeing blocks. 44510736Ssam * If we crash before free'ing blocks below, 44610736Ssam * the blocks will be returned to the free list. 44710736Ssam * lastiblock values are also normalized to -1 44810736Ssam * for calls to indirtrunc below. 4496569Smckusic */ 45010736Ssam tip = *oip; 45117942Smckusick tip.i_size = osize; 45210736Ssam for (level = TRIPLE; level >= SINGLE; level--) 45310736Ssam if (lastiblock[level] < 0) { 45410736Ssam oip->i_ib[level] = 0; 45510736Ssam lastiblock[level] = -1; 4569165Ssam } 45710736Ssam for (i = NDADDR - 1; i > lastblock; i--) 45810736Ssam oip->i_db[i] = 0; 45910736Ssam oip->i_flag |= ICHG|IUPD; 46039676Smckusick vinvalbuf(ITOV(oip), (length > 0)); 46139740Smckusick allerror = iupdat(oip, &time, &time, MNT_WAIT); 46210736Ssam 4636569Smckusic /* 46410736Ssam * Indirect blocks first. 4656569Smckusic */ 46617942Smckusick ip = &tip; 46710736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 46810736Ssam bn = ip->i_ib[level]; 4699165Ssam if (bn != 0) { 47037736Smckusick error = indirtrunc(ip, bn, lastiblock[level], level, 47137736Smckusick &count); 47237736Smckusick if (error) 47337736Smckusick allerror = error; 47437736Smckusick blocksreleased += count; 47510736Ssam if (lastiblock[level] < 0) { 47610736Ssam ip->i_ib[level] = 0; 47731402Smckusick blkfree(ip, bn, (off_t)fs->fs_bsize); 47810736Ssam blocksreleased += nblocks; 47910736Ssam } 48010736Ssam } 48110736Ssam if (lastiblock[level] >= 0) 48210736Ssam goto done; 4839165Ssam } 48410736Ssam 4856569Smckusic /* 48610736Ssam * All whole direct blocks or frags. 4876569Smckusic */ 4889165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 48926359Skarels register off_t bsize; 4909165Ssam 4916569Smckusic bn = ip->i_db[i]; 4929165Ssam if (bn == 0) 49324Sbill continue; 4949165Ssam ip->i_db[i] = 0; 49524525Sbloom bsize = (off_t)blksize(fs, ip, i); 49631402Smckusick blkfree(ip, bn, bsize); 49724525Sbloom blocksreleased += btodb(bsize); 49824Sbill } 49910736Ssam if (lastblock < 0) 50010736Ssam goto done; 50110736Ssam 5021203Sbill /* 5039165Ssam * Finally, look for a change in size of the 5049165Ssam * last direct block; release any frags. 5051203Sbill */ 50610736Ssam bn = ip->i_db[lastblock]; 50710736Ssam if (bn != 0) { 50826359Skarels off_t oldspace, newspace; 50910736Ssam 5109165Ssam /* 5119165Ssam * Calculate amount of space we're giving 5129165Ssam * back as old block size minus new block size. 5139165Ssam */ 51410736Ssam oldspace = blksize(fs, ip, lastblock); 5159165Ssam ip->i_size = length; 51610736Ssam newspace = blksize(fs, ip, lastblock); 51710736Ssam if (newspace == 0) 51810736Ssam panic("itrunc: newspace"); 51910736Ssam if (oldspace - newspace > 0) { 5209165Ssam /* 5219165Ssam * Block number of space to be free'd is 5229165Ssam * the old block # plus the number of frags 5239165Ssam * required for the storage we're keeping. 5249165Ssam */ 52510736Ssam bn += numfrags(fs, newspace); 52631402Smckusick blkfree(ip, bn, oldspace - newspace); 52712645Ssam blocksreleased += btodb(oldspace - newspace); 5289165Ssam } 5299165Ssam } 5309165Ssam done: 53110736Ssam /* BEGIN PARANOIA */ 53210736Ssam for (level = SINGLE; level <= TRIPLE; level++) 53310736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 53410736Ssam panic("itrunc1"); 53510736Ssam for (i = 0; i < NDADDR; i++) 53610736Ssam if (ip->i_db[i] != oip->i_db[i]) 53710736Ssam panic("itrunc2"); 53810736Ssam /* END PARANOIA */ 53912645Ssam oip->i_blocks -= blocksreleased; 54012645Ssam if (oip->i_blocks < 0) /* sanity */ 54112645Ssam oip->i_blocks = 0; 54212645Ssam oip->i_flag |= ICHG; 5439165Ssam #ifdef QUOTA 54441313Smckusick if (!getinoquota(oip)) 54541313Smckusick (void) chkdq(oip, -blocksreleased, NOCRED, 0); 5469165Ssam #endif 54737736Smckusick return (allerror); 54824Sbill } 54924Sbill 5509165Ssam /* 5519165Ssam * Release blocks associated with the inode ip and 5529165Ssam * stored in the indirect block bn. Blocks are free'd 5539165Ssam * in LIFO order up to (but not including) lastbn. If 55410736Ssam * level is greater than SINGLE, the block is an indirect 55510736Ssam * block and recursive calls to indirtrunc must be used to 55610736Ssam * cleanse other indirect blocks. 55710736Ssam * 55810736Ssam * NB: triple indirect blocks are untested. 5599165Ssam */ 56037736Smckusick indirtrunc(ip, bn, lastbn, level, countp) 5616569Smckusic register struct inode *ip; 5629165Ssam daddr_t bn, lastbn; 56310736Ssam int level; 56437736Smckusick long *countp; 56524Sbill { 5669165Ssam register int i; 56731661Smckusick struct buf *bp; 56831661Smckusick register struct fs *fs = ip->i_fs; 56924Sbill register daddr_t *bap; 57031661Smckusick daddr_t *copy, nb, last; 57137736Smckusick long blkcount, factor; 57237736Smckusick int nblocks, blocksreleased = 0; 57337736Smckusick int error, allerror = 0; 57424Sbill 57510736Ssam /* 57610736Ssam * Calculate index in current block of last 57710736Ssam * block to be kept. -1 indicates the entire 57810736Ssam * block so we need not calculate the index. 57910736Ssam */ 58010736Ssam factor = 1; 58110736Ssam for (i = SINGLE; i < level; i++) 58210736Ssam factor *= NINDIR(fs); 5839165Ssam last = lastbn; 58410736Ssam if (lastbn > 0) 58510736Ssam last /= factor; 58612645Ssam nblocks = btodb(fs->fs_bsize); 58710736Ssam /* 58810736Ssam * Get buffer of block pointers, zero those 58910736Ssam * entries corresponding to blocks to be free'd, 59010736Ssam * and update on disk copy first. 59110736Ssam */ 59238776Smckusick error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, 59338776Smckusick NOCRED, &bp); 59437736Smckusick if (error) { 59510736Ssam brelse(bp); 59637736Smckusick *countp = 0; 59737736Smckusick return (error); 59810736Ssam } 59910736Ssam bap = bp->b_un.b_daddr; 60031661Smckusick MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); 60131661Smckusick bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); 60210736Ssam bzero((caddr_t)&bap[last + 1], 60310736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 60439676Smckusick if (last == -1) 60539676Smckusick bp->b_flags |= B_INVAL; 60637736Smckusick error = bwrite(bp); 60737736Smckusick if (error) 60837736Smckusick allerror = error; 60931661Smckusick bap = copy; 61010736Ssam 61110736Ssam /* 61210736Ssam * Recursively free totally unused blocks. 61310736Ssam */ 6149165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 61524Sbill nb = bap[i]; 6169165Ssam if (nb == 0) 61724Sbill continue; 61837736Smckusick if (level > SINGLE) { 61937736Smckusick error = indirtrunc(ip, nb, (daddr_t)-1, level - 1, 62037736Smckusick &blkcount); 62137736Smckusick if (error) 62237736Smckusick allerror = error; 62337736Smckusick blocksreleased += blkcount; 62437736Smckusick } 62531402Smckusick blkfree(ip, nb, (off_t)fs->fs_bsize); 6269165Ssam blocksreleased += nblocks; 62724Sbill } 62810736Ssam 62910736Ssam /* 63010736Ssam * Recursively free last partial block. 63110736Ssam */ 63210736Ssam if (level > SINGLE && lastbn >= 0) { 63310736Ssam last = lastbn % factor; 6349165Ssam nb = bap[i]; 63537736Smckusick if (nb != 0) { 63637736Smckusick error = indirtrunc(ip, nb, last, level - 1, &blkcount); 63737736Smckusick if (error) 63837736Smckusick allerror = error; 63937736Smckusick blocksreleased += blkcount; 64037736Smckusick } 6419165Ssam } 64231661Smckusick FREE(copy, M_TEMP); 64337736Smckusick *countp = blocksreleased; 64437736Smckusick return (allerror); 64524Sbill } 64624Sbill 64724Sbill /* 6484818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6493617Sroot */ 6504818Swnj ilock(ip) 6514818Swnj register struct inode *ip; 6523617Sroot { 6533617Sroot 65437736Smckusick while (ip->i_flag & ILOCKED) { 65537736Smckusick ip->i_flag |= IWANT; 65639795Smckusick if (ip->i_spare0 == u.u_procp->p_pid) 65739795Smckusick panic("locking against myself"); 65839795Smckusick ip->i_spare1 = u.u_procp->p_pid; 65937736Smckusick (void) sleep((caddr_t)ip, PINOD); 66037736Smckusick } 66139795Smckusick ip->i_spare1 = 0; 66239795Smckusick ip->i_spare0 = u.u_procp->p_pid; 66339795Smckusick u.u_spare[0]++; 66437736Smckusick ip->i_flag |= ILOCKED; 6653617Sroot } 6663617Sroot 6673617Sroot /* 6684818Swnj * Unlock an inode. If WANT bit is on, wakeup. 6693617Sroot */ 6707118Smckusick iunlock(ip) 6714818Swnj register struct inode *ip; 6723617Sroot { 6733617Sroot 67437736Smckusick if ((ip->i_flag & ILOCKED) == 0) 67539676Smckusick vprint("iunlock: unlocked inode", ITOV(ip)); 67639795Smckusick ip->i_spare0 = 0; 67739795Smckusick u.u_spare[0]--; 67837736Smckusick ip->i_flag &= ~ILOCKED; 67937736Smckusick if (ip->i_flag&IWANT) { 68037736Smckusick ip->i_flag &= ~IWANT; 68137736Smckusick wakeup((caddr_t)ip); 68237736Smckusick } 6833617Sroot } 684