xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 7118)
1*7118Smckusick /*	lfs_inode.c	4.11	82/06/07	*/
224Sbill 
36569Smckusic /* merged into kernel:	@(#)iget.c 2.2 4/8/82 */
46569Smckusic 
524Sbill #include "../h/param.h"
624Sbill #include "../h/systm.h"
724Sbill #include "../h/mount.h"
824Sbill #include "../h/dir.h"
924Sbill #include "../h/user.h"
1024Sbill #include "../h/inode.h"
116569Smckusic #include "../h/fs.h"
1224Sbill #include "../h/conf.h"
1324Sbill #include "../h/buf.h"
1424Sbill #include "../h/inline.h"
1524Sbill 
1624Sbill #define	INOHSZ	63
1724Sbill #define	INOHASH(dev,ino)	(((dev)+(ino))%INOHSZ)
1824Sbill short	inohash[INOHSZ];
1924Sbill short	ifreel;
2024Sbill 
2124Sbill /*
2224Sbill  * Initialize hash links for inodes
2324Sbill  * and build inode free list.
2424Sbill  */
2524Sbill ihinit()
2624Sbill {
2724Sbill 	register int i;
282737Swnj 	register struct inode *ip = inode;
2924Sbill 
3024Sbill 	ifreel = 0;
312737Swnj 	for (i = 0; i < ninode-1; i++, ip++)
322737Swnj 		ip->i_hlink = i+1;
332737Swnj 	ip->i_hlink = -1;
3424Sbill 	for (i = 0; i < INOHSZ; i++)
3524Sbill 		inohash[i] = -1;
3624Sbill }
3724Sbill 
3824Sbill /*
3924Sbill  * Look up an inode by device,inumber.
4024Sbill  * If it is in core (in the inode structure),
4124Sbill  * honor the locking protocol.
4224Sbill  * If it is not in core, read it in from the
4324Sbill  * specified device.
4424Sbill  * If the inode is mounted on, perform
4524Sbill  * the indicated indirection.
4624Sbill  * In all cases, a pointer to a locked
4724Sbill  * inode structure is returned.
4824Sbill  *
4924Sbill  * panic: no imt -- if the mounted file
5024Sbill  *	system is not in the mount table.
5124Sbill  *	"cannot happen"
5224Sbill  */
5324Sbill struct inode *
546569Smckusic iget(dev, fs, ino)
554818Swnj 	dev_t dev;
566569Smckusic 	register struct fs *fs;
574818Swnj 	ino_t ino;
5824Sbill {
5924Sbill 	register struct inode *ip;
6024Sbill 	register struct mount *mp;
6124Sbill 	register struct buf *bp;
6224Sbill 	register struct dinode *dp;
6324Sbill 	register int slot;
6424Sbill 
6524Sbill loop:
666569Smckusic 	if (getfs(dev) != fs)
676569Smckusic 		panic("iget: bad fs");
6824Sbill 	slot = INOHASH(dev, ino);
6924Sbill 	ip = &inode[inohash[slot]];
7024Sbill 	while (ip != &inode[-1]) {
714818Swnj 		if (ino == ip->i_number && dev == ip->i_dev) {
724818Swnj 			if ((ip->i_flag&ILOCK) != 0) {
7324Sbill 				ip->i_flag |= IWANT;
7424Sbill 				sleep((caddr_t)ip, PINOD);
7524Sbill 				goto loop;
7624Sbill 			}
774818Swnj 			if ((ip->i_flag&IMOUNT) != 0) {
786569Smckusic 				for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
794818Swnj 				if (mp->m_inodp == ip) {
8024Sbill 					dev = mp->m_dev;
816569Smckusic 					fs = mp->m_bufp->b_un.b_fs;
8224Sbill 					ino = ROOTINO;
8324Sbill 					goto loop;
8424Sbill 				}
8524Sbill 				panic("no imt");
8624Sbill 			}
8724Sbill 			ip->i_count++;
8824Sbill 			ip->i_flag |= ILOCK;
8924Sbill 			return(ip);
9024Sbill 		}
9124Sbill 		ip = &inode[ip->i_hlink];
9224Sbill 	}
934818Swnj 	if (ifreel < 0) {
942933Swnj 		tablefull("inode");
9524Sbill 		u.u_error = ENFILE;
9624Sbill 		return(NULL);
9724Sbill 	}
9824Sbill 	ip = &inode[ifreel];
9924Sbill 	ifreel = ip->i_hlink;
10024Sbill 	ip->i_hlink = inohash[slot];
10124Sbill 	inohash[slot] = ip - inode;
10224Sbill 	ip->i_dev = dev;
1036569Smckusic 	ip->i_fs = fs;
10424Sbill 	ip->i_number = ino;
10524Sbill 	ip->i_flag = ILOCK;
10624Sbill 	ip->i_count++;
1076569Smckusic 	ip->i_lastr = 0;
1086569Smckusic 	bp = bread(dev, fsbtodb(fs, itod(fs, ino)), fs->fs_bsize);
10924Sbill 	/*
11024Sbill 	 * Check I/O errors
11124Sbill 	 */
1124818Swnj 	if ((bp->b_flags&B_ERROR) != 0) {
11324Sbill 		brelse(bp);
11424Sbill 		iput(ip);
11524Sbill 		return(NULL);
11624Sbill 	}
11724Sbill 	dp = bp->b_un.b_dino;
1186569Smckusic 	dp += itoo(fs, ino);
1196569Smckusic 	ip->i_ic = dp->di_ic;
12024Sbill 	brelse(bp);
1216569Smckusic 	return (ip);
12224Sbill }
12324Sbill 
12424Sbill /*
12524Sbill  * Decrement reference count of
12624Sbill  * an inode structure.
12724Sbill  * On the last reference,
12824Sbill  * write the inode out and if necessary,
12924Sbill  * truncate and deallocate the file.
13024Sbill  */
13124Sbill iput(ip)
1324818Swnj 	register struct inode *ip;
13324Sbill {
134*7118Smckusick 
135*7118Smckusick 	if ((ip->i_flag & ILOCK) == 0)
136*7118Smckusick 		panic("iput");
137*7118Smckusick 	iunlock(ip);
138*7118Smckusick 	irele(ip);
139*7118Smckusick }
140*7118Smckusick 
141*7118Smckusick irele(ip)
142*7118Smckusick 	register struct inode *ip;
143*7118Smckusick {
14424Sbill 	register int i, x;
14524Sbill 	register struct inode *jp;
1466569Smckusic 	int mode;
14724Sbill 
148*7118Smckusick 	if (ip->i_flag & ILOCK)
149*7118Smckusick 		panic("irele");
1504818Swnj 	if (ip->i_count == 1) {
15124Sbill 		ip->i_flag |= ILOCK;
1524818Swnj 		if (ip->i_nlink <= 0) {
15324Sbill 			itrunc(ip);
1546569Smckusic 			mode = ip->i_mode;
15524Sbill 			ip->i_mode = 0;
15624Sbill 			ip->i_flag |= IUPD|ICHG;
1576569Smckusic 			ifree(ip, ip->i_number, mode);
15824Sbill 		}
1591203Sbill 		IUPDAT(ip, &time, &time, 0);
160*7118Smckusick 		iunlock(ip);
16124Sbill 		i = INOHASH(ip->i_dev, ip->i_number);
16224Sbill 		x = ip - inode;
16324Sbill 		if (inohash[i] == x) {
16424Sbill 			inohash[i] = ip->i_hlink;
16524Sbill 		} else {
16624Sbill 			for (jp = &inode[inohash[i]]; jp != &inode[-1];
16724Sbill 			    jp = &inode[jp->i_hlink])
16824Sbill 				if (jp->i_hlink == x) {
16924Sbill 					jp->i_hlink = ip->i_hlink;
17024Sbill 					goto done;
17124Sbill 				}
17224Sbill 			panic("iput");
17324Sbill 		}
17424Sbill done:
17524Sbill 		ip->i_hlink = ifreel;
17624Sbill 		ifreel = x;
17724Sbill 		ip->i_flag = 0;
17824Sbill 		ip->i_number = 0;
179*7118Smckusick 	}
18024Sbill 	ip->i_count--;
18124Sbill }
18224Sbill 
18324Sbill /*
18424Sbill  * Check accessed and update flags on
18524Sbill  * an inode structure.
18624Sbill  * If any is on, update the inode
18724Sbill  * with the current time.
1881203Sbill  * If waitfor is given, then must insure
1891203Sbill  * i/o order so wait for write to complete.
19024Sbill  */
1911203Sbill iupdat(ip, ta, tm, waitfor)
1924818Swnj 	register struct inode *ip;
1934818Swnj 	time_t *ta, *tm;
1944818Swnj 	int waitfor;
19524Sbill {
19624Sbill 	register struct buf *bp;
19724Sbill 	struct dinode *dp;
1986569Smckusic 	register struct fs *fp;
19924Sbill 
2006569Smckusic 	fp = ip->i_fs;
2016569Smckusic 	if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) {
2026569Smckusic 		if (fp->fs_ronly)
20324Sbill 			return;
2046569Smckusic 		bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)),
2056569Smckusic 			fp->fs_bsize);
20624Sbill 		if (bp->b_flags & B_ERROR) {
20724Sbill 			brelse(bp);
20824Sbill 			return;
20924Sbill 		}
2104818Swnj 		if (ip->i_flag&IACC)
2116569Smckusic 			ip->i_atime = *ta;
2124818Swnj 		if (ip->i_flag&IUPD)
2136569Smckusic 			ip->i_mtime = *tm;
2144818Swnj 		if (ip->i_flag&ICHG)
2156569Smckusic 			ip->i_ctime = time;
21624Sbill 		ip->i_flag &= ~(IUPD|IACC|ICHG);
2176569Smckusic 		dp = bp->b_un.b_dino + itoo(fp, ip->i_number);
2186569Smckusic 		dp->di_ic = ip->i_ic;
2191203Sbill 		if (waitfor)
2201203Sbill 			bwrite(bp);
2211203Sbill 		else
2221203Sbill 			bdwrite(bp);
22324Sbill 	}
22424Sbill }
22524Sbill 
22624Sbill /*
22724Sbill  * Free all the disk blocks associated
22824Sbill  * with the specified inode structure.
22924Sbill  * The blocks of the file are removed
23024Sbill  * in reverse order. This FILO
23124Sbill  * algorithm will tend to maintain
23224Sbill  * a contiguous free list much longer
23324Sbill  * than FIFO.
23424Sbill  */
23524Sbill itrunc(ip)
2364818Swnj 	register struct inode *ip;
23724Sbill {
23824Sbill 	register i;
23924Sbill 	dev_t dev;
24024Sbill 	daddr_t bn;
2411203Sbill 	struct inode itmp;
2426569Smckusic 	register struct fs *fs;
24324Sbill 
24424Sbill 	i = ip->i_mode & IFMT;
2456569Smckusic 	if (i != IFREG && i != IFDIR && i != IFLNK)
24624Sbill 		return;
2471203Sbill 	/*
2481203Sbill 	 * Clean inode on disk before freeing blocks
2491203Sbill 	 * to insure no duplicates if system crashes.
2501203Sbill 	 */
2511203Sbill 	itmp = *ip;
2521203Sbill 	itmp.i_size = 0;
2536569Smckusic 	for (i = 0; i < NDADDR; i++)
2546569Smckusic 		itmp.i_db[i] = 0;
2556569Smckusic 	for (i = 0; i < NIADDR; i++)
2566569Smckusic 		itmp.i_ib[i] = 0;
2571203Sbill 	itmp.i_flag |= ICHG|IUPD;
2581203Sbill 	iupdat(&itmp, &time, &time, 1);
2591203Sbill 	ip->i_flag &= ~(IUPD|IACC|ICHG);
2601203Sbill 
2611203Sbill 	/*
2621203Sbill 	 * Now return blocks to free list... if machine
2631203Sbill 	 * crashes, they will be harmless MISSING blocks.
2641203Sbill 	 */
26524Sbill 	dev = ip->i_dev;
2666569Smckusic 	fs = ip->i_fs;
2676569Smckusic 	/*
2686569Smckusic 	 * release double indirect block first
2696569Smckusic 	 */
2706569Smckusic 	bn = ip->i_ib[NIADDR-1];
2716569Smckusic 	if (bn != (daddr_t)0) {
2726569Smckusic 		ip->i_ib[NIADDR - 1] = (daddr_t)0;
2736569Smckusic 		tloop(ip, bn, 1);
2746569Smckusic 	}
2756569Smckusic 	/*
2766569Smckusic 	 * release single indirect blocks second
2776569Smckusic 	 */
2786569Smckusic 	for (i = NIADDR - 2; i >= 0; i--) {
2796569Smckusic 		bn = ip->i_ib[i];
2806569Smckusic 		if (bn != (daddr_t)0) {
2816569Smckusic 			ip->i_ib[i] = (daddr_t)0;
2826569Smckusic 			tloop(ip, bn, 0);
2836569Smckusic 		}
2846569Smckusic 	}
2856569Smckusic 	/*
2866569Smckusic 	 * finally release direct blocks
2876569Smckusic 	 */
2886569Smckusic 	for (i = NDADDR - 1; i>=0; i--) {
2896569Smckusic 		bn = ip->i_db[i];
2904818Swnj 		if (bn == (daddr_t)0)
29124Sbill 			continue;
2926569Smckusic 		ip->i_db[i] = (daddr_t)0;
2936569Smckusic 		fre(ip, bn, (off_t)blksize(fs, ip, i));
29424Sbill 	}
29524Sbill 	ip->i_size = 0;
2961203Sbill 	/*
2971203Sbill 	 * Inode was written and flags updated above.
2981203Sbill 	 * No need to modify flags here.
2991203Sbill 	 */
30024Sbill }
30124Sbill 
3026569Smckusic tloop(ip, bn, indflg)
3036569Smckusic 	register struct inode *ip;
3046569Smckusic 	daddr_t bn;
3056569Smckusic 	int indflg;
30624Sbill {
30724Sbill 	register i;
30824Sbill 	register struct buf *bp;
30924Sbill 	register daddr_t *bap;
3106569Smckusic 	register struct fs *fs;
31124Sbill 	daddr_t nb;
31224Sbill 
31324Sbill 	bp = NULL;
3146569Smckusic 	fs = ip->i_fs;
3156569Smckusic 	for (i = NINDIR(fs) - 1; i >= 0; i--) {
3164818Swnj 		if (bp == NULL) {
3176569Smckusic 			bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize);
31824Sbill 			if (bp->b_flags & B_ERROR) {
31924Sbill 				brelse(bp);
32024Sbill 				return;
32124Sbill 			}
32224Sbill 			bap = bp->b_un.b_daddr;
32324Sbill 		}
32424Sbill 		nb = bap[i];
3254818Swnj 		if (nb == (daddr_t)0)
32624Sbill 			continue;
3276569Smckusic 		if (indflg)
3286569Smckusic 			tloop(ip, nb, 0);
3296569Smckusic 		else
3306569Smckusic 			fre(ip, nb, fs->fs_bsize);
33124Sbill 	}
3324818Swnj 	if (bp != NULL)
33324Sbill 		brelse(bp);
3346569Smckusic 	fre(ip, bn, fs->fs_bsize);
33524Sbill }
33624Sbill 
33724Sbill /*
33824Sbill  * Make a new file.
33924Sbill  */
34024Sbill struct inode *
34124Sbill maknode(mode)
3426569Smckusic 	int mode;
34324Sbill {
34424Sbill 	register struct inode *ip;
3456569Smckusic 	ino_t ipref;
34624Sbill 
3476569Smckusic 	if ((mode & IFMT) == IFDIR)
3486569Smckusic 		ipref = dirpref(u.u_pdir->i_fs);
3496569Smckusic 	else
3506569Smckusic 		ipref = u.u_pdir->i_number;
3516569Smckusic 	ip = ialloc(u.u_pdir, ipref, mode);
3524818Swnj 	if (ip == NULL) {
35324Sbill 		iput(u.u_pdir);
35424Sbill 		return(NULL);
35524Sbill 	}
35624Sbill 	ip->i_flag |= IACC|IUPD|ICHG;
3576569Smckusic 	if ((mode & IFMT) == 0)
35824Sbill 		mode |= IFREG;
35924Sbill 	ip->i_mode = mode & ~u.u_cmask;
36024Sbill 	ip->i_nlink = 1;
36124Sbill 	ip->i_uid = u.u_uid;
3625855Swnj 	ip->i_gid = u.u_pdir->i_gid;
3631203Sbill 
3641203Sbill 	/*
3651203Sbill 	 * Make sure inode goes to disk before directory entry.
3661203Sbill 	 */
3671203Sbill 	iupdat(ip, &time, &time, 1);
36824Sbill 	wdir(ip);
3696569Smckusic 	if (u.u_error) {
3706569Smckusic 		/*
3716569Smckusic 		 * write error occurred trying to update directory
3726569Smckusic 		 * so must deallocate the inode
3736569Smckusic 		 */
3746569Smckusic 		ip->i_nlink = 0;
3756569Smckusic 		ip->i_flag |= ICHG;
3766569Smckusic 		iput(ip);
3776569Smckusic 		return(NULL);
3786569Smckusic 	}
37924Sbill 	return(ip);
38024Sbill }
38124Sbill 
38224Sbill /*
38324Sbill  * Write a directory entry with
38424Sbill  * parameters left as side effects
38524Sbill  * to a call to namei.
38624Sbill  */
38724Sbill wdir(ip)
3884818Swnj 	struct inode *ip;
38924Sbill {
3906569Smckusic 	register struct direct *dp, *ndp;
3916569Smckusic 	struct fs *fs;
3926569Smckusic 	struct buf *bp;
3936569Smckusic 	int lbn, bn, base;
3946569Smckusic 	int loc, dsize, spccnt, newsize;
3956569Smckusic 	char *dirbuf;
39624Sbill 
39724Sbill 	u.u_dent.d_ino = ip->i_number;
39824Sbill 	u.u_segflg = 1;
3996569Smckusic 	newsize = DIRSIZ(&u.u_dent);
4006569Smckusic 	/*
4016569Smckusic 	 * if u.u_count == 0, a new directory block must be allocated.
4026569Smckusic 	 */
4036569Smckusic 	if (u.u_count == 0) {
4046569Smckusic 		u.u_dent.d_reclen = DIRBLKSIZ;
4056569Smckusic 		u.u_count = newsize;
4066569Smckusic 		u.u_base = (caddr_t)&u.u_dent;
4076569Smckusic 		writei(u.u_pdir);
4086569Smckusic 		iput(u.u_pdir);
4096569Smckusic 		return;
4106569Smckusic 	}
4116569Smckusic 	/*
4126569Smckusic 	 * must read in an existing directory block
4136569Smckusic 	 * to prepare to place the new entry into it.
4146569Smckusic 	 */
4156569Smckusic 	fs = u.u_pdir->i_fs;
4166569Smckusic 	lbn = lblkno(fs, u.u_offset);
4176569Smckusic 	base = blkoff(fs, u.u_offset);
4186569Smckusic 	bn = fsbtodb(fs, bmap(u.u_pdir, lbn, B_WRITE, base + u.u_count));
4196569Smckusic 	if (u.u_offset + u.u_count > u.u_pdir->i_size)
4206569Smckusic 		u.u_pdir->i_size = u.u_offset + u.u_count;
4216569Smckusic 	bp = bread(u.u_pdir->i_dev, bn, blksize(fs, u.u_pdir, lbn));
4226569Smckusic 	if (bp->b_flags & B_ERROR) {
4236569Smckusic 		brelse(bp);
4246569Smckusic 		return;
4256569Smckusic 	}
4266569Smckusic 	dirbuf = bp->b_un.b_addr + base;
4276569Smckusic 	dp = (struct direct *)dirbuf;
4286569Smckusic 	dsize = DIRSIZ(dp);
4296569Smckusic 	spccnt = dp->d_reclen - dsize;
4306569Smckusic 	/*
4316569Smckusic 	 * if there is insufficient room to make an entry at this point
4326569Smckusic 	 * namei insures that compacting from u.u_offset for u.u_count
4336569Smckusic 	 * bytes will provide the necessary space.
4346569Smckusic 	 */
4356569Smckusic 	for (loc = dp->d_reclen; loc < u.u_count; ) {
4366569Smckusic 		ndp = (struct direct *)(dirbuf + loc);
4376569Smckusic 		if (dp->d_ino == 0) {
4386569Smckusic 			spccnt += dsize;
4396569Smckusic 		} else {
4406569Smckusic 			dp->d_reclen = dsize;
4416569Smckusic 			dp = (struct direct *)((char *)dp + dsize);
4426569Smckusic 		}
4436569Smckusic 		dsize = DIRSIZ(ndp);
4446569Smckusic 		spccnt += ndp->d_reclen - dsize;
4456569Smckusic 		loc += ndp->d_reclen;
4466569Smckusic 		bcopy(ndp, dp, dsize);
4476569Smckusic 	}
4486569Smckusic 	/*
4496569Smckusic 	 * Update the pointer fields in the previous entry (if any),
4506569Smckusic 	 * copy in the new entry, and write out the block.
4516569Smckusic 	 */
4526569Smckusic 	if (dp->d_ino == 0) {
4536569Smckusic 		if (spccnt + dsize < newsize)
4546569Smckusic 			panic("wdir: compact failed");
4556569Smckusic 		u.u_dent.d_reclen = spccnt + dsize;
4566569Smckusic 	} else {
4576569Smckusic 		if (spccnt < newsize)
4586569Smckusic 			panic("wdir: compact failed");
4596569Smckusic 		u.u_dent.d_reclen = spccnt;
4606569Smckusic 		dp->d_reclen = dsize;
4616569Smckusic 		dp = (struct direct *)((char *)dp + dsize);
4626569Smckusic 	}
4636569Smckusic 	bcopy(&u.u_dent, dp, newsize);
4646569Smckusic 	bwrite(bp);
4656569Smckusic 	u.u_pdir->i_flag |= IUPD|ICHG;
46624Sbill 	iput(u.u_pdir);
46724Sbill }
4683617Sroot 
4694818Swnj #ifdef ilock
4704818Swnj #undef ilock
4713617Sroot #endif
472*7118Smckusick #ifdef iunlock
473*7118Smckusick #undef iunlock
4743617Sroot #endif
4753617Sroot /*
4764818Swnj  * Lock an inode. If its already locked, set the WANT bit and sleep.
4773617Sroot  */
4784818Swnj ilock(ip)
4794818Swnj 	register struct inode *ip;
4803617Sroot {
4813617Sroot 
4824818Swnj 	while (ip->i_flag&ILOCK) {
4833617Sroot 		ip->i_flag |= IWANT;
4843617Sroot 		sleep((caddr_t)ip, PINOD);
4853617Sroot 	}
4863617Sroot 	ip->i_flag |= ILOCK;
4873617Sroot }
4883617Sroot 
4893617Sroot /*
4904818Swnj  * Unlock an inode.  If WANT bit is on, wakeup.
4913617Sroot  */
492*7118Smckusick iunlock(ip)
4934818Swnj 	register struct inode *ip;
4943617Sroot {
4953617Sroot 
4963617Sroot 	ip->i_flag &= ~ILOCK;
4974818Swnj 	if (ip->i_flag&IWANT) {
4983617Sroot 		ip->i_flag &= ~IWANT;
4993617Sroot 		wakeup((caddr_t)ip);
5003617Sroot 	}
5013617Sroot }
502