NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: kern/41374: getnewvnode deadlock
The following reply was made to PR kern/41374; it has been noted by GNATS.
From: yamt%mwd.biglobe.ne.jp@localhost (YAMAMOTO Takashi)
To: ad%netbsd.org@localhost
Cc: gnats-bugs%NetBSD.org@localhost, kern-bug-people%netbsd.org@localhost,
gnats-admin%netbsd.org@localhost,
netbsd-bugs%netbsd.org@localhost
Subject: Re: kern/41374: getnewvnode deadlock
Date: Sun, 10 May 2009 09:44:41 +0000 (UTC)
hi,
> On Thu, May 07, 2009 at 04:45:01AM +0000, yamt%mwd.biglobe.ne.jp@localhost
> wrote:
>
>> in the case of getcleanvnode,
>> set VI_XLOCK before incrementing v_usecount?
>
> I think insufficient because vtryget() is lockless.
i was thinking something like the following. (untested)
> How about making XLOCK
> a flag bit in v_useconut?
it sounds like a good idea.
YAMAMOTO Takashi
Index: sys/vnode.h
===================================================================
RCS file: /cvsroot/src/sys/sys/vnode.h,v
retrieving revision 1.191.4.2
diff -u -p -r1.191.4.2 vnode.h
--- sys/vnode.h 4 May 2009 08:14:36 -0000 1.191.4.2
+++ sys/vnode.h 10 May 2009 09:42:33 -0000
@@ -227,6 +227,7 @@ typedef struct vnode vnode_t;
#define VI_WRMAP 0x00000400 /* might have PROT_WRITE u.
mappings */
#define VI_WRMAPDIRTY 0x00000800 /* might have dirty pages */
#define VI_XLOCK 0x00001000 /* vnode is locked to change
type */
+#define VI_CLEANING 0x00002000 /* being cleaned by vclean */
#define VI_ONWORKLST 0x00004000 /* On syncer work-list */
#define VI_MARKER 0x00008000 /* Dummy marker vnode */
#define VI_LAYER 0x00020000 /* vnode is on a layer
filesystem */
@@ -243,7 +244,7 @@ typedef struct vnode vnode_t;
#define VNODE_FLAGBITS \
"\20\1ROOT\2SYSTEM\3ISTTY\4MAPPED\5MPSAFE\6LOCKSWORK\11TEXT\12EXECMAP" \
- "\13WRMAP\14WRMAPDIRTY\15XLOCK\17ONWORKLST\20MARKER" \
+ "\13WRMAP\14WRMAPDIRTY\15XLOCK\16CLEANING\17ONWORKLST\20MARKER" \
"\22LAYER\24CLEAN\25INACTPEND\26INACTREDO\27FREEING" \
"\30INACTNOW\31DIROP"
Index: kern/vfs_subr.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_subr.c,v
retrieving revision 1.336.4.2
diff -u -p -r1.336.4.2 vfs_subr.c
--- kern/vfs_subr.c 4 May 2009 08:13:49 -0000 1.336.4.2
+++ kern/vfs_subr.c 10 May 2009 09:42:34 -0000
@@ -361,6 +361,17 @@ try_nextlist:
* before doing this. If the vnode gains another reference while
* being cleaned out then we lose - retry.
*/
+ KASSERT(mutex_owned(&vp->v_interlock));
+ KASSERT((vp->v_iflag & VI_XLOCK) == 0);
+ KASSERT((vp->v_iflag & VI_CLEAN) == 0);
+ KASSERT(vp->v_usecount == 0);
+ /*
+ * after we increment v_usecount below, another thread can
+ * do vtryget successfully. set VI_XLOCK before that, so that
+ * the competing thread can notice our activities.
+ */
+ vp->v_iflag |= VI_XLOCK;
+ membar_producer();
atomic_inc_uint(&vp->v_usecount);
vclean(vp, DOCLOSE);
if (vp->v_usecount == 1) {
@@ -1783,8 +1794,8 @@ vclean(vnode_t *vp, int flags)
KASSERT(vp->v_usecount != 0);
/* If cleaning is already in progress wait until done and return. */
- if (vp->v_iflag & VI_XLOCK) {
- vwait(vp, VI_XLOCK);
+ if (vp->v_iflag & VI_CLEANING) {
+ vwait(vp, VI_CLEANING);
return;
}
@@ -1797,7 +1808,7 @@ vclean(vnode_t *vp, int flags)
* Prevent the vnode from being recycled or brought into use
* while we clean it out.
*/
- vp->v_iflag |= VI_XLOCK;
+ vp->v_iflag |= VI_XLOCK | VI_CLEANING;
if (vp->v_iflag & VI_EXECMAP) {
atomic_add_int(&uvmexp.execpages, -vp->v_uobj.uo_npages);
atomic_add_int(&uvmexp.filepages, vp->v_uobj.uo_npages);
@@ -1857,7 +1868,7 @@ vclean(vnode_t *vp, int flags)
vp->v_tag = VT_NON;
vp->v_vnlock = &vp->v_lock;
KNOTE(&vp->v_klist, NOTE_REVOKE);
- vp->v_iflag &= ~(VI_XLOCK | VI_FREEING);
+ vp->v_iflag &= ~(VI_XLOCK | VI_FREEING | VI_CLEANING);
vp->v_vflag &= ~VV_LOCKSWORK;
if ((flags & DOCLOSE) != 0) {
vp->v_iflag |= VI_CLEAN;
Index: kern/vfs_cache.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_cache.c,v
retrieving revision 1.74.4.2
diff -u -p -r1.74.4.2 vfs_cache.c
--- kern/vfs_cache.c 4 May 2009 08:13:49 -0000 1.74.4.2
+++ kern/vfs_cache.c 10 May 2009 09:42:34 -0000
@@ -464,6 +464,15 @@ cache_lookup_raw(struct vnode *dvp, stru
return ENOENT;
}
if (vtryget(vp)) {
+ membar_consumer();
+ if ((vp->v_iflag & VI_XLOCK) != 0) {
+ mutex_exit(&ncp->nc_lock);
+ mutex_exit(&cpup->cpu_lock);
+ vrele(vp);
+ COUNT(cpup->cpu_stats, ncs_falsehits);
+ *vpp = NULL;
+ return -1;
+ }
mutex_exit(&ncp->nc_lock);
mutex_exit(&cpup->cpu_lock);
} else {
Home |
Main Index |
Thread Index |
Old Index