/* @(#)iget.c	1.4 */#include "sys/param.h"#include "sys/types.h"#include "sys/sysmacros.h"#include "sys/systm.h"#include "sys/sysinfo.h"#include "sys/mount.h"#include "sys/dir.h"#include "sys/signal.h"#include "sys/user.h"#include "sys/errno.h"#include "sys/inode.h"#include "sys/file.h"#include "sys/ino.h"#include "sys/filsys.h"#include "sys/buf.h"#include "sys/var.h"/* * Look up an inode by device,inumber. * If it is in core (in the inode structure), honor the locking protocol. * If it is not in core, read it in from the specified device. * If the inode is mounted on, perform the indicated indirection. * In all cases, a pointer to a locked inode structure is returned. * * printf warning: no inodes -- if the inode structure is full * panic: no imt -- if the mounted filesystem is not in the mount table. *	"cannot happen" */#define	NHINO	128	/* must be power of 2 */#define	ihash(X)	(&hinode[(int)(X) & (NHINO-1)])struct	hinode {	struct inode *i_forw;} hinode[NHINO];struct inode *ifreelist;struct inode *iget(dev, ino)dev_t dev;ino_t ino;{	register struct inode *ip;	register struct hinode *hip;	register struct mount *mp;	struct inode *iread();	sysinfo.iget++;loop:	hip = ihash(ino);	for (ip = hip->i_forw; ip; ip = ip->i_forw)		if (ino == ip->i_number && dev == ip->i_dev)			goto found;	if ((ip = ifreelist) == NULL) {		printf("Inode table overflow\n");		syserr.inodeovf++;		u.u_error = ENFILE;		return(NULL);	}	ifreelist = ip->i_forw;	if (ip->i_forw = hip->i_forw)		ip->i_forw->i_back = ip;	ip->i_back = (struct inode *)hip;	hip->i_forw = ip;	ip->i_dev = dev;	ip->i_number = ino;	ip->i_flag = ILOCK;	ip->i_count++;	ip->i_lastr = 0;	return(iread(ip));found:	if((ip->i_flag&ILOCK) != 0) {		ip->i_flag |= IWANT;		(void) sleep((caddr_t)ip, PINOD);		goto loop;	}	if((ip->i_flag&IMOUNT) != 0) {		for(mp = &mount[0]; mp < (struct mount *)v.ve_mount; mp++)		if(mp->m_inodp == ip) {			dev = mp->m_dev;			ino = ROOTINO;			if (ip = mp->m_mount)				goto found;			else				goto loop;		}		panic("no imt");	}	ip->i_count++;	ip->i_flag |= ILOCK;	return(ip);}inoinit(){	register struct inode *ip;	register short i;	ifreelist = ip = &inode[0];	i = v.v_inode - 1 - 1;	do {		ip->i_forw = ip+1;		ip++;	} while (--i != -1);#ifdef notdef	register i = v.v_inode;	while (--i)		inode[i-1].i_forw = &inode[i];	ifreelist = &inode[0];#endif}struct inode *iread(ip)register struct inode *ip;{	register char *p1, *p2;	register struct dinode *dp;	struct buf *bp;	register short i;	bp = bread(ip->i_dev, FsITOD(ip->i_dev, ip->i_number));	if (u.u_error) {		brelse(bp);		iput(ip);		return(NULL);	}	dp = bp->b_un.b_dino;	dp += FsITOO(ip->i_dev, ip->i_number);	ip->i_mode = dp->di_mode;	ip->i_nlink = dp->di_nlink;	ip->i_uid = dp->di_uid;	ip->i_gid = dp->di_gid;	ip->i_size = dp->di_size;	p1 = (char *)ip->i_addr;	p2 = (char *)dp->di_addr;	i = NADDR - 1;	do {		*p1++ = 0;		*p1++ = *p2++;		*p1++ = *p2++;		*p1++ = *p2++;	} while (--i != -1);	brelse(bp);	return(ip);}/* * Decrement reference count of an inode structure. * On the last reference, write the inode out and if necessary, * truncate and deallocate the file. */iput(ip)register struct inode *ip;{	if(ip->i_count == 1) {		ip->i_flag |= ILOCK;		if(ip->i_nlink <= 0) {			itrunc(ip);			ip->i_mode = 0;			ip->i_flag |= IUPD|ICHG;			ifree(ip->i_dev, ip->i_number);		}		if(ip->i_flag&(IACC|IUPD|ICHG))			iupdat(ip, &time, &time);		prele(ip);		if (ip->i_back->i_forw = ip->i_forw)			ip->i_forw->i_back = ip->i_back;		ip->i_forw = ifreelist;		ifreelist = ip;		ip->i_flag = 0;		ip->i_number = 0;		ip->i_count = 0;		return;	}	ip->i_count--;	prele(ip);}/* * Update the inode with the current time. */iupdat(ip, ta, tm)register struct inode *ip;time_t *ta, *tm;{	register struct buf *bp;	struct dinode *dp;	register char *p1;	char *p2;	register short i;	if(getfs(ip->i_dev)->s_ronly) {		if(ip->i_flag&(IUPD|ICHG))			u.u_error = EROFS;		ip->i_flag &= ~(IACC|IUPD|ICHG|ISYN);		return;	}	bp = bread(ip->i_dev, FsITOD(ip->i_dev, ip->i_number));	if (bp->b_flags & B_ERROR) {		brelse(bp);		return;	}	dp = bp->b_un.b_dino;	dp += FsITOO(ip->i_dev, ip->i_number);	dp->di_mode = ip->i_mode;	dp->di_nlink = ip->i_nlink;	dp->di_uid = ip->i_uid;	dp->di_gid = ip->i_gid;	dp->di_size = ip->i_size;	p1 = (char *)dp->di_addr;	p2 = (char *)ip->i_addr;	if ((ip->i_mode&IFMT)==IFIFO) {		i = NFADDR - 1;		do {			if (*p2++ != 0)				printf("iaddress > 2^24\n");			*p1++ = *p2++;			*p1++ = *p2++;			*p1++ = *p2++;		} while (--i != -1);		i = NADDR - NFADDR - 1;		if (i >= 0) {			do {				*p1++ = 0;				*p1++ = 0;				*p1++ = 0;			} while (--i != -1);		}	} else {		i = NADDR - 1;		do {			if(*p2++ != 0)				printf("iaddress > 2^24\n");			*p1++ = *p2++;			*p1++ = *p2++;			*p1++ = *p2++;		} while (--i != -1);	}	if(ip->i_flag&IACC)		dp->di_atime = *ta;	if(ip->i_flag&IUPD)		dp->di_mtime = *tm;	if(ip->i_flag&ICHG)		dp->di_ctime = time;	if (ip->i_flag&ISYN)		bwrite(bp);	else		bdwrite(bp);	ip->i_flag &= ~(IACC|IUPD|ICHG|ISYN);}/* * Free all the disk blocks associated with the specified inode structure. * The blocks of the file are removed in reverse order. This FILO * algorithm will tend to maintain * a contiguous free list much longer than FIFO. */itrunc(ip)register struct inode *ip;{	register i;	dev_t dev;	daddr_t bn;	i = ip->i_mode & IFMT;	if (i!=IFREG && i!=IFDIR)		return;	dev = ip->i_dev;	for(i=NADDR-1; i>=0; i--) {		bn = ip->i_addr[i];		if(bn == (daddr_t)0)			continue;		ip->i_addr[i] = (daddr_t)0;		switch(i) {		default:			free(dev, bn);			break;		case NADDR-3:			tloop(dev, bn, 0, 0);			break;		case NADDR-2:			tloop(dev, bn, 1, 0);			break;		case NADDR-1:			tloop(dev, bn, 1, 1);		}	}	ip->i_size = 0;	ip->i_flag |= IUPD|ICHG;}tloop(dev, bn, f1, f2)dev_t dev;daddr_t bn;{	register i;	register struct buf *bp;	register daddr_t *bap;	daddr_t nb;	bp = NULL;	for(i=FsNINDIR(dev)-1; i>=0; i--) {		if(bp == NULL) {			bp = bread(dev, bn);			if (bp->b_flags & B_ERROR) {				brelse(bp);				return;			}			bap = bp->b_un.b_daddr;		}		nb = bap[i];		if(nb == (daddr_t)0)			continue;		if(f1) {			brelse(bp);			bp = NULL;			tloop(dev, nb, f2, 0);		} else			free(dev, nb);	}	if(bp != NULL)		brelse(bp);	free(dev, bn);}/* * Make a new file. */struct inode *maknode(mode)register mode;{	register struct inode *ip;	if ((mode&IFMT) == 0)		mode |= IFREG;	mode &= ~u.u_cmask;	ip = ialloc(u.u_pdir->i_dev, mode, 1);	if (ip == NULL) {		iput(u.u_pdir);		return(NULL);	}	wdir(ip);	return(ip);}/* * Write a directory entry with parameters left as side effects * to a call to namei. */wdir(ip)struct inode *ip;{	register struct user *up;	up = &u;	up->u_dent.d_ino = ip->i_number;	up->u_count = sizeof(struct direct);	up->u_segflg = 1;	up->u_base = (caddr_t)&up->u_dent;	up->u_fmode = FWRITE;	writei(up->u_pdir);	iput(up->u_pdir);}