xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 6569)
1*6569Smckusic /*	lfs_inode.c	4.10	82/04/19	*/
224Sbill 
3*6569Smckusic /* merged into kernel:	@(#)iget.c 2.2 4/8/82 */
4*6569Smckusic 
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"
11*6569Smckusic #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 *
54*6569Smckusic iget(dev, fs, ino)
554818Swnj 	dev_t dev;
56*6569Smckusic 	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:
66*6569Smckusic 	if (getfs(dev) != fs)
67*6569Smckusic 		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) {
78*6569Smckusic 				for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
794818Swnj 				if (mp->m_inodp == ip) {
8024Sbill 					dev = mp->m_dev;
81*6569Smckusic 					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;
103*6569Smckusic 	ip->i_fs = fs;
10424Sbill 	ip->i_number = ino;
10524Sbill 	ip->i_flag = ILOCK;
10624Sbill 	ip->i_count++;
107*6569Smckusic 	ip->i_lastr = 0;
108*6569Smckusic 	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;
118*6569Smckusic 	dp += itoo(fs, ino);
119*6569Smckusic 	ip->i_ic = dp->di_ic;
12024Sbill 	brelse(bp);
121*6569Smckusic 	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 {
13424Sbill 	register int i, x;
13524Sbill 	register struct inode *jp;
136*6569Smckusic 	int mode;
13724Sbill 
1384818Swnj 	if (ip->i_count == 1) {
13924Sbill 		ip->i_flag |= ILOCK;
1404818Swnj 		if (ip->i_nlink <= 0) {
14124Sbill 			itrunc(ip);
142*6569Smckusic 			mode = ip->i_mode;
14324Sbill 			ip->i_mode = 0;
14424Sbill 			ip->i_flag |= IUPD|ICHG;
145*6569Smckusic 			ifree(ip, ip->i_number, mode);
14624Sbill 		}
1471203Sbill 		IUPDAT(ip, &time, &time, 0);
1484818Swnj 		irele(ip);
14924Sbill 		i = INOHASH(ip->i_dev, ip->i_number);
15024Sbill 		x = ip - inode;
15124Sbill 		if (inohash[i] == x) {
15224Sbill 			inohash[i] = ip->i_hlink;
15324Sbill 		} else {
15424Sbill 			for (jp = &inode[inohash[i]]; jp != &inode[-1];
15524Sbill 			    jp = &inode[jp->i_hlink])
15624Sbill 				if (jp->i_hlink == x) {
15724Sbill 					jp->i_hlink = ip->i_hlink;
15824Sbill 					goto done;
15924Sbill 				}
16024Sbill 			panic("iput");
16124Sbill 		}
16224Sbill done:
16324Sbill 		ip->i_hlink = ifreel;
16424Sbill 		ifreel = x;
16524Sbill 		ip->i_flag = 0;
16624Sbill 		ip->i_number = 0;
16724Sbill 	} else
1684818Swnj 		irele(ip);
16924Sbill 	ip->i_count--;
17024Sbill }
17124Sbill 
17224Sbill /*
17324Sbill  * Check accessed and update flags on
17424Sbill  * an inode structure.
17524Sbill  * If any is on, update the inode
17624Sbill  * with the current time.
1771203Sbill  * If waitfor is given, then must insure
1781203Sbill  * i/o order so wait for write to complete.
17924Sbill  */
1801203Sbill iupdat(ip, ta, tm, waitfor)
1814818Swnj 	register struct inode *ip;
1824818Swnj 	time_t *ta, *tm;
1834818Swnj 	int waitfor;
18424Sbill {
18524Sbill 	register struct buf *bp;
18624Sbill 	struct dinode *dp;
187*6569Smckusic 	register struct fs *fp;
18824Sbill 
189*6569Smckusic 	fp = ip->i_fs;
190*6569Smckusic 	if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) {
191*6569Smckusic 		if (fp->fs_ronly)
19224Sbill 			return;
193*6569Smckusic 		bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)),
194*6569Smckusic 			fp->fs_bsize);
19524Sbill 		if (bp->b_flags & B_ERROR) {
19624Sbill 			brelse(bp);
19724Sbill 			return;
19824Sbill 		}
1994818Swnj 		if (ip->i_flag&IACC)
200*6569Smckusic 			ip->i_atime = *ta;
2014818Swnj 		if (ip->i_flag&IUPD)
202*6569Smckusic 			ip->i_mtime = *tm;
2034818Swnj 		if (ip->i_flag&ICHG)
204*6569Smckusic 			ip->i_ctime = time;
20524Sbill 		ip->i_flag &= ~(IUPD|IACC|ICHG);
206*6569Smckusic 		dp = bp->b_un.b_dino + itoo(fp, ip->i_number);
207*6569Smckusic 		dp->di_ic = ip->i_ic;
2081203Sbill 		if (waitfor)
2091203Sbill 			bwrite(bp);
2101203Sbill 		else
2111203Sbill 			bdwrite(bp);
21224Sbill 	}
21324Sbill }
21424Sbill 
21524Sbill /*
21624Sbill  * Free all the disk blocks associated
21724Sbill  * with the specified inode structure.
21824Sbill  * The blocks of the file are removed
21924Sbill  * in reverse order. This FILO
22024Sbill  * algorithm will tend to maintain
22124Sbill  * a contiguous free list much longer
22224Sbill  * than FIFO.
22324Sbill  */
22424Sbill itrunc(ip)
2254818Swnj 	register struct inode *ip;
22624Sbill {
22724Sbill 	register i;
22824Sbill 	dev_t dev;
22924Sbill 	daddr_t bn;
2301203Sbill 	struct inode itmp;
231*6569Smckusic 	register struct fs *fs;
23224Sbill 
23324Sbill 	i = ip->i_mode & IFMT;
234*6569Smckusic 	if (i != IFREG && i != IFDIR && i != IFLNK)
23524Sbill 		return;
2361203Sbill 	/*
2371203Sbill 	 * Clean inode on disk before freeing blocks
2381203Sbill 	 * to insure no duplicates if system crashes.
2391203Sbill 	 */
2401203Sbill 	itmp = *ip;
2411203Sbill 	itmp.i_size = 0;
242*6569Smckusic 	for (i = 0; i < NDADDR; i++)
243*6569Smckusic 		itmp.i_db[i] = 0;
244*6569Smckusic 	for (i = 0; i < NIADDR; i++)
245*6569Smckusic 		itmp.i_ib[i] = 0;
2461203Sbill 	itmp.i_flag |= ICHG|IUPD;
2471203Sbill 	iupdat(&itmp, &time, &time, 1);
2481203Sbill 	ip->i_flag &= ~(IUPD|IACC|ICHG);
2491203Sbill 
2501203Sbill 	/*
2511203Sbill 	 * Now return blocks to free list... if machine
2521203Sbill 	 * crashes, they will be harmless MISSING blocks.
2531203Sbill 	 */
25424Sbill 	dev = ip->i_dev;
255*6569Smckusic 	fs = ip->i_fs;
256*6569Smckusic 	/*
257*6569Smckusic 	 * release double indirect block first
258*6569Smckusic 	 */
259*6569Smckusic 	bn = ip->i_ib[NIADDR-1];
260*6569Smckusic 	if (bn != (daddr_t)0) {
261*6569Smckusic 		ip->i_ib[NIADDR - 1] = (daddr_t)0;
262*6569Smckusic 		tloop(ip, bn, 1);
263*6569Smckusic 	}
264*6569Smckusic 	/*
265*6569Smckusic 	 * release single indirect blocks second
266*6569Smckusic 	 */
267*6569Smckusic 	for (i = NIADDR - 2; i >= 0; i--) {
268*6569Smckusic 		bn = ip->i_ib[i];
269*6569Smckusic 		if (bn != (daddr_t)0) {
270*6569Smckusic 			ip->i_ib[i] = (daddr_t)0;
271*6569Smckusic 			tloop(ip, bn, 0);
272*6569Smckusic 		}
273*6569Smckusic 	}
274*6569Smckusic 	/*
275*6569Smckusic 	 * finally release direct blocks
276*6569Smckusic 	 */
277*6569Smckusic 	for (i = NDADDR - 1; i>=0; i--) {
278*6569Smckusic 		bn = ip->i_db[i];
2794818Swnj 		if (bn == (daddr_t)0)
28024Sbill 			continue;
281*6569Smckusic 		ip->i_db[i] = (daddr_t)0;
282*6569Smckusic 		fre(ip, bn, (off_t)blksize(fs, ip, i));
28324Sbill 	}
28424Sbill 	ip->i_size = 0;
2851203Sbill 	/*
2861203Sbill 	 * Inode was written and flags updated above.
2871203Sbill 	 * No need to modify flags here.
2881203Sbill 	 */
28924Sbill }
29024Sbill 
291*6569Smckusic tloop(ip, bn, indflg)
292*6569Smckusic 	register struct inode *ip;
293*6569Smckusic 	daddr_t bn;
294*6569Smckusic 	int indflg;
29524Sbill {
29624Sbill 	register i;
29724Sbill 	register struct buf *bp;
29824Sbill 	register daddr_t *bap;
299*6569Smckusic 	register struct fs *fs;
30024Sbill 	daddr_t nb;
30124Sbill 
30224Sbill 	bp = NULL;
303*6569Smckusic 	fs = ip->i_fs;
304*6569Smckusic 	for (i = NINDIR(fs) - 1; i >= 0; i--) {
3054818Swnj 		if (bp == NULL) {
306*6569Smckusic 			bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize);
30724Sbill 			if (bp->b_flags & B_ERROR) {
30824Sbill 				brelse(bp);
30924Sbill 				return;
31024Sbill 			}
31124Sbill 			bap = bp->b_un.b_daddr;
31224Sbill 		}
31324Sbill 		nb = bap[i];
3144818Swnj 		if (nb == (daddr_t)0)
31524Sbill 			continue;
316*6569Smckusic 		if (indflg)
317*6569Smckusic 			tloop(ip, nb, 0);
318*6569Smckusic 		else
319*6569Smckusic 			fre(ip, nb, fs->fs_bsize);
32024Sbill 	}
3214818Swnj 	if (bp != NULL)
32224Sbill 		brelse(bp);
323*6569Smckusic 	fre(ip, bn, fs->fs_bsize);
32424Sbill }
32524Sbill 
32624Sbill /*
32724Sbill  * Make a new file.
32824Sbill  */
32924Sbill struct inode *
33024Sbill maknode(mode)
331*6569Smckusic 	int mode;
33224Sbill {
33324Sbill 	register struct inode *ip;
334*6569Smckusic 	ino_t ipref;
33524Sbill 
336*6569Smckusic 	if ((mode & IFMT) == IFDIR)
337*6569Smckusic 		ipref = dirpref(u.u_pdir->i_fs);
338*6569Smckusic 	else
339*6569Smckusic 		ipref = u.u_pdir->i_number;
340*6569Smckusic 	ip = ialloc(u.u_pdir, ipref, mode);
3414818Swnj 	if (ip == NULL) {
34224Sbill 		iput(u.u_pdir);
34324Sbill 		return(NULL);
34424Sbill 	}
34524Sbill 	ip->i_flag |= IACC|IUPD|ICHG;
346*6569Smckusic 	if ((mode & IFMT) == 0)
34724Sbill 		mode |= IFREG;
34824Sbill 	ip->i_mode = mode & ~u.u_cmask;
34924Sbill 	ip->i_nlink = 1;
35024Sbill 	ip->i_uid = u.u_uid;
3515855Swnj 	ip->i_gid = u.u_pdir->i_gid;
3521203Sbill 
3531203Sbill 	/*
3541203Sbill 	 * Make sure inode goes to disk before directory entry.
3551203Sbill 	 */
3561203Sbill 	iupdat(ip, &time, &time, 1);
35724Sbill 	wdir(ip);
358*6569Smckusic 	if (u.u_error) {
359*6569Smckusic 		/*
360*6569Smckusic 		 * write error occurred trying to update directory
361*6569Smckusic 		 * so must deallocate the inode
362*6569Smckusic 		 */
363*6569Smckusic 		ip->i_nlink = 0;
364*6569Smckusic 		ip->i_flag |= ICHG;
365*6569Smckusic 		iput(ip);
366*6569Smckusic 		return(NULL);
367*6569Smckusic 	}
36824Sbill 	return(ip);
36924Sbill }
37024Sbill 
37124Sbill /*
37224Sbill  * Write a directory entry with
37324Sbill  * parameters left as side effects
37424Sbill  * to a call to namei.
37524Sbill  */
37624Sbill wdir(ip)
3774818Swnj 	struct inode *ip;
37824Sbill {
379*6569Smckusic 	register struct direct *dp, *ndp;
380*6569Smckusic 	struct fs *fs;
381*6569Smckusic 	struct buf *bp;
382*6569Smckusic 	int lbn, bn, base;
383*6569Smckusic 	int loc, dsize, spccnt, newsize;
384*6569Smckusic 	char *dirbuf;
38524Sbill 
38624Sbill 	u.u_dent.d_ino = ip->i_number;
38724Sbill 	u.u_segflg = 1;
388*6569Smckusic 	newsize = DIRSIZ(&u.u_dent);
389*6569Smckusic 	/*
390*6569Smckusic 	 * if u.u_count == 0, a new directory block must be allocated.
391*6569Smckusic 	 */
392*6569Smckusic 	if (u.u_count == 0) {
393*6569Smckusic 		u.u_dent.d_reclen = DIRBLKSIZ;
394*6569Smckusic 		u.u_count = newsize;
395*6569Smckusic 		u.u_base = (caddr_t)&u.u_dent;
396*6569Smckusic 		writei(u.u_pdir);
397*6569Smckusic 		iput(u.u_pdir);
398*6569Smckusic 		return;
399*6569Smckusic 	}
400*6569Smckusic 	/*
401*6569Smckusic 	 * must read in an existing directory block
402*6569Smckusic 	 * to prepare to place the new entry into it.
403*6569Smckusic 	 */
404*6569Smckusic 	fs = u.u_pdir->i_fs;
405*6569Smckusic 	lbn = lblkno(fs, u.u_offset);
406*6569Smckusic 	base = blkoff(fs, u.u_offset);
407*6569Smckusic 	bn = fsbtodb(fs, bmap(u.u_pdir, lbn, B_WRITE, base + u.u_count));
408*6569Smckusic 	if (u.u_offset + u.u_count > u.u_pdir->i_size)
409*6569Smckusic 		u.u_pdir->i_size = u.u_offset + u.u_count;
410*6569Smckusic 	bp = bread(u.u_pdir->i_dev, bn, blksize(fs, u.u_pdir, lbn));
411*6569Smckusic 	if (bp->b_flags & B_ERROR) {
412*6569Smckusic 		brelse(bp);
413*6569Smckusic 		return;
414*6569Smckusic 	}
415*6569Smckusic 	dirbuf = bp->b_un.b_addr + base;
416*6569Smckusic 	dp = (struct direct *)dirbuf;
417*6569Smckusic 	dsize = DIRSIZ(dp);
418*6569Smckusic 	spccnt = dp->d_reclen - dsize;
419*6569Smckusic 	/*
420*6569Smckusic 	 * if there is insufficient room to make an entry at this point
421*6569Smckusic 	 * namei insures that compacting from u.u_offset for u.u_count
422*6569Smckusic 	 * bytes will provide the necessary space.
423*6569Smckusic 	 */
424*6569Smckusic 	for (loc = dp->d_reclen; loc < u.u_count; ) {
425*6569Smckusic 		ndp = (struct direct *)(dirbuf + loc);
426*6569Smckusic 		if (dp->d_ino == 0) {
427*6569Smckusic 			spccnt += dsize;
428*6569Smckusic 		} else {
429*6569Smckusic 			dp->d_reclen = dsize;
430*6569Smckusic 			dp = (struct direct *)((char *)dp + dsize);
431*6569Smckusic 		}
432*6569Smckusic 		dsize = DIRSIZ(ndp);
433*6569Smckusic 		spccnt += ndp->d_reclen - dsize;
434*6569Smckusic 		loc += ndp->d_reclen;
435*6569Smckusic 		bcopy(ndp, dp, dsize);
436*6569Smckusic 	}
437*6569Smckusic 	/*
438*6569Smckusic 	 * Update the pointer fields in the previous entry (if any),
439*6569Smckusic 	 * copy in the new entry, and write out the block.
440*6569Smckusic 	 */
441*6569Smckusic 	if (dp->d_ino == 0) {
442*6569Smckusic 		if (spccnt + dsize < newsize)
443*6569Smckusic 			panic("wdir: compact failed");
444*6569Smckusic 		u.u_dent.d_reclen = spccnt + dsize;
445*6569Smckusic 	} else {
446*6569Smckusic 		if (spccnt < newsize)
447*6569Smckusic 			panic("wdir: compact failed");
448*6569Smckusic 		u.u_dent.d_reclen = spccnt;
449*6569Smckusic 		dp->d_reclen = dsize;
450*6569Smckusic 		dp = (struct direct *)((char *)dp + dsize);
451*6569Smckusic 	}
452*6569Smckusic 	bcopy(&u.u_dent, dp, newsize);
453*6569Smckusic 	bwrite(bp);
454*6569Smckusic 	u.u_pdir->i_flag |= IUPD|ICHG;
45524Sbill 	iput(u.u_pdir);
45624Sbill }
4573617Sroot 
4584818Swnj #ifdef ilock
4594818Swnj #undef ilock
4603617Sroot #endif
4614818Swnj #ifdef irele
4624818Swnj #undef irele
4633617Sroot #endif
4643617Sroot /*
4654818Swnj  * Lock an inode. If its already locked, set the WANT bit and sleep.
4663617Sroot  */
4674818Swnj ilock(ip)
4684818Swnj 	register struct inode *ip;
4693617Sroot {
4703617Sroot 
4714818Swnj 	while (ip->i_flag&ILOCK) {
4723617Sroot 		ip->i_flag |= IWANT;
4733617Sroot 		sleep((caddr_t)ip, PINOD);
4743617Sroot 	}
4753617Sroot 	ip->i_flag |= ILOCK;
4763617Sroot }
4773617Sroot 
4783617Sroot /*
4794818Swnj  * Unlock an inode.  If WANT bit is on, wakeup.
4803617Sroot  */
4814818Swnj irele(ip)
4824818Swnj 	register struct inode *ip;
4833617Sroot {
4843617Sroot 
4853617Sroot 	ip->i_flag &= ~ILOCK;
4864818Swnj 	if (ip->i_flag&IWANT) {
4873617Sroot 		ip->i_flag &= ~IWANT;
4883617Sroot 		wakeup((caddr_t)ip);
4893617Sroot 	}
4903617Sroot }
491