xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 9165)
1*9165Ssam /*	lfs_inode.c	4.31	82/11/13	*/
224Sbill 
324Sbill #include "../h/param.h"
424Sbill #include "../h/systm.h"
524Sbill #include "../h/mount.h"
624Sbill #include "../h/dir.h"
724Sbill #include "../h/user.h"
824Sbill #include "../h/inode.h"
96569Smckusic #include "../h/fs.h"
1024Sbill #include "../h/conf.h"
1124Sbill #include "../h/buf.h"
127651Ssam #ifdef QUOTA
137504Sroot #include "../h/quota.h"
147504Sroot #endif
158106Sroot #include "../h/kernel.h"
1624Sbill 
1724Sbill #define	INOHSZ	63
187334Skre #if	((INOHSZ&(INOHSZ-1)) == 0)
197334Skre #define	INOHASH(dev,ino)	(((dev)+(ino))&(INOHSZ-1))
207334Skre #else
2124Sbill #define	INOHASH(dev,ino)	(((dev)+(ino))%INOHSZ)
227334Skre #endif
2324Sbill 
247334Skre union ihead {				/* inode LRU cache, Chris Maltby */
257334Skre 	union  ihead *ih_head[2];
267334Skre 	struct inode *ih_chain[2];
277334Skre } ihead[INOHSZ];
287334Skre 
297334Skre struct inode *ifreeh, **ifreet;
307334Skre 
3124Sbill /*
3224Sbill  * Initialize hash links for inodes
3324Sbill  * and build inode free list.
3424Sbill  */
3524Sbill ihinit()
3624Sbill {
3724Sbill 	register int i;
382737Swnj 	register struct inode *ip = inode;
397334Skre 	register union  ihead *ih = ihead;
4024Sbill 
417334Skre 	for (i = INOHSZ; --i >= 0; ih++) {
427334Skre 		ih->ih_head[0] = ih;
437334Skre 		ih->ih_head[1] = ih;
447334Skre 	}
457334Skre 	ifreeh = ip;
467334Skre 	ifreet = &ip->i_freef;
477334Skre 	ip->i_freeb = &ifreeh;
487334Skre 	ip->i_forw = ip;
497334Skre 	ip->i_back = ip;
507334Skre 	for (i = ninode; --i > 0; ) {
517334Skre 		++ip;
527334Skre 		ip->i_forw = ip;
537334Skre 		ip->i_back = ip;
547334Skre 		*ifreet = ip;
557334Skre 		ip->i_freeb = ifreet;
567334Skre 		ifreet = &ip->i_freef;
577334Skre 	}
587334Skre 	ip->i_freef = NULL;
5924Sbill }
6024Sbill 
617334Skre #ifdef notdef
6224Sbill /*
637334Skre  * Find an inode if it is incore.
647334Skre  * This is the equivalent, for inodes,
657334Skre  * of ``incore'' in bio.c or ``pfind'' in subr.c.
667334Skre  */
677334Skre struct inode *
687334Skre ifind(dev, ino)
697334Skre 	dev_t dev;
707334Skre 	ino_t ino;
717334Skre {
727334Skre 	register struct inode *ip;
737334Skre 	register union  ihead *ih;
747334Skre 
757334Skre 	ih = &ihead[INOHASH(dev, ino)];
767334Skre 	for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
777334Skre 		if (ino==ip->i_number && dev==ip->i_dev)
787334Skre 			return (ip);
797334Skre 	return ((struct inode *)0);
807334Skre }
817334Skre #endif notdef
827334Skre 
837334Skre /*
8424Sbill  * Look up an inode by device,inumber.
8524Sbill  * If it is in core (in the inode structure),
8624Sbill  * honor the locking protocol.
8724Sbill  * If it is not in core, read it in from the
8824Sbill  * specified device.
8924Sbill  * If the inode is mounted on, perform
9024Sbill  * the indicated indirection.
9124Sbill  * In all cases, a pointer to a locked
9224Sbill  * inode structure is returned.
9324Sbill  *
9424Sbill  * panic: no imt -- if the mounted file
9524Sbill  *	system is not in the mount table.
9624Sbill  *	"cannot happen"
9724Sbill  */
9824Sbill struct inode *
996569Smckusic iget(dev, fs, ino)
1004818Swnj 	dev_t dev;
1016569Smckusic 	register struct fs *fs;
1024818Swnj 	ino_t ino;
10324Sbill {
1047335Skre 	register struct inode *ip;
1057335Skre 	register union  ihead *ih;
10624Sbill 	register struct mount *mp;
10724Sbill 	register struct buf *bp;
10824Sbill 	register struct dinode *dp;
1097334Skre 	register struct inode *iq;
11024Sbill 
11124Sbill loop:
1126569Smckusic 	if (getfs(dev) != fs)
1136569Smckusic 		panic("iget: bad fs");
1147334Skre 	ih = &ihead[INOHASH(dev, ino)];
1157334Skre 	for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
1164818Swnj 		if (ino == ip->i_number && dev == ip->i_dev) {
1178452Sroot 			if ((ip->i_flag&ILOCKED) != 0) {
11824Sbill 				ip->i_flag |= IWANT;
11924Sbill 				sleep((caddr_t)ip, PINOD);
12024Sbill 				goto loop;
12124Sbill 			}
1224818Swnj 			if ((ip->i_flag&IMOUNT) != 0) {
1236569Smckusic 				for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
1247334Skre 					if(mp->m_inodp == ip) {
1257334Skre 						dev = mp->m_dev;
1267334Skre 						fs = mp->m_bufp->b_un.b_fs;
1277334Skre 						ino = ROOTINO;
1287334Skre 						goto loop;
1297334Skre 					}
13024Sbill 				panic("no imt");
13124Sbill 			}
1327334Skre 			if (ip->i_count == 0) {		/* ino on free list */
1337334Skre 				if (iq = ip->i_freef)
1347334Skre 					iq->i_freeb = ip->i_freeb;
1357334Skre 				else
1367334Skre 					ifreet = ip->i_freeb;
1377334Skre 				*ip->i_freeb = iq;
1387334Skre 				ip->i_freef = NULL;
1397334Skre 				ip->i_freeb = NULL;
1407334Skre 			}
14124Sbill 			ip->i_count++;
1428452Sroot 			ip->i_flag |= ILOCKED;
14324Sbill 			return(ip);
14424Sbill 		}
1457334Skre 
1467334Skre 	if ((ip = ifreeh) == NULL) {
1472933Swnj 		tablefull("inode");
14824Sbill 		u.u_error = ENFILE;
14924Sbill 		return(NULL);
15024Sbill 	}
1517334Skre 	if (iq = ip->i_freef)
1527334Skre 		iq->i_freeb = &ifreeh;
1537334Skre 	ifreeh = iq;
1547334Skre 	ip->i_freef = NULL;
1557334Skre 	ip->i_freeb = NULL;
1567334Skre 	/*
1577334Skre 	 * Now to take inode off the hash chain it was on
1587334Skre 	 * (initially, or after an iflush, it is on a "hash chain"
1597334Skre 	 * consisting entirely of itself, and pointed to by no-one,
1607334Skre 	 * but that doesn't matter), and put it on the chain for
1617334Skre 	 * its new (ino, dev) pair
1627334Skre 	 */
1637335Skre 	remque(ip);
1647335Skre 	insque(ip, ih);
1657651Ssam #ifdef QUOTA
1667492Skre 	dqrele(ip->i_dquot);
1677492Skre #endif
16824Sbill 	ip->i_dev = dev;
1696569Smckusic 	ip->i_fs = fs;
17024Sbill 	ip->i_number = ino;
1718452Sroot 	ip->i_flag = ILOCKED;
17224Sbill 	ip->i_count++;
1736569Smckusic 	ip->i_lastr = 0;
1748618Sroot 	bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize);
17524Sbill 	/*
17624Sbill 	 * Check I/O errors
17724Sbill 	 */
1784818Swnj 	if ((bp->b_flags&B_ERROR) != 0) {
17924Sbill 		brelse(bp);
1807334Skre 		/*
1817334Skre 		 * the inode doesn't contain anything useful, so it would
1827334Skre 		 * be misleading to leave it on its hash chain.
1837334Skre 		 * 'iput' will take care of putting it back on the free list.
1847334Skre 		 */
1857335Skre 		remque(ip);
1867334Skre 		ip->i_forw = ip;
1877334Skre 		ip->i_back = ip;
1887334Skre 		/*
1897334Skre 		 * we also loose its inumber, just in case (as iput
1907334Skre 		 * doesn't do that any more) - but as it isn't on its
1917334Skre 		 * hash chain, I doubt if this is really necessary .. kre
1927334Skre 		 * (probably the two methods are interchangable)
1937334Skre 		 */
1947334Skre 		ip->i_number = 0;
1957651Ssam #ifdef QUOTA
1967492Skre 		ip->i_dquot = NODQUOT;
1977492Skre #endif
19824Sbill 		iput(ip);
19924Sbill 		return(NULL);
20024Sbill 	}
20124Sbill 	dp = bp->b_un.b_dino;
2026569Smckusic 	dp += itoo(fs, ino);
2036569Smckusic 	ip->i_ic = dp->di_ic;
20424Sbill 	brelse(bp);
2057651Ssam #ifdef QUOTA
2067492Skre 	if (ip->i_mode == 0)
2077492Skre 		ip->i_dquot = NODQUOT;
2087492Skre 	else
2097492Skre 		ip->i_dquot = inoquota(ip);
2107492Skre #endif
2116569Smckusic 	return (ip);
21224Sbill }
21324Sbill 
21424Sbill /*
21524Sbill  * Decrement reference count of
21624Sbill  * an inode structure.
21724Sbill  * On the last reference,
21824Sbill  * write the inode out and if necessary,
21924Sbill  * truncate and deallocate the file.
22024Sbill  */
22124Sbill iput(ip)
2224818Swnj 	register struct inode *ip;
22324Sbill {
2247118Smckusick 
2258452Sroot 	if ((ip->i_flag & ILOCKED) == 0)
2267118Smckusick 		panic("iput");
2277118Smckusick 	iunlock(ip);
2287118Smckusick 	irele(ip);
2297118Smckusick }
2307118Smckusick 
2317118Smckusick irele(ip)
2327118Smckusick 	register struct inode *ip;
2337118Smckusick {
2346569Smckusic 	int mode;
23524Sbill 
2364818Swnj 	if (ip->i_count == 1) {
2378452Sroot 		ip->i_flag |= ILOCKED;
2384818Swnj 		if (ip->i_nlink <= 0) {
239*9165Ssam 			itrunc(ip, (u_long)0);
2406569Smckusic 			mode = ip->i_mode;
24124Sbill 			ip->i_mode = 0;
2427351Skre 			ip->i_rdev = 0;
24324Sbill 			ip->i_flag |= IUPD|ICHG;
2446569Smckusic 			ifree(ip, ip->i_number, mode);
2457651Ssam #ifdef QUOTA
246*9165Ssam 			(void)chkiq(ip->i_dev, ip, ip->i_uid, 0);
2477492Skre 			dqrele(ip->i_dquot);
2487492Skre 			ip->i_dquot = NODQUOT;
2497492Skre #endif
25024Sbill 		}
2518671Sroot 		IUPDAT(ip, &time, &time, 0);
2527118Smckusick 		iunlock(ip);
2537334Skre 		ip->i_flag = 0;
2547334Skre 		/*
2557334Skre 		 * Put the inode on the end of the free list.
2567334Skre 		 * Possibly in some cases it would be better to
2577334Skre 		 * put the inode at the head of the free list,
2587334Skre 		 * (eg: where i_mode == 0 || i_number == 0)
2597334Skre 		 * but I will think about that later .. kre
2607334Skre 		 * (i_number is rarely 0 - only after an i/o error in iget,
2617334Skre 		 * where i_mode == 0, the inode will probably be wanted
2627334Skre 		 * again soon for an ialloc, so possibly we should keep it)
2637334Skre 		 */
2647334Skre 		if (ifreeh) {
2657334Skre 			*ifreet = ip;
2667334Skre 			ip->i_freeb = ifreet;
26724Sbill 		} else {
2687334Skre 			ifreeh = ip;
2697334Skre 			ip->i_freeb = &ifreeh;
27024Sbill 		}
2717334Skre 		ip->i_freef = NULL;
2727334Skre 		ifreet = &ip->i_freef;
2737118Smckusick 	}
27424Sbill 	ip->i_count--;
27524Sbill }
27624Sbill 
27724Sbill /*
27824Sbill  * Check accessed and update flags on
27924Sbill  * an inode structure.
28024Sbill  * If any is on, update the inode
28124Sbill  * with the current time.
2821203Sbill  * If waitfor is given, then must insure
2831203Sbill  * i/o order so wait for write to complete.
28424Sbill  */
2851203Sbill iupdat(ip, ta, tm, waitfor)
2864818Swnj 	register struct inode *ip;
2878630Sroot 	struct timeval *ta, *tm;
2884818Swnj 	int waitfor;
28924Sbill {
29024Sbill 	register struct buf *bp;
29124Sbill 	struct dinode *dp;
2926569Smckusic 	register struct fs *fp;
29324Sbill 
2946569Smckusic 	fp = ip->i_fs;
2956569Smckusic 	if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) {
2966569Smckusic 		if (fp->fs_ronly)
29724Sbill 			return;
2986569Smckusic 		bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)),
2998618Sroot 			(int)fp->fs_bsize);
30024Sbill 		if (bp->b_flags & B_ERROR) {
30124Sbill 			brelse(bp);
30224Sbill 			return;
30324Sbill 		}
3044818Swnj 		if (ip->i_flag&IACC)
3058630Sroot 			ip->i_atime = ta->tv_sec;
3064818Swnj 		if (ip->i_flag&IUPD)
3078630Sroot 			ip->i_mtime = tm->tv_sec;
3084818Swnj 		if (ip->i_flag&ICHG)
3098106Sroot 			ip->i_ctime = time.tv_sec;
31024Sbill 		ip->i_flag &= ~(IUPD|IACC|ICHG);
3117343Skre 		dp = bp->b_un.b_dino + itoo(fp, ip->i_number);
3127343Skre 		dp->di_ic = ip->i_ic;
3131203Sbill 		if (waitfor)
3141203Sbill 			bwrite(bp);
3151203Sbill 		else
3161203Sbill 			bdwrite(bp);
31724Sbill 	}
31824Sbill }
31924Sbill 
32024Sbill /*
3217702Ssam  * Truncate the inode ip to at most
3227702Ssam  * length size.  Free affected disk
3237702Ssam  * blocks -- the blocks of the file
3247702Ssam  * are removed in reverse order.
32524Sbill  */
3267702Ssam itrunc(ip, length)
3274818Swnj 	register struct inode *ip;
328*9165Ssam 	u_long length;
32924Sbill {
33024Sbill 	register i;
331*9165Ssam 	register daddr_t lastblock;
332*9165Ssam 	daddr_t bn, lastdiblock, lastsiblock;
3336569Smckusic 	register struct fs *fs;
334*9165Ssam 	int j;
3357651Ssam #ifdef QUOTA
336*9165Ssam 	long blocksreleased = 0, nblocks;
337*9165Ssam 	long indirtrunc();
3387492Skre #endif
339*9165Ssam 
340*9165Ssam 	if (ip->i_size <= length)
341*9165Ssam 		return;
342*9165Ssam #ifdef notdef
343*9165Ssam 	/* this is superfluous given size check above */
3447606Ssam 	i = ip->i_mode & IFMT;
345*9165Ssam 	if (i != IFREG && i != IFDIR && i != IFLNK) {
346*9165Ssam 		printf("itrunc: i# %d, size %d\n", ip->i_number, ip->i_size);
3477606Ssam 		return;
348*9165Ssam 	}
349*9165Ssam #endif
3501203Sbill 	/*
351*9165Ssam 	 * Update size of file on disk before
352*9165Ssam 	 * we start freeing blocks.  If we crash
353*9165Ssam 	 * while free'ing blocks below, the file
354*9165Ssam 	 * size will be believed and the blocks
355*9165Ssam 	 * returned to the free list.
356*9165Ssam 	 * After updating the copy on disk we
357*9165Ssam 	 * put the old size back so macros like
358*9165Ssam 	 * blksize will work.
3591203Sbill 	 */
360*9165Ssam 	j = ip->i_size;
361*9165Ssam 	ip->i_size = length;
362*9165Ssam 	ip->i_flag |= ICHG|IUPD;
363*9165Ssam 	iupdat(ip, &time, &time, 1);
364*9165Ssam 	ip->i_size = j;
3651203Sbill 
3661203Sbill 	/*
367*9165Ssam 	 * Calculate last direct, single indirect and
368*9165Ssam 	 * double indirect block (if any) which we want
369*9165Ssam 	 * to keep.  Lastblock is -1 when the file is
370*9165Ssam 	 * truncated to 0.
3711203Sbill 	 */
3726569Smckusic 	fs = ip->i_fs;
373*9165Ssam 	lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
374*9165Ssam 	lastsiblock = lastblock - NDADDR;
375*9165Ssam 	lastdiblock = lastsiblock - NINDIR(fs);
376*9165Ssam #ifdef QUOTA
377*9165Ssam 	nblocks = fs->fs_bsize / DEV_BSIZE;
378*9165Ssam #endif
3796569Smckusic 	/*
380*9165Ssam 	 * Double indirect block first
3816569Smckusic 	 */
382*9165Ssam 	bn = ip->i_ib[NIADDR - 1];
383*9165Ssam 	if (bn != 0) {
384*9165Ssam 		/*
385*9165Ssam 		 * If lastdiblock is negative, it's value
386*9165Ssam 		 * is meaningless; in this case we set it to
387*9165Ssam 		 * -NINDIR(fs) so calculations performed in
388*9165Ssam 		 * indirtrunc come out right.
389*9165Ssam 		 */
390*9165Ssam 		if (lastdiblock < 0)
391*9165Ssam 			lastdiblock -= lastsiblock;
3927651Ssam #ifdef QUOTA
393*9165Ssam 		blocksreleased +=
3947492Skre #endif
395*9165Ssam 			indirtrunc(ip, bn, lastdiblock, 1);
396*9165Ssam 		if (lastdiblock < 0) {
397*9165Ssam 			ip->i_ib[NIADDR - 1] = 0;
398*9165Ssam 			free(ip, bn, (off_t)fs->fs_bsize);
399*9165Ssam #ifdef QUOTA
400*9165Ssam 			blocksreleased += nblocks;
401*9165Ssam #endif
402*9165Ssam 		}
4036569Smckusic 	}
404*9165Ssam 	if (lastdiblock >= 0)
405*9165Ssam 		goto done;
4066569Smckusic 	/*
407*9165Ssam 	 * Single indirect blocks second.
408*9165Ssam 	 * First, those which can be totally
409*9165Ssam 	 * zapped, then possibly one which
410*9165Ssam 	 * needs to be partially cleared.
4116569Smckusic 	 */
412*9165Ssam 	j = lastsiblock < 0 ? -1 : lastsiblock / NINDIR(fs);
413*9165Ssam 	for (i = NIADDR - 2; i > j; i--) {
4146569Smckusic 		bn = ip->i_ib[i];
415*9165Ssam 		if (bn != 0) {
4167651Ssam #ifdef QUOTA
417*9165Ssam 			blocksreleased += nblocks +
4187492Skre #endif
419*9165Ssam 				indirtrunc(ip, bn, (daddr_t)-1, 0);
420*9165Ssam 			ip->i_ib[i] = 0;
421*9165Ssam 			free(ip, bn, (off_t)fs->fs_bsize);
4226569Smckusic 		}
4236569Smckusic 	}
424*9165Ssam 	if (lastsiblock >= 0) {
425*9165Ssam 		bn = ip->i_ib[j];
426*9165Ssam 		if (bn != 0)
427*9165Ssam #ifdef QUOTA
428*9165Ssam 			blocksreleased +=
429*9165Ssam #endif
430*9165Ssam 				indirtrunc(ip, bn, lastsiblock, 0);
431*9165Ssam 		goto done;
432*9165Ssam 	}
4336569Smckusic 	/*
434*9165Ssam 	 * All whole direct blocks.
4356569Smckusic 	 */
436*9165Ssam 	for (i = NDADDR - 1; i > lastblock; i--) {
437*9165Ssam 		register int size;
438*9165Ssam 
4396569Smckusic 		bn = ip->i_db[i];
440*9165Ssam 		if (bn == 0)
44124Sbill 			continue;
442*9165Ssam 		ip->i_db[i] = 0;
443*9165Ssam 		size = (off_t)blksize(fs, ip, i);
444*9165Ssam 		free(ip, bn, size);
445*9165Ssam #ifdef QUOTA
446*9165Ssam 		blocksreleased += size / DEV_BSIZE;
4477492Skre #endif
44824Sbill 	}
4491203Sbill 	/*
450*9165Ssam 	 * Finally, look for a change in size of the
451*9165Ssam 	 * last direct block; release any frags.
4521203Sbill 	 */
453*9165Ssam 	if (lastblock >= 0 && ip->i_db[lastblock] != 0) {
454*9165Ssam 		/*
455*9165Ssam 		 * Calculate amount of space we're giving
456*9165Ssam 		 * back as old block size minus new block size.
457*9165Ssam 		 */
458*9165Ssam 		i = blksize(fs, ip, lastblock);
459*9165Ssam 		ip->i_size = length;
460*9165Ssam 		i = i - blksize(fs, ip, lastblock);
461*9165Ssam 		if (i > 0) {
462*9165Ssam 			/*
463*9165Ssam 			 * Block number of space to be free'd is
464*9165Ssam 			 * the old block # plus the number of frags
465*9165Ssam 			 * required for the storage we're keeping.
466*9165Ssam 			 */
467*9165Ssam 			bn = ip->i_db[lastblock] +
468*9165Ssam 				numfrags(fs, fs->fs_bsize - i);
469*9165Ssam 			free(ip, bn, i);
4707651Ssam #ifdef QUOTA
471*9165Ssam 			blocksreleased += i / DEV_BSIZE;
4727492Skre #endif
473*9165Ssam 		}
474*9165Ssam 	}
475*9165Ssam done:
476*9165Ssam 	/*
477*9165Ssam 	 * Finished free'ing blocks, complete
478*9165Ssam 	 * inode update to reflect new length.
479*9165Ssam 	 */
480*9165Ssam #ifdef QUOTA
481*9165Ssam 	(void) chkdq(ip, -blocksreleased, 0);
482*9165Ssam #endif
483*9165Ssam 	ip->i_size = length;
484*9165Ssam 	ip->i_flag |= ICHG|IUPD;
485*9165Ssam 	iupdat(ip, &time, &time, 1);
48624Sbill }
48724Sbill 
488*9165Ssam /*
489*9165Ssam  * Release blocks associated with the inode ip and
490*9165Ssam  * stored in the indirect block bn.  Blocks are free'd
491*9165Ssam  * in LIFO order up to (but not including) lastbn.  If
492*9165Ssam  * doubleindirect is indicated, this block is a double
493*9165Ssam  * indirect block and recursive calls to indirtrunc must
494*9165Ssam  * be used to cleanse single indirect blocks instead of
495*9165Ssam  * a simple free.
496*9165Ssam  */
4977651Ssam #ifdef QUOTA
4987492Skre long
4997492Skre #endif
500*9165Ssam indirtrunc(ip, bn, lastbn, doubleindirect)
5016569Smckusic 	register struct inode *ip;
502*9165Ssam 	daddr_t bn, lastbn;
503*9165Ssam 	int doubleindirect;
50424Sbill {
505*9165Ssam 	register int i;
506*9165Ssam 	struct buf *bp;
50724Sbill 	register daddr_t *bap;
5086569Smckusic 	register struct fs *fs;
509*9165Ssam 	daddr_t nb, last;
5107651Ssam #ifdef QUOTA
511*9165Ssam 	int blocksreleased = 0, nblocks;
5127492Skre #endif
51324Sbill 
51424Sbill 	bp = NULL;
5156569Smckusic 	fs = ip->i_fs;
516*9165Ssam 	last = lastbn;
517*9165Ssam 	if (doubleindirect)
518*9165Ssam 		last /= NINDIR(fs);
519*9165Ssam #ifdef QUOTA
520*9165Ssam 	nblocks = fs->fs_bsize / DEV_BSIZE;
521*9165Ssam #endif
522*9165Ssam 	for (i = NINDIR(fs) - 1; i > last; i--) {
5234818Swnj 		if (bp == NULL) {
524*9165Ssam 			struct buf *copy;
525*9165Ssam 
526*9165Ssam 			copy = geteblk((int)fs->fs_bsize);
5278618Sroot 			bp = bread(ip->i_dev, fsbtodb(fs, bn),
5288618Sroot 				(int)fs->fs_bsize);
529*9165Ssam 			if (bp->b_flags&B_ERROR) {
530*9165Ssam 				brelse(copy);
53124Sbill 				brelse(bp);
532*9165Ssam 				return (NULL);
53324Sbill 			}
53424Sbill 			bap = bp->b_un.b_daddr;
535*9165Ssam 			/*
536*9165Ssam 			 * Update pointers before freeing blocks.
537*9165Ssam 			 * If we crash before freeing the blocks
538*9165Ssam 			 * they'll be recovered as missing.
539*9165Ssam 			 */
540*9165Ssam 			bcopy((caddr_t)bap, (caddr_t)copy->b_un.b_daddr,
541*9165Ssam 				(u_int)fs->fs_bsize);
542*9165Ssam 			bzero((caddr_t)&bap[last + 1],
543*9165Ssam 			  (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
544*9165Ssam 			bwrite(bp);
545*9165Ssam 			bp = copy, bap = bp->b_un.b_daddr;
54624Sbill 		}
54724Sbill 		nb = bap[i];
548*9165Ssam 		if (nb == 0)
54924Sbill 			continue;
550*9165Ssam 		if (doubleindirect)
5517651Ssam #ifdef QUOTA
552*9165Ssam 			blocksreleased +=
5537492Skre #endif
554*9165Ssam 				indirtrunc(ip, nb, (daddr_t)-1, 0);
555*9165Ssam 		free(ip, nb, (int)fs->fs_bsize);
5567651Ssam #ifdef QUOTA
557*9165Ssam 		blocksreleased += nblocks;
5587492Skre #endif
55924Sbill 	}
560*9165Ssam 	if (doubleindirect && lastbn >= 0) {
561*9165Ssam 		last = lastbn % NINDIR(fs);
562*9165Ssam 		if (bp == NULL)
563*9165Ssam 			panic("indirtrunc");
564*9165Ssam 		nb = bap[i];
565*9165Ssam 		if (nb != 0)
566*9165Ssam #ifdef QUOTA
567*9165Ssam 			blocksreleased +=
568*9165Ssam #endif
569*9165Ssam 				indirtrunc(ip, nb, last, 0);
570*9165Ssam 	}
5714818Swnj 	if (bp != NULL)
57224Sbill 		brelse(bp);
5737651Ssam #ifdef QUOTA
574*9165Ssam 	return (blocksreleased);
5757492Skre #endif
57624Sbill }
57724Sbill 
57824Sbill /*
5797334Skre  * remove any inodes in the inode cache belonging to dev
5807334Skre  *
5817334Skre  * There should not be any active ones, return error if any are found
5827334Skre  * (nb: this is a user error, not a system err)
5837334Skre  *
5847334Skre  * Also, count the references to dev by block devices - this really
5857334Skre  * has nothing to do with the object of the procedure, but as we have
5867334Skre  * to scan the inode table here anyway, we might as well get the
5877334Skre  * extra benefit.
5887334Skre  *
5897334Skre  * this is called from sumount()/sys3.c when dev is being unmounted
5907334Skre  */
5917651Ssam #ifdef QUOTA
5927504Sroot iflush(dev, iq)
5937492Skre 	dev_t dev;
5947504Sroot 	struct inode *iq;
5957492Skre #else
5967334Skre iflush(dev)
5977334Skre 	dev_t dev;
5987492Skre #endif
5997334Skre {
6007335Skre 	register struct inode *ip;
6017334Skre 	register open = 0;
6027334Skre 
6037334Skre 	for (ip = inode; ip < inodeNINODE; ip++) {
6047651Ssam #ifdef QUOTA
6057492Skre 		if (ip != iq && ip->i_dev == dev)
6067492Skre #else
6077334Skre 		if (ip->i_dev == dev)
6087492Skre #endif
6097334Skre 			if (ip->i_count)
6107334Skre 				return(-1);
6117334Skre 			else {
6127335Skre 				remque(ip);
6137334Skre 				ip->i_forw = ip;
6147334Skre 				ip->i_back = ip;
6157334Skre 				/*
6167334Skre 				 * as i_count == 0, the inode was on the free
6177334Skre 				 * list already, just leave it there, it will
6187334Skre 				 * fall off the bottom eventually. We could
6197334Skre 				 * perhaps move it to the head of the free
6207334Skre 				 * list, but as umounts are done so
6217334Skre 				 * infrequently, we would gain very little,
6227334Skre 				 * while making the code bigger.
6237334Skre 				 */
6247651Ssam #ifdef QUOTA
6257492Skre 				dqrele(ip->i_dquot);
6267492Skre 				ip->i_dquot = NODQUOT;
6277492Skre #endif
6287334Skre 			}
6297334Skre 		else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK &&
6307334Skre 		    ip->i_rdev == dev)
6317334Skre 			open++;
6327334Skre 	}
6337334Skre 	return (open);
6347334Skre }
6357334Skre 
6363617Sroot /*
6374818Swnj  * Lock an inode. If its already locked, set the WANT bit and sleep.
6383617Sroot  */
6394818Swnj ilock(ip)
6404818Swnj 	register struct inode *ip;
6413617Sroot {
6423617Sroot 
6438452Sroot 	ILOCK(ip);
6443617Sroot }
6453617Sroot 
6463617Sroot /*
6474818Swnj  * Unlock an inode.  If WANT bit is on, wakeup.
6483617Sroot  */
6497118Smckusick iunlock(ip)
6504818Swnj 	register struct inode *ip;
6513617Sroot {
6523617Sroot 
6538452Sroot 	IUNLOCK(ip);
6543617Sroot }
655