Make dksubr use a spin-mutex again, since some drivers still call dk_done
from hardware interrupt. Instead, release mutex while calling start routine. The buffer peek/use/get sequence which can no longer be atomic. So consume the buffer directly and on error privately save and retry the buffer later. The dk_drain function is used to flush such a deferred buffer together with the buffer queue. Adjust drivers to use dk_drain. Fix an error path where dk_done was called while the lock was already held.
This commit is contained in:
parent
d6cc60697d
commit
7874349bce
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: xbd_xenbus.c,v 1.72 2015/08/16 18:00:03 mlelstv Exp $ */
|
||||
/* $NetBSD: xbd_xenbus.c,v 1.73 2015/08/27 05:51:50 mlelstv Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Manuel Bouyer.
|
||||
|
@ -50,7 +50,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: xbd_xenbus.c,v 1.72 2015/08/16 18:00:03 mlelstv Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: xbd_xenbus.c,v 1.73 2015/08/27 05:51:50 mlelstv Exp $");
|
||||
|
||||
#include "opt_xen.h"
|
||||
|
||||
|
@ -363,11 +363,9 @@ xbd_xenbus_detach(device_t dev, int flags)
|
|||
/* Delete all of our wedges. */
|
||||
dkwedge_delall(&sc->sc_dksc.sc_dkdev);
|
||||
|
||||
s = splbio();
|
||||
/* Kill off any queued buffers. */
|
||||
bufq_drain(sc->sc_dksc.sc_bufq);
|
||||
dk_drain(&sc->sc_dksc);
|
||||
bufq_free(sc->sc_dksc.sc_bufq);
|
||||
splx(s);
|
||||
|
||||
/* detach disk */
|
||||
disk_detach(&sc->sc_dksc.sc_dkdev);
|
||||
|
@ -701,12 +699,11 @@ again:
|
|||
next:
|
||||
if (bp->b_data != xbdreq->req_data)
|
||||
xbd_unmap_align(xbdreq);
|
||||
disk_unbusy(&sc->sc_dksc.sc_dkdev,
|
||||
(bp->b_bcount - bp->b_resid),
|
||||
(bp->b_flags & B_READ));
|
||||
|
||||
rnd_add_uint32(&sc->sc_rnd_source,
|
||||
bp->b_blkno);
|
||||
biodone(bp);
|
||||
dk_done(&sc->sc_dksc, bp);
|
||||
|
||||
SLIST_INSERT_HEAD(&sc->sc_xbdreq_head, xbdreq, req_next);
|
||||
}
|
||||
done:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: cgd.c,v 1.103 2015/08/21 09:33:53 christos Exp $ */
|
||||
/* $NetBSD: cgd.c,v 1.104 2015/08/27 05:51:50 mlelstv Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 The NetBSD Foundation, Inc.
|
||||
|
@ -30,7 +30,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.103 2015/08/21 09:33:53 christos Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.104 2015/08/27 05:51:50 mlelstv Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
|
@ -565,7 +565,7 @@ cgdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
|
|||
return VOP_IOCTL(cs->sc_tvn, cmd, data, flag, l->l_cred);
|
||||
case DIOCGSTRATEGY:
|
||||
case DIOCSSTRATEGY:
|
||||
if ((dksc->sc_flags & DKF_INITED) == 0)
|
||||
if (!DK_ATTACHED(dksc))
|
||||
return ENOENT;
|
||||
/*FALLTHROUGH*/
|
||||
default:
|
||||
|
@ -722,7 +722,6 @@ bail:
|
|||
static int
|
||||
cgd_ioctl_clr(struct cgd_softc *cs, struct lwp *l)
|
||||
{
|
||||
int s;
|
||||
struct dk_softc *dksc = &cs->sc_dksc;
|
||||
|
||||
if (!DK_ATTACHED(dksc))
|
||||
|
@ -732,9 +731,7 @@ cgd_ioctl_clr(struct cgd_softc *cs, struct lwp *l)
|
|||
dkwedge_delall(&dksc->sc_dkdev);
|
||||
|
||||
/* Kill off any queued buffers. */
|
||||
s = splbio();
|
||||
bufq_drain(dksc->sc_bufq);
|
||||
splx(s);
|
||||
dk_drain(dksc);
|
||||
bufq_free(dksc->sc_bufq);
|
||||
|
||||
(void)vn_close(cs->sc_tvn, FREAD|FWRITE, l->l_cred);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: dksubr.c,v 1.73 2015/08/23 07:47:52 mlelstv Exp $ */
|
||||
/* $NetBSD: dksubr.c,v 1.74 2015/08/27 05:51:50 mlelstv Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996, 1997, 1998, 1999, 2002, 2008 The NetBSD Foundation, Inc.
|
||||
|
@ -30,7 +30,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: dksubr.c,v 1.73 2015/08/23 07:47:52 mlelstv Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: dksubr.c,v 1.74 2015/08/27 05:51:50 mlelstv Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -74,6 +74,7 @@ static int dk_subr_modcmd(modcmd_t, void *);
|
|||
|
||||
static void dk_makedisklabel(struct dk_softc *);
|
||||
static int dk_translate(struct dk_softc *, struct buf *);
|
||||
static void dk_done1(struct dk_softc *, struct buf *, bool);
|
||||
|
||||
void
|
||||
dk_init(struct dk_softc *dksc, device_t dev, int dtype)
|
||||
|
@ -90,7 +91,7 @@ dk_init(struct dk_softc *dksc, device_t dev, int dtype)
|
|||
void
|
||||
dk_attach(struct dk_softc *dksc)
|
||||
{
|
||||
mutex_init(&dksc->sc_iolock, MUTEX_DEFAULT, IPL_NONE);
|
||||
mutex_init(&dksc->sc_iolock, MUTEX_DEFAULT, IPL_VM);
|
||||
dksc->sc_flags |= DKF_INITED;
|
||||
#ifdef DIAGNOSTIC
|
||||
dksc->sc_flags |= DKF_WARNLABEL | DKF_LABELSANITY;
|
||||
|
@ -294,41 +295,55 @@ dk_start(struct dk_softc *dksc, struct buf *bp)
|
|||
{
|
||||
const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
|
||||
int error;
|
||||
struct buf *qbp __diagused;
|
||||
|
||||
mutex_enter(&dksc->sc_iolock);
|
||||
|
||||
if (bp != NULL)
|
||||
bufq_put(dksc->sc_bufq, bp);
|
||||
|
||||
while ((bp = bufq_peek(dksc->sc_bufq)) != NULL) {
|
||||
/*
|
||||
* Peeking at the buffer queue and committing the operation
|
||||
* only after success isn't atomic.
|
||||
*
|
||||
* So when a diskstart fails, the buffer is saved
|
||||
* and tried again before the next buffer is fetched.
|
||||
* dk_drain() handles flushing of a saved buffer.
|
||||
*
|
||||
* This keeps order of I/O operations, unlike bufq_put.
|
||||
*/
|
||||
|
||||
bp = dksc->sc_deferred;
|
||||
dksc->sc_deferred = NULL;
|
||||
|
||||
if (bp == NULL)
|
||||
bp = bufq_get(dksc->sc_bufq);
|
||||
|
||||
while (bp != NULL) {
|
||||
|
||||
disk_busy(&dksc->sc_dkdev);
|
||||
mutex_exit(&dksc->sc_iolock);
|
||||
error = dkd->d_diskstart(dksc->sc_dev, bp);
|
||||
mutex_enter(&dksc->sc_iolock);
|
||||
if (error == EAGAIN) {
|
||||
dksc->sc_deferred = bp;
|
||||
disk_unbusy(&dksc->sc_dkdev, 0, (bp->b_flags & B_READ));
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
qbp = bufq_get(dksc->sc_bufq);
|
||||
KASSERT(bp == qbp);
|
||||
#else
|
||||
(void) bufq_get(dksc->sc_bufq);
|
||||
#endif
|
||||
|
||||
if (error != 0) {
|
||||
bp->b_error = error;
|
||||
bp->b_resid = bp->b_bcount;
|
||||
dk_done(dksc, bp);
|
||||
dk_done1(dksc, bp, false);
|
||||
}
|
||||
|
||||
bp = bufq_get(dksc->sc_bufq);
|
||||
}
|
||||
|
||||
mutex_exit(&dksc->sc_iolock);
|
||||
}
|
||||
|
||||
void
|
||||
dk_done(struct dk_softc *dksc, struct buf *bp)
|
||||
static void
|
||||
dk_done1(struct dk_softc *dksc, struct buf *bp, bool lock)
|
||||
{
|
||||
struct disk *dk = &dksc->sc_dkdev;
|
||||
|
||||
|
@ -340,9 +355,11 @@ dk_done(struct dk_softc *dksc, struct buf *bp)
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
mutex_enter(&dksc->sc_iolock);
|
||||
if (lock)
|
||||
mutex_enter(&dksc->sc_iolock);
|
||||
disk_unbusy(dk, bp->b_bcount - bp->b_resid, (bp->b_flags & B_READ));
|
||||
mutex_exit(&dksc->sc_iolock);
|
||||
if (lock)
|
||||
mutex_exit(&dksc->sc_iolock);
|
||||
|
||||
#ifdef notyet
|
||||
rnd_add_uint(&dksc->sc_rnd_source, bp->b_rawblkno);
|
||||
|
@ -351,6 +368,28 @@ dk_done(struct dk_softc *dksc, struct buf *bp)
|
|||
biodone(bp);
|
||||
}
|
||||
|
||||
void
|
||||
dk_done(struct dk_softc *dksc, struct buf *bp)
|
||||
{
|
||||
dk_done1(dksc, bp, true);
|
||||
}
|
||||
|
||||
void
|
||||
dk_drain(struct dk_softc *dksc)
|
||||
{
|
||||
struct buf *bp;
|
||||
|
||||
mutex_enter(&dksc->sc_iolock);
|
||||
bp = dksc->sc_deferred;
|
||||
if (bp != NULL) {
|
||||
bp->b_error = EIO;
|
||||
bp->b_resid = bp->b_bcount;
|
||||
biodone(bp);
|
||||
}
|
||||
bufq_drain(dksc->sc_bufq);
|
||||
mutex_exit(&dksc->sc_iolock);
|
||||
}
|
||||
|
||||
int
|
||||
dk_discard(struct dk_softc *dksc, dev_t dev, off_t pos, off_t len)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: dkvar.h,v 1.21 2015/08/16 18:00:03 mlelstv Exp $ */
|
||||
/* $NetBSD: dkvar.h,v 1.22 2015/08/27 05:51:50 mlelstv Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 The NetBSD Foundation, Inc.
|
||||
|
@ -47,6 +47,7 @@ struct dk_softc {
|
|||
kmutex_t sc_iolock; /* protects buffer queue */
|
||||
struct bufq_state *sc_bufq; /* buffer queue */
|
||||
int sc_dtype; /* disk type */
|
||||
struct buf *sc_deferred; /* retry after start failed */
|
||||
};
|
||||
|
||||
/* sc_flags:
|
||||
|
@ -62,6 +63,7 @@ struct dk_softc {
|
|||
#define DKF_TAKEDUMP 0x00200000 /* allow dumping */
|
||||
#define DKF_KLABEL 0x00400000 /* keep label on close */
|
||||
#define DKF_VLABEL 0x00800000 /* label is valid */
|
||||
#define DKF_SLEEP 0x80000000 /* dk_start/dk_done may sleep */
|
||||
|
||||
/* Mask of flags that dksubr.c understands, other flags are fair game */
|
||||
#define DK_FLAGMASK 0xffff0000
|
||||
|
@ -89,6 +91,7 @@ void dk_strategy(struct dk_softc *, struct buf *);
|
|||
int dk_discard(struct dk_softc *, dev_t, off_t, off_t);
|
||||
void dk_start(struct dk_softc *, struct buf *);
|
||||
void dk_done(struct dk_softc *, struct buf *);
|
||||
void dk_drain(struct dk_softc *);
|
||||
int dk_size(struct dk_softc *, dev_t);
|
||||
int dk_ioctl(struct dk_softc *, dev_t,
|
||||
u_long, void *, int, struct lwp *);
|
||||
|
|
13
sys/dev/ld.c
13
sys/dev/ld.c
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ld.c,v 1.91 2015/08/18 04:20:25 mlelstv Exp $ */
|
||||
/* $NetBSD: ld.c,v 1.92 2015/08/27 05:51:50 mlelstv Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
|
||||
|
@ -34,7 +34,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.91 2015/08/18 04:20:25 mlelstv Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.92 2015/08/27 05:51:50 mlelstv Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -197,8 +197,6 @@ ldbegindetach(struct ld_softc *sc, int flags)
|
|||
mutex_enter(&sc->sc_mutex);
|
||||
sc->sc_maxqueuecnt = 0;
|
||||
|
||||
dk_detach(dksc);
|
||||
|
||||
while (sc->sc_queuecnt > 0) {
|
||||
sc->sc_flags |= LDF_DRAIN;
|
||||
cv_wait(&sc->sc_drain, &sc->sc_mutex);
|
||||
|
@ -224,11 +222,10 @@ ldenddetach(struct ld_softc *sc)
|
|||
if (cv_timedwait(&sc->sc_drain, &sc->sc_mutex, 30 * hz))
|
||||
printf("%s: not drained\n", dksc->sc_xname);
|
||||
}
|
||||
|
||||
/* Kill off any queued buffers. */
|
||||
bufq_drain(dksc->sc_bufq);
|
||||
mutex_exit(&sc->sc_mutex);
|
||||
|
||||
/* Kill off any queued buffers. */
|
||||
dk_drain(dksc);
|
||||
bufq_free(dksc->sc_bufq);
|
||||
|
||||
/* Locate the major numbers. */
|
||||
|
@ -249,6 +246,8 @@ ldenddetach(struct ld_softc *sc)
|
|||
disk_detach(&dksc->sc_dkdev);
|
||||
disk_destroy(&dksc->sc_dkdev);
|
||||
|
||||
dk_detach(dksc);
|
||||
|
||||
/* Unhook the entropy source. */
|
||||
rnd_detach_source(&sc->sc_rnd_source);
|
||||
|
||||
|
|
Loading…
Reference in New Issue