From owner-freebsd-bugs Thu Jul 20 17:29:47 1995 Return-Path: bugs-owner Received: (from majordom@localhost) by freefall.cdrom.com (8.6.11/8.6.6) id RAA00328 for bugs-outgoing; Thu, 20 Jul 1995 17:29:47 -0700 Received: from blob.best.net (blob.best.net [204.156.128.88]) by freefall.cdrom.com (8.6.11/8.6.6) with ESMTP id RAA00322 for ; Thu, 20 Jul 1995 17:29:46 -0700 Received: from shell1.best.com (shell1 [204.156.128.10]) by blob.best.net (8.6.12/8.6.5) with ESMTP id RAA04918 for ; Thu, 20 Jul 1995 17:29:45 -0700 Received: (root@localhost) by shell1.best.com (8.6.12/8.6.5) id RAA21522; Thu, 20 Jul 1995 17:29:43 -0700 Date: Thu, 20 Jul 1995 17:29:43 -0700 From: Matt Dillon Message-Id: <199507210029.RAA21522@shell1.best.com> To: bugs@freebsd.org Subject: verification of ffs_vget() bug Sender: bugs-owner@freebsd.org Precedence: bulk Here are some real numbers... the collision occurs much more often then I would have thought in a heavily loaded system! I believe this solves the 'dup alloc' panic we were getting in the inode allocation routines. I still will not know for sure for another day or two to see if the machine panics again. The panics generally occured once a day, but it is obvious from the numbers below that the actual inodes were getting munged much more often then that. (my temporary ffs_vget() code is included below as well) -Matt Jul 20 12:40:09 shell1 /kernel: INODE COLLISION: mount f21a3e00 ino 54994 Jul 20 12:49:00 shell1 /kernel: INODE COLLISION: mount f21a3e00 ino 55046 Jul 20 12:54:24 shell1 /kernel: INODE COLLISION: mount f21a3a00 ino 38675 Jul 20 12:55:58 shell1 /kernel: INODE COLLISION: mount f21a3e00 ino 54978 Jul 20 13:08:39 shell1 /kernel: INODE COLLISION: mount f21a3e00 ino 55135 Jul 20 13:21:34 shell1 /kernel: INODE COLLISION: mount f21a3e00 ino 54978 Jul 20 13:21:43 shell1 /kernel: INODE COLLISION: mount f21a3e00 ino 54984 Jul 20 13:34:21 shell1 /kernel: INODE COLLISION: mount f21a3e00 ino 55177 Jul 20 13:40:50 shell1 /kernel: INODE COLLISION: mount f21a3e00 ino 55001 Jul 20 13:49:44 shell1 /kernel: INODE COLLISION: mount f21a3e00 ino 53837 Jul 20 14:04:19 shell1 /kernel: INODE COLLISION: mount f21a3e00 ino 55045 Jul 20 14:09:02 shell1 /kernel: INODE COLLISION: mount f21a3e00 ino 55169 Jul 20 14:30:16 shell1 /kernel: INODE COLLISION: mount f21a3e00 ino 53837 Jul 20 15:04:44 shell1 /kernel: INODE COLLISION: mount f219f200 ino 39130 Jul 20 17:09:37 shell1 /kernel: INODE COLLISION: mount f219f200 ino 92571 Jul 20 17:11:46 shell1 /kernel: INODE COLLISION: mount f21a3a00 ino 222911 /* * Look up a FFS dinode number to find its incore vnode, otherwise read it * in from disk. If it is in core, wait for the lock bit to clear, then * return the inode locked. Detection and handling of mount points must be * done by the calling routine. */ int ffs_inode_hash_lock = 0; int ffs_vget(mp, ino, vpp) struct mount *mp; ino_t ino; struct vnode **vpp; { register struct fs *fs; register struct inode *ip; struct ufsmount *ump; struct buf *bp; struct vnode *vp; dev_t dev; int type, error; ump = VFSTOUFS(mp); dev = ump->um_dev; if ((*vpp = ufs_ihashget(dev, ino)) != NULL) return (0); /* * lockout the creation of new entries in the FFS * hash table in case getnewvnode/MALLOC blocks, * otherwise a duplicate could occur! */ if (ffs_inode_hash_lock) { while (ffs_inode_hash_lock) { ffs_inode_hash_lock = -1; tsleep(&ffs_inode_hash_lock, PVM, "ffsinohs", 0); } /* * someone else allocated (dev,ino) before we could */ if ((*vpp = ufs_ihashget(dev, ino)) != NULL) { printf("INODE COLLISION: mount %08lx ino %d\n", (u_long)mp, (int)ino ); return (0); } } ffs_inode_hash_lock = 1; /* Allocate a new vnode/inode. */ type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */ if ((error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) != 0) { if (ffs_inode_hash_lock < 0) { wakeup(&ffs_inode_hash_lock); } ffs_inode_hash_lock = 0; *vpp = NULL; return (error); } MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK); bzero((caddr_t)ip, sizeof(struct inode)); vp->v_data = ip; ip->i_vnode = vp; ip->i_fs = fs = ump->um_fs; ip->i_dev = dev; ip->i_number = ino; #ifdef QUOTA { int i; for (i = 0; i < MAXQUOTAS; i++) ip->i_dquot[i] = NODQUOT; } #endif /* * 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. */ ufs_ihashins(ip); /* * Wakeup anybody blocked in our lock */ if (ffs_inode_hash_lock < 0) { wakeup(&ffs_inode_hash_lock); } ffs_inode_hash_lock = 0; /* Read in the disk contents for the inode, copy into the inode. */ error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), (int)fs->fs_bsize, NOCRED, &bp); if (error) { /* * The inode does not contain anything useful, so it would * be misleading to leave it on its hash chain. With mode * still zero, it will be unlinked and returned to the free * list by vput(). */ vput(vp); brelse(bp); *vpp = NULL; return (error); } ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino)); brelse(bp); /* * Initialize the vnode from the inode, check for aliases. * Note that the underlying vnode may have changed. */ error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp); if (error) { vput(vp); *vpp = NULL; return (error); } /* * Finish inode initialization now that aliasing has been resolved. */ ip->i_devvp = ump->um_devvp; VREF(ip->i_devvp); /* * 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->mnt_flag & MNT_RDONLY) == 0) ip->i_flag |= IN_MODIFIED; } /* * Ensure that uid and gid are correct. This is a temporary * fix until fsck has been changed to do the update. */ if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ ip->i_uid = ip->i_din.di_ouid; /* XXX */ ip->i_gid = ip->i_din.di_ogid; /* XXX */ } /* XXX */ *vpp = vp; return (0); }