123399Smckusick /* 229117Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323399Smckusick * All rights reserved. The Berkeley software License Agreement 423399Smckusick * specifies the terms and conditions for redistribution. 523399Smckusick * 6*31661Smckusick * @(#)lfs_inode.c 7.5 (Berkeley) 06/21/87 723399Smckusick */ 824Sbill 917099Sbloom #include "param.h" 1017099Sbloom #include "systm.h" 1117099Sbloom #include "mount.h" 1217099Sbloom #include "dir.h" 1317099Sbloom #include "user.h" 1417099Sbloom #include "inode.h" 1517099Sbloom #include "fs.h" 1617099Sbloom #include "buf.h" 1724525Sbloom #include "cmap.h" 187651Ssam #ifdef QUOTA 1917099Sbloom #include "quota.h" 207504Sroot #endif 2117099Sbloom #include "kernel.h" 22*31661Smckusick #include "malloc.h" 2324Sbill 2416840Smckusick #define INOHSZ 512 257334Skre #if ((INOHSZ&(INOHSZ-1)) == 0) 267334Skre #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 277334Skre #else 2810852Ssam #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ) 297334Skre #endif 3024Sbill 317334Skre union ihead { /* inode LRU cache, Chris Maltby */ 327334Skre union ihead *ih_head[2]; 337334Skre struct inode *ih_chain[2]; 347334Skre } ihead[INOHSZ]; 357334Skre 367334Skre struct inode *ifreeh, **ifreet; 377334Skre 3824Sbill /* 3924Sbill * Initialize hash links for inodes 4024Sbill * and build inode free list. 4124Sbill */ 4224Sbill ihinit() 4324Sbill { 4424Sbill register int i; 452737Swnj register struct inode *ip = inode; 467334Skre register union ihead *ih = ihead; 4724Sbill 487334Skre for (i = INOHSZ; --i >= 0; ih++) { 497334Skre ih->ih_head[0] = ih; 507334Skre ih->ih_head[1] = ih; 517334Skre } 527334Skre ifreeh = ip; 537334Skre ifreet = &ip->i_freef; 547334Skre ip->i_freeb = &ifreeh; 557334Skre ip->i_forw = ip; 567334Skre ip->i_back = ip; 577334Skre for (i = ninode; --i > 0; ) { 587334Skre ++ip; 597334Skre ip->i_forw = ip; 607334Skre ip->i_back = ip; 617334Skre *ifreet = ip; 627334Skre ip->i_freeb = ifreet; 637334Skre ifreet = &ip->i_freef; 647334Skre } 657334Skre ip->i_freef = NULL; 6624Sbill } 6724Sbill 687334Skre #ifdef notdef 6924Sbill /* 707334Skre * Find an inode if it is incore. 717334Skre * This is the equivalent, for inodes, 727334Skre * of ``incore'' in bio.c or ``pfind'' in subr.c. 737334Skre */ 747334Skre struct inode * 757334Skre ifind(dev, ino) 767334Skre dev_t dev; 777334Skre ino_t ino; 787334Skre { 797334Skre register struct inode *ip; 807334Skre register union ihead *ih; 817334Skre 827334Skre ih = &ihead[INOHASH(dev, ino)]; 837334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 847334Skre if (ino==ip->i_number && dev==ip->i_dev) 857334Skre return (ip); 867334Skre return ((struct inode *)0); 877334Skre } 887334Skre #endif notdef 897334Skre 907334Skre /* 9124Sbill * Look up an inode by device,inumber. 9224Sbill * If it is in core (in the inode structure), 9324Sbill * honor the locking protocol. 9424Sbill * If it is not in core, read it in from the 9524Sbill * specified device. 9624Sbill * If the inode is mounted on, perform 9724Sbill * the indicated indirection. 9824Sbill * In all cases, a pointer to a locked 9924Sbill * inode structure is returned. 10024Sbill * 10124Sbill * panic: no imt -- if the mounted file 10224Sbill * system is not in the mount table. 10324Sbill * "cannot happen" 10424Sbill */ 10524Sbill struct inode * 1066569Smckusic iget(dev, fs, ino) 1074818Swnj dev_t dev; 1086569Smckusic register struct fs *fs; 1094818Swnj ino_t ino; 11024Sbill { 1117335Skre register struct inode *ip; 1127335Skre register union ihead *ih; 11324Sbill register struct mount *mp; 11424Sbill register struct buf *bp; 11524Sbill register struct dinode *dp; 1167334Skre register struct inode *iq; 11724Sbill 11824Sbill loop: 1197334Skre ih = &ihead[INOHASH(dev, ino)]; 1207334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 1214818Swnj if (ino == ip->i_number && dev == ip->i_dev) { 12216642Ssam /* 12316642Ssam * Following is essentially an inline expanded 12416642Ssam * copy of igrab(), expanded inline for speed, 12516642Ssam * and so that the test for a mounted on inode 12616642Ssam * can be deferred until after we are sure that 12716642Ssam * the inode isn't busy. 12816642Ssam */ 1298452Sroot if ((ip->i_flag&ILOCKED) != 0) { 13024Sbill ip->i_flag |= IWANT; 13124Sbill sleep((caddr_t)ip, PINOD); 13224Sbill goto loop; 13324Sbill } 1344818Swnj if ((ip->i_flag&IMOUNT) != 0) { 1356569Smckusic for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 1367334Skre if(mp->m_inodp == ip) { 1377334Skre dev = mp->m_dev; 13831659Smckusick fs = mp->m_fs; 1397334Skre ino = ROOTINO; 1407334Skre goto loop; 1417334Skre } 14224Sbill panic("no imt"); 14324Sbill } 1447334Skre if (ip->i_count == 0) { /* ino on free list */ 1457334Skre if (iq = ip->i_freef) 1467334Skre iq->i_freeb = ip->i_freeb; 1477334Skre else 1487334Skre ifreet = ip->i_freeb; 1497334Skre *ip->i_freeb = iq; 1507334Skre ip->i_freef = NULL; 1517334Skre ip->i_freeb = NULL; 1527334Skre } 15324Sbill ip->i_count++; 1548452Sroot ip->i_flag |= ILOCKED; 15524Sbill return(ip); 15624Sbill } 1577334Skre 1587334Skre if ((ip = ifreeh) == NULL) { 1592933Swnj tablefull("inode"); 16024Sbill u.u_error = ENFILE; 16124Sbill return(NULL); 16224Sbill } 16316720Skarels if (ip->i_count) 16416720Skarels panic("free inode isn't"); 1657334Skre if (iq = ip->i_freef) 1667334Skre iq->i_freeb = &ifreeh; 1677334Skre ifreeh = iq; 1687334Skre ip->i_freef = NULL; 1697334Skre ip->i_freeb = NULL; 1707334Skre /* 1717334Skre * Now to take inode off the hash chain it was on 1727334Skre * (initially, or after an iflush, it is on a "hash chain" 1737334Skre * consisting entirely of itself, and pointed to by no-one, 1747334Skre * but that doesn't matter), and put it on the chain for 1757334Skre * its new (ino, dev) pair 1767334Skre */ 1777335Skre remque(ip); 1787335Skre insque(ip, ih); 17924Sbill ip->i_dev = dev; 1806569Smckusic ip->i_fs = fs; 18124Sbill ip->i_number = ino; 18216738Smckusick cacheinval(ip); 1838452Sroot ip->i_flag = ILOCKED; 18424Sbill ip->i_count++; 1856569Smckusic ip->i_lastr = 0; 18616720Skarels #ifdef QUOTA 18716720Skarels dqrele(ip->i_dquot); 18816720Skarels #endif 1898618Sroot bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize); 19024Sbill /* 19124Sbill * Check I/O errors 19224Sbill */ 1934818Swnj if ((bp->b_flags&B_ERROR) != 0) { 19424Sbill brelse(bp); 1957334Skre /* 1967334Skre * the inode doesn't contain anything useful, so it would 1977334Skre * be misleading to leave it on its hash chain. 1987334Skre * 'iput' will take care of putting it back on the free list. 1997334Skre */ 2007335Skre remque(ip); 2017334Skre ip->i_forw = ip; 2027334Skre ip->i_back = ip; 2037334Skre /* 2047334Skre * we also loose its inumber, just in case (as iput 2057334Skre * doesn't do that any more) - but as it isn't on its 2067334Skre * hash chain, I doubt if this is really necessary .. kre 2077334Skre * (probably the two methods are interchangable) 2087334Skre */ 2097334Skre ip->i_number = 0; 2107651Ssam #ifdef QUOTA 2117492Skre ip->i_dquot = NODQUOT; 2127492Skre #endif 21324Sbill iput(ip); 21424Sbill return(NULL); 21524Sbill } 21624Sbill dp = bp->b_un.b_dino; 2176569Smckusic dp += itoo(fs, ino); 2186569Smckusic ip->i_ic = dp->di_ic; 21924Sbill brelse(bp); 2207651Ssam #ifdef QUOTA 2217492Skre if (ip->i_mode == 0) 2227492Skre ip->i_dquot = NODQUOT; 2237492Skre else 2247492Skre ip->i_dquot = inoquota(ip); 2257492Skre #endif 2266569Smckusic return (ip); 22724Sbill } 22824Sbill 22924Sbill /* 23016642Ssam * Convert a pointer to an inode into a reference to an inode. 23116642Ssam * 23216642Ssam * This is basically the internal piece of iget (after the 23316642Ssam * inode pointer is located) but without the test for mounted 23416642Ssam * filesystems. It is caller's responsibility to check that 23516642Ssam * the inode pointer is valid. 23616642Ssam */ 23716642Ssam igrab(ip) 23816642Ssam register struct inode *ip; 23916642Ssam { 24016642Ssam while ((ip->i_flag&ILOCKED) != 0) { 24116642Ssam ip->i_flag |= IWANT; 24216642Ssam sleep((caddr_t)ip, PINOD); 24316642Ssam } 24416642Ssam if (ip->i_count == 0) { /* ino on free list */ 24516642Ssam register struct inode *iq; 24616642Ssam 24716642Ssam if (iq = ip->i_freef) 24816642Ssam iq->i_freeb = ip->i_freeb; 24916642Ssam else 25016642Ssam ifreet = ip->i_freeb; 25116642Ssam *ip->i_freeb = iq; 25216642Ssam ip->i_freef = NULL; 25316642Ssam ip->i_freeb = NULL; 25416642Ssam } 25516642Ssam ip->i_count++; 25616642Ssam ip->i_flag |= ILOCKED; 25716642Ssam } 25816642Ssam 25916642Ssam /* 26024Sbill * Decrement reference count of 26124Sbill * an inode structure. 26224Sbill * On the last reference, 26324Sbill * write the inode out and if necessary, 26424Sbill * truncate and deallocate the file. 26524Sbill */ 26624Sbill iput(ip) 2674818Swnj register struct inode *ip; 26824Sbill { 2697118Smckusick 2708452Sroot if ((ip->i_flag & ILOCKED) == 0) 2717118Smckusick panic("iput"); 27216665Smckusick IUNLOCK(ip); 2737118Smckusick irele(ip); 2747118Smckusick } 2757118Smckusick 2767118Smckusick irele(ip) 2777118Smckusick register struct inode *ip; 2787118Smckusick { 2796569Smckusic int mode; 28024Sbill 28118445Smckusick if (ip->i_count == 1) { 2828452Sroot ip->i_flag |= ILOCKED; 28318445Smckusick if (ip->i_nlink <= 0 && ip->i_fs->fs_ronly == 0) { 2849165Ssam itrunc(ip, (u_long)0); 2856569Smckusic mode = ip->i_mode; 28624Sbill ip->i_mode = 0; 2877351Skre ip->i_rdev = 0; 28824Sbill ip->i_flag |= IUPD|ICHG; 2896569Smckusic ifree(ip, ip->i_number, mode); 2907651Ssam #ifdef QUOTA 29112645Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 0); 2927492Skre dqrele(ip->i_dquot); 2937492Skre ip->i_dquot = NODQUOT; 2947492Skre #endif 29524Sbill } 2968671Sroot IUPDAT(ip, &time, &time, 0); 29716665Smckusick IUNLOCK(ip); 2987334Skre ip->i_flag = 0; 2997334Skre /* 3007334Skre * Put the inode on the end of the free list. 3017334Skre * Possibly in some cases it would be better to 3027334Skre * put the inode at the head of the free list, 3037334Skre * (eg: where i_mode == 0 || i_number == 0) 3047334Skre * but I will think about that later .. kre 3057334Skre * (i_number is rarely 0 - only after an i/o error in iget, 3067334Skre * where i_mode == 0, the inode will probably be wanted 3077334Skre * again soon for an ialloc, so possibly we should keep it) 3087334Skre */ 3097334Skre if (ifreeh) { 3107334Skre *ifreet = ip; 3117334Skre ip->i_freeb = ifreet; 31224Sbill } else { 3137334Skre ifreeh = ip; 3147334Skre ip->i_freeb = &ifreeh; 31524Sbill } 3167334Skre ip->i_freef = NULL; 3177334Skre ifreet = &ip->i_freef; 31816058Skarels } else if (!(ip->i_flag & ILOCKED)) 31916058Skarels ITIMES(ip, &time, &time); 32024Sbill ip->i_count--; 32124Sbill } 32224Sbill 32324Sbill /* 32424Sbill * Check accessed and update flags on 32524Sbill * an inode structure. 32624Sbill * If any is on, update the inode 32724Sbill * with the current time. 3281203Sbill * If waitfor is given, then must insure 3291203Sbill * i/o order so wait for write to complete. 33024Sbill */ 3311203Sbill iupdat(ip, ta, tm, waitfor) 3324818Swnj register struct inode *ip; 3338630Sroot struct timeval *ta, *tm; 3344818Swnj int waitfor; 33524Sbill { 33624Sbill register struct buf *bp; 33724Sbill struct dinode *dp; 33830749Skarels register struct fs *fs; 33924Sbill 34030749Skarels fs = ip->i_fs; 34116058Skarels if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) { 34230749Skarels if (fs->fs_ronly) 34324Sbill return; 34430749Skarels bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)), 34530749Skarels (int)fs->fs_bsize); 34624Sbill if (bp->b_flags & B_ERROR) { 34724Sbill brelse(bp); 34824Sbill return; 34924Sbill } 3504818Swnj if (ip->i_flag&IACC) 3518630Sroot ip->i_atime = ta->tv_sec; 3524818Swnj if (ip->i_flag&IUPD) 3538630Sroot ip->i_mtime = tm->tv_sec; 3544818Swnj if (ip->i_flag&ICHG) 3558106Sroot ip->i_ctime = time.tv_sec; 35616058Skarels ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 35730749Skarels dp = bp->b_un.b_dino + itoo(fs, ip->i_number); 3587343Skre dp->di_ic = ip->i_ic; 3591203Sbill if (waitfor) 3601203Sbill bwrite(bp); 3611203Sbill else 3621203Sbill bdwrite(bp); 36324Sbill } 36424Sbill } 36524Sbill 36610736Ssam #define SINGLE 0 /* index of single indirect block */ 36710736Ssam #define DOUBLE 1 /* index of double indirect block */ 36810736Ssam #define TRIPLE 2 /* index of triple indirect block */ 36924Sbill /* 3707702Ssam * Truncate the inode ip to at most 3717702Ssam * length size. Free affected disk 3727702Ssam * blocks -- the blocks of the file 3737702Ssam * are removed in reverse order. 37410736Ssam * 37510736Ssam * NB: triple indirect blocks are untested. 37624Sbill */ 37710736Ssam itrunc(oip, length) 37817942Smckusick register struct inode *oip; 3799165Ssam u_long length; 38024Sbill { 3819165Ssam register daddr_t lastblock; 38226272Skarels daddr_t bn, lbn, lastiblock[NIADDR]; 3836569Smckusic register struct fs *fs; 38410736Ssam register struct inode *ip; 38517942Smckusick struct buf *bp; 38630749Skarels int offset, osize, size, count, level; 38717942Smckusick long nblocks, blocksreleased = 0; 38817942Smckusick register int i; 38917942Smckusick dev_t dev; 39010736Ssam struct inode tip; 39117942Smckusick extern long indirtrunc(); 3929165Ssam 39313000Ssam if (oip->i_size <= length) { 39413000Ssam oip->i_flag |= ICHG|IUPD; 39513000Ssam iupdat(oip, &time, &time, 1); 3969165Ssam return; 39713000Ssam } 3981203Sbill /* 39910736Ssam * Calculate index into inode's block list of 40010736Ssam * last direct and indirect blocks (if any) 40110736Ssam * which we want to keep. Lastblock is -1 when 40210736Ssam * the file is truncated to 0. 4031203Sbill */ 40410736Ssam fs = oip->i_fs; 4059165Ssam lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 40610736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 40710736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 40810736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 40912645Ssam nblocks = btodb(fs->fs_bsize); 4106569Smckusic /* 41117942Smckusick * Update the size of the file. If the file is not being 41217942Smckusick * truncated to a block boundry, the contents of the 41317942Smckusick * partial block following the end of the file must be 41417942Smckusick * zero'ed in case it ever become accessable again because 41517942Smckusick * of subsequent file growth. 41617942Smckusick */ 41717942Smckusick osize = oip->i_size; 41817942Smckusick offset = blkoff(fs, length); 41917942Smckusick if (offset == 0) { 42017942Smckusick oip->i_size = length; 42117942Smckusick } else { 42217942Smckusick lbn = lblkno(fs, length); 42317942Smckusick bn = fsbtodb(fs, bmap(oip, lbn, B_WRITE, offset)); 42417942Smckusick if (u.u_error || (long)bn < 0) 42517942Smckusick return; 42617942Smckusick oip->i_size = length; 42717942Smckusick size = blksize(fs, oip, lbn); 42830749Skarels count = howmany(size, CLBYTES); 42917942Smckusick dev = oip->i_dev; 43030749Skarels for (i = 0; i < count; i++) 43130749Skarels munhash(dev, bn + i * CLBYTES / DEV_BSIZE); 43217942Smckusick bp = bread(dev, bn, size); 43317942Smckusick if (bp->b_flags & B_ERROR) { 43417942Smckusick u.u_error = EIO; 43517942Smckusick oip->i_size = osize; 43617942Smckusick brelse(bp); 43717942Smckusick return; 43817942Smckusick } 43926272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 44017942Smckusick 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; 46017942Smckusick syncip(oip); 46110736Ssam 4626569Smckusic /* 46310736Ssam * Indirect blocks first. 4646569Smckusic */ 46517942Smckusick ip = &tip; 46610736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 46710736Ssam bn = ip->i_ib[level]; 4689165Ssam if (bn != 0) { 46910736Ssam blocksreleased += 47012645Ssam indirtrunc(ip, bn, lastiblock[level], level); 47110736Ssam if (lastiblock[level] < 0) { 47210736Ssam ip->i_ib[level] = 0; 47331402Smckusick blkfree(ip, bn, (off_t)fs->fs_bsize); 47410736Ssam blocksreleased += nblocks; 47510736Ssam } 47610736Ssam } 47710736Ssam if (lastiblock[level] >= 0) 47810736Ssam goto done; 4799165Ssam } 48010736Ssam 4816569Smckusic /* 48210736Ssam * All whole direct blocks or frags. 4836569Smckusic */ 4849165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 48526359Skarels register off_t bsize; 4869165Ssam 4876569Smckusic bn = ip->i_db[i]; 4889165Ssam if (bn == 0) 48924Sbill continue; 4909165Ssam ip->i_db[i] = 0; 49124525Sbloom bsize = (off_t)blksize(fs, ip, i); 49231402Smckusick blkfree(ip, bn, bsize); 49324525Sbloom blocksreleased += btodb(bsize); 49424Sbill } 49510736Ssam if (lastblock < 0) 49610736Ssam goto done; 49710736Ssam 4981203Sbill /* 4999165Ssam * Finally, look for a change in size of the 5009165Ssam * last direct block; release any frags. 5011203Sbill */ 50210736Ssam bn = ip->i_db[lastblock]; 50310736Ssam if (bn != 0) { 50426359Skarels off_t oldspace, newspace; 50510736Ssam 5069165Ssam /* 5079165Ssam * Calculate amount of space we're giving 5089165Ssam * back as old block size minus new block size. 5099165Ssam */ 51010736Ssam oldspace = blksize(fs, ip, lastblock); 5119165Ssam ip->i_size = length; 51210736Ssam newspace = blksize(fs, ip, lastblock); 51310736Ssam if (newspace == 0) 51410736Ssam panic("itrunc: newspace"); 51510736Ssam if (oldspace - newspace > 0) { 5169165Ssam /* 5179165Ssam * Block number of space to be free'd is 5189165Ssam * the old block # plus the number of frags 5199165Ssam * required for the storage we're keeping. 5209165Ssam */ 52110736Ssam bn += numfrags(fs, newspace); 52231402Smckusick blkfree(ip, bn, oldspace - newspace); 52312645Ssam blocksreleased += btodb(oldspace - newspace); 5249165Ssam } 5259165Ssam } 5269165Ssam done: 52710736Ssam /* BEGIN PARANOIA */ 52810736Ssam for (level = SINGLE; level <= TRIPLE; level++) 52910736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 53010736Ssam panic("itrunc1"); 53110736Ssam for (i = 0; i < NDADDR; i++) 53210736Ssam if (ip->i_db[i] != oip->i_db[i]) 53310736Ssam panic("itrunc2"); 53410736Ssam /* END PARANOIA */ 53512645Ssam oip->i_blocks -= blocksreleased; 53612645Ssam if (oip->i_blocks < 0) /* sanity */ 53712645Ssam oip->i_blocks = 0; 53812645Ssam oip->i_flag |= ICHG; 5399165Ssam #ifdef QUOTA 54012645Ssam (void) chkdq(oip, -blocksreleased, 0); 5419165Ssam #endif 54224Sbill } 54324Sbill 5449165Ssam /* 5459165Ssam * Release blocks associated with the inode ip and 5469165Ssam * stored in the indirect block bn. Blocks are free'd 5479165Ssam * in LIFO order up to (but not including) lastbn. If 54810736Ssam * level is greater than SINGLE, the block is an indirect 54910736Ssam * block and recursive calls to indirtrunc must be used to 55010736Ssam * cleanse other indirect blocks. 55110736Ssam * 55210736Ssam * NB: triple indirect blocks are untested. 5539165Ssam */ 5547492Skre long 55510736Ssam indirtrunc(ip, bn, lastbn, level) 5566569Smckusic register struct inode *ip; 5579165Ssam daddr_t bn, lastbn; 55810736Ssam int level; 55924Sbill { 5609165Ssam register int i; 561*31661Smckusick struct buf *bp; 562*31661Smckusick register struct fs *fs = ip->i_fs; 56324Sbill register daddr_t *bap; 564*31661Smckusick daddr_t *copy, nb, last; 56510736Ssam long factor; 5669165Ssam int blocksreleased = 0, nblocks; 56724Sbill 56810736Ssam /* 56910736Ssam * Calculate index in current block of last 57010736Ssam * block to be kept. -1 indicates the entire 57110736Ssam * block so we need not calculate the index. 57210736Ssam */ 57310736Ssam factor = 1; 57410736Ssam for (i = SINGLE; i < level; i++) 57510736Ssam factor *= NINDIR(fs); 5769165Ssam last = lastbn; 57710736Ssam if (lastbn > 0) 57810736Ssam last /= factor; 57912645Ssam nblocks = btodb(fs->fs_bsize); 58010736Ssam /* 58110736Ssam * Get buffer of block pointers, zero those 58210736Ssam * entries corresponding to blocks to be free'd, 58310736Ssam * and update on disk copy first. 58410736Ssam */ 58510736Ssam bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize); 58610736Ssam if (bp->b_flags&B_ERROR) { 58710736Ssam brelse(bp); 58810736Ssam return (0); 58910736Ssam } 59010736Ssam bap = bp->b_un.b_daddr; 591*31661Smckusick MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); 592*31661Smckusick bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); 59310736Ssam bzero((caddr_t)&bap[last + 1], 59410736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 59510736Ssam bwrite(bp); 596*31661Smckusick bap = copy; 59710736Ssam 59810736Ssam /* 59910736Ssam * Recursively free totally unused blocks. 60010736Ssam */ 6019165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 60224Sbill nb = bap[i]; 6039165Ssam if (nb == 0) 60424Sbill continue; 60510736Ssam if (level > SINGLE) 6069165Ssam blocksreleased += 60712645Ssam indirtrunc(ip, nb, (daddr_t)-1, level - 1); 60831402Smckusick blkfree(ip, nb, (off_t)fs->fs_bsize); 6099165Ssam blocksreleased += nblocks; 61024Sbill } 61110736Ssam 61210736Ssam /* 61310736Ssam * Recursively free last partial block. 61410736Ssam */ 61510736Ssam if (level > SINGLE && lastbn >= 0) { 61610736Ssam last = lastbn % factor; 6179165Ssam nb = bap[i]; 6189165Ssam if (nb != 0) 61912645Ssam blocksreleased += indirtrunc(ip, nb, last, level - 1); 6209165Ssam } 621*31661Smckusick FREE(copy, M_TEMP); 6229165Ssam return (blocksreleased); 62324Sbill } 62424Sbill 62524Sbill /* 62630749Skarels * Remove any inodes in the inode cache belonging to dev. 6277334Skre * 6287334Skre * There should not be any active ones, return error if any are found 62930749Skarels * (nb: this is a user error, not a system err). 6307334Skre */ 6317651Ssam #ifdef QUOTA 6327504Sroot iflush(dev, iq) 6337492Skre dev_t dev; 6347504Sroot struct inode *iq; 6357492Skre #else 6367334Skre iflush(dev) 6377334Skre dev_t dev; 6387492Skre #endif 6397334Skre { 6407335Skre register struct inode *ip; 6417334Skre 6427334Skre for (ip = inode; ip < inodeNINODE; ip++) { 6437651Ssam #ifdef QUOTA 6447492Skre if (ip != iq && ip->i_dev == dev) 6457492Skre #else 6467334Skre if (ip->i_dev == dev) 6477492Skre #endif 6487334Skre if (ip->i_count) 64930749Skarels return (EBUSY); 6507334Skre else { 6517335Skre remque(ip); 6527334Skre ip->i_forw = ip; 6537334Skre ip->i_back = ip; 6547334Skre /* 6557334Skre * as i_count == 0, the inode was on the free 6567334Skre * list already, just leave it there, it will 6577334Skre * fall off the bottom eventually. We could 6587334Skre * perhaps move it to the head of the free 6597334Skre * list, but as umounts are done so 6607334Skre * infrequently, we would gain very little, 6617334Skre * while making the code bigger. 6627334Skre */ 6637651Ssam #ifdef QUOTA 6647492Skre dqrele(ip->i_dquot); 6657492Skre ip->i_dquot = NODQUOT; 6667492Skre #endif 6677334Skre } 6687334Skre } 66930749Skarels return (0); 6707334Skre } 6717334Skre 6723617Sroot /* 6734818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6743617Sroot */ 6754818Swnj ilock(ip) 6764818Swnj register struct inode *ip; 6773617Sroot { 6783617Sroot 6798452Sroot ILOCK(ip); 6803617Sroot } 6813617Sroot 6823617Sroot /* 6834818Swnj * Unlock an inode. If WANT bit is on, wakeup. 6843617Sroot */ 6857118Smckusick iunlock(ip) 6864818Swnj register struct inode *ip; 6873617Sroot { 6883617Sroot 6898452Sroot IUNLOCK(ip); 6903617Sroot } 691