diff options
author | kib <kib@FreeBSD.org> | 2006-12-14 11:34:07 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2006-12-14 11:34:07 +0000 |
commit | e7cdcb324074afe862ff79dff4056e372d7a7dcc (patch) | |
tree | b4491be126c4489f10c7fd21ffcd58a2b9876bfd | |
parent | d828ea069054def0683feaaa0ab3b996287edc4e (diff) | |
download | FreeBSD-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.c | 9 | ||||
-rw-r--r-- | sys/kern/vfs_bio.c | 3 | ||||
-rw-r--r-- | sys/sys/vnode.h | 1 |
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 |