xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 2737)
1*2737Swnj /*	lfs_inode.c	4.2	02/26/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;
27*2737Swnj 	register struct inode *ip = inode;
2824Sbill 
2924Sbill 	ifreel = 0;
30*2737Swnj 	for (i = 0; i < ninode-1; i++, ip++)
31*2737Swnj 		ip->i_hlink = i+1;
32*2737Swnj 	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  * printf warning: no inodes -- if the inode
6824Sbill  *	structure is full
6924Sbill  * panic: no imt -- if the mounted file
7024Sbill  *	system is not in the mount table.
7124Sbill  *	"cannot happen"
7224Sbill  */
7324Sbill struct inode *
7424Sbill iget(dev, ino)
7524Sbill dev_t dev;
7624Sbill ino_t ino;
7724Sbill {
7824Sbill 	register struct inode *ip;
7924Sbill 	register struct mount *mp;
8024Sbill 	register struct buf *bp;
8124Sbill 	register struct dinode *dp;
8224Sbill 	register int slot;
8324Sbill 
8424Sbill loop:
8524Sbill 	slot = INOHASH(dev, ino);
8624Sbill 	ip = &inode[inohash[slot]];
8724Sbill 	while (ip != &inode[-1]) {
8824Sbill 		if(ino == ip->i_number && dev == ip->i_dev) {
8924Sbill 			if((ip->i_flag&ILOCK) != 0) {
9024Sbill 				ip->i_flag |= IWANT;
9124Sbill 				sleep((caddr_t)ip, PINOD);
9224Sbill 				goto loop;
9324Sbill 			}
9424Sbill 			if((ip->i_flag&IMOUNT) != 0) {
9524Sbill 				for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
9624Sbill 				if(mp->m_inodp == ip) {
9724Sbill 					dev = mp->m_dev;
9824Sbill 					ino = ROOTINO;
9924Sbill 					goto loop;
10024Sbill 				}
10124Sbill 				panic("no imt");
10224Sbill 			}
10324Sbill 			ip->i_count++;
10424Sbill 			ip->i_flag |= ILOCK;
10524Sbill 			return(ip);
10624Sbill 		}
10724Sbill 		ip = &inode[ip->i_hlink];
10824Sbill 	}
10924Sbill 	if(ifreel < 0) {
11024Sbill 		printf("Inode table overflow\n");
11124Sbill 		u.u_error = ENFILE;
11224Sbill 		return(NULL);
11324Sbill 	}
11424Sbill 	ip = &inode[ifreel];
11524Sbill 	ifreel = ip->i_hlink;
11624Sbill 	ip->i_hlink = inohash[slot];
11724Sbill 	inohash[slot] = ip - inode;
11824Sbill 	ip->i_dev = dev;
11924Sbill 	ip->i_number = ino;
12024Sbill 	ip->i_flag = ILOCK;
12124Sbill 	ip->i_count++;
12224Sbill 	ip->i_un.i_lastr = 0;
12324Sbill 	bp = bread(dev, itod(ino));
12424Sbill 	/*
12524Sbill 	 * Check I/O errors
12624Sbill 	 */
12724Sbill 	if((bp->b_flags&B_ERROR) != 0) {
12824Sbill 		brelse(bp);
12924Sbill 		iput(ip);
13024Sbill 		return(NULL);
13124Sbill 	}
13224Sbill 	dp = bp->b_un.b_dino;
13324Sbill 	dp += itoo(ino);
13424Sbill 	iexpand(ip, dp);
13524Sbill 	brelse(bp);
13624Sbill 	return(ip);
13724Sbill }
13824Sbill 
13924Sbill iexpand(ip, dp)
14024Sbill register struct inode *ip;
14124Sbill register struct dinode *dp;
14224Sbill {
14324Sbill 	register char *p1, *p2;
14424Sbill 	register int i;
14524Sbill 
14624Sbill 	ip->i_mode = dp->di_mode;
14724Sbill 	ip->i_nlink = dp->di_nlink;
14824Sbill 	ip->i_uid = dp->di_uid;
14924Sbill 	ip->i_gid = dp->di_gid;
15024Sbill 	ip->i_size = dp->di_size;
15124Sbill 	p1 = (char *)ip->i_un.i_addr;
15224Sbill 	p2 = (char *)dp->di_addr;
15324Sbill 	for(i=0; i<NADDR; i++) {
15424Sbill 		*p1++ = *p2++;
15524Sbill 		*p1++ = *p2++;
15624Sbill 		*p1++ = *p2++;
15724Sbill 		*p1++ = 0;
15824Sbill 	}
15924Sbill }
16024Sbill 
16124Sbill /*
16224Sbill  * Decrement reference count of
16324Sbill  * an inode structure.
16424Sbill  * On the last reference,
16524Sbill  * write the inode out and if necessary,
16624Sbill  * truncate and deallocate the file.
16724Sbill  */
16824Sbill iput(ip)
16924Sbill register struct inode *ip;
17024Sbill {
17124Sbill 	register int i, x;
17224Sbill 	register struct inode *jp;
17324Sbill 
17424Sbill 	if(ip->i_count == 1) {
17524Sbill 		ip->i_flag |= ILOCK;
17624Sbill 		if(ip->i_nlink <= 0) {
17724Sbill 			itrunc(ip);
17824Sbill 			ip->i_mode = 0;
17924Sbill 			ip->i_flag |= IUPD|ICHG;
18024Sbill 			ifree(ip->i_dev, ip->i_number);
18124Sbill 		}
1821203Sbill 		IUPDAT(ip, &time, &time, 0);
18324Sbill 		prele(ip);
18424Sbill 		i = INOHASH(ip->i_dev, ip->i_number);
18524Sbill 		x = ip - inode;
18624Sbill 		if (inohash[i] == x) {
18724Sbill 			inohash[i] = ip->i_hlink;
18824Sbill 		} else {
18924Sbill 			for (jp = &inode[inohash[i]]; jp != &inode[-1];
19024Sbill 			    jp = &inode[jp->i_hlink])
19124Sbill 				if (jp->i_hlink == x) {
19224Sbill 					jp->i_hlink = ip->i_hlink;
19324Sbill 					goto done;
19424Sbill 				}
19524Sbill 			panic("iput");
19624Sbill 		}
19724Sbill done:
19824Sbill 		ip->i_hlink = ifreel;
19924Sbill 		ifreel = x;
20024Sbill 		ip->i_flag = 0;
20124Sbill 		ip->i_number = 0;
20224Sbill 	} else
20324Sbill 		prele(ip);
20424Sbill 	ip->i_count--;
20524Sbill }
20624Sbill 
20724Sbill /*
20824Sbill  * Check accessed and update flags on
20924Sbill  * an inode structure.
21024Sbill  * If any is on, update the inode
21124Sbill  * with the current time.
2121203Sbill  * If waitfor is given, then must insure
2131203Sbill  * i/o order so wait for write to complete.
21424Sbill  */
2151203Sbill iupdat(ip, ta, tm, waitfor)
21624Sbill register struct inode *ip;
21724Sbill time_t *ta, *tm;
2181203Sbill int waitfor;
21924Sbill {
22024Sbill 	register struct buf *bp;
22124Sbill 	struct dinode *dp;
22224Sbill 	register char *p1, *p2;
22324Sbill 	register int i;
22424Sbill 
22524Sbill 	if((ip->i_flag&(IUPD|IACC|ICHG)) != 0) {
22624Sbill 		if(getfs(ip->i_dev)->s_ronly)
22724Sbill 			return;
22824Sbill 		bp = bread(ip->i_dev, itod(ip->i_number));
22924Sbill 		if (bp->b_flags & B_ERROR) {
23024Sbill 			brelse(bp);
23124Sbill 			return;
23224Sbill 		}
23324Sbill 		dp = bp->b_un.b_dino;
23424Sbill 		dp += itoo(ip->i_number);
23524Sbill 		dp->di_mode = ip->i_mode;
23624Sbill 		dp->di_nlink = ip->i_nlink;
23724Sbill 		dp->di_uid = ip->i_uid;
23824Sbill 		dp->di_gid = ip->i_gid;
23924Sbill 		dp->di_size = ip->i_size;
24024Sbill 		p1 = (char *)dp->di_addr;
24124Sbill 		p2 = (char *)ip->i_un.i_addr;
24224Sbill 		for(i=0; i<NADDR; i++) {
24324Sbill 			*p1++ = *p2++;
24424Sbill 			*p1++ = *p2++;
24524Sbill 			*p1++ = *p2++;
24624Sbill 			if(*p2++ != 0 && (ip->i_mode&IFMT)!=IFMPC
24724Sbill 			   && (ip->i_mode&IFMT)!=IFMPB)
24824Sbill 				printf("iaddress > 2^24\n");
24924Sbill 		}
25024Sbill 		if(ip->i_flag&IACC)
25124Sbill 			dp->di_atime = *ta;
25224Sbill 		if(ip->i_flag&IUPD)
25324Sbill 			dp->di_mtime = *tm;
25424Sbill 		if(ip->i_flag&ICHG)
25524Sbill 			dp->di_ctime = time;
25624Sbill 		ip->i_flag &= ~(IUPD|IACC|ICHG);
2571203Sbill 		if (waitfor)
2581203Sbill 			bwrite(bp);
2591203Sbill 		else
2601203Sbill 			bdwrite(bp);
26124Sbill 	}
26224Sbill }
26324Sbill 
26424Sbill /*
26524Sbill  * Free all the disk blocks associated
26624Sbill  * with the specified inode structure.
26724Sbill  * The blocks of the file are removed
26824Sbill  * in reverse order. This FILO
26924Sbill  * algorithm will tend to maintain
27024Sbill  * a contiguous free list much longer
27124Sbill  * than FIFO.
27224Sbill  */
27324Sbill itrunc(ip)
27424Sbill register struct inode *ip;
27524Sbill {
27624Sbill 	register i;
27724Sbill 	dev_t dev;
27824Sbill 	daddr_t bn;
2791203Sbill 	struct inode itmp;
28024Sbill 
28124Sbill 	if (ip->i_vfdcnt)
28224Sbill 		panic("itrunc");
28324Sbill 	i = ip->i_mode & IFMT;
28424Sbill 	if (i!=IFREG && i!=IFDIR)
28524Sbill 		return;
2861203Sbill 
2871203Sbill 	/*
2881203Sbill 	 * Clean inode on disk before freeing blocks
2891203Sbill 	 * to insure no duplicates if system crashes.
2901203Sbill 	 */
2911203Sbill 	itmp = *ip;
2921203Sbill 	itmp.i_size = 0;
2931203Sbill 	for (i = 0; i < NADDR; i++)
2941203Sbill 		itmp.i_un.i_addr[i] = 0;
2951203Sbill 	itmp.i_flag |= ICHG|IUPD;
2961203Sbill 	iupdat(&itmp, &time, &time, 1);
2971203Sbill 	ip->i_flag &= ~(IUPD|IACC|ICHG);
2981203Sbill 
2991203Sbill 	/*
3001203Sbill 	 * Now return blocks to free list... if machine
3011203Sbill 	 * crashes, they will be harmless MISSING blocks.
3021203Sbill 	 */
30324Sbill 	dev = ip->i_dev;
30424Sbill 	for(i=NADDR-1; i>=0; i--) {
30524Sbill 		bn = ip->i_un.i_addr[i];
30624Sbill 		if(bn == (daddr_t)0)
30724Sbill 			continue;
30824Sbill 		ip->i_un.i_addr[i] = (daddr_t)0;
30924Sbill 		switch(i) {
31024Sbill 
31124Sbill 		default:
31224Sbill 			free(dev, bn);
31324Sbill 			break;
31424Sbill 
31524Sbill 		case NADDR-3:
31624Sbill 			tloop(dev, bn, 0, 0);
31724Sbill 			break;
31824Sbill 
31924Sbill 		case NADDR-2:
32024Sbill 			tloop(dev, bn, 1, 0);
32124Sbill 			break;
32224Sbill 
32324Sbill 		case NADDR-1:
32424Sbill 			tloop(dev, bn, 1, 1);
32524Sbill 		}
32624Sbill 	}
32724Sbill 	ip->i_size = 0;
3281203Sbill 	/*
3291203Sbill 	 * Inode was written and flags updated above.
3301203Sbill 	 * No need to modify flags here.
3311203Sbill 	 */
33224Sbill }
33324Sbill 
33424Sbill tloop(dev, bn, f1, f2)
33524Sbill dev_t dev;
33624Sbill daddr_t bn;
33724Sbill {
33824Sbill 	register i;
33924Sbill 	register struct buf *bp;
34024Sbill 	register daddr_t *bap;
34124Sbill 	daddr_t nb;
34224Sbill 
34324Sbill 	bp = NULL;
34424Sbill 	for(i=NINDIR-1; i>=0; i--) {
34524Sbill 		if(bp == NULL) {
34624Sbill 			bp = bread(dev, bn);
34724Sbill 			if (bp->b_flags & B_ERROR) {
34824Sbill 				brelse(bp);
34924Sbill 				return;
35024Sbill 			}
35124Sbill 			bap = bp->b_un.b_daddr;
35224Sbill 		}
35324Sbill 		nb = bap[i];
35424Sbill 		if(nb == (daddr_t)0)
35524Sbill 			continue;
35624Sbill 		if(f1) {
35724Sbill 			brelse(bp);
35824Sbill 			bp = NULL;
35924Sbill 			tloop(dev, nb, f2, 0);
36024Sbill 		} else
36124Sbill 			free(dev, nb);
36224Sbill 	}
36324Sbill 	if(bp != NULL)
36424Sbill 		brelse(bp);
36524Sbill 	free(dev, bn);
36624Sbill }
36724Sbill 
36824Sbill /*
36924Sbill  * Make a new file.
37024Sbill  */
37124Sbill struct inode *
37224Sbill maknode(mode)
37324Sbill {
37424Sbill 	register struct inode *ip;
37524Sbill 
37624Sbill 	ip = ialloc(u.u_pdir->i_dev);
37724Sbill 	if(ip == NULL) {
37824Sbill 		iput(u.u_pdir);
37924Sbill 		return(NULL);
38024Sbill 	}
38124Sbill 	ip->i_flag |= IACC|IUPD|ICHG;
38224Sbill 	if((mode&IFMT) == 0)
38324Sbill 		mode |= IFREG;
38424Sbill 	ip->i_mode = mode & ~u.u_cmask;
38524Sbill 	ip->i_nlink = 1;
38624Sbill 	ip->i_uid = u.u_uid;
38724Sbill 	ip->i_gid = u.u_gid;
3881203Sbill 
3891203Sbill 	/*
3901203Sbill 	 * Make sure inode goes to disk before directory entry.
3911203Sbill 	 */
3921203Sbill 	iupdat(ip, &time, &time, 1);
3931203Sbill 
39424Sbill 	wdir(ip);
39524Sbill 	return(ip);
39624Sbill }
39724Sbill 
39824Sbill /*
39924Sbill  * Write a directory entry with
40024Sbill  * parameters left as side effects
40124Sbill  * to a call to namei.
40224Sbill  */
40324Sbill wdir(ip)
40424Sbill struct inode *ip;
40524Sbill {
40624Sbill 
40724Sbill 	u.u_dent.d_ino = ip->i_number;
40824Sbill 	bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_dent.d_name, DIRSIZ);
40924Sbill 	u.u_count = sizeof(struct direct);
41024Sbill 	u.u_segflg = 1;
41124Sbill 	u.u_base = (caddr_t)&u.u_dent;
41224Sbill 	writei(u.u_pdir);
41324Sbill 	iput(u.u_pdir);
41424Sbill }
415