X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/6459ebe02c8462c90494d12e080fe0c4952ff0c0..c39ea692ce2ede0ec345503854d7c4c824ca8cc1:/usr/src/sys/ufs/ffs/ufs_inode.c diff --git a/usr/src/sys/ufs/ffs/ufs_inode.c b/usr/src/sys/ufs/ffs/ufs_inode.c index c0d39c2026..bcfb3ef403 100644 --- a/usr/src/sys/ufs/ffs/ufs_inode.c +++ b/usr/src/sys/ufs/ffs/ufs_inode.c @@ -1,6 +1,4 @@ -/* ufs_inode.c 4.10 82/04/19 */ - -/* merged into kernel: @(#)iget.c 2.2 4/8/82 */ +/* ufs_inode.c 4.16 82/07/01 */ #include "../h/param.h" #include "../h/systm.h" @@ -14,9 +12,18 @@ #include "../h/inline.h" #define INOHSZ 63 +#if ((INOHSZ&(INOHSZ-1)) == 0) +#define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) +#else #define INOHASH(dev,ino) (((dev)+(ino))%INOHSZ) -short inohash[INOHSZ]; -short ifreel; +#endif + +union ihead { /* inode LRU cache, Chris Maltby */ + union ihead *ih_head[2]; + struct inode *ih_chain[2]; +} ihead[INOHSZ]; + +struct inode *ifreeh, **ifreet; /* * Initialize hash links for inodes @@ -26,14 +33,49 @@ ihinit() { register int i; register struct inode *ip = inode; + register union ihead *ih = ihead; + + for (i = INOHSZ; --i >= 0; ih++) { + ih->ih_head[0] = ih; + ih->ih_head[1] = ih; + } + ifreeh = ip; + ifreet = &ip->i_freef; + ip->i_freeb = &ifreeh; + ip->i_forw = ip; + ip->i_back = ip; + for (i = ninode; --i > 0; ) { + ++ip; + ip->i_forw = ip; + ip->i_back = ip; + *ifreet = ip; + ip->i_freeb = ifreet; + ifreet = &ip->i_freef; + } + ip->i_freef = NULL; +} + +#ifdef notdef +/* + * Find an inode if it is incore. + * This is the equivalent, for inodes, + * of ``incore'' in bio.c or ``pfind'' in subr.c. + */ +struct inode * +ifind(dev, ino) + dev_t dev; + ino_t ino; +{ + register struct inode *ip; + register union ihead *ih; - ifreel = 0; - for (i = 0; i < ninode-1; i++, ip++) - ip->i_hlink = i+1; - ip->i_hlink = -1; - for (i = 0; i < INOHSZ; i++) - inohash[i] = -1; + ih = &ihead[INOHASH(dev, ino)]; + for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) + if (ino==ip->i_number && dev==ip->i_dev) + return (ip); + return ((struct inode *)0); } +#endif notdef /* * Look up an inode by device,inumber. @@ -57,17 +99,17 @@ iget(dev, fs, ino) ino_t ino; { register struct inode *ip; + register union ihead *ih; register struct mount *mp; register struct buf *bp; register struct dinode *dp; - register int slot; + register struct inode *iq; loop: if (getfs(dev) != fs) panic("iget: bad fs"); - slot = INOHASH(dev, ino); - ip = &inode[inohash[slot]]; - while (ip != &inode[-1]) { + ih = &ihead[INOHASH(dev, ino)]; + for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) if (ino == ip->i_number && dev == ip->i_dev) { if ((ip->i_flag&ILOCK) != 0) { ip->i_flag |= IWANT; @@ -76,29 +118,47 @@ loop: } if ((ip->i_flag&IMOUNT) != 0) { for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) - if (mp->m_inodp == ip) { - dev = mp->m_dev; - fs = mp->m_bufp->b_un.b_fs; - ino = ROOTINO; - goto loop; - } + if(mp->m_inodp == ip) { + dev = mp->m_dev; + fs = mp->m_bufp->b_un.b_fs; + ino = ROOTINO; + goto loop; + } panic("no imt"); } + if (ip->i_count == 0) { /* ino on free list */ + if (iq = ip->i_freef) + iq->i_freeb = ip->i_freeb; + else + ifreet = ip->i_freeb; + *ip->i_freeb = iq; + ip->i_freef = NULL; + ip->i_freeb = NULL; + } ip->i_count++; ip->i_flag |= ILOCK; return(ip); } - ip = &inode[ip->i_hlink]; - } - if (ifreel < 0) { + + if ((ip = ifreeh) == NULL) { tablefull("inode"); u.u_error = ENFILE; return(NULL); } - ip = &inode[ifreel]; - ifreel = ip->i_hlink; - ip->i_hlink = inohash[slot]; - inohash[slot] = ip - inode; + if (iq = ip->i_freef) + iq->i_freeb = &ifreeh; + ifreeh = iq; + ip->i_freef = NULL; + ip->i_freeb = NULL; + /* + * Now to take inode off the hash chain it was on + * (initially, or after an iflush, it is on a "hash chain" + * consisting entirely of itself, and pointed to by no-one, + * but that doesn't matter), and put it on the chain for + * its new (ino, dev) pair + */ + remque(ip); + insque(ip, ih); ip->i_dev = dev; ip->i_fs = fs; ip->i_number = ino; @@ -111,6 +171,21 @@ loop: */ if ((bp->b_flags&B_ERROR) != 0) { brelse(bp); + /* + * the inode doesn't contain anything useful, so it would + * be misleading to leave it on its hash chain. + * 'iput' will take care of putting it back on the free list. + */ + remque(ip); + ip->i_forw = ip; + ip->i_back = ip; + /* + * we also loose its inumber, just in case (as iput + * doesn't do that any more) - but as it isn't on its + * hash chain, I doubt if this is really necessary .. kre + * (probably the two methods are interchangable) + */ + ip->i_number = 0; iput(ip); return(NULL); } @@ -131,6 +206,16 @@ loop: iput(ip) register struct inode *ip; { + + if ((ip->i_flag & ILOCK) == 0) + panic("iput"); + iunlock(ip); + irele(ip); +} + +irele(ip) + register struct inode *ip; +{ register int i, x; register struct inode *jp; int mode; @@ -145,27 +230,28 @@ iput(ip) ifree(ip, ip->i_number, mode); } IUPDAT(ip, &time, &time, 0); - irele(ip); - i = INOHASH(ip->i_dev, ip->i_number); - x = ip - inode; - if (inohash[i] == x) { - inohash[i] = ip->i_hlink; + iunlock(ip); + ip->i_flag = 0; + /* + * Put the inode on the end of the free list. + * Possibly in some cases it would be better to + * put the inode at the head of the free list, + * (eg: where i_mode == 0 || i_number == 0) + * but I will think about that later .. kre + * (i_number is rarely 0 - only after an i/o error in iget, + * where i_mode == 0, the inode will probably be wanted + * again soon for an ialloc, so possibly we should keep it) + */ + if (ifreeh) { + *ifreet = ip; + ip->i_freeb = ifreet; } else { - for (jp = &inode[inohash[i]]; jp != &inode[-1]; - jp = &inode[jp->i_hlink]) - if (jp->i_hlink == x) { - jp->i_hlink = ip->i_hlink; - goto done; - } - panic("iput"); + ifreeh = ip; + ip->i_freeb = &ifreeh; } -done: - ip->i_hlink = ifreel; - ifreel = x; - ip->i_flag = 0; - ip->i_number = 0; - } else - irele(ip); + ip->i_freef = NULL; + ifreet = &ip->i_freef; + } ip->i_count--; } @@ -230,9 +316,6 @@ itrunc(ip) struct inode itmp; register struct fs *fs; - i = ip->i_mode & IFMT; - if (i != IFREG && i != IFDIR && i != IFLNK) - return; /* * Clean inode on disk before freeing blocks * to insure no duplicates if system crashes. @@ -247,6 +330,13 @@ itrunc(ip) iupdat(&itmp, &time, &time, 1); ip->i_flag &= ~(IUPD|IACC|ICHG); + /* + * Only plain files, directories and symbolic + * links contain blocks. + */ + i = ip->i_mode & IFMT; + if (i != IFREG && i != IFDIR && i != IFLNK) + return; /* * Now return blocks to free list... if machine * crashes, they will be harmless MISSING blocks. @@ -455,11 +545,55 @@ wdir(ip) iput(u.u_pdir); } +/* + * remove any inodes in the inode cache belonging to dev + * + * There should not be any active ones, return error if any are found + * (nb: this is a user error, not a system err) + * + * Also, count the references to dev by block devices - this really + * has nothing to do with the object of the procedure, but as we have + * to scan the inode table here anyway, we might as well get the + * extra benefit. + * + * this is called from sumount()/sys3.c when dev is being unmounted + */ +iflush(dev) + dev_t dev; +{ + register struct inode *ip; + register open = 0; + + for (ip = inode; ip < inodeNINODE; ip++) { + if (ip->i_dev == dev) + if (ip->i_count) + return(-1); + else { + remque(ip); + ip->i_forw = ip; + ip->i_back = ip; + /* + * as i_count == 0, the inode was on the free + * list already, just leave it there, it will + * fall off the bottom eventually. We could + * perhaps move it to the head of the free + * list, but as umounts are done so + * infrequently, we would gain very little, + * while making the code bigger. + */ + } + else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK && + ip->i_rdev == dev) + open++; + } + return (open); +} + #ifdef ilock #undef ilock #endif -#ifdef irele -#undef irele +#ifdef iunlock +#undef iunlock #endif /* * Lock an inode. If its already locked, set the WANT bit and sleep. @@ -478,7 +612,7 @@ ilock(ip) /* * Unlock an inode. If WANT bit is on, wakeup. */ -irele(ip) +iunlock(ip) register struct inode *ip; {