- Don't detach configured devices on last close.

- No kmem allocation and biodone() under lock (from rmind@netbsd.org).
This commit is contained in:
hannken 2010-11-25 08:53:30 +00:00
parent b6fc822fcf
commit 83b532dd44

View File

@ -1,4 +1,4 @@
/* $NetBSD: md.c,v 1.65 2010/11/23 09:30:43 hannken Exp $ */
/* $NetBSD: md.c,v 1.66 2010/11/25 08:53:30 hannken Exp $ */
/*
* Copyright (c) 1995 Gordon W. Ross, Leo Weppelman.
@ -40,7 +40,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: md.c,v 1.65 2010/11/23 09:30:43 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: md.c,v 1.66 2010/11/25 08:53:30 hannken Exp $");
#ifdef _KERNEL_OPT
#include "opt_md.h"
@ -85,7 +85,7 @@ struct md_softc {
struct disk sc_dkdev; /* hook for generic disk handling */
struct md_conf sc_md;
kmutex_t sc_lock; /* Protect self. */
kcondvar_t sc_cv; /* Signal work. */
kcondvar_t sc_cv; /* Wait here for work. */
struct bufq_state *sc_buflist;
};
/* shorthand for fields in sc_md: */
@ -146,6 +146,7 @@ md_attach(device_t parent, device_t self, void *aux)
struct md_softc *sc = device_private(self);
sc->sc_dev = self;
sc->sc_type = MD_UNCONFIGURED;
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
cv_init(&sc->sc_cv, "mdidle");
bufq_alloc(&sc->sc_buflist, "fcfs", 0);
@ -181,7 +182,7 @@ md_detach(device_t self, int flags)
rc = 0;
mutex_enter(&sc->sc_dkdev.dk_openlock);
if (sc->sc_dkdev.dk_openmask == 0)
if (sc->sc_dkdev.dk_openmask == 0 && sc->sc_type == MD_UNCONFIGURED)
; /* nothing to do */
else if ((flags & DETACH_FORCE) == 0)
rc = EBUSY;
@ -433,10 +434,11 @@ mdstrategy(struct buf *bp)
bp->b_error = EIO;
break;
}
done:
biodone(bp);
done:
mutex_exit(&sc->sc_lock);
biodone(bp);
}
static int
@ -561,14 +563,23 @@ md_ioctl_kalloc(struct md_softc *sc, struct md_conf *umd,
vaddr_t addr;
vsize_t size;
KASSERT(mutex_owned(&sc->sc_lock));
mutex_exit(&sc->sc_lock);
/* Sanity check the size. */
size = umd->md_size;
addr = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_WIRED|UVM_KMF_ZERO);
mutex_enter(&sc->sc_lock);
if (!addr)
return ENOMEM;
/* If another thread beat us to configure this unit: fail. */
if (sc->sc_type != MD_UNCONFIGURED) {
uvm_km_free(kernel_map, addr, size, UVM_KMF_WIRED);
return EINVAL;
}
/* This unit is now configured. */
sc->sc_addr = (void *)addr; /* kernel space */
sc->sc_size = (size_t)size;