summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2006-12-14 11:34:07 +0000
committerkib <kib@FreeBSD.org>2006-12-14 11:34:07 +0000
commite7cdcb324074afe862ff79dff4056e372d7a7dcc (patch)
treeb4491be126c4489f10c7fd21ffcd58a2b9876bfd
parentd828ea069054def0683feaaa0ab3b996287edc4e (diff)
downloadFreeBSD-src-e7cdcb324074afe862ff79dff4056e372d7a7dcc.zip
FreeBSD-src-e7cdcb324074afe862ff79dff4056e372d7a7dcc.tar.gz
Resolve two deadlocks that could be caused by busy md device backed
by vnode. Allow for md thread and the thread that owns lock on vnode backing the md device to do the write even when runningbufspace is exhausted. Tested by: Peter Holm Reviewed by: tegge MFC after: 2 weeks
-rw-r--r--sys/dev/md/md.c9
-rw-r--r--sys/kern/vfs_bio.c3
-rw-r--r--sys/sys/vnode.h1
3 files changed, 12 insertions, 1 deletions
diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c
index 3b6cc6b..06a813f 100644
--- a/sys/dev/md/md.c
+++ b/sys/dev/md/md.c
@@ -693,6 +693,8 @@ md_kthread(void *arg)
mtx_lock_spin(&sched_lock);
sched_prio(curthread, PRIBIO);
mtx_unlock_spin(&sched_lock);
+ if (sc->type == MD_VNODE)
+ curthread->td_pflags |= TDP_NORUNNINGBUF;
for (;;) {
mtx_lock(&sc->queue_mtx);
@@ -923,6 +925,7 @@ mdcreate_vnode(struct md_s *sc, struct md_ioctl *mdio, struct thread *td)
VFS_UNLOCK_GIANT(vfslocked);
return (error ? error : EINVAL);
}
+ nd.ni_vp->v_vflag |= VV_MD;
VOP_UNLOCK(nd.ni_vp, 0, td);
if (mdio->md_fwsectors != 0)
@@ -936,6 +939,9 @@ mdcreate_vnode(struct md_s *sc, struct md_ioctl *mdio, struct thread *td)
error = mdsetcred(sc, td->td_ucred);
if (error != 0) {
+ vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY, td);
+ nd.ni_vp->v_vflag &= ~VV_MD;
+ VOP_UNLOCK(nd.ni_vp, 0, td);
(void)vn_close(nd.ni_vp, flags, td->td_ucred, td);
VFS_UNLOCK_GIANT(vfslocked);
return (error);
@@ -966,6 +972,9 @@ mddestroy(struct md_s *sc, struct thread *td)
mtx_destroy(&sc->queue_mtx);
if (sc->vnode != NULL) {
vfslocked = VFS_LOCK_GIANT(sc->vnode->v_mount);
+ vn_lock(sc->vnode, LK_EXCLUSIVE | LK_RETRY, td);
+ sc->vnode->v_vflag &= ~VV_MD;
+ VOP_UNLOCK(sc->vnode, 0, td);
(void)vn_close(sc->vnode, sc->flags & MD_READONLY ?
FREAD : (FREAD|FWRITE), sc->cred, td);
VFS_UNLOCK_GIANT(vfslocked);
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index db2aacd..0d49710 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -871,7 +871,8 @@ bufwrite(struct buf *bp)
* or syncer daemon trying to clean up as that can lead
* to deadlock.
*/
- if ((curthread->td_pflags & TDP_NORUNNINGBUF) == 0)
+ if ((curthread->td_pflags & TDP_NORUNNINGBUF) == 0 &&
+ (bp->b_vp->v_vflag & VV_MD) == 0)
waitrunningbufspace();
}
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index d877ab9..4495155 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -254,6 +254,7 @@ struct xvnode {
#define VV_PROCDEP 0x0100 /* vnode is process dependent */
#define VV_NOKNOTE 0x0200 /* don't activate knotes on this vnode */
#define VV_DELETED 0x0400 /* should be removed */
+#define VV_MD 0x0800 /* vnode backs the md device */
/*
* Vnode attributes. A field value of VNOVAL represents a field whose value
OpenPOWER on IntegriCloud