xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 7504)
1*7504Sroot /*	lfs_inode.c	4.19	82/07/24	*/
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"
13*7504Sroot #ifdef	QUOTA
14*7504Sroot #include "../h/quota.h"
15*7504Sroot #endif
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) {
1174818Swnj 			if ((ip->i_flag&ILOCK) != 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++;
14224Sbill 			ip->i_flag |= ILOCK;
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);
1657492Skre #ifdef	QUOTA
1667492Skre 	dqrele(ip->i_dquot);
1677492Skre #endif
16824Sbill 	ip->i_dev = dev;
1696569Smckusic 	ip->i_fs = fs;
17024Sbill 	ip->i_number = ino;
17124Sbill 	ip->i_flag = ILOCK;
17224Sbill 	ip->i_count++;
1736569Smckusic 	ip->i_lastr = 0;
1746569Smckusic 	bp = bread(dev, fsbtodb(fs, itod(fs, ino)), 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;
1957492Skre #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);
2057492Skre #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 
214*7504Sroot int	badinum = -1;
21524Sbill /*
21624Sbill  * Decrement reference count of
21724Sbill  * an inode structure.
21824Sbill  * On the last reference,
21924Sbill  * write the inode out and if necessary,
22024Sbill  * truncate and deallocate the file.
22124Sbill  */
22224Sbill iput(ip)
2234818Swnj 	register struct inode *ip;
22424Sbill {
2257118Smckusick 
2267118Smckusick 	if ((ip->i_flag & ILOCK) == 0)
2277118Smckusick 		panic("iput");
228*7504Sroot /* XXX */
229*7504Sroot 	if (ip->i_number == badinum && (ip->i_mode&IFMT) == IFCHR &&
230*7504Sroot 	    (major(ip->i_dev) != 3 || minor(ip->i_dev) != 2))
231*7504Sroot 		panic("/dev/null");
232*7504Sroot /* XXX */
2337118Smckusick 	iunlock(ip);
2347118Smckusick 	irele(ip);
2357118Smckusick }
2367118Smckusick 
2377118Smckusick irele(ip)
2387118Smckusick 	register struct inode *ip;
2397118Smckusick {
24024Sbill 	register int i, x;
24124Sbill 	register struct inode *jp;
2426569Smckusic 	int mode;
24324Sbill 
2444818Swnj 	if (ip->i_count == 1) {
24524Sbill 		ip->i_flag |= ILOCK;
2464818Swnj 		if (ip->i_nlink <= 0) {
24724Sbill 			itrunc(ip);
2486569Smckusic 			mode = ip->i_mode;
24924Sbill 			ip->i_mode = 0;
2507351Skre 			ip->i_rdev = 0;
25124Sbill 			ip->i_flag |= IUPD|ICHG;
2526569Smckusic 			ifree(ip, ip->i_number, mode);
2537492Skre #ifdef	QUOTA
2547492Skre 			chkiq(ip->i_dev, ip, ip->i_uid, 0);
2557492Skre 			dqrele(ip->i_dquot);
2567492Skre 			ip->i_dquot = NODQUOT;
2577492Skre #endif
25824Sbill 		}
2591203Sbill 		IUPDAT(ip, &time, &time, 0);
2607118Smckusick 		iunlock(ip);
2617334Skre 		ip->i_flag = 0;
2627334Skre 		/*
2637334Skre 		 * Put the inode on the end of the free list.
2647334Skre 		 * Possibly in some cases it would be better to
2657334Skre 		 * put the inode at the head of the free list,
2667334Skre 		 * (eg: where i_mode == 0 || i_number == 0)
2677334Skre 		 * but I will think about that later .. kre
2687334Skre 		 * (i_number is rarely 0 - only after an i/o error in iget,
2697334Skre 		 * where i_mode == 0, the inode will probably be wanted
2707334Skre 		 * again soon for an ialloc, so possibly we should keep it)
2717334Skre 		 */
2727334Skre 		if (ifreeh) {
2737334Skre 			*ifreet = ip;
2747334Skre 			ip->i_freeb = ifreet;
27524Sbill 		} else {
2767334Skre 			ifreeh = ip;
2777334Skre 			ip->i_freeb = &ifreeh;
27824Sbill 		}
2797334Skre 		ip->i_freef = NULL;
2807334Skre 		ifreet = &ip->i_freef;
2817118Smckusick 	}
28224Sbill 	ip->i_count--;
28324Sbill }
28424Sbill 
28524Sbill /*
28624Sbill  * Check accessed and update flags on
28724Sbill  * an inode structure.
28824Sbill  * If any is on, update the inode
28924Sbill  * with the current time.
2901203Sbill  * If waitfor is given, then must insure
2911203Sbill  * i/o order so wait for write to complete.
29224Sbill  */
2931203Sbill iupdat(ip, ta, tm, waitfor)
2944818Swnj 	register struct inode *ip;
2954818Swnj 	time_t *ta, *tm;
2964818Swnj 	int waitfor;
29724Sbill {
29824Sbill 	register struct buf *bp;
29924Sbill 	struct dinode *dp;
3006569Smckusic 	register struct fs *fp;
30124Sbill 
3026569Smckusic 	fp = ip->i_fs;
3036569Smckusic 	if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) {
3046569Smckusic 		if (fp->fs_ronly)
30524Sbill 			return;
3066569Smckusic 		bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)),
3076569Smckusic 			fp->fs_bsize);
30824Sbill 		if (bp->b_flags & B_ERROR) {
30924Sbill 			brelse(bp);
31024Sbill 			return;
31124Sbill 		}
3124818Swnj 		if (ip->i_flag&IACC)
3136569Smckusic 			ip->i_atime = *ta;
3144818Swnj 		if (ip->i_flag&IUPD)
3156569Smckusic 			ip->i_mtime = *tm;
3164818Swnj 		if (ip->i_flag&ICHG)
3176569Smckusic 			ip->i_ctime = time;
31824Sbill 		ip->i_flag &= ~(IUPD|IACC|ICHG);
3197343Skre 		dp = bp->b_un.b_dino + itoo(fp, ip->i_number);
3207343Skre 		dp->di_ic = ip->i_ic;
3211203Sbill 		if (waitfor)
3221203Sbill 			bwrite(bp);
3231203Sbill 		else
3241203Sbill 			bdwrite(bp);
32524Sbill 	}
32624Sbill }
32724Sbill 
32824Sbill /*
32924Sbill  * Free all the disk blocks associated
33024Sbill  * with the specified inode structure.
33124Sbill  * The blocks of the file are removed
33224Sbill  * in reverse order. This FILO
33324Sbill  * algorithm will tend to maintain
33424Sbill  * a contiguous free list much longer
33524Sbill  * than FIFO.
33624Sbill  */
33724Sbill itrunc(ip)
3384818Swnj 	register struct inode *ip;
33924Sbill {
34024Sbill 	register i;
34124Sbill 	dev_t dev;
34224Sbill 	daddr_t bn;
3431203Sbill 	struct inode itmp;
3446569Smckusic 	register struct fs *fs;
3457492Skre #ifdef	QUOTA
3467492Skre 	register long cnt = 0;
3477492Skre 	long tloop();
3487492Skre #endif
34924Sbill 
3501203Sbill 	/*
3511203Sbill 	 * Clean inode on disk before freeing blocks
3521203Sbill 	 * to insure no duplicates if system crashes.
3531203Sbill 	 */
3541203Sbill 	itmp = *ip;
3551203Sbill 	itmp.i_size = 0;
3566569Smckusic 	for (i = 0; i < NDADDR; i++)
3576569Smckusic 		itmp.i_db[i] = 0;
3586569Smckusic 	for (i = 0; i < NIADDR; i++)
3596569Smckusic 		itmp.i_ib[i] = 0;
3601203Sbill 	itmp.i_flag |= ICHG|IUPD;
3611203Sbill 	iupdat(&itmp, &time, &time, 1);
3621203Sbill 	ip->i_flag &= ~(IUPD|IACC|ICHG);
3631203Sbill 
3641203Sbill 	/*
3657341Sroot 	 * Only plain files, directories and symbolic
3667341Sroot 	 * links contain blocks.
3677341Sroot 	 */
3687341Sroot 	i = ip->i_mode & IFMT;
3697341Sroot 	if (i != IFREG && i != IFDIR && i != IFLNK)
3707341Sroot 		return;
3717341Sroot 	/*
3721203Sbill 	 * Now return blocks to free list... if machine
3731203Sbill 	 * crashes, they will be harmless MISSING blocks.
3741203Sbill 	 */
37524Sbill 	dev = ip->i_dev;
3766569Smckusic 	fs = ip->i_fs;
3776569Smckusic 	/*
3786569Smckusic 	 * release double indirect block first
3796569Smckusic 	 */
3806569Smckusic 	bn = ip->i_ib[NIADDR-1];
3816569Smckusic 	if (bn != (daddr_t)0) {
3826569Smckusic 		ip->i_ib[NIADDR - 1] = (daddr_t)0;
3837492Skre #ifdef	QUOTA
3847492Skre 		cnt +=
3857492Skre #endif
3867492Skre 			tloop(ip, bn, 1);
3876569Smckusic 	}
3886569Smckusic 	/*
3896569Smckusic 	 * release single indirect blocks second
3906569Smckusic 	 */
3916569Smckusic 	for (i = NIADDR - 2; i >= 0; i--) {
3926569Smckusic 		bn = ip->i_ib[i];
3936569Smckusic 		if (bn != (daddr_t)0) {
3946569Smckusic 			ip->i_ib[i] = (daddr_t)0;
3957492Skre #ifdef	QUOTA
3967492Skre 			cnt +=
3977492Skre #endif
3987492Skre 				tloop(ip, bn, 0);
3996569Smckusic 		}
4006569Smckusic 	}
4016569Smckusic 	/*
4026569Smckusic 	 * finally release direct blocks
4036569Smckusic 	 */
4046569Smckusic 	for (i = NDADDR - 1; i>=0; i--) {
4057492Skre 		register size;
4067492Skre 
4076569Smckusic 		bn = ip->i_db[i];
4084818Swnj 		if (bn == (daddr_t)0)
40924Sbill 			continue;
4106569Smckusic 		ip->i_db[i] = (daddr_t)0;
4117492Skre 		fre(ip, bn, size = (off_t)blksize(fs, ip, i));
4127492Skre #ifdef	QUOTA
4137492Skre 		cnt += size / DEV_BSIZE;
4147492Skre #endif
41524Sbill 	}
41624Sbill 	ip->i_size = 0;
4171203Sbill 	/*
4181203Sbill 	 * Inode was written and flags updated above.
4191203Sbill 	 * No need to modify flags here.
4201203Sbill 	 */
4217492Skre #ifdef	QUOTA
4227492Skre 	(void) chkdq(ip, -cnt, 0);
4237492Skre #endif
42424Sbill }
42524Sbill 
4267492Skre #ifdef	QUOTA
4277492Skre long
4287492Skre #endif
4296569Smckusic tloop(ip, bn, indflg)
4306569Smckusic 	register struct inode *ip;
4316569Smckusic 	daddr_t bn;
4326569Smckusic 	int indflg;
43324Sbill {
43424Sbill 	register i;
43524Sbill 	register struct buf *bp;
43624Sbill 	register daddr_t *bap;
4376569Smckusic 	register struct fs *fs;
43824Sbill 	daddr_t nb;
4397492Skre #ifdef	QUOTA
4407492Skre 	register long cnt = 0;
4417492Skre #endif
44224Sbill 
44324Sbill 	bp = NULL;
4446569Smckusic 	fs = ip->i_fs;
4456569Smckusic 	for (i = NINDIR(fs) - 1; i >= 0; i--) {
4464818Swnj 		if (bp == NULL) {
4476569Smckusic 			bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize);
44824Sbill 			if (bp->b_flags & B_ERROR) {
44924Sbill 				brelse(bp);
45024Sbill 				return;
45124Sbill 			}
45224Sbill 			bap = bp->b_un.b_daddr;
45324Sbill 		}
45424Sbill 		nb = bap[i];
4554818Swnj 		if (nb == (daddr_t)0)
45624Sbill 			continue;
4577492Skre 		if (indflg) {
4587492Skre #ifdef	QUOTA
4597492Skre 			cnt +=
4607492Skre #endif
4617492Skre 				tloop(ip, nb, 0);
4627492Skre 		} else {
4636569Smckusic 			fre(ip, nb, fs->fs_bsize);
4647492Skre #ifdef	QUOTA
4657492Skre 			cnt += fs->fs_bsize / DEV_BSIZE;
4667492Skre #endif
4677492Skre 		}
46824Sbill 	}
4694818Swnj 	if (bp != NULL)
47024Sbill 		brelse(bp);
4716569Smckusic 	fre(ip, bn, fs->fs_bsize);
4727492Skre #ifdef	QUOTA
4737492Skre 	cnt += fs->fs_bsize / DEV_BSIZE;
4747492Skre 	return(cnt);
4757492Skre #endif
47624Sbill }
47724Sbill 
47824Sbill /*
47924Sbill  * Make a new file.
48024Sbill  */
48124Sbill struct inode *
48224Sbill maknode(mode)
4836569Smckusic 	int mode;
48424Sbill {
48524Sbill 	register struct inode *ip;
4866569Smckusic 	ino_t ipref;
48724Sbill 
4886569Smckusic 	if ((mode & IFMT) == IFDIR)
4896569Smckusic 		ipref = dirpref(u.u_pdir->i_fs);
4906569Smckusic 	else
4916569Smckusic 		ipref = u.u_pdir->i_number;
4926569Smckusic 	ip = ialloc(u.u_pdir, ipref, mode);
4934818Swnj 	if (ip == NULL) {
49424Sbill 		iput(u.u_pdir);
49524Sbill 		return(NULL);
49624Sbill 	}
4977492Skre #ifdef	QUOTA
4987492Skre 	if (ip->i_dquot != NODQUOT)
4997492Skre 		panic("maknode: dquot");
5007492Skre #endif
50124Sbill 	ip->i_flag |= IACC|IUPD|ICHG;
5026569Smckusic 	if ((mode & IFMT) == 0)
50324Sbill 		mode |= IFREG;
50424Sbill 	ip->i_mode = mode & ~u.u_cmask;
50524Sbill 	ip->i_nlink = 1;
50624Sbill 	ip->i_uid = u.u_uid;
5075855Swnj 	ip->i_gid = u.u_pdir->i_gid;
5087492Skre #ifdef	QUOTA
5097492Skre 	ip->i_dquot = inoquota(ip);
5107492Skre #endif
5111203Sbill 
5121203Sbill 	/*
5131203Sbill 	 * Make sure inode goes to disk before directory entry.
5141203Sbill 	 */
5151203Sbill 	iupdat(ip, &time, &time, 1);
51624Sbill 	wdir(ip);
5176569Smckusic 	if (u.u_error) {
5186569Smckusic 		/*
5196569Smckusic 		 * write error occurred trying to update directory
5206569Smckusic 		 * so must deallocate the inode
5216569Smckusic 		 */
5226569Smckusic 		ip->i_nlink = 0;
5236569Smckusic 		ip->i_flag |= ICHG;
5246569Smckusic 		iput(ip);
5256569Smckusic 		return(NULL);
5266569Smckusic 	}
52724Sbill 	return(ip);
52824Sbill }
52924Sbill 
53024Sbill /*
53124Sbill  * Write a directory entry with
53224Sbill  * parameters left as side effects
53324Sbill  * to a call to namei.
53424Sbill  */
53524Sbill wdir(ip)
5364818Swnj 	struct inode *ip;
53724Sbill {
5386569Smckusic 	register struct direct *dp, *ndp;
5396569Smckusic 	struct fs *fs;
5406569Smckusic 	struct buf *bp;
5416569Smckusic 	int lbn, bn, base;
5426569Smckusic 	int loc, dsize, spccnt, newsize;
5436569Smckusic 	char *dirbuf;
54424Sbill 
54524Sbill 	u.u_dent.d_ino = ip->i_number;
54624Sbill 	u.u_segflg = 1;
5476569Smckusic 	newsize = DIRSIZ(&u.u_dent);
5486569Smckusic 	/*
5496569Smckusic 	 * if u.u_count == 0, a new directory block must be allocated.
5506569Smckusic 	 */
5516569Smckusic 	if (u.u_count == 0) {
5526569Smckusic 		u.u_dent.d_reclen = DIRBLKSIZ;
5536569Smckusic 		u.u_count = newsize;
5546569Smckusic 		u.u_base = (caddr_t)&u.u_dent;
555*7504Sroot /*ZZ*/if((u.u_offset&0x1ff))panic("wdir: newblk");
5566569Smckusic 		writei(u.u_pdir);
5576569Smckusic 		iput(u.u_pdir);
5586569Smckusic 		return;
5596569Smckusic 	}
5606569Smckusic 	/*
5616569Smckusic 	 * must read in an existing directory block
5626569Smckusic 	 * to prepare to place the new entry into it.
5636569Smckusic 	 */
5646569Smckusic 	fs = u.u_pdir->i_fs;
5656569Smckusic 	lbn = lblkno(fs, u.u_offset);
5666569Smckusic 	base = blkoff(fs, u.u_offset);
5676569Smckusic 	bn = fsbtodb(fs, bmap(u.u_pdir, lbn, B_WRITE, base + u.u_count));
5686569Smckusic 	if (u.u_offset + u.u_count > u.u_pdir->i_size)
569*7504Sroot /*ZZ*/{if((u.u_offset+u.u_count-1&~0x1ff)!=(u.u_pdir->i_size-1&~0x1ff))
570*7504Sroot /*ZZ*/  printf("wdir i_size dir %s/%d (of=%d,cnt=%d,psz=%d))\n",
571*7504Sroot /*ZZ*/       u.u_pdir->i_fs->fs_fsmnt,u.u_pdir->i_number,u.u_offset,
572*7504Sroot /*ZZ*/       u.u_count,u.u_pdir->i_size);
5736569Smckusic 		u.u_pdir->i_size = u.u_offset + u.u_count;
574*7504Sroot /*ZZ*/}
5756569Smckusic 	bp = bread(u.u_pdir->i_dev, bn, blksize(fs, u.u_pdir, lbn));
5766569Smckusic 	if (bp->b_flags & B_ERROR) {
5776569Smckusic 		brelse(bp);
5786569Smckusic 		return;
5796569Smckusic 	}
5806569Smckusic 	dirbuf = bp->b_un.b_addr + base;
5816569Smckusic 	dp = (struct direct *)dirbuf;
5826569Smckusic 	dsize = DIRSIZ(dp);
5836569Smckusic 	spccnt = dp->d_reclen - dsize;
5846569Smckusic 	/*
5856569Smckusic 	 * if there is insufficient room to make an entry at this point
5866569Smckusic 	 * namei insures that compacting from u.u_offset for u.u_count
5876569Smckusic 	 * bytes will provide the necessary space.
5886569Smckusic 	 */
5896569Smckusic 	for (loc = dp->d_reclen; loc < u.u_count; ) {
5906569Smckusic 		ndp = (struct direct *)(dirbuf + loc);
5916569Smckusic 		if (dp->d_ino == 0) {
5926569Smckusic 			spccnt += dsize;
5936569Smckusic 		} else {
5946569Smckusic 			dp->d_reclen = dsize;
5956569Smckusic 			dp = (struct direct *)((char *)dp + dsize);
5966569Smckusic 		}
5976569Smckusic 		dsize = DIRSIZ(ndp);
5986569Smckusic 		spccnt += ndp->d_reclen - dsize;
599*7504Sroot /*ZZ*/if(spccnt>512)panic("wdir spccnt");
600*7504Sroot /*ZZ*/if((loc&~0x1ff)!=(loc+ndp->d_reclen-1&~0x1ff))
601*7504Sroot /*ZZ*/printf("wdir: compact loc %d reclen %d (dir %s/%d)\n",loc,ndp->d_reclen,
602*7504Sroot /*ZZ*/u.u_pdir->i_fs->fs_fsmnt,u.u_pdir->i_number);
6036569Smckusic 		loc += ndp->d_reclen;
6046569Smckusic 		bcopy(ndp, dp, dsize);
6056569Smckusic 	}
6066569Smckusic 	/*
6076569Smckusic 	 * Update the pointer fields in the previous entry (if any),
6086569Smckusic 	 * copy in the new entry, and write out the block.
6096569Smckusic 	 */
6106569Smckusic 	if (dp->d_ino == 0) {
6116569Smckusic 		if (spccnt + dsize < newsize)
612*7504Sroot 			panic("wdir: compact failed (1)");
613*7504Sroot /*ZZ*/if(spccnt+dsize>512)panic("wdir: compact screwup");
6146569Smckusic 		u.u_dent.d_reclen = spccnt + dsize;
6156569Smckusic 	} else {
6166569Smckusic 		if (spccnt < newsize)
617*7504Sroot 			panic("wdir: compact failed (2)");
6186569Smckusic 		u.u_dent.d_reclen = spccnt;
619*7504Sroot /*ZZ*/if ((((char *)dp-bp->b_un.b_addr)&0x1ff)+dsize>512) panic("wdir: reclen");
6206569Smckusic 		dp->d_reclen = dsize;
6216569Smckusic 		dp = (struct direct *)((char *)dp + dsize);
6226569Smckusic 	}
623*7504Sroot /*ZZ*/if((((char*)dp-bp->b_un.b_addr)&0x1ff)+u.u_dent.d_reclen>512)panic("wdir: botch");
6246569Smckusic 	bcopy(&u.u_dent, dp, newsize);
6256569Smckusic 	bwrite(bp);
6266569Smckusic 	u.u_pdir->i_flag |= IUPD|ICHG;
62724Sbill 	iput(u.u_pdir);
62824Sbill }
6293617Sroot 
6307334Skre /*
6317334Skre  * remove any inodes in the inode cache belonging to dev
6327334Skre  *
6337334Skre  * There should not be any active ones, return error if any are found
6347334Skre  * (nb: this is a user error, not a system err)
6357334Skre  *
6367334Skre  * Also, count the references to dev by block devices - this really
6377334Skre  * has nothing to do with the object of the procedure, but as we have
6387334Skre  * to scan the inode table here anyway, we might as well get the
6397334Skre  * extra benefit.
6407334Skre  *
6417334Skre  * this is called from sumount()/sys3.c when dev is being unmounted
6427334Skre  */
6437492Skre #ifdef	QUOTA
644*7504Sroot iflush(dev, iq)
6457492Skre 	dev_t dev;
646*7504Sroot 	struct inode *iq;
6477492Skre #else
6487334Skre iflush(dev)
6497334Skre 	dev_t dev;
6507492Skre #endif
6517334Skre {
6527335Skre 	register struct inode *ip;
6537334Skre 	register open = 0;
6547334Skre 
6557334Skre 	for (ip = inode; ip < inodeNINODE; ip++) {
6567492Skre #ifdef	QUOTA
6577492Skre 		if (ip != iq && ip->i_dev == dev)
6587492Skre #else
6597334Skre 		if (ip->i_dev == dev)
6607492Skre #endif
6617334Skre 			if (ip->i_count)
6627334Skre 				return(-1);
6637334Skre 			else {
6647335Skre 				remque(ip);
6657334Skre 				ip->i_forw = ip;
6667334Skre 				ip->i_back = ip;
6677334Skre 				/*
6687334Skre 				 * as i_count == 0, the inode was on the free
6697334Skre 				 * list already, just leave it there, it will
6707334Skre 				 * fall off the bottom eventually. We could
6717334Skre 				 * perhaps move it to the head of the free
6727334Skre 				 * list, but as umounts are done so
6737334Skre 				 * infrequently, we would gain very little,
6747334Skre 				 * while making the code bigger.
6757334Skre 				 */
6767492Skre #ifdef	QUOTA
6777492Skre 				dqrele(ip->i_dquot);
6787492Skre 				ip->i_dquot = NODQUOT;
6797492Skre #endif
6807334Skre 			}
6817334Skre 		else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK &&
6827334Skre 		    ip->i_rdev == dev)
6837334Skre 			open++;
6847334Skre 	}
6857334Skre 	return (open);
6867334Skre }
6877334Skre 
6884818Swnj #ifdef ilock
6894818Swnj #undef ilock
6903617Sroot #endif
6917118Smckusick #ifdef iunlock
6927118Smckusick #undef iunlock
6933617Sroot #endif
6943617Sroot /*
6954818Swnj  * Lock an inode. If its already locked, set the WANT bit and sleep.
6963617Sroot  */
6974818Swnj ilock(ip)
6984818Swnj 	register struct inode *ip;
6993617Sroot {
7003617Sroot 
7014818Swnj 	while (ip->i_flag&ILOCK) {
7023617Sroot 		ip->i_flag |= IWANT;
7033617Sroot 		sleep((caddr_t)ip, PINOD);
7043617Sroot 	}
7053617Sroot 	ip->i_flag |= ILOCK;
7063617Sroot }
7073617Sroot 
7083617Sroot /*
7094818Swnj  * Unlock an inode.  If WANT bit is on, wakeup.
7103617Sroot  */
7117118Smckusick iunlock(ip)
7124818Swnj 	register struct inode *ip;
7133617Sroot {
7143617Sroot 
7153617Sroot 	ip->i_flag &= ~ILOCK;
7164818Swnj 	if (ip->i_flag&IWANT) {
7173617Sroot 		ip->i_flag &= ~IWANT;
7183617Sroot 		wakeup((caddr_t)ip);
7193617Sroot 	}
7203617Sroot }
721