xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 7492)
1*7492Skre /*	lfs_inode.c	4.18	82/07/22	*/
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"
1224Sbill #include "../h/inline.h"
1324Sbill 
1424Sbill #define	INOHSZ	63
157334Skre #if	((INOHSZ&(INOHSZ-1)) == 0)
167334Skre #define	INOHASH(dev,ino)	(((dev)+(ino))&(INOHSZ-1))
177334Skre #else
1824Sbill #define	INOHASH(dev,ino)	(((dev)+(ino))%INOHSZ)
197334Skre #endif
2024Sbill 
217334Skre union ihead {				/* inode LRU cache, Chris Maltby */
227334Skre 	union  ihead *ih_head[2];
237334Skre 	struct inode *ih_chain[2];
247334Skre } ihead[INOHSZ];
257334Skre 
267334Skre struct inode *ifreeh, **ifreet;
277334Skre 
2824Sbill /*
2924Sbill  * Initialize hash links for inodes
3024Sbill  * and build inode free list.
3124Sbill  */
3224Sbill ihinit()
3324Sbill {
3424Sbill 	register int i;
352737Swnj 	register struct inode *ip = inode;
367334Skre 	register union  ihead *ih = ihead;
3724Sbill 
387334Skre 	for (i = INOHSZ; --i >= 0; ih++) {
397334Skre 		ih->ih_head[0] = ih;
407334Skre 		ih->ih_head[1] = ih;
417334Skre 	}
427334Skre 	ifreeh = ip;
437334Skre 	ifreet = &ip->i_freef;
447334Skre 	ip->i_freeb = &ifreeh;
457334Skre 	ip->i_forw = ip;
467334Skre 	ip->i_back = ip;
477334Skre 	for (i = ninode; --i > 0; ) {
487334Skre 		++ip;
497334Skre 		ip->i_forw = ip;
507334Skre 		ip->i_back = ip;
517334Skre 		*ifreet = ip;
527334Skre 		ip->i_freeb = ifreet;
537334Skre 		ifreet = &ip->i_freef;
547334Skre 	}
557334Skre 	ip->i_freef = NULL;
5624Sbill }
5724Sbill 
587334Skre #ifdef notdef
5924Sbill /*
607334Skre  * Find an inode if it is incore.
617334Skre  * This is the equivalent, for inodes,
627334Skre  * of ``incore'' in bio.c or ``pfind'' in subr.c.
637334Skre  */
647334Skre struct inode *
657334Skre ifind(dev, ino)
667334Skre 	dev_t dev;
677334Skre 	ino_t ino;
687334Skre {
697334Skre 	register struct inode *ip;
707334Skre 	register union  ihead *ih;
717334Skre 
727334Skre 	ih = &ihead[INOHASH(dev, ino)];
737334Skre 	for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
747334Skre 		if (ino==ip->i_number && dev==ip->i_dev)
757334Skre 			return (ip);
767334Skre 	return ((struct inode *)0);
777334Skre }
787334Skre #endif notdef
797334Skre 
807334Skre /*
8124Sbill  * Look up an inode by device,inumber.
8224Sbill  * If it is in core (in the inode structure),
8324Sbill  * honor the locking protocol.
8424Sbill  * If it is not in core, read it in from the
8524Sbill  * specified device.
8624Sbill  * If the inode is mounted on, perform
8724Sbill  * the indicated indirection.
8824Sbill  * In all cases, a pointer to a locked
8924Sbill  * inode structure is returned.
9024Sbill  *
9124Sbill  * panic: no imt -- if the mounted file
9224Sbill  *	system is not in the mount table.
9324Sbill  *	"cannot happen"
9424Sbill  */
9524Sbill struct inode *
966569Smckusic iget(dev, fs, ino)
974818Swnj 	dev_t dev;
986569Smckusic 	register struct fs *fs;
994818Swnj 	ino_t ino;
10024Sbill {
1017335Skre 	register struct inode *ip;
1027335Skre 	register union  ihead *ih;
10324Sbill 	register struct mount *mp;
10424Sbill 	register struct buf *bp;
10524Sbill 	register struct dinode *dp;
1067334Skre 	register struct inode *iq;
10724Sbill 
10824Sbill loop:
1096569Smckusic 	if (getfs(dev) != fs)
1106569Smckusic 		panic("iget: bad fs");
1117334Skre 	ih = &ihead[INOHASH(dev, ino)];
1127334Skre 	for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
1134818Swnj 		if (ino == ip->i_number && dev == ip->i_dev) {
1144818Swnj 			if ((ip->i_flag&ILOCK) != 0) {
11524Sbill 				ip->i_flag |= IWANT;
11624Sbill 				sleep((caddr_t)ip, PINOD);
11724Sbill 				goto loop;
11824Sbill 			}
1194818Swnj 			if ((ip->i_flag&IMOUNT) != 0) {
1206569Smckusic 				for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
1217334Skre 					if(mp->m_inodp == ip) {
1227334Skre 						dev = mp->m_dev;
1237334Skre 						fs = mp->m_bufp->b_un.b_fs;
1247334Skre 						ino = ROOTINO;
1257334Skre 						goto loop;
1267334Skre 					}
12724Sbill 				panic("no imt");
12824Sbill 			}
1297334Skre 			if (ip->i_count == 0) {		/* ino on free list */
1307334Skre 				if (iq = ip->i_freef)
1317334Skre 					iq->i_freeb = ip->i_freeb;
1327334Skre 				else
1337334Skre 					ifreet = ip->i_freeb;
1347334Skre 				*ip->i_freeb = iq;
1357334Skre 				ip->i_freef = NULL;
1367334Skre 				ip->i_freeb = NULL;
1377334Skre 			}
13824Sbill 			ip->i_count++;
13924Sbill 			ip->i_flag |= ILOCK;
14024Sbill 			return(ip);
14124Sbill 		}
1427334Skre 
1437334Skre 	if ((ip = ifreeh) == NULL) {
1442933Swnj 		tablefull("inode");
14524Sbill 		u.u_error = ENFILE;
14624Sbill 		return(NULL);
14724Sbill 	}
1487334Skre 	if (iq = ip->i_freef)
1497334Skre 		iq->i_freeb = &ifreeh;
1507334Skre 	ifreeh = iq;
1517334Skre 	ip->i_freef = NULL;
1527334Skre 	ip->i_freeb = NULL;
1537334Skre 	/*
1547334Skre 	 * Now to take inode off the hash chain it was on
1557334Skre 	 * (initially, or after an iflush, it is on a "hash chain"
1567334Skre 	 * consisting entirely of itself, and pointed to by no-one,
1577334Skre 	 * but that doesn't matter), and put it on the chain for
1587334Skre 	 * its new (ino, dev) pair
1597334Skre 	 */
1607335Skre 	remque(ip);
1617335Skre 	insque(ip, ih);
162*7492Skre #ifdef	QUOTA
163*7492Skre 	dqrele(ip->i_dquot);
164*7492Skre #endif
16524Sbill 	ip->i_dev = dev;
1666569Smckusic 	ip->i_fs = fs;
16724Sbill 	ip->i_number = ino;
16824Sbill 	ip->i_flag = ILOCK;
16924Sbill 	ip->i_count++;
1706569Smckusic 	ip->i_lastr = 0;
1716569Smckusic 	bp = bread(dev, fsbtodb(fs, itod(fs, ino)), fs->fs_bsize);
17224Sbill 	/*
17324Sbill 	 * Check I/O errors
17424Sbill 	 */
1754818Swnj 	if ((bp->b_flags&B_ERROR) != 0) {
17624Sbill 		brelse(bp);
1777334Skre 		/*
1787334Skre 		 * the inode doesn't contain anything useful, so it would
1797334Skre 		 * be misleading to leave it on its hash chain.
1807334Skre 		 * 'iput' will take care of putting it back on the free list.
1817334Skre 		 */
1827335Skre 		remque(ip);
1837334Skre 		ip->i_forw = ip;
1847334Skre 		ip->i_back = ip;
1857334Skre 		/*
1867334Skre 		 * we also loose its inumber, just in case (as iput
1877334Skre 		 * doesn't do that any more) - but as it isn't on its
1887334Skre 		 * hash chain, I doubt if this is really necessary .. kre
1897334Skre 		 * (probably the two methods are interchangable)
1907334Skre 		 */
1917334Skre 		ip->i_number = 0;
192*7492Skre #ifdef	QUOTA
193*7492Skre 		ip->i_dquot = NODQUOT;
194*7492Skre #endif
19524Sbill 		iput(ip);
19624Sbill 		return(NULL);
19724Sbill 	}
19824Sbill 	dp = bp->b_un.b_dino;
1996569Smckusic 	dp += itoo(fs, ino);
2006569Smckusic 	ip->i_ic = dp->di_ic;
20124Sbill 	brelse(bp);
202*7492Skre #ifdef	QUOTA
203*7492Skre 	if (ip->i_mode == 0)
204*7492Skre 		ip->i_dquot = NODQUOT;
205*7492Skre 	else
206*7492Skre 		ip->i_dquot = inoquota(ip);
207*7492Skre #endif
2086569Smckusic 	return (ip);
20924Sbill }
21024Sbill 
21124Sbill /*
21224Sbill  * Decrement reference count of
21324Sbill  * an inode structure.
21424Sbill  * On the last reference,
21524Sbill  * write the inode out and if necessary,
21624Sbill  * truncate and deallocate the file.
21724Sbill  */
21824Sbill iput(ip)
2194818Swnj 	register struct inode *ip;
22024Sbill {
2217118Smckusick 
2227118Smckusick 	if ((ip->i_flag & ILOCK) == 0)
2237118Smckusick 		panic("iput");
2247118Smckusick 	iunlock(ip);
2257118Smckusick 	irele(ip);
2267118Smckusick }
2277118Smckusick 
2287118Smckusick irele(ip)
2297118Smckusick 	register struct inode *ip;
2307118Smckusick {
23124Sbill 	register int i, x;
23224Sbill 	register struct inode *jp;
2336569Smckusic 	int mode;
23424Sbill 
2354818Swnj 	if (ip->i_count == 1) {
23624Sbill 		ip->i_flag |= ILOCK;
2374818Swnj 		if (ip->i_nlink <= 0) {
23824Sbill 			itrunc(ip);
2396569Smckusic 			mode = ip->i_mode;
24024Sbill 			ip->i_mode = 0;
2417351Skre 			ip->i_rdev = 0;
24224Sbill 			ip->i_flag |= IUPD|ICHG;
2436569Smckusic 			ifree(ip, ip->i_number, mode);
244*7492Skre #ifdef	QUOTA
245*7492Skre 			chkiq(ip->i_dev, ip, ip->i_uid, 0);
246*7492Skre 			dqrele(ip->i_dquot);
247*7492Skre 			ip->i_dquot = NODQUOT;
248*7492Skre #endif
24924Sbill 		}
2501203Sbill 		IUPDAT(ip, &time, &time, 0);
2517118Smckusick 		iunlock(ip);
2527334Skre 		ip->i_flag = 0;
2537334Skre 		/*
2547334Skre 		 * Put the inode on the end of the free list.
2557334Skre 		 * Possibly in some cases it would be better to
2567334Skre 		 * put the inode at the head of the free list,
2577334Skre 		 * (eg: where i_mode == 0 || i_number == 0)
2587334Skre 		 * but I will think about that later .. kre
2597334Skre 		 * (i_number is rarely 0 - only after an i/o error in iget,
2607334Skre 		 * where i_mode == 0, the inode will probably be wanted
2617334Skre 		 * again soon for an ialloc, so possibly we should keep it)
2627334Skre 		 */
2637334Skre 		if (ifreeh) {
2647334Skre 			*ifreet = ip;
2657334Skre 			ip->i_freeb = ifreet;
26624Sbill 		} else {
2677334Skre 			ifreeh = ip;
2687334Skre 			ip->i_freeb = &ifreeh;
26924Sbill 		}
2707334Skre 		ip->i_freef = NULL;
2717334Skre 		ifreet = &ip->i_freef;
2727118Smckusick 	}
27324Sbill 	ip->i_count--;
27424Sbill }
27524Sbill 
27624Sbill /*
27724Sbill  * Check accessed and update flags on
27824Sbill  * an inode structure.
27924Sbill  * If any is on, update the inode
28024Sbill  * with the current time.
2811203Sbill  * If waitfor is given, then must insure
2821203Sbill  * i/o order so wait for write to complete.
28324Sbill  */
2841203Sbill iupdat(ip, ta, tm, waitfor)
2854818Swnj 	register struct inode *ip;
2864818Swnj 	time_t *ta, *tm;
2874818Swnj 	int waitfor;
28824Sbill {
28924Sbill 	register struct buf *bp;
29024Sbill 	struct dinode *dp;
2916569Smckusic 	register struct fs *fp;
29224Sbill 
2936569Smckusic 	fp = ip->i_fs;
2946569Smckusic 	if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) {
2956569Smckusic 		if (fp->fs_ronly)
29624Sbill 			return;
2976569Smckusic 		bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)),
2986569Smckusic 			fp->fs_bsize);
29924Sbill 		if (bp->b_flags & B_ERROR) {
30024Sbill 			brelse(bp);
30124Sbill 			return;
30224Sbill 		}
3034818Swnj 		if (ip->i_flag&IACC)
3046569Smckusic 			ip->i_atime = *ta;
3054818Swnj 		if (ip->i_flag&IUPD)
3066569Smckusic 			ip->i_mtime = *tm;
3074818Swnj 		if (ip->i_flag&ICHG)
3086569Smckusic 			ip->i_ctime = time;
30924Sbill 		ip->i_flag &= ~(IUPD|IACC|ICHG);
3107343Skre 		dp = bp->b_un.b_dino + itoo(fp, ip->i_number);
3117343Skre 		dp->di_ic = ip->i_ic;
3121203Sbill 		if (waitfor)
3131203Sbill 			bwrite(bp);
3141203Sbill 		else
3151203Sbill 			bdwrite(bp);
31624Sbill 	}
31724Sbill }
31824Sbill 
31924Sbill /*
32024Sbill  * Free all the disk blocks associated
32124Sbill  * with the specified inode structure.
32224Sbill  * The blocks of the file are removed
32324Sbill  * in reverse order. This FILO
32424Sbill  * algorithm will tend to maintain
32524Sbill  * a contiguous free list much longer
32624Sbill  * than FIFO.
32724Sbill  */
32824Sbill itrunc(ip)
3294818Swnj 	register struct inode *ip;
33024Sbill {
33124Sbill 	register i;
33224Sbill 	dev_t dev;
33324Sbill 	daddr_t bn;
3341203Sbill 	struct inode itmp;
3356569Smckusic 	register struct fs *fs;
336*7492Skre #ifdef	QUOTA
337*7492Skre 	register long cnt = 0;
338*7492Skre 	long tloop();
339*7492Skre #endif
34024Sbill 
3411203Sbill 	/*
3421203Sbill 	 * Clean inode on disk before freeing blocks
3431203Sbill 	 * to insure no duplicates if system crashes.
3441203Sbill 	 */
3451203Sbill 	itmp = *ip;
3461203Sbill 	itmp.i_size = 0;
3476569Smckusic 	for (i = 0; i < NDADDR; i++)
3486569Smckusic 		itmp.i_db[i] = 0;
3496569Smckusic 	for (i = 0; i < NIADDR; i++)
3506569Smckusic 		itmp.i_ib[i] = 0;
3511203Sbill 	itmp.i_flag |= ICHG|IUPD;
3521203Sbill 	iupdat(&itmp, &time, &time, 1);
3531203Sbill 	ip->i_flag &= ~(IUPD|IACC|ICHG);
3541203Sbill 
3551203Sbill 	/*
3567341Sroot 	 * Only plain files, directories and symbolic
3577341Sroot 	 * links contain blocks.
3587341Sroot 	 */
3597341Sroot 	i = ip->i_mode & IFMT;
3607341Sroot 	if (i != IFREG && i != IFDIR && i != IFLNK)
3617341Sroot 		return;
3627341Sroot 	/*
3631203Sbill 	 * Now return blocks to free list... if machine
3641203Sbill 	 * crashes, they will be harmless MISSING blocks.
3651203Sbill 	 */
36624Sbill 	dev = ip->i_dev;
3676569Smckusic 	fs = ip->i_fs;
3686569Smckusic 	/*
3696569Smckusic 	 * release double indirect block first
3706569Smckusic 	 */
3716569Smckusic 	bn = ip->i_ib[NIADDR-1];
3726569Smckusic 	if (bn != (daddr_t)0) {
3736569Smckusic 		ip->i_ib[NIADDR - 1] = (daddr_t)0;
374*7492Skre #ifdef	QUOTA
375*7492Skre 		cnt +=
376*7492Skre #endif
377*7492Skre 			tloop(ip, bn, 1);
3786569Smckusic 	}
3796569Smckusic 	/*
3806569Smckusic 	 * release single indirect blocks second
3816569Smckusic 	 */
3826569Smckusic 	for (i = NIADDR - 2; i >= 0; i--) {
3836569Smckusic 		bn = ip->i_ib[i];
3846569Smckusic 		if (bn != (daddr_t)0) {
3856569Smckusic 			ip->i_ib[i] = (daddr_t)0;
386*7492Skre #ifdef	QUOTA
387*7492Skre 			cnt +=
388*7492Skre #endif
389*7492Skre 				tloop(ip, bn, 0);
3906569Smckusic 		}
3916569Smckusic 	}
3926569Smckusic 	/*
3936569Smckusic 	 * finally release direct blocks
3946569Smckusic 	 */
3956569Smckusic 	for (i = NDADDR - 1; i>=0; i--) {
396*7492Skre 		register size;
397*7492Skre 
3986569Smckusic 		bn = ip->i_db[i];
3994818Swnj 		if (bn == (daddr_t)0)
40024Sbill 			continue;
4016569Smckusic 		ip->i_db[i] = (daddr_t)0;
402*7492Skre 		fre(ip, bn, size = (off_t)blksize(fs, ip, i));
403*7492Skre #ifdef	QUOTA
404*7492Skre 		cnt += size / DEV_BSIZE;
405*7492Skre #endif
40624Sbill 	}
40724Sbill 	ip->i_size = 0;
4081203Sbill 	/*
4091203Sbill 	 * Inode was written and flags updated above.
4101203Sbill 	 * No need to modify flags here.
4111203Sbill 	 */
412*7492Skre #ifdef	QUOTA
413*7492Skre 	(void) chkdq(ip, -cnt, 0);
414*7492Skre #endif
41524Sbill }
41624Sbill 
417*7492Skre #ifdef	QUOTA
418*7492Skre long
419*7492Skre #endif
4206569Smckusic tloop(ip, bn, indflg)
4216569Smckusic 	register struct inode *ip;
4226569Smckusic 	daddr_t bn;
4236569Smckusic 	int indflg;
42424Sbill {
42524Sbill 	register i;
42624Sbill 	register struct buf *bp;
42724Sbill 	register daddr_t *bap;
4286569Smckusic 	register struct fs *fs;
42924Sbill 	daddr_t nb;
430*7492Skre #ifdef	QUOTA
431*7492Skre 	register long cnt = 0;
432*7492Skre #endif
43324Sbill 
43424Sbill 	bp = NULL;
4356569Smckusic 	fs = ip->i_fs;
4366569Smckusic 	for (i = NINDIR(fs) - 1; i >= 0; i--) {
4374818Swnj 		if (bp == NULL) {
4386569Smckusic 			bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize);
43924Sbill 			if (bp->b_flags & B_ERROR) {
44024Sbill 				brelse(bp);
44124Sbill 				return;
44224Sbill 			}
44324Sbill 			bap = bp->b_un.b_daddr;
44424Sbill 		}
44524Sbill 		nb = bap[i];
4464818Swnj 		if (nb == (daddr_t)0)
44724Sbill 			continue;
448*7492Skre 		if (indflg) {
449*7492Skre #ifdef	QUOTA
450*7492Skre 			cnt +=
451*7492Skre #endif
452*7492Skre 				tloop(ip, nb, 0);
453*7492Skre 		} else {
4546569Smckusic 			fre(ip, nb, fs->fs_bsize);
455*7492Skre #ifdef	QUOTA
456*7492Skre 			cnt += fs->fs_bsize / DEV_BSIZE;
457*7492Skre #endif
458*7492Skre 		}
45924Sbill 	}
4604818Swnj 	if (bp != NULL)
46124Sbill 		brelse(bp);
4626569Smckusic 	fre(ip, bn, fs->fs_bsize);
463*7492Skre #ifdef	QUOTA
464*7492Skre 	cnt += fs->fs_bsize / DEV_BSIZE;
465*7492Skre 	return(cnt);
466*7492Skre #endif
46724Sbill }
46824Sbill 
46924Sbill /*
47024Sbill  * Make a new file.
47124Sbill  */
47224Sbill struct inode *
47324Sbill maknode(mode)
4746569Smckusic 	int mode;
47524Sbill {
47624Sbill 	register struct inode *ip;
4776569Smckusic 	ino_t ipref;
47824Sbill 
4796569Smckusic 	if ((mode & IFMT) == IFDIR)
4806569Smckusic 		ipref = dirpref(u.u_pdir->i_fs);
4816569Smckusic 	else
4826569Smckusic 		ipref = u.u_pdir->i_number;
4836569Smckusic 	ip = ialloc(u.u_pdir, ipref, mode);
4844818Swnj 	if (ip == NULL) {
48524Sbill 		iput(u.u_pdir);
48624Sbill 		return(NULL);
48724Sbill 	}
488*7492Skre #ifdef	QUOTA
489*7492Skre 	if (ip->i_dquot != NODQUOT)
490*7492Skre 		panic("maknode: dquot");
491*7492Skre #endif
49224Sbill 	ip->i_flag |= IACC|IUPD|ICHG;
4936569Smckusic 	if ((mode & IFMT) == 0)
49424Sbill 		mode |= IFREG;
49524Sbill 	ip->i_mode = mode & ~u.u_cmask;
49624Sbill 	ip->i_nlink = 1;
49724Sbill 	ip->i_uid = u.u_uid;
4985855Swnj 	ip->i_gid = u.u_pdir->i_gid;
499*7492Skre #ifdef	QUOTA
500*7492Skre 	ip->i_dquot = inoquota(ip);
501*7492Skre #endif
5021203Sbill 
5031203Sbill 	/*
5041203Sbill 	 * Make sure inode goes to disk before directory entry.
5051203Sbill 	 */
5061203Sbill 	iupdat(ip, &time, &time, 1);
50724Sbill 	wdir(ip);
5086569Smckusic 	if (u.u_error) {
5096569Smckusic 		/*
5106569Smckusic 		 * write error occurred trying to update directory
5116569Smckusic 		 * so must deallocate the inode
5126569Smckusic 		 */
5136569Smckusic 		ip->i_nlink = 0;
5146569Smckusic 		ip->i_flag |= ICHG;
5156569Smckusic 		iput(ip);
5166569Smckusic 		return(NULL);
5176569Smckusic 	}
51824Sbill 	return(ip);
51924Sbill }
52024Sbill 
52124Sbill /*
52224Sbill  * Write a directory entry with
52324Sbill  * parameters left as side effects
52424Sbill  * to a call to namei.
52524Sbill  */
52624Sbill wdir(ip)
5274818Swnj 	struct inode *ip;
52824Sbill {
5296569Smckusic 	register struct direct *dp, *ndp;
5306569Smckusic 	struct fs *fs;
5316569Smckusic 	struct buf *bp;
5326569Smckusic 	int lbn, bn, base;
5336569Smckusic 	int loc, dsize, spccnt, newsize;
5346569Smckusic 	char *dirbuf;
53524Sbill 
53624Sbill 	u.u_dent.d_ino = ip->i_number;
53724Sbill 	u.u_segflg = 1;
5386569Smckusic 	newsize = DIRSIZ(&u.u_dent);
5396569Smckusic 	/*
5406569Smckusic 	 * if u.u_count == 0, a new directory block must be allocated.
5416569Smckusic 	 */
5426569Smckusic 	if (u.u_count == 0) {
5436569Smckusic 		u.u_dent.d_reclen = DIRBLKSIZ;
5446569Smckusic 		u.u_count = newsize;
5456569Smckusic 		u.u_base = (caddr_t)&u.u_dent;
5466569Smckusic 		writei(u.u_pdir);
5476569Smckusic 		iput(u.u_pdir);
5486569Smckusic 		return;
5496569Smckusic 	}
5506569Smckusic 	/*
5516569Smckusic 	 * must read in an existing directory block
5526569Smckusic 	 * to prepare to place the new entry into it.
5536569Smckusic 	 */
5546569Smckusic 	fs = u.u_pdir->i_fs;
5556569Smckusic 	lbn = lblkno(fs, u.u_offset);
5566569Smckusic 	base = blkoff(fs, u.u_offset);
5576569Smckusic 	bn = fsbtodb(fs, bmap(u.u_pdir, lbn, B_WRITE, base + u.u_count));
5586569Smckusic 	if (u.u_offset + u.u_count > u.u_pdir->i_size)
5596569Smckusic 		u.u_pdir->i_size = u.u_offset + u.u_count;
5606569Smckusic 	bp = bread(u.u_pdir->i_dev, bn, blksize(fs, u.u_pdir, lbn));
5616569Smckusic 	if (bp->b_flags & B_ERROR) {
5626569Smckusic 		brelse(bp);
5636569Smckusic 		return;
5646569Smckusic 	}
5656569Smckusic 	dirbuf = bp->b_un.b_addr + base;
5666569Smckusic 	dp = (struct direct *)dirbuf;
5676569Smckusic 	dsize = DIRSIZ(dp);
5686569Smckusic 	spccnt = dp->d_reclen - dsize;
5696569Smckusic 	/*
5706569Smckusic 	 * if there is insufficient room to make an entry at this point
5716569Smckusic 	 * namei insures that compacting from u.u_offset for u.u_count
5726569Smckusic 	 * bytes will provide the necessary space.
5736569Smckusic 	 */
5746569Smckusic 	for (loc = dp->d_reclen; loc < u.u_count; ) {
5756569Smckusic 		ndp = (struct direct *)(dirbuf + loc);
5766569Smckusic 		if (dp->d_ino == 0) {
5776569Smckusic 			spccnt += dsize;
5786569Smckusic 		} else {
5796569Smckusic 			dp->d_reclen = dsize;
5806569Smckusic 			dp = (struct direct *)((char *)dp + dsize);
5816569Smckusic 		}
5826569Smckusic 		dsize = DIRSIZ(ndp);
5836569Smckusic 		spccnt += ndp->d_reclen - dsize;
5846569Smckusic 		loc += ndp->d_reclen;
5856569Smckusic 		bcopy(ndp, dp, dsize);
5866569Smckusic 	}
5876569Smckusic 	/*
5886569Smckusic 	 * Update the pointer fields in the previous entry (if any),
5896569Smckusic 	 * copy in the new entry, and write out the block.
5906569Smckusic 	 */
5916569Smckusic 	if (dp->d_ino == 0) {
5926569Smckusic 		if (spccnt + dsize < newsize)
5936569Smckusic 			panic("wdir: compact failed");
5946569Smckusic 		u.u_dent.d_reclen = spccnt + dsize;
5956569Smckusic 	} else {
5966569Smckusic 		if (spccnt < newsize)
5976569Smckusic 			panic("wdir: compact failed");
5986569Smckusic 		u.u_dent.d_reclen = spccnt;
5996569Smckusic 		dp->d_reclen = dsize;
6006569Smckusic 		dp = (struct direct *)((char *)dp + dsize);
6016569Smckusic 	}
6026569Smckusic 	bcopy(&u.u_dent, dp, newsize);
6036569Smckusic 	bwrite(bp);
6046569Smckusic 	u.u_pdir->i_flag |= IUPD|ICHG;
60524Sbill 	iput(u.u_pdir);
60624Sbill }
6073617Sroot 
6087334Skre /*
6097334Skre  * remove any inodes in the inode cache belonging to dev
6107334Skre  *
6117334Skre  * There should not be any active ones, return error if any are found
6127334Skre  * (nb: this is a user error, not a system err)
6137334Skre  *
6147334Skre  * Also, count the references to dev by block devices - this really
6157334Skre  * has nothing to do with the object of the procedure, but as we have
6167334Skre  * to scan the inode table here anyway, we might as well get the
6177334Skre  * extra benefit.
6187334Skre  *
6197334Skre  * this is called from sumount()/sys3.c when dev is being unmounted
6207334Skre  */
621*7492Skre #ifdef	QUOTA
622*7492Skre iflush(dev, qi);
623*7492Skre 	dev_t dev;
624*7492Skre 	struct inode *qi;
625*7492Skre #else
6267334Skre iflush(dev)
6277334Skre 	dev_t dev;
628*7492Skre #endif
6297334Skre {
6307335Skre 	register struct inode *ip;
6317334Skre 	register open = 0;
6327334Skre 
6337334Skre 	for (ip = inode; ip < inodeNINODE; ip++) {
634*7492Skre #ifdef	QUOTA
635*7492Skre 		if (ip != iq && ip->i_dev == dev)
636*7492Skre #else
6377334Skre 		if (ip->i_dev == dev)
638*7492Skre #endif
6397334Skre 			if (ip->i_count)
6407334Skre 				return(-1);
6417334Skre 			else {
6427335Skre 				remque(ip);
6437334Skre 				ip->i_forw = ip;
6447334Skre 				ip->i_back = ip;
6457334Skre 				/*
6467334Skre 				 * as i_count == 0, the inode was on the free
6477334Skre 				 * list already, just leave it there, it will
6487334Skre 				 * fall off the bottom eventually. We could
6497334Skre 				 * perhaps move it to the head of the free
6507334Skre 				 * list, but as umounts are done so
6517334Skre 				 * infrequently, we would gain very little,
6527334Skre 				 * while making the code bigger.
6537334Skre 				 */
654*7492Skre #ifdef	QUOTA
655*7492Skre 				dqrele(ip->i_dquot);
656*7492Skre 				ip->i_dquot = NODQUOT;
657*7492Skre #endif
6587334Skre 			}
6597334Skre 		else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK &&
6607334Skre 		    ip->i_rdev == dev)
6617334Skre 			open++;
6627334Skre 	}
6637334Skre 	return (open);
6647334Skre }
6657334Skre 
6664818Swnj #ifdef ilock
6674818Swnj #undef ilock
6683617Sroot #endif
6697118Smckusick #ifdef iunlock
6707118Smckusick #undef iunlock
6713617Sroot #endif
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 
6794818Swnj 	while (ip->i_flag&ILOCK) {
6803617Sroot 		ip->i_flag |= IWANT;
6813617Sroot 		sleep((caddr_t)ip, PINOD);
6823617Sroot 	}
6833617Sroot 	ip->i_flag |= ILOCK;
6843617Sroot }
6853617Sroot 
6863617Sroot /*
6874818Swnj  * Unlock an inode.  If WANT bit is on, wakeup.
6883617Sroot  */
6897118Smckusick iunlock(ip)
6904818Swnj 	register struct inode *ip;
6913617Sroot {
6923617Sroot 
6933617Sroot 	ip->i_flag &= ~ILOCK;
6944818Swnj 	if (ip->i_flag&IWANT) {
6953617Sroot 		ip->i_flag &= ~IWANT;
6963617Sroot 		wakeup((caddr_t)ip);
6973617Sroot 	}
6983617Sroot }
699