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>
