Skip site navigation (1)Skip section navigation (2)
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>