- 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;
- ITOV(ip)->v_data = (qaddr_t)ip;
- for (i = ninode; --i > 0; ) {
- ++ip;
- ip->i_forw = ip;
- ip->i_back = ip;
- ITOV(ip)->v_data = (qaddr_t)ip;
- *ifreet = ip;
- ip->i_freeb = ifreet;
- ifreet = &ip->i_freef;
- }
- ip->i_freef = NULL;
-}
-
-/*
- * Look up an vnode/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.
- * Callers must check for mount points!!
- * In all cases, a pointer to a locked
- * inode structure is returned.
- */
-iget(xp, ino, ipp)
- struct inode *xp;
- ino_t ino;
- struct inode **ipp;
-{
- dev_t dev = xp->i_dev;
- struct mount *mntp = ITOV(xp)->v_mount;
- register struct fs *fs = VFSTOUFS(mntp)->um_fs;
- register struct inode *ip, *iq;
- register struct vnode *vp;
- struct inode *nip;
- struct buf *bp;
- struct dinode tdip, *dp;
- union ihead *ih;
- int error;
-
-loop:
- 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) {
- /*
- * Following is essentially an inline expanded
- * copy of igrab(), expanded inline for speed,
- * and so that the test for a mounted on inode
- * can be deferred until after we are sure that
- * the inode isn't busy.
- */
- if ((ip->i_flag&ILOCKED) != 0) {
- ip->i_flag |= IWANT;
- sleep((caddr_t)ip, PINOD);
- goto loop;
- }
- vp = ITOV(ip);
- if (vp->v_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;
- }
- ILOCK(ip);
- VREF(vp);
- *ipp = ip;
- return(0);
- }
- if (error = getnewino(dev, ino, &nip)) {
- *ipp = 0;
- return (error);
- }
- ip = nip;
- /*
- * Read in the disk contents for the inode.
- */
- if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)),
- (int)fs->fs_bsize, &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. We also
- * lose its inumber, just in case.
- */
- remque(ip);
- ip->i_forw = ip;
- ip->i_back = ip;
- ip->i_number = 0;
- INSFREE(ip);
- iunlock(ip);
- ip->i_flag = 0;
- brelse(bp);
- *ipp = 0;
- return(error);
- }
- /*
- * Check to see if the new inode represents a block device
- * for which we already have an inode (either because of
- * bdevvp() or because of a different inode representing
- * the same block device). If such an alias exists, put the
- * just allocated inode back on the free list, and replace
- * the contents of the existing inode with the contents of
- * the new inode.
- */
- dp = bp->b_un.b_dino;
- dp += itoo(fs, ino);
- if ((dp->di_mode & IFMT) != IFBLK) {
- ip->i_ic = dp->di_ic;
- brelse(bp);
- } else {
-again:
- for (iq = bdevlisth; iq; iq = iq->i_devlst) {
- if (dp->di_rdev != ITOV(iq)->v_rdev)
- continue;
- igrab(iq);
- if (dp->di_rdev != ITOV(iq)->v_rdev) {
- iput(iq);
- goto again;
- }
- /*
- * Discard unneeded inode.
- */
- remque(ip);
- ip->i_forw = ip;
- ip->i_back = ip;
- ip->i_number = 0;
- INSFREE(ip);
- iunlock(ip);
- ip->i_flag = 0;
- /*
- * Reinitialize aliased inode.
- * We must release the buffer that we just read
- * before doing the iupdat() to avoid a possible
- * deadlock with updating an inode in the same
- * disk block.
- */
- ip = iq;
- vp = ITOV(iq);
- tdip.di_ic = dp->di_ic;
- brelse(bp);
- error = iupdat(ip, &time, &time, 1);
- ip->i_ic = tdip.di_ic;
- remque(ip);
- insque(ip, ih);
- ip->i_dev = dev;
- ip->i_number = ino;
- if (ip->i_devvp) {
- vrele(ip->i_devvp);
- ip->i_devvp = 0;
- }
- cache_purge(vp);
- break;
- }
- if (iq == 0) {
- ip->i_ic = dp->di_ic;
- brelse(bp);
- ip->i_devlst = bdevlisth;
- bdevlisth = ip;
- }
- }
- /*
- * Finish inode initialization.
- */
- ip->i_fs = fs;
- ip->i_devvp = VFSTOUFS(mntp)->um_devvp;
- VREF(ip->i_devvp);
- /*
- * Initialize the associated vnode
- */
- vp = ITOV(ip);
- vinit(vp, mntp, IFTOVT(ip->i_mode), &ufs_vnodeops);
- if (vp->v_type == VCHR || vp->v_type == VBLK) {
- vp->v_rdev = ip->i_rdev;
- vp->v_op = &blk_vnodeops;
- }
- if (ino == ROOTINO)
- vp->v_flag |= VROOT;
-#ifdef QUOTA
- if (ip->i_mode != 0)
- ip->i_dquot = inoquota(ip);
-#endif
- /*
- * Set up a generation number for this inode if it does not
- * already have one. This should only happen on old filesystems.
- */
- if (ip->i_gen == 0) {
- if (++nextgennumber < (u_long)time.tv_sec)
- nextgennumber = time.tv_sec;
- ip->i_gen = nextgennumber;
- if ((vp->v_mount->m_flag & M_RDONLY) == 0)
- ip->i_flag |= IMOD;
- }
- *ipp = ip;
- return (0);
-}
-
-/*
- * Allocate a new inode.
- *
- * Put it onto its hash chain and lock it so that other requests for
- * this inode will block if they arrive while we are sleeping waiting
- * for old data structures to be purged or for the contents of the disk
- * portion of this inode to be read.
- */
-getnewino(dev, ino, ipp)
- dev_t dev;
- ino_t ino;
- struct inode **ipp;
-{
- union ihead *ih;
- register struct inode *ip, *iq;
- register struct vnode *vp;