xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 2933)
1*2933Swnj /*	lfs_inode.c	4.3	03/06/81	*/
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)
4424Sbill dev_t dev;
4524Sbill 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)
7324Sbill dev_t dev;
7424Sbill 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]) {
8624Sbill 		if(ino == ip->i_number && dev == ip->i_dev) {
8724Sbill 			if((ip->i_flag&ILOCK) != 0) {
8824Sbill 				ip->i_flag |= IWANT;
8924Sbill 				sleep((caddr_t)ip, PINOD);
9024Sbill 				goto loop;
9124Sbill 			}
9224Sbill 			if((ip->i_flag&IMOUNT) != 0) {
9324Sbill 				for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
9424Sbill 				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 	}
10724Sbill 	if(ifreel < 0) {
108*2933Swnj 		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 	 */
12524Sbill 	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)
13824Sbill register struct inode *ip;
13924Sbill 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)
16724Sbill register struct inode *ip;
16824Sbill {
16924Sbill 	register int i, x;
17024Sbill 	register struct inode *jp;
17124Sbill 
17224Sbill 	if(ip->i_count == 1) {
17324Sbill 		ip->i_flag |= ILOCK;
17424Sbill 		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);
18124Sbill 		prele(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
20124Sbill 		prele(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)
21424Sbill register struct inode *ip;
21524Sbill time_t *ta, *tm;
2161203Sbill int waitfor;
21724Sbill {
21824Sbill 	register struct buf *bp;
21924Sbill 	struct dinode *dp;
22024Sbill 	register char *p1, *p2;
22124Sbill 	register int i;
22224Sbill 
22324Sbill 	if((ip->i_flag&(IUPD|IACC|ICHG)) != 0) {
22424Sbill 		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++;
24424Sbill 			if(*p2++ != 0 && (ip->i_mode&IFMT)!=IFMPC
24524Sbill 			   && (ip->i_mode&IFMT)!=IFMPB)
24624Sbill 				printf("iaddress > 2^24\n");
24724Sbill 		}
24824Sbill 		if(ip->i_flag&IACC)
24924Sbill 			dp->di_atime = *ta;
25024Sbill 		if(ip->i_flag&IUPD)
25124Sbill 			dp->di_mtime = *tm;
25224Sbill 		if(ip->i_flag&ICHG)
25324Sbill 			dp->di_ctime = time;
25424Sbill 		ip->i_flag &= ~(IUPD|IACC|ICHG);
2551203Sbill 		if (waitfor)
2561203Sbill 			bwrite(bp);
2571203Sbill 		else
2581203Sbill 			bdwrite(bp);
25924Sbill 	}
26024Sbill }
26124Sbill 
26224Sbill /*
26324Sbill  * Free all the disk blocks associated
26424Sbill  * with the specified inode structure.
26524Sbill  * The blocks of the file are removed
26624Sbill  * in reverse order. This FILO
26724Sbill  * algorithm will tend to maintain
26824Sbill  * a contiguous free list much longer
26924Sbill  * than FIFO.
27024Sbill  */
27124Sbill itrunc(ip)
27224Sbill register struct inode *ip;
27324Sbill {
27424Sbill 	register i;
27524Sbill 	dev_t dev;
27624Sbill 	daddr_t bn;
2771203Sbill 	struct inode itmp;
27824Sbill 
27924Sbill 	if (ip->i_vfdcnt)
28024Sbill 		panic("itrunc");
28124Sbill 	i = ip->i_mode & IFMT;
28224Sbill 	if (i!=IFREG && i!=IFDIR)
28324Sbill 		return;
2841203Sbill 
2851203Sbill 	/*
2861203Sbill 	 * Clean inode on disk before freeing blocks
2871203Sbill 	 * to insure no duplicates if system crashes.
2881203Sbill 	 */
2891203Sbill 	itmp = *ip;
2901203Sbill 	itmp.i_size = 0;
2911203Sbill 	for (i = 0; i < NADDR; i++)
2921203Sbill 		itmp.i_un.i_addr[i] = 0;
2931203Sbill 	itmp.i_flag |= ICHG|IUPD;
2941203Sbill 	iupdat(&itmp, &time, &time, 1);
2951203Sbill 	ip->i_flag &= ~(IUPD|IACC|ICHG);
2961203Sbill 
2971203Sbill 	/*
2981203Sbill 	 * Now return blocks to free list... if machine
2991203Sbill 	 * crashes, they will be harmless MISSING blocks.
3001203Sbill 	 */
30124Sbill 	dev = ip->i_dev;
30224Sbill 	for(i=NADDR-1; i>=0; i--) {
30324Sbill 		bn = ip->i_un.i_addr[i];
30424Sbill 		if(bn == (daddr_t)0)
30524Sbill 			continue;
30624Sbill 		ip->i_un.i_addr[i] = (daddr_t)0;
30724Sbill 		switch(i) {
30824Sbill 
30924Sbill 		default:
31024Sbill 			free(dev, bn);
31124Sbill 			break;
31224Sbill 
31324Sbill 		case NADDR-3:
31424Sbill 			tloop(dev, bn, 0, 0);
31524Sbill 			break;
31624Sbill 
31724Sbill 		case NADDR-2:
31824Sbill 			tloop(dev, bn, 1, 0);
31924Sbill 			break;
32024Sbill 
32124Sbill 		case NADDR-1:
32224Sbill 			tloop(dev, bn, 1, 1);
32324Sbill 		}
32424Sbill 	}
32524Sbill 	ip->i_size = 0;
3261203Sbill 	/*
3271203Sbill 	 * Inode was written and flags updated above.
3281203Sbill 	 * No need to modify flags here.
3291203Sbill 	 */
33024Sbill }
33124Sbill 
33224Sbill tloop(dev, bn, f1, f2)
33324Sbill dev_t dev;
33424Sbill daddr_t bn;
33524Sbill {
33624Sbill 	register i;
33724Sbill 	register struct buf *bp;
33824Sbill 	register daddr_t *bap;
33924Sbill 	daddr_t nb;
34024Sbill 
34124Sbill 	bp = NULL;
34224Sbill 	for(i=NINDIR-1; i>=0; i--) {
34324Sbill 		if(bp == NULL) {
34424Sbill 			bp = bread(dev, bn);
34524Sbill 			if (bp->b_flags & B_ERROR) {
34624Sbill 				brelse(bp);
34724Sbill 				return;
34824Sbill 			}
34924Sbill 			bap = bp->b_un.b_daddr;
35024Sbill 		}
35124Sbill 		nb = bap[i];
35224Sbill 		if(nb == (daddr_t)0)
35324Sbill 			continue;
35424Sbill 		if(f1) {
35524Sbill 			brelse(bp);
35624Sbill 			bp = NULL;
35724Sbill 			tloop(dev, nb, f2, 0);
35824Sbill 		} else
35924Sbill 			free(dev, nb);
36024Sbill 	}
36124Sbill 	if(bp != NULL)
36224Sbill 		brelse(bp);
36324Sbill 	free(dev, bn);
36424Sbill }
36524Sbill 
36624Sbill /*
36724Sbill  * Make a new file.
36824Sbill  */
36924Sbill struct inode *
37024Sbill maknode(mode)
37124Sbill {
37224Sbill 	register struct inode *ip;
37324Sbill 
37424Sbill 	ip = ialloc(u.u_pdir->i_dev);
37524Sbill 	if(ip == NULL) {
37624Sbill 		iput(u.u_pdir);
37724Sbill 		return(NULL);
37824Sbill 	}
37924Sbill 	ip->i_flag |= IACC|IUPD|ICHG;
38024Sbill 	if((mode&IFMT) == 0)
38124Sbill 		mode |= IFREG;
38224Sbill 	ip->i_mode = mode & ~u.u_cmask;
38324Sbill 	ip->i_nlink = 1;
38424Sbill 	ip->i_uid = u.u_uid;
38524Sbill 	ip->i_gid = u.u_gid;
3861203Sbill 
3871203Sbill 	/*
3881203Sbill 	 * Make sure inode goes to disk before directory entry.
3891203Sbill 	 */
3901203Sbill 	iupdat(ip, &time, &time, 1);
3911203Sbill 
39224Sbill 	wdir(ip);
39324Sbill 	return(ip);
39424Sbill }
39524Sbill 
39624Sbill /*
39724Sbill  * Write a directory entry with
39824Sbill  * parameters left as side effects
39924Sbill  * to a call to namei.
40024Sbill  */
40124Sbill wdir(ip)
40224Sbill struct inode *ip;
40324Sbill {
40424Sbill 
40524Sbill 	u.u_dent.d_ino = ip->i_number;
40624Sbill 	bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_dent.d_name, DIRSIZ);
40724Sbill 	u.u_count = sizeof(struct direct);
40824Sbill 	u.u_segflg = 1;
40924Sbill 	u.u_base = (caddr_t)&u.u_dent;
41024Sbill 	writei(u.u_pdir);
41124Sbill 	iput(u.u_pdir);
41224Sbill }
413