Date: Fri, 1 Mar 1996 16:34:55 -0700 (MST) From: Terry Lambert <terry@lambert.org> To: jhay@mikom.csir.co.za (John Hay) Cc: freebsd-current@FreeBSD.org Subject: Re: rename panics kernel Message-ID: <199603012334.QAA21796@phaeton.artisoft.com> In-Reply-To: <199603012017.WAA17044@zibbi.mikom.csir.co.za> from "John Hay" at Mar 1, 96 10:17:58 pm
next in thread | previous in thread | raw e-mail | index | archive | help
> > Resently I got a "panic : vrele : negative reference count". > > The vrele() was called from rename(). > > > > I tried a simple script to exercise rename (attached below) and a > > current system seems to panic (trapped in ufs_rename). There's a race > > condition lurking, it seems. I havent tried other than the sticky /tmp > > directory as the source and target files parent directory. Also the > > test was run under root's account, if it matters. > > > > Rename exercise: > > ------ > > #!/bin/sh > > a=/tmp/foo.now > > b=/tmp/foo.prev > > while true > > do > > for n in 1 2 3 4 5 6 7 8 9 0 > > do > > (mv $a $b ; touch $a) & > > done > > wait > > done > > ------ > > Well I tried this on a -stable machine and one with -current. Both did > panic. :-( The -current kernel is a week old. Here is its panic message: > > Fatal trap 12: page fault while in kernel mode > fault virtual address = 0x68 > fault code = supervisor read, page not present > instruction pointer = 0x8:0xf015ffb9 > code segment = base 0x0, limit 0xfffff, type 0x1b > = DPL 0, pres 1, def32 1, gran 1 > processor eflags = interrupt enabled, resume, IOPL = 0 > current process = 341 (mv) > interrupt mask = > panic: page fault > > f015feb4 t _ufs_chown > f015ff78 T _ufs_ioctl > f015ff84 T _ufs_select > f015ff90 T _ufs_mmap > f015ff9c T _ufs_seek > f015ffa4 T _ufs_remove > f0160028 T _ufs_link > f01602b8 T _ufs_rename > f0160cf8 T _ufs_mkdir > f0160f70 T _ufs_rmdir > f01610cc T _ufs_symlink Tee Hee Hee. I tried this on -current and my box panic'ed too. Then I installed my FS patches and tried it again. No panic... did get bored watching the messages scroll by, though. 8-) 8-) 8-) 8-) 8-) 8-) 8-) 8-) 8-) 8-) 8-) 8-) 8-) 8-) 8-) 8-) The fix is a side effect of my reordering for single-entry/single-exit and the semantic changes for the: /* * Fall through causes potentially bogus * semantic override. Test cases are: * * mkdir foo ; cd foo * mv . . * mv . .. * mv .. . * mv .. .. */ case. Here is my rename from my /sys/kern/vfs_syscalls.c (note: it won't work without the nameifree() changes; fix by deintegrating them to assume that the underlying FS is freeing the path buffer for you (ie: comment them out). This file is integrated with -current as of 29 Feb 96. Told you I fixed some race conditions. 8-P. ========================================================================= /* * Rename files. Source and destination must either both be directories, * or both not be directories. If target is a directory, it must be empty. * * XXX this code is broken (or is at the very least non-POSIX). See the * XXX semantic notes below. */ #ifndef _SYS_SYSPROTO_H_ struct rename_args { char *from; char *to; }; #endif /* ARGSUSED */ int rename(p, uap, retval) struct proc *p; register struct rename_args *uap; int *retval; { register struct vnode *tvp, *fvp, *tdvp; struct nameidata fromnd, tond; int error; NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, uap->from, p); if( !(error = namei(&fromnd))) { fvp = fromnd.ni_vp; NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, UIO_USERSPACE, uap->to, p); if (fromnd.ni_vp->v_type == VDIR) tond.ni_cnd.cn_flags |= WILLBEDIR; if( error = namei(&tond)) { /* Translate error code for rename("dir1", "dir2/."). */ if (error == EISDIR && fvp->v_type == VDIR) error = EINVAL; VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); vrele(fromnd.ni_dvp); vrele(fvp); /* fall through to fromdir/path cleanup*/ } else { tdvp = tond.ni_dvp; tvp = tond.ni_vp; if (tvp != NULL) { if (fvp->v_type == VDIR && tvp->v_type != VDIR) { error = ENOTDIR; } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { error = EISDIR; } } /* * If no directory source/target errors, check * for semantic override for an identical * source and target. */ if( !error) { if (fvp == tdvp) error = EINVAL; /* * Fall through causes potentially bogus * semantic override. Test cases are: * * mkdir foo ; cd foo * mv . . * mv . .. * mv .. . * mv .. .. */ /* * If source is the same as the destination * (that is the same inode number with the * same name in the same directory), then * there is nothing to do. */ if (fvp == tvp && fromnd.ni_dvp == tdvp && fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, fromnd.ni_cnd.cn_namelen)) error = -1; } if (!error) { LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); if (fromnd.ni_dvp != tdvp) { LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); } if (tvp) { LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); (void) vnode_pager_uncache(tvp); } error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); } else { VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); if (tdvp == tvp) vrele(tdvp); else vput(tdvp); if (tvp) vput(tvp); VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); vrele(fromnd.ni_dvp); vrele(fvp); } vrele(tond.ni_startdir); nameifree( &tond); } if (fromnd.ni_startdir) vrele(fromnd.ni_startdir); nameifree( &fromnd); if (error == -1) error = 0; } return (error); } ========================================================================= Terry Lambert terry@lambert.org --- Any opinions in this posting are my own and not those of my present or previous employers.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199603012334.QAA21796>