Date: Fri, 05 Aug 2011 10:18:49 +0200 From: Martin Matuska <mm@FreeBSD.org> To: Kostik Belousov <kostikbel@gmail.com> Cc: Xin Li <delphij@FreeBSD.org>, current@FreeBSD.org Subject: Re: panic: share -> excl @r224632 Message-ID: <4E3BA769.3090408@FreeBSD.org> In-Reply-To: <20110804135932.GG17489@deviant.kiev.zoral.com.ua> References: <20110804125454.GI29364@albert.catwhisker.org> <20110804135932.GG17489@deviant.kiev.zoral.com.ua>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------050805060602090007070309
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
I agree to Kostik's approach, but I suggest implementing it in a
separate function and also use for the unmount() part.
Please review attached patch.
On 04.08.2011 15:59, Kostik Belousov wrote:
> On Thu, Aug 04, 2011 at 05:54:54AM -0700, David Wolfskill wrote:
>> I've only seen this on my laptop; my build machine doesn't exhibit the
>> panic.
>>
>> r224602 is the most recent point I've built that does not exhibit the
>> panic at all.
>>
>> The first few lines (hand-transcribed; I have no serial console on this
>> laptop -- the one shortcoming it has):
>>
>> shared lock of (lockmgr) devfs @/usr/src/sys/kern/vfs_cache.c:1116
>> while exclusively locked from /usr/src/sys/kern/vfs_subr.c:2134
>> panic: share -> excl
>>
>> The backtrace (which I wasn't patient enough to trto transcribe twice;
>> sorry) appeared to involve "nmount", and the panic occurred directly
>> after mounting the file systems during the transition from single-user
>> mode to multi-user mode.
>>
>> The output from "svn update" going from r224602 -> r224632 shows the
>> following files being updated:
>>
>> U usr.sbin/faithd/faithd.8
>> U usr.sbin/jail/jail.8
>> U lib/libproc/proc_create.c
>> U sys/arm/arm/irq_dispatch.S
>> U sys/arm/sa11x0/sa11x0_irq.S
>> U sys/powerpc/booke/locore.S
>> U sys/powerpc/booke/platform_bare.c
>> U sys/powerpc/booke/pmap.c
>> U sys/nfsclient/nfsnode.h
>> U sys/nfsclient/nfs_node.c
>> U sys/kern/kern_jail.c
>> U sys/kern/vfs_mount.c
>> U sys/fs/nfsclient/nfsnode.h
>> U sys/fs/nfsclient/nfs_clnode.c
>> U sys/mips/mips/exception.S
>> U sys/dev/ahci/ahci.c
>> U sys/dev/ata/chipsets/ata-nvidia.c
>> U sys/dev/ath/ath_hal/ah_eeprom_v4k.c
>> U sys/i386/ibcs2/imgact_coff.c
>> U sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
>> Updated to revision 224632.
>>
>> Updating to r224648 (this morning) has had no apparent effect on the
>> cited panic: it occurs in the same way, at the same time, accompanied by
>> the same messages (citing the same files and lines).
>>
>> I've attached dmesg.boot from r224602.
>>
>> I will see if I can find a commit that affected at least one of the
>> affected files in the above list that I can revert to avoid the panic,
>> but I'm a bit slow for a while yet, so I figured I'd finally get around
>> to posting this, in the hope that someone cleverer than me will spot
>> the problem and suggest a circumvention to try.
>>
>> And I'm quite willing to try such things.
>>
>> Note: this is FreeBSD/i386; nothing special: no jails; running on real
>> hardware; no attempts to use ZFS....
> I am sure that this is caused by r224614.
> I forgot that vn_fullpath cannot operate on the locked vnode.
>
> Try this.
>
> diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
> index d601c56..54f123c 100644
> --- a/sys/kern/vfs_mount.c
> +++ b/sys/kern/vfs_mount.c
> @@ -746,13 +746,15 @@ vfs_domount_first(
> struct thread *td, /* Calling thread. */
> struct vfsconf *vfsp, /* File system type. */
> struct vnode *vp, /* Vnode to be covered. */
> + char *ufspath,
> int fsflags, /* Flags common to all filesystems. */
> struct vfsoptlist **optlist /* Options local to the filesystem. */
> )
> {
> struct vattr va;
> + struct nameidata nd;
> struct mount *mp;
> - struct vnode *newdp;
> + struct vnode *newdp, *vp1;
> char *fspath, *fbuf;
> int error;
>
> @@ -761,16 +763,45 @@ vfs_domount_first(
> KASSERT((fsflags & MNT_UPDATE) == 0, ("MNT_UPDATE shouldn't be here"));
>
> /* Construct global filesystem path from vp. */
> + VOP_UNLOCK(vp, 0);
> error = vn_fullpath_global(td, vp, &fspath, &fbuf);
> if (error != 0) {
> - vput(vp);
> + vrele(vp);
> return (error);
> }
> if (strlen(fspath) >= MNAMELEN) {
> - vput(vp);
> + vrele(vp);
> free(fbuf, M_TEMP);
> return (ENAMETOOLONG);
> }
> + if ((vp->v_iflag & VI_DOOMED) != 0) {
> + vrele(vp);
> + free(fbuf, M_TEMP);
> + return (EBADF);
> + }
> +
> + /*
> + * Re-lookup the vnode by path. As a side effect, the vnode is
> + * relocked. If vnode was renamed, return ENOENT.
> + */
> + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
> + UIO_SYSSPACE, ufspath, td);
> + error = namei(&nd);
> + if (error != 0) {
> + vrele(vp);
> + free(fbuf, M_TEMP);
> + return (error);
> + }
> + if (NDHASGIANT(&nd))
> + mtx_unlock(&Giant);
> + NDFREE(&nd, NDF_ONLY_PNBUF);
> + vp1 = nd.ni_vp;
> + vrele(vp);
> + if (vp1 != vp) {
> + vput(vp1);
> + free(fbuf, M_TEMP);
> + return (ENOENT);
> + }
>
> /*
> * If the user is not root, ensure that they own the directory
> @@ -1084,14 +1115,11 @@ vfs_domount(
> NDFREE(&nd, NDF_ONLY_PNBUF);
> vp = nd.ni_vp;
> if ((fsflags & MNT_UPDATE) == 0)
> - error = vfs_domount_first(td, vfsp, vp, fsflags, optlist);
> + error = vfs_domount_first(td, vfsp, vp, fspath, fsflags, optlist);
> else
> error = vfs_domount_update(td, vp, fsflags, optlist);
> mtx_unlock(&Giant);
>
> - ASSERT_VI_UNLOCKED(vp, __func__);
> - ASSERT_VOP_UNLOCKED(vp, __func__);
> -
> return (error);
> }
>
--
Martin Matuska
FreeBSD committer
http://blog.vx.sk
--------------050805060602090007070309
Content-Type: text/x-patch;
name="vfs_mount.c.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="vfs_mount.c.patch"
Index: sys/kern/vfs_mount.c
===================================================================
--- sys/kern/vfs_mount.c (revision 224654)
+++ sys/kern/vfs_mount.c (working copy)
@@ -362,6 +362,64 @@ vfs_mergeopts(struct vfsoptlist *toopts, struct vf
}
/*
+ * Verify vnode's global path
+ */
+static int
+vfs_verify_global_path(struct thread *td, struct vnode *vp, char *fspath)
+{
+ struct nameidata nd;
+ struct vnode *vp1;
+ char *rpath, *fbuf;
+ int error;
+
+ ASSERT_VOP_ELOCKED(vp, __func__);
+
+ /* Construct global filesystem path from vp. */
+ VOP_UNLOCK(vp, 0);
+ error = vn_fullpath_global(td, vp, &rpath, &fbuf);
+ if (error != 0) {
+ vrele(vp);
+ return (error);
+ }
+ if (strlen(rpath) >= MNAMELEN) {
+ vrele(vp);
+ free(fbuf, M_TEMP);
+ return (ENAMETOOLONG);
+ }
+ if ((vp->v_iflag & VI_DOOMED) != 0) {
+ vrele(vp);
+ free(fbuf, M_TEMP);
+ return (EBADF);
+ }
+
+ /*
+ * Re-lookup the vnode by path. As a side effect, the vnode is
+ * relocked. If vnode was renamed, return ENOENT.
+ */
+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
+ UIO_SYSSPACE, fspath, td);
+ error = namei(&nd);
+ if (error != 0) {
+ vrele(vp);
+ free(fbuf, M_TEMP);
+ return (error);
+ }
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ vp1 = nd.ni_vp;
+ vrele(vp);
+ if (vp1 != vp) {
+ vput(vp1);
+ free(fbuf, M_TEMP);
+ return (ENOENT);
+ }
+
+ strlcpy(fspath,rpath,MNAMELEN);
+ free(fbuf, M_TEMP);
+
+ return (error);
+}
+
+/*
* Mount a filesystem.
*/
int
@@ -745,6 +803,7 @@ static int
vfs_domount_first(
struct thread *td, /* Calling thread. */
struct vfsconf *vfsp, /* File system type. */
+ char *fspath, /* Mount path. */
struct vnode *vp, /* Vnode to be covered. */
int fsflags, /* Flags common to all filesystems. */
struct vfsoptlist **optlist /* Options local to the filesystem. */
@@ -753,25 +812,12 @@ vfs_domount_first(
struct vattr va;
struct mount *mp;
struct vnode *newdp;
- char *fspath, *fbuf;
int error;
mtx_assert(&Giant, MA_OWNED);
ASSERT_VOP_ELOCKED(vp, __func__);
KASSERT((fsflags & MNT_UPDATE) == 0, ("MNT_UPDATE shouldn't be here"));
- /* Construct global filesystem path from vp. */
- error = vn_fullpath_global(td, vp, &fspath, &fbuf);
- if (error != 0) {
- vput(vp);
- return (error);
- }
- if (strlen(fspath) >= MNAMELEN) {
- vput(vp);
- free(fbuf, M_TEMP);
- return (ENAMETOOLONG);
- }
-
/*
* If the user is not root, ensure that they own the directory
* onto which we are attempting to mount.
@@ -793,14 +839,12 @@ vfs_domount_first(
}
if (error != 0) {
vput(vp);
- free(fbuf, M_TEMP);
return (error);
}
VOP_UNLOCK(vp, 0);
/* Allocate and initialize the filesystem. */
mp = vfs_mount_alloc(vp, vfsp, fspath, td->td_ucred);
- free(fbuf, M_TEMP);
/* XXXMAC: pass to vfs_mount_alloc? */
mp->mnt_optnew = *optlist;
/* Set the mount level flags. */
@@ -1083,15 +1127,15 @@ vfs_domount(
mtx_lock(&Giant);
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
- if ((fsflags & MNT_UPDATE) == 0)
- error = vfs_domount_first(td, vfsp, vp, fsflags, optlist);
- else
+ if ((fsflags & MNT_UPDATE) == 0) {
+ error = vfs_verify_global_path(td, vp, fspath);
+ if (error == 0)
+ error = vfs_domount_first(td, vfsp, fspath, vp,
+ fsflags, optlist);
+ } else
error = vfs_domount_update(td, vp, fsflags, optlist);
mtx_unlock(&Giant);
- ASSERT_VI_UNLOCKED(vp, __func__);
- ASSERT_VOP_UNLOCKED(vp, __func__);
-
return (error);
}
@@ -1118,7 +1162,7 @@ unmount(td, uap)
{
struct mount *mp;
struct nameidata nd;
- char *pathbuf, *rpathbuf, *fbuf;
+ char *pathbuf;
int error, id0, id1;
AUDIT_ARG_VALUE(uap->flags);
@@ -1164,15 +1208,10 @@ unmount(td, uap)
UIO_SYSSPACE, pathbuf, td);
if (namei(&nd) == 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
- if (vn_fullpath_global(td, nd.ni_vp, &rpathbuf,
- &fbuf) == 0) {
- if (strlen(rpathbuf) < MNAMELEN) {
- strlcpy(pathbuf, rpathbuf,
- MNAMELEN);
- }
- free(fbuf, M_TEMP);
- }
- vput(nd.ni_vp);
+ error = vfs_verify_global_path(td, nd.ni_vp,
+ pathbuf);
+ if (error == 0)
+ vput(nd.ni_vp);
}
}
mtx_lock(&mountlist_mtx);
--------------050805060602090007070309--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4E3BA769.3090408>
