xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 5855)
1*5855Swnj /*	lfs_inode.c	4.8	82/02/15	*/
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"
924Sbill #include "../h/ino.h"
1024Sbill #include "../h/filsys.h"
1124Sbill #include "../h/conf.h"
1224Sbill #include "../h/buf.h"
1324Sbill #include "../h/inline.h"
1424Sbill 
1524Sbill #define	INOHSZ	63
1624Sbill #define	INOHASH(dev,ino)	(((dev)+(ino))%INOHSZ)
1724Sbill short	inohash[INOHSZ];
1824Sbill short	ifreel;
1924Sbill 
2024Sbill /*
2124Sbill  * Initialize hash links for inodes
2224Sbill  * and build inode free list.
2324Sbill  */
2424Sbill ihinit()
2524Sbill {
2624Sbill 	register int i;
272737Swnj 	register struct inode *ip = inode;
2824Sbill 
2924Sbill 	ifreel = 0;
302737Swnj 	for (i = 0; i < ninode-1; i++, ip++)
312737Swnj 		ip->i_hlink = i+1;
322737Swnj 	ip->i_hlink = -1;
3324Sbill 	for (i = 0; i < INOHSZ; i++)
3424Sbill 		inohash[i] = -1;
3524Sbill }
3624Sbill 
3724Sbill /*
3824Sbill  * Find an inode if it is incore.
3924Sbill  * This is the equivalent, for inodes,
4024Sbill  * of ``incore'' in bio.c or ``pfind'' in subr.c.
4124Sbill  */
4224Sbill struct inode *
4324Sbill ifind(dev, ino)
444818Swnj 	dev_t dev;
454818Swnj 	ino_t ino;
4624Sbill {
4724Sbill 	register struct inode *ip;
4824Sbill 
4924Sbill 	for (ip = &inode[inohash[INOHASH(dev,ino)]]; ip != &inode[-1];
5024Sbill 	    ip = &inode[ip->i_hlink])
5124Sbill 		if (ino==ip->i_number && dev==ip->i_dev)
5224Sbill 			return (ip);
5324Sbill 	return ((struct inode *)0);
5424Sbill }
5524Sbill 
5624Sbill /*
5724Sbill  * Look up an inode by device,inumber.
5824Sbill  * If it is in core (in the inode structure),
5924Sbill  * honor the locking protocol.
6024Sbill  * If it is not in core, read it in from the
6124Sbill  * specified device.
6224Sbill  * If the inode is mounted on, perform
6324Sbill  * the indicated indirection.
6424Sbill  * In all cases, a pointer to a locked
6524Sbill  * inode structure is returned.
6624Sbill  *
6724Sbill  * panic: no imt -- if the mounted file
6824Sbill  *	system is not in the mount table.
6924Sbill  *	"cannot happen"
7024Sbill  */
7124Sbill struct inode *
7224Sbill iget(dev, ino)
734818Swnj 	dev_t dev;
744818Swnj 	ino_t ino;
7524Sbill {
7624Sbill 	register struct inode *ip;
7724Sbill 	register struct mount *mp;
7824Sbill 	register struct buf *bp;
7924Sbill 	register struct dinode *dp;
8024Sbill 	register int slot;
8124Sbill 
8224Sbill loop:
8324Sbill 	slot = INOHASH(dev, ino);
8424Sbill 	ip = &inode[inohash[slot]];
8524Sbill 	while (ip != &inode[-1]) {
864818Swnj 		if (ino == ip->i_number && dev == ip->i_dev) {
874818Swnj 			if ((ip->i_flag&ILOCK) != 0) {
8824Sbill 				ip->i_flag |= IWANT;
8924Sbill 				sleep((caddr_t)ip, PINOD);
9024Sbill 				goto loop;
9124Sbill 			}
924818Swnj 			if ((ip->i_flag&IMOUNT) != 0) {
9324Sbill 				for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
944818Swnj 				if (mp->m_inodp == ip) {
9524Sbill 					dev = mp->m_dev;
9624Sbill 					ino = ROOTINO;
9724Sbill 					goto loop;
9824Sbill 				}
9924Sbill 				panic("no imt");
10024Sbill 			}
10124Sbill 			ip->i_count++;
10224Sbill 			ip->i_flag |= ILOCK;
10324Sbill 			return(ip);
10424Sbill 		}
10524Sbill 		ip = &inode[ip->i_hlink];
10624Sbill 	}
1074818Swnj 	if (ifreel < 0) {
1082933Swnj 		tablefull("inode");
10924Sbill 		u.u_error = ENFILE;
11024Sbill 		return(NULL);
11124Sbill 	}
11224Sbill 	ip = &inode[ifreel];
11324Sbill 	ifreel = ip->i_hlink;
11424Sbill 	ip->i_hlink = inohash[slot];
11524Sbill 	inohash[slot] = ip - inode;
11624Sbill 	ip->i_dev = dev;
11724Sbill 	ip->i_number = ino;
11824Sbill 	ip->i_flag = ILOCK;
11924Sbill 	ip->i_count++;
12024Sbill 	ip->i_un.i_lastr = 0;
12124Sbill 	bp = bread(dev, itod(ino));
12224Sbill 	/*
12324Sbill 	 * Check I/O errors
12424Sbill 	 */
1254818Swnj 	if ((bp->b_flags&B_ERROR) != 0) {
12624Sbill 		brelse(bp);
12724Sbill 		iput(ip);
12824Sbill 		return(NULL);
12924Sbill 	}
13024Sbill 	dp = bp->b_un.b_dino;
13124Sbill 	dp += itoo(ino);
13224Sbill 	iexpand(ip, dp);
13324Sbill 	brelse(bp);
13424Sbill 	return(ip);
13524Sbill }
13624Sbill 
13724Sbill iexpand(ip, dp)
1384818Swnj 	register struct inode *ip;
1394818Swnj 	register struct dinode *dp;
14024Sbill {
14124Sbill 	register char *p1, *p2;
14224Sbill 	register int i;
14324Sbill 
14424Sbill 	ip->i_mode = dp->di_mode;
14524Sbill 	ip->i_nlink = dp->di_nlink;
14624Sbill 	ip->i_uid = dp->di_uid;
14724Sbill 	ip->i_gid = dp->di_gid;
14824Sbill 	ip->i_size = dp->di_size;
14924Sbill 	p1 = (char *)ip->i_un.i_addr;
15024Sbill 	p2 = (char *)dp->di_addr;
15124Sbill 	for(i=0; i<NADDR; i++) {
15224Sbill 		*p1++ = *p2++;
15324Sbill 		*p1++ = *p2++;
15424Sbill 		*p1++ = *p2++;
15524Sbill 		*p1++ = 0;
15624Sbill 	}
15724Sbill }
15824Sbill 
15924Sbill /*
16024Sbill  * Decrement reference count of
16124Sbill  * an inode structure.
16224Sbill  * On the last reference,
16324Sbill  * write the inode out and if necessary,
16424Sbill  * truncate and deallocate the file.
16524Sbill  */
16624Sbill iput(ip)
1674818Swnj 	register struct inode *ip;
16824Sbill {
16924Sbill 	register int i, x;
17024Sbill 	register struct inode *jp;
17124Sbill 
1724818Swnj 	if (ip->i_count == 1) {
17324Sbill 		ip->i_flag |= ILOCK;
1744818Swnj 		if (ip->i_nlink <= 0) {
17524Sbill 			itrunc(ip);
17624Sbill 			ip->i_mode = 0;
17724Sbill 			ip->i_flag |= IUPD|ICHG;
17824Sbill 			ifree(ip->i_dev, ip->i_number);
17924Sbill 		}
1801203Sbill 		IUPDAT(ip, &time, &time, 0);
1814818Swnj 		irele(ip);
18224Sbill 		i = INOHASH(ip->i_dev, ip->i_number);
18324Sbill 		x = ip - inode;
18424Sbill 		if (inohash[i] == x) {
18524Sbill 			inohash[i] = ip->i_hlink;
18624Sbill 		} else {
18724Sbill 			for (jp = &inode[inohash[i]]; jp != &inode[-1];
18824Sbill 			    jp = &inode[jp->i_hlink])
18924Sbill 				if (jp->i_hlink == x) {
19024Sbill 					jp->i_hlink = ip->i_hlink;
19124Sbill 					goto done;
19224Sbill 				}
19324Sbill 			panic("iput");
19424Sbill 		}
19524Sbill done:
19624Sbill 		ip->i_hlink = ifreel;
19724Sbill 		ifreel = x;
19824Sbill 		ip->i_flag = 0;
19924Sbill 		ip->i_number = 0;
20024Sbill 	} else
2014818Swnj 		irele(ip);
20224Sbill 	ip->i_count--;
20324Sbill }
20424Sbill 
20524Sbill /*
20624Sbill  * Check accessed and update flags on
20724Sbill  * an inode structure.
20824Sbill  * If any is on, update the inode
20924Sbill  * with the current time.
2101203Sbill  * If waitfor is given, then must insure
2111203Sbill  * i/o order so wait for write to complete.
21224Sbill  */
2131203Sbill iupdat(ip, ta, tm, waitfor)
2144818Swnj 	register struct inode *ip;
2154818Swnj 	time_t *ta, *tm;
2164818Swnj 	int waitfor;
21724Sbill {
21824Sbill 	register struct buf *bp;
21924Sbill 	struct dinode *dp;
22024Sbill 	register char *p1, *p2;
22124Sbill 	register int i;
22224Sbill 
2234818Swnj 	if ((ip->i_flag&(IUPD|IACC|ICHG)) != 0) {
2244818Swnj 		if (getfs(ip->i_dev)->s_ronly)
22524Sbill 			return;
22624Sbill 		bp = bread(ip->i_dev, itod(ip->i_number));
22724Sbill 		if (bp->b_flags & B_ERROR) {
22824Sbill 			brelse(bp);
22924Sbill 			return;
23024Sbill 		}
23124Sbill 		dp = bp->b_un.b_dino;
23224Sbill 		dp += itoo(ip->i_number);
23324Sbill 		dp->di_mode = ip->i_mode;
23424Sbill 		dp->di_nlink = ip->i_nlink;
23524Sbill 		dp->di_uid = ip->i_uid;
23624Sbill 		dp->di_gid = ip->i_gid;
23724Sbill 		dp->di_size = ip->i_size;
23824Sbill 		p1 = (char *)dp->di_addr;
23924Sbill 		p2 = (char *)ip->i_un.i_addr;
24024Sbill 		for(i=0; i<NADDR; i++) {
24124Sbill 			*p1++ = *p2++;
24224Sbill 			*p1++ = *p2++;
24324Sbill 			*p1++ = *p2++;
2444818Swnj 			if (*p2++ != 0)
24524Sbill 				printf("iaddress > 2^24\n");
24624Sbill 		}
2474818Swnj 		if (ip->i_flag&IACC)
24824Sbill 			dp->di_atime = *ta;
2494818Swnj 		if (ip->i_flag&IUPD)
25024Sbill 			dp->di_mtime = *tm;
2514818Swnj 		if (ip->i_flag&ICHG)
25224Sbill 			dp->di_ctime = time;
25324Sbill 		ip->i_flag &= ~(IUPD|IACC|ICHG);
2541203Sbill 		if (waitfor)
2551203Sbill 			bwrite(bp);
2561203Sbill 		else
2571203Sbill 			bdwrite(bp);
25824Sbill 	}
25924Sbill }
26024Sbill 
26124Sbill /*
26224Sbill  * Free all the disk blocks associated
26324Sbill  * with the specified inode structure.
26424Sbill  * The blocks of the file are removed
26524Sbill  * in reverse order. This FILO
26624Sbill  * algorithm will tend to maintain
26724Sbill  * a contiguous free list much longer
26824Sbill  * than FIFO.
26924Sbill  */
27024Sbill itrunc(ip)
2714818Swnj 	register struct inode *ip;
27224Sbill {
27324Sbill 	register i;
27424Sbill 	dev_t dev;
27524Sbill 	daddr_t bn;
2761203Sbill 	struct inode itmp;
27724Sbill 
27824Sbill 	i = ip->i_mode & IFMT;
27924Sbill 	if (i!=IFREG && i!=IFDIR)
28024Sbill 		return;
2811203Sbill 
2821203Sbill 	/*
2831203Sbill 	 * Clean inode on disk before freeing blocks
2841203Sbill 	 * to insure no duplicates if system crashes.
2851203Sbill 	 */
2861203Sbill 	itmp = *ip;
2871203Sbill 	itmp.i_size = 0;
2881203Sbill 	for (i = 0; i < NADDR; i++)
2891203Sbill 		itmp.i_un.i_addr[i] = 0;
2901203Sbill 	itmp.i_flag |= ICHG|IUPD;
2911203Sbill 	iupdat(&itmp, &time, &time, 1);
2921203Sbill 	ip->i_flag &= ~(IUPD|IACC|ICHG);
2931203Sbill 
2941203Sbill 	/*
2951203Sbill 	 * Now return blocks to free list... if machine
2961203Sbill 	 * crashes, they will be harmless MISSING blocks.
2971203Sbill 	 */
29824Sbill 	dev = ip->i_dev;
29924Sbill 	for(i=NADDR-1; i>=0; i--) {
30024Sbill 		bn = ip->i_un.i_addr[i];
3014818Swnj 		if (bn == (daddr_t)0)
30224Sbill 			continue;
30324Sbill 		ip->i_un.i_addr[i] = (daddr_t)0;
30424Sbill 		switch(i) {
30524Sbill 
30624Sbill 		default:
30724Sbill 			free(dev, bn);
30824Sbill 			break;
30924Sbill 
31024Sbill 		case NADDR-3:
31124Sbill 			tloop(dev, bn, 0, 0);
31224Sbill 			break;
31324Sbill 
31424Sbill 		case NADDR-2:
31524Sbill 			tloop(dev, bn, 1, 0);
31624Sbill 			break;
31724Sbill 
31824Sbill 		case NADDR-1:
31924Sbill 			tloop(dev, bn, 1, 1);
32024Sbill 		}
32124Sbill 	}
32224Sbill 	ip->i_size = 0;
3231203Sbill 	/*
3241203Sbill 	 * Inode was written and flags updated above.
3251203Sbill 	 * No need to modify flags here.
3261203Sbill 	 */
32724Sbill }
32824Sbill 
32924Sbill tloop(dev, bn, f1, f2)
33024Sbill dev_t dev;
33124Sbill daddr_t bn;
33224Sbill {
33324Sbill 	register i;
33424Sbill 	register struct buf *bp;
33524Sbill 	register daddr_t *bap;
33624Sbill 	daddr_t nb;
33724Sbill 
33824Sbill 	bp = NULL;
33924Sbill 	for(i=NINDIR-1; i>=0; i--) {
3404818Swnj 		if (bp == NULL) {
34124Sbill 			bp = bread(dev, bn);
34224Sbill 			if (bp->b_flags & B_ERROR) {
34324Sbill 				brelse(bp);
34424Sbill 				return;
34524Sbill 			}
34624Sbill 			bap = bp->b_un.b_daddr;
34724Sbill 		}
34824Sbill 		nb = bap[i];
3494818Swnj 		if (nb == (daddr_t)0)
35024Sbill 			continue;
3514818Swnj 		if (f1) {
35224Sbill 			brelse(bp);
35324Sbill 			bp = NULL;
35424Sbill 			tloop(dev, nb, f2, 0);
35524Sbill 		} else
35624Sbill 			free(dev, nb);
35724Sbill 	}
3584818Swnj 	if (bp != NULL)
35924Sbill 		brelse(bp);
36024Sbill 	free(dev, bn);
36124Sbill }
36224Sbill 
36324Sbill /*
36424Sbill  * Make a new file.
36524Sbill  */
36624Sbill struct inode *
36724Sbill maknode(mode)
36824Sbill {
36924Sbill 	register struct inode *ip;
37024Sbill 
37124Sbill 	ip = ialloc(u.u_pdir->i_dev);
3724818Swnj 	if (ip == NULL) {
37324Sbill 		iput(u.u_pdir);
37424Sbill 		return(NULL);
37524Sbill 	}
37624Sbill 	ip->i_flag |= IACC|IUPD|ICHG;
3774818Swnj 	if ((mode&IFMT) == 0)
37824Sbill 		mode |= IFREG;
37924Sbill 	ip->i_mode = mode & ~u.u_cmask;
38024Sbill 	ip->i_nlink = 1;
38124Sbill 	ip->i_uid = u.u_uid;
382*5855Swnj 	ip->i_gid = u.u_pdir->i_gid;
3831203Sbill 
3841203Sbill 	/*
3851203Sbill 	 * Make sure inode goes to disk before directory entry.
3861203Sbill 	 */
3871203Sbill 	iupdat(ip, &time, &time, 1);
3881203Sbill 
38924Sbill 	wdir(ip);
39024Sbill 	return(ip);
39124Sbill }
39224Sbill 
39324Sbill /*
39424Sbill  * Write a directory entry with
39524Sbill  * parameters left as side effects
39624Sbill  * to a call to namei.
39724Sbill  */
39824Sbill wdir(ip)
3994818Swnj 	struct inode *ip;
40024Sbill {
40124Sbill 
40224Sbill 	u.u_dent.d_ino = ip->i_number;
40324Sbill 	bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_dent.d_name, DIRSIZ);
40424Sbill 	u.u_count = sizeof(struct direct);
40524Sbill 	u.u_segflg = 1;
40624Sbill 	u.u_base = (caddr_t)&u.u_dent;
40724Sbill 	writei(u.u_pdir);
40824Sbill 	iput(u.u_pdir);
40924Sbill }
4103617Sroot 
4114818Swnj #ifdef ilock
4124818Swnj #undef ilock
4133617Sroot #endif
4144818Swnj #ifdef irele
4154818Swnj #undef irele
4163617Sroot #endif
4173617Sroot /*
4184818Swnj  * Lock an inode. If its already locked, set the WANT bit and sleep.
4193617Sroot  */
4204818Swnj ilock(ip)
4214818Swnj 	register struct inode *ip;
4223617Sroot {
4233617Sroot 
4244818Swnj 	while (ip->i_flag&ILOCK) {
4253617Sroot 		ip->i_flag |= IWANT;
4263617Sroot 		sleep((caddr_t)ip, PINOD);
4273617Sroot 	}
4283617Sroot 	ip->i_flag |= ILOCK;
4293617Sroot }
4303617Sroot 
4313617Sroot /*
4324818Swnj  * Unlock an inode.  If WANT bit is on, wakeup.
4333617Sroot  */
4344818Swnj irele(ip)
4354818Swnj 	register struct inode *ip;
4363617Sroot {
4373617Sroot 
4383617Sroot 	ip->i_flag &= ~ILOCK;
4394818Swnj 	if (ip->i_flag&IWANT) {
4403617Sroot 		ip->i_flag &= ~IWANT;
4413617Sroot 		wakeup((caddr_t)ip);
4423617Sroot 	}
4433617Sroot }
444