kern/102335: [devfs] sx vnode deadlock
Alex Unleashed
unledev at gmail.com
Mon Sep 4 10:40:32 UTC 2006
The following reply was made to PR kern/102335; it has been noted by GNATS.
From: "Alex Unleashed" <unledev at gmail.com>
To: bug-followup at freebsd.org
Cc:
Subject: Re: kern/102335: [devfs] sx vnode deadlock
Date: Mon, 4 Sep 2006 12:32:17 +0200
------=_Part_100777_6803680.1157365937363
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Konstantin Belousov created the following patch against -CURRENT noting that
devfs from 6.X should be replaced by -CURRENT soon enough. This patch trades
the deadlock for a race at unmount time.
Index: devfs.h
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/fs/devfs/devfs.h,v
retrieving revision 1.29
diff -u -r1.29 devfs.h
--- devfs.h 12 Apr 2006 12:17:29 -0000 1.29
+++ devfs.h 1 Sep 2006 11:00:34 -0000
@@ -163,7 +163,7 @@
void devfs_rules_apply(struct devfs_mount *dm, struct devfs_dirent *de);
void devfs_rules_cleanup (struct devfs_mount *dm);
int devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data,
struct thread *td);
-int devfs_allocv (struct devfs_dirent *de, struct mount *mp, struct vnode
**vpp, struct thread *td);
+int devfs_allocv (struct devfs_dirent *de, struct mount *mp, struct vnode
**vpp, int *dm_lock, struct thread *td);
void devfs_delete(struct devfs_mount *dm, struct devfs_dirent *de);
void devfs_populate (struct devfs_mount *dm);
void devfs_cleanup (struct devfs_mount *dm);
Index: devfs_vfsops.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/fs/devfs/devfs_vfsops.c,v
retrieving revision 1.50
diff -u -r1.50 devfs_vfsops.c
--- devfs_vfsops.c 17 Jul 2006 09:07:01 -0000 1.50
+++ devfs_vfsops.c 1 Sep 2006 11:00:34 -0000
@@ -135,9 +135,11 @@
int error;
struct vnode *vp;
struct devfs_mount *dmp;
+ int dm_lock;
dmp = VFSTODEVFS(mp);
- error = devfs_allocv(dmp->dm_rootdir, mp, &vp, td);
+ dm_lock = 0;
+ error = devfs_allocv(dmp->dm_rootdir, mp, &vp, &dm_lock, td);
if (error)
return (error);
vp->v_vflag |= VV_ROOT;
Index: devfs_vnops.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/fs/devfs/devfs_vnops.c,v
retrieving revision 1.133
diff -u -r1.133 devfs_vnops.c
--- devfs_vnops.c 17 Jul 2006 09:07:01 -0000 1.133
+++ devfs_vnops.c 1 Sep 2006 11:00:34 -0000
@@ -126,20 +126,26 @@
}
int
-devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp,
struct thread *td)
+devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp,
+ int *dm_unlock, struct thread *td)
{
int error;
struct vnode *vp;
struct cdev *dev;
+ struct devfs_mount *dmp;
KASSERT(td == curthread, ("devfs_allocv: td != curthread"));
+ dmp = VFSTODEVFS(mp);
loop:
-
mtx_lock(&devfs_de_interlock);
vp = de->de_vnode;
if (vp != NULL) {
VI_LOCK(vp);
mtx_unlock(&devfs_de_interlock);
+ if (*dm_unlock) {
+ sx_xunlock(&dmp->dm_lock);
+ *dm_unlock = 0;
+ }
if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td))
goto loop;
*vpp = vp;
@@ -182,6 +188,10 @@
vp->v_data = de;
de->de_vnode = vp;
mtx_unlock(&devfs_de_interlock);
+ if (*dm_unlock) {
+ sx_xunlock(&dmp->dm_lock);
+ *dm_unlock = 0;
+ }
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
#ifdef MAC
mac_associate_vnode_devfs(mp, de, vp);
@@ -456,7 +466,7 @@
}
static int
-devfs_lookupx(struct vop_lookup_args *ap)
+devfs_lookupx(struct vop_lookup_args *ap, int *dm_unlock)
{
struct componentname *cnp;
struct vnode *dvp, **vpp;
@@ -507,7 +517,7 @@
de = TAILQ_FIRST(&dd->de_dlist); /* "." */
de = TAILQ_NEXT(de, de_list); /* ".." */
de = de->de_dir;
- error = devfs_allocv(de, dvp->v_mount, vpp, td);
+ error = devfs_allocv(de, dvp->v_mount, vpp, dm_unlock, td);
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
return (error);
}
@@ -564,7 +574,7 @@
return (0);
}
}
- error = devfs_allocv(de, dvp->v_mount, vpp, td);
+ error = devfs_allocv(de, dvp->v_mount, vpp, dm_unlock, td);
return (error);
}
@@ -573,11 +583,14 @@
{
int j;
struct devfs_mount *dmp;
+ int dm_unlock;
dmp = VFSTODEVFS(ap->a_dvp->v_mount);
+ dm_unlock = 1;
sx_xlock(&dmp->dm_lock);
- j = devfs_lookupx(ap);
- sx_xunlock(&dmp->dm_lock);
+ j = devfs_lookupx(ap, &dm_unlock);
+ if (dm_unlock == 1)
+ sx_xunlock(&dmp->dm_lock);
return (j);
}
@@ -589,6 +602,7 @@
struct thread *td;
struct devfs_dirent *dd, *de;
struct devfs_mount *dmp;
+ int dm_unlock;
int error;
/*
@@ -600,6 +614,7 @@
dvp = ap->a_dvp;
dmp = VFSTODEVFS(dvp->v_mount);
sx_xlock(&dmp->dm_lock);
+ dm_unlock = 1;
cnp = ap->a_cnp;
vpp = ap->a_vpp;
@@ -620,9 +635,10 @@
if (de == NULL)
goto notfound;
de->de_flags &= ~DE_WHITEOUT;
- error = devfs_allocv(de, dvp->v_mount, vpp, td);
+ error = devfs_allocv(de, dvp->v_mount, vpp, &dm_unlock, td);
notfound:
- sx_xunlock(&dmp->dm_lock);
+ if (dm_unlock == 1)
+ sx_xunlock(&dmp->dm_lock);
return (error);
}
@@ -1102,6 +1118,7 @@
struct devfs_dirent *de;
struct devfs_mount *dmp;
struct thread *td;
+ int dm_unlock;
td = ap->a_cnp->cn_thread;
KASSERT(td == curthread, ("devfs_symlink: td != curthread"));
@@ -1120,12 +1137,14 @@
de->de_symlink = malloc(i, M_DEVFS, M_WAITOK);
bcopy(ap->a_target, de->de_symlink, i);
sx_xlock(&dmp->dm_lock);
+ dm_unlock = 1;
#ifdef MAC
mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de);
#endif
TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
- devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, td);
- sx_xunlock(&dmp->dm_lock);
+ devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, &dm_unlock, td);
+ if (dm_unlock == 1)
+ sx_xunlock(&dmp->dm_lock);
return (0);
}
------=_Part_100777_6803680.1157365937363
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Konstantin Belousov created the following patch against -CURRENT noting that devfs from 6.X should be replaced by -CURRENT soon enough. This patch trades the deadlock for a race at unmount time.<br><br>Index: devfs.h<br>===================================================================
<br><div style="direction: ltr;">RCS file: /usr/local/arch/ncvs/src/sys/fs/devfs/devfs.h,v<br>retrieving revision 1.29<br>diff -u -r1.29 devfs.h<br>--- devfs.h 12 Apr 2006 12:17:29 -0000 1.29<br>+++ devfs.h 1 Sep 2006 11:00:34 -0000
<br>@@ -163,7 +163,7 @@<br> void devfs_rules_apply(struct devfs_mount *dm, struct devfs_dirent *de);<br> void devfs_rules_cleanup (struct devfs_mount *dm);<br> int devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct thread *td);
<br>-int devfs_allocv (struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td);<br>+int devfs_allocv (struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, int *dm_lock, struct thread *td);
<br> void devfs_delete(struct devfs_mount *dm, struct devfs_dirent *de);<br> void devfs_populate (struct devfs_mount *dm);<br> void devfs_cleanup (struct devfs_mount *dm);<br>Index: devfs_vfsops.c<br>===================================================================
<br>RCS file: /usr/local/arch/ncvs/src/sys/fs/devfs/devfs_vfsops.c,v<br>retrieving revision 1.50<br>diff -u -r1.50 devfs_vfsops.c<br>--- devfs_vfsops.c 17 Jul 2006 09:07:01 -0000 1.50<br>+++ devfs_vfsops.c 1 Sep 2006 11:00:34 -0000
<br>@@ -135,9 +135,11 @@<br> int error;<br> struct vnode *vp;<br> struct devfs_mount *dmp;<br>+ int dm_lock;<br><br> dmp = VFSTODEVFS(mp);<br>- error = devfs_allocv(dmp->dm_rootdir, mp, &vp, td);
<br>+ dm_lock = 0;<br>+ error = devfs_allocv(dmp->dm_rootdir, mp, &vp, &dm_lock, td);<br> if (error)<br> return (error);<br> vp->v_vflag |= VV_ROOT;<br>Index: devfs_vnops.c
<br>===================================================================<br>RCS file: /usr/local/arch/ncvs/src/sys/fs/devfs/devfs_vnops.c,v<br>retrieving revision 1.133<br>diff -u -r1.133 devfs_vnops.c<br>--- devfs_vnops.c 17 Jul 2006 09:07:01 -0000
1.133<br>+++ devfs_vnops.c 1 Sep 2006 11:00:34 -0000<br>@@ -126,20 +126,26 @@<br> }<br><br> int<br>-devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td)<br>+devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp,
<br>+ int *dm_unlock, struct thread *td)<br> {<br> int error;<br> struct vnode *vp;<br> struct cdev *dev;<br>+ struct devfs_mount *dmp;<br><br> KASSERT(td == curthread, ("devfs_allocv: td != curthread"));
<br>+ dmp = VFSTODEVFS(mp);<br> loop:<br>-<br> mtx_lock(&devfs_de_interlock);<br> vp = de->de_vnode;<br> if (vp != NULL) {<br> VI_LOCK(vp);<br> mtx_unlock(&devfs_de_interlock);
<br>+ if (*dm_unlock) {<br>+ sx_xunlock(&dmp->dm_lock);<br>+ *dm_unlock = 0;<br>+ }<br> if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td))
<br> goto loop;<br> *vpp = vp;<br>@@ -182,6 +188,10 @@<br> vp->v_data = de;<br> de->de_vnode = vp;<br> mtx_unlock(&devfs_de_interlock);<br>+ if (*dm_unlock) {
<br>+ sx_xunlock(&dmp->dm_lock);<br>+ *dm_unlock = 0;<br>+ }<br> vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);<br> #ifdef MAC<br> mac_associate_vnode_devfs(mp, de, vp);<br>
@@ -456,7 +466,7 @@<br> }<br><br> static int<br>-devfs_lookupx(struct vop_lookup_args *ap)<br>+devfs_lookupx(struct vop_lookup_args *ap, int *dm_unlock)<br> {<br> struct componentname *cnp;<br> struct vnode *dvp, **vpp;
<br>@@ -507,7 +517,7 @@<br> de = TAILQ_FIRST(&dd->de_dlist); /* "." */<br> de = TAILQ_NEXT(de, de_list); /* ".." */<br> de = de->de_dir;
<br>- error = devfs_allocv(de, dvp->v_mount, vpp, td);<br>+ error = devfs_allocv(de, dvp->v_mount, vpp, dm_unlock, td);<br> vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);<br> return (error);
<br> }<br>@@ -564,7 +574,7 @@<br> return (0);<br> }<br> }<br>- error = devfs_allocv(de, dvp->v_mount, vpp, td);<br>+ error = devfs_allocv(de, dvp->v_mount, vpp, dm_unlock, td);
<br> return (error);<br> }<br><br>@@ -573,11 +583,14 @@<br> {<br> int j;<br> struct devfs_mount *dmp;<br>+ int dm_unlock;<br><br> dmp = VFSTODEVFS(ap->a_dvp->v_mount);<br>+ dm_unlock = 1;
<br> sx_xlock(&dmp->dm_lock);<br>- j = devfs_lookupx(ap);<br>- sx_xunlock(&dmp->dm_lock);<br>+ j = devfs_lookupx(ap, &dm_unlock);<br>+ if (dm_unlock == 1)<br>+ sx_xunlock(&dmp->dm_lock);
<br> return (j);<br> }<br><br>@@ -589,6 +602,7 @@<br> struct thread *td;<br> struct devfs_dirent *dd, *de;<br> struct devfs_mount *dmp;<br>+ int dm_unlock;<br> int error;<br><br> /*
<br>@@ -600,6 +614,7 @@<br> dvp = ap->a_dvp;<br> dmp = VFSTODEVFS(dvp->v_mount);<br> sx_xlock(&dmp->dm_lock);<br>+ dm_unlock = 1;<br><br> cnp = ap->a_cnp;<br> vpp = ap->a_vpp;
<br>@@ -620,9 +635,10 @@<br> if (de == NULL)<br> goto notfound;<br> de->de_flags &= ~DE_WHITEOUT;<br>- error = devfs_allocv(de, dvp->v_mount, vpp, td);<br>+ error = devfs_allocv(de, dvp->v_mount, vpp, &dm_unlock, td);
<br> notfound:<br>- sx_xunlock(&dmp->dm_lock);<br>+ if (dm_unlock == 1)<br>+ sx_xunlock(&dmp->dm_lock);<br> return (error);<br> }<br><br>@@ -1102,6 +1118,7 @@<br> struct devfs_dirent *de;
<br> struct devfs_mount *dmp;<br> struct thread *td;<br>+ int dm_unlock;<br><br> td = ap->a_cnp->cn_thread;<br> KASSERT(td == curthread, ("devfs_symlink: td != curthread"));
<br>@@ -1120,12 +1137,14 @@<br> de->de_symlink = malloc(i, M_DEVFS, M_WAITOK);<br> bcopy(ap->a_target, de->de_symlink, i);<br> sx_xlock(&dmp->dm_lock);<br>+ dm_unlock = 1;<br> #ifdef MAC
<br> mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de);<br> #endif<br> TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);<br>- devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, td);
<br>- sx_xunlock(&dmp->dm_lock);<br>+ devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, &dm_unlock, td);<br>+ if (dm_unlock == 1)<br>+ sx_xunlock(&dmp->dm_lock);<br>
return (0);<br> }<br></div><br><br>
------=_Part_100777_6803680.1157365937363--
More information about the freebsd-bugs
mailing list