- 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;
- ITOV(ip)->v_type = VNON;
- 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) {
- vp = ITOV(iq);
- if (dp->di_rdev != vp->v_rdev)
- continue;
- igrab(iq);
- if (dp->di_rdev != vp->v_rdev) {
- iput(iq);
- goto again;
- }
- /*
- * Discard unneeded inode.
- */
- remque(ip);
- ip->i_forw = ip;
- ip->i_back = ip;
- ip->i_number = 0;
- ITOV(ip)->v_type = VNON;
- 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;
- 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);