Use a per-device worker thread to avoid blocking in mdstrategy()

until the I/O completes. This fixes some easily reproducable deadlocks
that occur when using md(4) with GEOM.

Reviewed by:	phk
This commit is contained in:
Ian Dowse 2002-06-03 22:09:04 +00:00
parent 7b5e6f62fb
commit 5c97ca54e5

View File

@ -67,6 +67,7 @@
#include <sys/disk.h> #include <sys/disk.h>
#include <sys/fcntl.h> #include <sys/fcntl.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/linker.h> #include <sys/linker.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/malloc.h> #include <sys/malloc.h>
@ -78,8 +79,6 @@
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <sys/vnode.h> #include <sys/vnode.h>
#include <machine/atomic.h>
#include <vm/vm.h> #include <vm/vm.h>
#include <vm/vm_object.h> #include <vm/vm_object.h>
#include <vm/vm_page.h> #include <vm/vm_page.h>
@ -89,6 +88,8 @@
#define MD_MODVER 1 #define MD_MODVER 1
#define MD_SHUTDOWN 0x10000 /* Tell worker thread to terminate. */
#ifndef MD_NSECT #ifndef MD_NSECT
#define MD_NSECT (10000 * 2) #define MD_NSECT (10000 * 2)
#endif #endif
@ -167,13 +168,13 @@ struct md_s {
struct bio_queue_head bio_queue; struct bio_queue_head bio_queue;
struct disk disk; struct disk disk;
dev_t dev; dev_t dev;
int busy;
enum md_types type; enum md_types type;
unsigned nsect; unsigned nsect;
unsigned opencount; unsigned opencount;
unsigned secsize; unsigned secsize;
unsigned flags; unsigned flags;
char name[20]; char name[20];
struct proc *procp;
/* MD_MALLOC related fields */ /* MD_MALLOC related fields */
struct indir *indir; struct indir *indir;
@ -546,7 +547,6 @@ static void
mdstrategy(struct bio *bp) mdstrategy(struct bio *bp)
{ {
struct md_s *sc; struct md_s *sc;
int error;
if (md_debug > 1) if (md_debug > 1)
printf("mdstrategy(%p) %s %x, %lld, %ld, %p)\n", printf("mdstrategy(%p) %s %x, %lld, %ld, %p)\n",
@ -560,18 +560,35 @@ mdstrategy(struct bio *bp)
bioqdisksort(&sc->bio_queue, bp); bioqdisksort(&sc->bio_queue, bp);
/* XXX: UNLOCK(sc->lock) */ /* XXX: UNLOCK(sc->lock) */
if (atomic_cmpset_int(&sc->busy, 0, 1) == 0) wakeup(sc);
return; }
static void
md_kthread(void *arg)
{
struct md_s *sc;
struct bio *bp;
int error;
sc = arg;
curthread->td_base_pri = PRIBIO;
mtx_lock(&Giant);
for (;;) { for (;;) {
/* XXX: LOCK(unique unit numbers) */ /* XXX: LOCK(unique unit numbers) */
bp = bioq_first(&sc->bio_queue); bp = bioq_first(&sc->bio_queue);
if (bp) if (bp)
bioq_remove(&sc->bio_queue, bp); bioq_remove(&sc->bio_queue, bp);
/* XXX: UNLOCK(unique unit numbers) */ /* XXX: UNLOCK(unique unit numbers) */
if (!bp) if (!bp) {
break; tsleep(sc, PRIBIO, "mdwait", 0);
if (sc->flags & MD_SHUTDOWN) {
sc->procp = NULL;
wakeup(&sc->procp);
kthread_exit(0);
}
continue;
}
switch (sc->type) { switch (sc->type) {
case MD_MALLOC: case MD_MALLOC:
@ -597,7 +614,6 @@ mdstrategy(struct bio *bp)
if (error != -1) if (error != -1)
biofinish(bp, &sc->stats, error); biofinish(bp, &sc->stats, error);
} }
sc->busy = 0;
} }
static struct md_s * static struct md_s *
@ -618,7 +634,7 @@ static struct md_s *
mdnew(int unit) mdnew(int unit)
{ {
struct md_s *sc; struct md_s *sc;
int max = -1; int error, max = -1;
/* XXX: LOCK(unique unit numbers) */ /* XXX: LOCK(unique unit numbers) */
LIST_FOREACH(sc, &md_softc_list, list) { LIST_FOREACH(sc, &md_softc_list, list) {
@ -636,6 +652,11 @@ mdnew(int unit)
sc = (struct md_s *)malloc(sizeof *sc, M_MD, M_WAITOK | M_ZERO); sc = (struct md_s *)malloc(sizeof *sc, M_MD, M_WAITOK | M_ZERO);
sc->unit = unit; sc->unit = unit;
sprintf(sc->name, "md%d", unit); sprintf(sc->name, "md%d", unit);
error = kthread_create(md_kthread, sc, &sc->procp, 0, "%s", sc->name);
if (error) {
free(sc, M_MD);
return (NULL);
}
LIST_INSERT_HEAD(&md_softc_list, sc, list); LIST_INSERT_HEAD(&md_softc_list, sc, list);
/* XXX: UNLOCK(unique unit numbers) */ /* XXX: UNLOCK(unique unit numbers) */
return (sc); return (sc);
@ -861,6 +882,10 @@ mddestroy(struct md_s *sc, struct thread *td)
devstat_remove_entry(&sc->stats); devstat_remove_entry(&sc->stats);
disk_destroy(sc->dev); disk_destroy(sc->dev);
} }
sc->flags |= MD_SHUTDOWN;
wakeup(sc);
while (sc->procp != NULL)
tsleep(&sc->procp, PRIBIO, "mddestroy", hz / 10);
if (sc->vnode != NULL) if (sc->vnode != NULL)
(void)vn_close(sc->vnode, sc->flags & MD_READONLY ? (void)vn_close(sc->vnode, sc->flags & MD_READONLY ?
FREAD : (FREAD|FWRITE), sc->cred, td); FREAD : (FREAD|FWRITE), sc->cred, td);