xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 1203)
1*1203Sbill /*	lfs_inode.c	3.5	10/03/80	*/
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;
2724Sbill 
2824Sbill 	ifreel = 0;
2924Sbill 	for (i = 0; i < NINODE - 1; i++)
3024Sbill 		inode[i].i_hlink = i+1;
3124Sbill 	inode[NINODE - 1].i_hlink = -1;
3224Sbill 	for (i = 0; i < INOHSZ; i++)
3324Sbill 		inohash[i] = -1;
3424Sbill }
3524Sbill 
3624Sbill /*
3724Sbill  * Find an inode if it is incore.
3824Sbill  * This is the equivalent, for inodes,
3924Sbill  * of ``incore'' in bio.c or ``pfind'' in subr.c.
4024Sbill  */
4124Sbill struct inode *
4224Sbill ifind(dev, ino)
4324Sbill dev_t dev;
4424Sbill ino_t ino;
4524Sbill {
4624Sbill 	register struct inode *ip;
4724Sbill 
4824Sbill 	for (ip = &inode[inohash[INOHASH(dev,ino)]]; ip != &inode[-1];
4924Sbill 	    ip = &inode[ip->i_hlink])
5024Sbill 		if (ino==ip->i_number && dev==ip->i_dev)
5124Sbill 			return (ip);
5224Sbill 	return ((struct inode *)0);
5324Sbill }
5424Sbill 
5524Sbill /*
5624Sbill  * Look up an inode by device,inumber.
5724Sbill  * If it is in core (in the inode structure),
5824Sbill  * honor the locking protocol.
5924Sbill  * If it is not in core, read it in from the
6024Sbill  * specified device.
6124Sbill  * If the inode is mounted on, perform
6224Sbill  * the indicated indirection.
6324Sbill  * In all cases, a pointer to a locked
6424Sbill  * inode structure is returned.
6524Sbill  *
6624Sbill  * printf warning: no inodes -- if the inode
6724Sbill  *	structure is full
6824Sbill  * panic: no imt -- if the mounted file
6924Sbill  *	system is not in the mount table.
7024Sbill  *	"cannot happen"
7124Sbill  */
7224Sbill struct inode *
7324Sbill iget(dev, ino)
7424Sbill dev_t dev;
7524Sbill ino_t ino;
7624Sbill {
7724Sbill 	register struct inode *ip;
7824Sbill 	register struct mount *mp;
7924Sbill 	register struct buf *bp;
8024Sbill 	register struct dinode *dp;
8124Sbill 	register int slot;
8224Sbill 
8324Sbill loop:
8424Sbill 	slot = INOHASH(dev, ino);
8524Sbill 	ip = &inode[inohash[slot]];
8624Sbill 	while (ip != &inode[-1]) {
8724Sbill 		if(ino == ip->i_number && dev == ip->i_dev) {
8824Sbill 			if((ip->i_flag&ILOCK) != 0) {
8924Sbill 				ip->i_flag |= IWANT;
9024Sbill 				sleep((caddr_t)ip, PINOD);
9124Sbill 				goto loop;
9224Sbill 			}
9324Sbill 			if((ip->i_flag&IMOUNT) != 0) {
9424Sbill 				for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
9524Sbill 				if(mp->m_inodp == ip) {
9624Sbill 					dev = mp->m_dev;
9724Sbill 					ino = ROOTINO;
9824Sbill 					goto loop;
9924Sbill 				}
10024Sbill 				panic("no imt");
10124Sbill 			}
10224Sbill 			ip->i_count++;
10324Sbill 			ip->i_flag |= ILOCK;
10424Sbill 			return(ip);
10524Sbill 		}
10624Sbill 		ip = &inode[ip->i_hlink];
10724Sbill 	}
10824Sbill 	if(ifreel < 0) {
10924Sbill 		printf("Inode table overflow\n");
11024Sbill 		u.u_error = ENFILE;
11124Sbill 		return(NULL);
11224Sbill 	}
11324Sbill 	ip = &inode[ifreel];
11424Sbill 	ifreel = ip->i_hlink;
11524Sbill 	ip->i_hlink = inohash[slot];
11624Sbill 	inohash[slot] = ip - inode;
11724Sbill 	ip->i_dev = dev;
11824Sbill 	ip->i_number = ino;
11924Sbill 	ip->i_flag = ILOCK;
12024Sbill 	ip->i_count++;
12124Sbill 	ip->i_un.i_lastr = 0;
12224Sbill 	bp = bread(dev, itod(ino));
12324Sbill 	/*
12424Sbill 	 * Check I/O errors
12524Sbill 	 */
12624Sbill 	if((bp->b_flags&B_ERROR) != 0) {
12724Sbill 		brelse(bp);
12824Sbill 		iput(ip);
12924Sbill 		return(NULL);
13024Sbill 	}
13124Sbill 	dp = bp->b_un.b_dino;
13224Sbill 	dp += itoo(ino);
13324Sbill 	iexpand(ip, dp);
13424Sbill 	brelse(bp);
13524Sbill 	return(ip);
13624Sbill }
13724Sbill 
13824Sbill iexpand(ip, dp)
13924Sbill register struct inode *ip;
14024Sbill register struct dinode *dp;
14124Sbill {
14224Sbill 	register char *p1, *p2;
14324Sbill 	register int i;
14424Sbill 
14524Sbill 	ip->i_mode = dp->di_mode;
14624Sbill 	ip->i_nlink = dp->di_nlink;
14724Sbill 	ip->i_uid = dp->di_uid;
14824Sbill 	ip->i_gid = dp->di_gid;
14924Sbill 	ip->i_size = dp->di_size;
15024Sbill 	p1 = (char *)ip->i_un.i_addr;
15124Sbill 	p2 = (char *)dp->di_addr;
15224Sbill 	for(i=0; i<NADDR; i++) {
15324Sbill 		*p1++ = *p2++;
15424Sbill 		*p1++ = *p2++;
15524Sbill 		*p1++ = *p2++;
15624Sbill 		*p1++ = 0;
15724Sbill 	}
15824Sbill }
15924Sbill 
16024Sbill /*
16124Sbill  * Decrement reference count of
16224Sbill  * an inode structure.
16324Sbill  * On the last reference,
16424Sbill  * write the inode out and if necessary,
16524Sbill  * truncate and deallocate the file.
16624Sbill  */
16724Sbill iput(ip)
16824Sbill register struct inode *ip;
16924Sbill {
17024Sbill 	register int i, x;
17124Sbill 	register struct inode *jp;
17224Sbill 
17324Sbill 	if(ip->i_count == 1) {
17424Sbill 		ip->i_flag |= ILOCK;
17524Sbill 		if(ip->i_nlink <= 0) {
17624Sbill 			itrunc(ip);
17724Sbill 			ip->i_mode = 0;
17824Sbill 			ip->i_flag |= IUPD|ICHG;
17924Sbill 			ifree(ip->i_dev, ip->i_number);
18024Sbill 		}
181*1203Sbill 		IUPDAT(ip, &time, &time, 0);
18224Sbill 		prele(ip);
18324Sbill 		i = INOHASH(ip->i_dev, ip->i_number);
18424Sbill 		x = ip - inode;
18524Sbill 		if (inohash[i] == x) {
18624Sbill 			inohash[i] = ip->i_hlink;
18724Sbill 		} else {
18824Sbill 			for (jp = &inode[inohash[i]]; jp != &inode[-1];
18924Sbill 			    jp = &inode[jp->i_hlink])
19024Sbill 				if (jp->i_hlink == x) {
19124Sbill 					jp->i_hlink = ip->i_hlink;
19224Sbill 					goto done;
19324Sbill 				}
19424Sbill 			panic("iput");
19524Sbill 		}
19624Sbill done:
19724Sbill 		ip->i_hlink = ifreel;
19824Sbill 		ifreel = x;
19924Sbill 		ip->i_flag = 0;
20024Sbill 		ip->i_number = 0;
20124Sbill 	} else
20224Sbill 		prele(ip);
20324Sbill 	ip->i_count--;
20424Sbill }
20524Sbill 
20624Sbill /*
20724Sbill  * Check accessed and update flags on
20824Sbill  * an inode structure.
20924Sbill  * If any is on, update the inode
21024Sbill  * with the current time.
211*1203Sbill  * If waitfor is given, then must insure
212*1203Sbill  * i/o order so wait for write to complete.
21324Sbill  */
214*1203Sbill iupdat(ip, ta, tm, waitfor)
21524Sbill register struct inode *ip;
21624Sbill time_t *ta, *tm;
217*1203Sbill int waitfor;
21824Sbill {
21924Sbill 	register struct buf *bp;
22024Sbill 	struct dinode *dp;
22124Sbill 	register char *p1, *p2;
22224Sbill 	register int i;
22324Sbill 
22424Sbill 	if((ip->i_flag&(IUPD|IACC|ICHG)) != 0) {
22524Sbill 		if(getfs(ip->i_dev)->s_ronly)
22624Sbill 			return;
22724Sbill 		bp = bread(ip->i_dev, itod(ip->i_number));
22824Sbill 		if (bp->b_flags & B_ERROR) {
22924Sbill 			brelse(bp);
23024Sbill 			return;
23124Sbill 		}
23224Sbill 		dp = bp->b_un.b_dino;
23324Sbill 		dp += itoo(ip->i_number);
23424Sbill 		dp->di_mode = ip->i_mode;
23524Sbill 		dp->di_nlink = ip->i_nlink;
23624Sbill 		dp->di_uid = ip->i_uid;
23724Sbill 		dp->di_gid = ip->i_gid;
23824Sbill 		dp->di_size = ip->i_size;
23924Sbill 		p1 = (char *)dp->di_addr;
24024Sbill 		p2 = (char *)ip->i_un.i_addr;
24124Sbill 		for(i=0; i<NADDR; i++) {
24224Sbill 			*p1++ = *p2++;
24324Sbill 			*p1++ = *p2++;
24424Sbill 			*p1++ = *p2++;
24524Sbill 			if(*p2++ != 0 && (ip->i_mode&IFMT)!=IFMPC
24624Sbill 			   && (ip->i_mode&IFMT)!=IFMPB)
24724Sbill 				printf("iaddress > 2^24\n");
24824Sbill 		}
24924Sbill 		if(ip->i_flag&IACC)
25024Sbill 			dp->di_atime = *ta;
25124Sbill 		if(ip->i_flag&IUPD)
25224Sbill 			dp->di_mtime = *tm;
25324Sbill 		if(ip->i_flag&ICHG)
25424Sbill 			dp->di_ctime = time;
25524Sbill 		ip->i_flag &= ~(IUPD|IACC|ICHG);
256*1203Sbill 		if (waitfor)
257*1203Sbill 			bwrite(bp);
258*1203Sbill 		else
259*1203Sbill 			bdwrite(bp);
26024Sbill 	}
26124Sbill }
26224Sbill 
26324Sbill /*
26424Sbill  * Free all the disk blocks associated
26524Sbill  * with the specified inode structure.
26624Sbill  * The blocks of the file are removed
26724Sbill  * in reverse order. This FILO
26824Sbill  * algorithm will tend to maintain
26924Sbill  * a contiguous free list much longer
27024Sbill  * than FIFO.
27124Sbill  */
27224Sbill itrunc(ip)
27324Sbill register struct inode *ip;
27424Sbill {
27524Sbill 	register i;
27624Sbill 	dev_t dev;
27724Sbill 	daddr_t bn;
278*1203Sbill 	struct inode itmp;
27924Sbill 
28024Sbill 	if (ip->i_vfdcnt)
28124Sbill 		panic("itrunc");
28224Sbill 	i = ip->i_mode & IFMT;
28324Sbill 	if (i!=IFREG && i!=IFDIR)
28424Sbill 		return;
285*1203Sbill 
286*1203Sbill 	/*
287*1203Sbill 	 * Clean inode on disk before freeing blocks
288*1203Sbill 	 * to insure no duplicates if system crashes.
289*1203Sbill 	 */
290*1203Sbill 	itmp = *ip;
291*1203Sbill 	itmp.i_size = 0;
292*1203Sbill 	for (i = 0; i < NADDR; i++)
293*1203Sbill 		itmp.i_un.i_addr[i] = 0;
294*1203Sbill 	itmp.i_flag |= ICHG|IUPD;
295*1203Sbill 	iupdat(&itmp, &time, &time, 1);
296*1203Sbill 	ip->i_flag &= ~(IUPD|IACC|ICHG);
297*1203Sbill 
298*1203Sbill 	/*
299*1203Sbill 	 * Now return blocks to free list... if machine
300*1203Sbill 	 * crashes, they will be harmless MISSING blocks.
301*1203Sbill 	 */
30224Sbill 	dev = ip->i_dev;
30324Sbill 	for(i=NADDR-1; i>=0; i--) {
30424Sbill 		bn = ip->i_un.i_addr[i];
30524Sbill 		if(bn == (daddr_t)0)
30624Sbill 			continue;
30724Sbill 		ip->i_un.i_addr[i] = (daddr_t)0;
30824Sbill 		switch(i) {
30924Sbill 
31024Sbill 		default:
31124Sbill 			free(dev, bn);
31224Sbill 			break;
31324Sbill 
31424Sbill 		case NADDR-3:
31524Sbill 			tloop(dev, bn, 0, 0);
31624Sbill 			break;
31724Sbill 
31824Sbill 		case NADDR-2:
31924Sbill 			tloop(dev, bn, 1, 0);
32024Sbill 			break;
32124Sbill 
32224Sbill 		case NADDR-1:
32324Sbill 			tloop(dev, bn, 1, 1);
32424Sbill 		}
32524Sbill 	}
32624Sbill 	ip->i_size = 0;
327*1203Sbill 	/*
328*1203Sbill 	 * Inode was written and flags updated above.
329*1203Sbill 	 * No need to modify flags here.
330*1203Sbill 	 */
33124Sbill }
33224Sbill 
33324Sbill tloop(dev, bn, f1, f2)
33424Sbill dev_t dev;
33524Sbill daddr_t bn;
33624Sbill {
33724Sbill 	register i;
33824Sbill 	register struct buf *bp;
33924Sbill 	register daddr_t *bap;
34024Sbill 	daddr_t nb;
34124Sbill 
34224Sbill 	bp = NULL;
34324Sbill 	for(i=NINDIR-1; i>=0; i--) {
34424Sbill 		if(bp == NULL) {
34524Sbill 			bp = bread(dev, bn);
34624Sbill 			if (bp->b_flags & B_ERROR) {
34724Sbill 				brelse(bp);
34824Sbill 				return;
34924Sbill 			}
35024Sbill 			bap = bp->b_un.b_daddr;
35124Sbill 		}
35224Sbill 		nb = bap[i];
35324Sbill 		if(nb == (daddr_t)0)
35424Sbill 			continue;
35524Sbill 		if(f1) {
35624Sbill 			brelse(bp);
35724Sbill 			bp = NULL;
35824Sbill 			tloop(dev, nb, f2, 0);
35924Sbill 		} else
36024Sbill 			free(dev, nb);
36124Sbill 	}
36224Sbill 	if(bp != NULL)
36324Sbill 		brelse(bp);
36424Sbill 	free(dev, bn);
36524Sbill }
36624Sbill 
36724Sbill /*
36824Sbill  * Make a new file.
36924Sbill  */
37024Sbill struct inode *
37124Sbill maknode(mode)
37224Sbill {
37324Sbill 	register struct inode *ip;
37424Sbill 
37524Sbill 	ip = ialloc(u.u_pdir->i_dev);
37624Sbill 	if(ip == NULL) {
37724Sbill 		iput(u.u_pdir);
37824Sbill 		return(NULL);
37924Sbill 	}
38024Sbill 	ip->i_flag |= IACC|IUPD|ICHG;
38124Sbill 	if((mode&IFMT) == 0)
38224Sbill 		mode |= IFREG;
38324Sbill 	ip->i_mode = mode & ~u.u_cmask;
38424Sbill 	ip->i_nlink = 1;
38524Sbill 	ip->i_uid = u.u_uid;
38624Sbill 	ip->i_gid = u.u_gid;
387*1203Sbill 
388*1203Sbill 	/*
389*1203Sbill 	 * Make sure inode goes to disk before directory entry.
390*1203Sbill 	 */
391*1203Sbill 	iupdat(ip, &time, &time, 1);
392*1203Sbill 
39324Sbill 	wdir(ip);
39424Sbill 	return(ip);
39524Sbill }
39624Sbill 
39724Sbill /*
39824Sbill  * Write a directory entry with
39924Sbill  * parameters left as side effects
40024Sbill  * to a call to namei.
40124Sbill  */
40224Sbill wdir(ip)
40324Sbill struct inode *ip;
40424Sbill {
40524Sbill 
40624Sbill 	u.u_dent.d_ino = ip->i_number;
40724Sbill 	bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_dent.d_name, DIRSIZ);
40824Sbill 	u.u_count = sizeof(struct direct);
40924Sbill 	u.u_segflg = 1;
41024Sbill 	u.u_base = (caddr_t)&u.u_dent;
41124Sbill 	writei(u.u_pdir);
41224Sbill 	iput(u.u_pdir);
41324Sbill }
414