summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authormlelstv <mlelstv@NetBSD.org>2015-08-16 18:00:03 +0000
committermlelstv <mlelstv@NetBSD.org>2015-08-16 18:00:03 +0000
commit0816f4a9f915c8a6887cb0793bb309ebc4433b89 (patch)
tree81601b5094536ba7048473d11e9715ccdda6aca3 /sys/dev
parent64fa860da242df5b4f4dc1638e72f5310f6ceecd (diff)
Two changes to the dksubr interface.
- d_diskstart callback now processes a single buffer only. The new wrapper function dk_start processes the queue, performs other buffer handling and also provides locking for the the data structures. - add d_discard callback to handle device specific function inside the new dk_discard helper function. Replace splbio with mutex to protect queue and disk structure. Refactor common code in dk_strategy and dk_discard into dk_translate. Adjust and simplify ld(4), cgd(4) and xbd(4) drivers accordingly. ld(4) now becomes MP_SAFE. Bump kernel version.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/cgd.c124
-rw-r--r--sys/dev/dksubr.c170
-rw-r--r--sys/dev/dkvar.h5
-rw-r--r--sys/dev/ld.c67
4 files changed, 198 insertions, 168 deletions
diff --git a/sys/dev/cgd.c b/sys/dev/cgd.c
index 83b38e5bd9d..2faf5fd495d 100644
--- a/sys/dev/cgd.c
+++ b/sys/dev/cgd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cgd.c,v 1.98 2015/05/02 08:00:08 mlelstv Exp $ */
+/* $NetBSD: cgd.c,v 1.99 2015/08/16 18:00:03 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.98 2015/05/02 08:00:08 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.99 2015/08/16 18:00:03 mlelstv Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -104,7 +104,7 @@ static int cgd_destroy(device_t);
/* Internal Functions */
-static void cgd_start(device_t);
+static int cgd_diskstart(device_t, struct buf *);
static void cgdiodone(struct buf *);
static int cgd_ioctl_set(struct cgd_softc *, void *, struct lwp *);
@@ -121,7 +121,7 @@ static struct dkdriver cgddkdriver = {
.d_close = cgdclose,
.d_strategy = cgdstrategy,
.d_iosize = NULL,
- .d_diskstart = cgd_start,
+ .d_diskstart = cgd_diskstart,
.d_dumpblocks = NULL,
.d_lastclose = NULL
};
@@ -379,79 +379,65 @@ cgd_putdata(struct dk_softc *dksc, void *data)
}
}
-static void
-cgd_start(device_t dev)
+static int
+cgd_diskstart(device_t dev, struct buf *bp)
{
struct cgd_softc *cs = device_private(dev);
struct dk_softc *dksc = &cs->sc_dksc;
- struct buf *bp, *nbp;
-#ifdef DIAGNOSTIC
- struct buf *qbp;
-#endif
+ struct buf *nbp;
void * addr;
void * newaddr;
daddr_t bn;
struct vnode *vp;
- while ((bp = bufq_peek(dksc->sc_bufq)) != NULL) {
+ DPRINTF_FOLLOW(("cgd_diskstart(%p, %p)\n", dksc, bp));
- DPRINTF_FOLLOW(("cgd_start(%p, %p)\n", dksc, bp));
- disk_busy(&dksc->sc_dkdev);
+ bn = bp->b_rawblkno;
- bn = bp->b_rawblkno;
+ /*
+ * We attempt to allocate all of our resources up front, so that
+ * we can fail quickly if they are unavailable.
+ */
+ nbp = getiobuf(cs->sc_tvn, false);
+ if (nbp == NULL)
+ return EAGAIN;
- /*
- * We attempt to allocate all of our resources up front, so that
- * we can fail quickly if they are unavailable.
- */
- nbp = getiobuf(cs->sc_tvn, false);
- if (nbp == NULL) {
- disk_unbusy(&dksc->sc_dkdev, 0, (bp->b_flags & B_READ));
- break;
+ /*
+ * If we are writing, then we need to encrypt the outgoing
+ * block into a new block of memory.
+ */
+ newaddr = addr = bp->b_data;
+ if ((bp->b_flags & B_READ) == 0) {
+ newaddr = cgd_getdata(dksc, bp->b_bcount);
+ if (!newaddr) {
+ putiobuf(nbp);
+ return EAGAIN;
}
+ cgd_cipher(cs, newaddr, addr, bp->b_bcount, bn,
+ DEV_BSIZE, CGD_CIPHER_ENCRYPT);
+ }
- /*
- * If we are writing, then we need to encrypt the outgoing
- * block into a new block of memory.
- */
- newaddr = addr = bp->b_data;
- if ((bp->b_flags & B_READ) == 0) {
- newaddr = cgd_getdata(dksc, bp->b_bcount);
- if (!newaddr) {
- putiobuf(nbp);
- disk_unbusy(&dksc->sc_dkdev, 0, (bp->b_flags & B_READ));
- break;
- }
- cgd_cipher(cs, newaddr, addr, bp->b_bcount, bn,
- DEV_BSIZE, CGD_CIPHER_ENCRYPT);
- }
- /* we now have all needed resources to process this buf */
-#ifdef DIAGNOSTIC
- qbp = bufq_get(dksc->sc_bufq);
- KASSERT(bp == qbp);
-#else
- (void)bufq_get(dksc->sc_bufq);
-#endif
- nbp->b_data = newaddr;
- nbp->b_flags = bp->b_flags;
- nbp->b_oflags = bp->b_oflags;
- nbp->b_cflags = bp->b_cflags;
- nbp->b_iodone = cgdiodone;
- nbp->b_proc = bp->b_proc;
- nbp->b_blkno = bn;
- nbp->b_bcount = bp->b_bcount;
- nbp->b_private = bp;
-
- BIO_COPYPRIO(nbp, bp);
-
- if ((nbp->b_flags & B_READ) == 0) {
- vp = nbp->b_vp;
- mutex_enter(vp->v_interlock);
- vp->v_numoutput++;
- mutex_exit(vp->v_interlock);
- }
- VOP_STRATEGY(cs->sc_tvn, nbp);
+ nbp->b_data = newaddr;
+ nbp->b_flags = bp->b_flags;
+ nbp->b_oflags = bp->b_oflags;
+ nbp->b_cflags = bp->b_cflags;
+ nbp->b_iodone = cgdiodone;
+ nbp->b_proc = bp->b_proc;
+ nbp->b_blkno = bn;
+ nbp->b_bcount = bp->b_bcount;
+ nbp->b_private = bp;
+
+ BIO_COPYPRIO(nbp, bp);
+
+ if ((nbp->b_flags & B_READ) == 0) {
+ vp = nbp->b_vp;
+ mutex_enter(vp->v_interlock);
+ vp->v_numoutput++;
+ mutex_exit(vp->v_interlock);
}
+ VOP_STRATEGY(cs->sc_tvn, nbp);
+
+ return 0;
}
static void
@@ -460,7 +446,6 @@ cgdiodone(struct buf *nbp)
struct buf *obp = nbp->b_private;
struct cgd_softc *cs = getcgd_softc(obp->b_dev);
struct dk_softc *dksc = &cs->sc_dksc;
- int s;
KDASSERT(cs);
@@ -492,16 +477,7 @@ cgdiodone(struct buf *nbp)
putiobuf(nbp);
- /* Request is complete for whatever reason */
- obp->b_resid = 0;
- if (obp->b_error != 0)
- obp->b_resid = obp->b_bcount;
- s = splbio();
- disk_unbusy(&dksc->sc_dkdev, obp->b_bcount - obp->b_resid,
- (obp->b_flags & B_READ));
- biodone(obp);
- cgd_start(dksc->sc_dev);
- splx(s);
+ dk_done(dksc, obp);
}
/* XXX: we should probably put these into dksubr.c, mostly */
diff --git a/sys/dev/dksubr.c b/sys/dev/dksubr.c
index 8cccca5e014..52bf51fdc93 100644
--- a/sys/dev/dksubr.c
+++ b/sys/dev/dksubr.c
@@ -1,4 +1,4 @@
-/* $NetBSD: dksubr.c,v 1.70 2015/08/16 17:28:28 mlelstv Exp $ */
+/* $NetBSD: dksubr.c,v 1.71 2015/08/16 18:00:03 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.70 2015/08/16 17:28:28 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dksubr.c,v 1.71 2015/08/16 18:00:03 mlelstv Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -73,6 +73,7 @@ static int dk_subr_modcmd(modcmd_t, void *);
(MAKEDISKDEV(major((dev)), DISKUNIT((dev)), RAW_PART))
static void dk_makedisklabel(struct dk_softc *);
+static int dk_translate(struct dk_softc *, struct buf *);
void
dk_init(struct dk_softc *dksc, device_t dev, int dtype)
@@ -89,6 +90,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_VM);
dksc->sc_flags |= DKF_INITED;
#ifdef DIAGNOSTIC
dksc->sc_flags |= DKF_WARNLABEL | DKF_LABELSANITY;
@@ -99,6 +101,7 @@ void
dk_detach(struct dk_softc *dksc)
{
dksc->sc_flags &= ~DKF_INITED;
+ mutex_destroy(&dksc->sc_iolock);
}
/* ARGSUSED */
@@ -199,11 +202,10 @@ dk_close(struct dk_softc *dksc, dev_t dev,
return 0;
}
-void
-dk_strategy(struct dk_softc *dksc, struct buf *bp)
+static int
+dk_translate(struct dk_softc *dksc, struct buf *bp)
{
- const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
- int s, part;
+ int part;
int wlabel;
daddr_t blkno;
struct disklabel *lp;
@@ -211,16 +213,6 @@ dk_strategy(struct dk_softc *dksc, struct buf *bp)
uint64_t numsecs;
unsigned secsize;
- DPRINTF_FOLLOW(("dk_strategy(%s, %p, %p)\n",
- dksc->sc_xname, dksc, bp));
-
- if (!(dksc->sc_flags & DKF_INITED)) {
- DPRINTF_FOLLOW(("dk_strategy: not inited\n"));
- bp->b_error = ENXIO;
- biodone(bp);
- return;
- }
-
lp = dksc->sc_dkdev.dk_label;
dk = &dksc->sc_dkdev;
@@ -234,29 +226,20 @@ dk_strategy(struct dk_softc *dksc, struct buf *bp)
* The transfer must be a whole number of blocks and the offset must
* not be negative.
*/
- if ((bp->b_bcount % secsize) != 0 || bp->b_blkno < 0) {
- bp->b_error = EINVAL;
- biodone(bp);
- return;
- }
+ if ((bp->b_bcount % secsize) != 0 || bp->b_blkno < 0)
+ return EINVAL;
/* If there is nothing to do, then we are done */
- if (bp->b_bcount == 0) {
- biodone(bp);
- return;
- }
+ if (bp->b_bcount == 0)
+ return 0;
wlabel = dksc->sc_flags & (DKF_WLABEL|DKF_LABELLING);
if (part == RAW_PART) {
- if (bounds_check_with_mediasize(bp, DEV_BSIZE, numsecs) <= 0) {
- biodone(bp);
- return;
- }
+ if (bounds_check_with_mediasize(bp, DEV_BSIZE, numsecs) <= 0)
+ return bp->b_error;
} else {
- if (bounds_check_with_label(&dksc->sc_dkdev, bp, wlabel) <= 0) {
- biodone(bp);
- return;
- }
+ if (bounds_check_with_label(&dksc->sc_dkdev, bp, wlabel) <= 0)
+ return bp->b_error;
}
/*
@@ -272,15 +255,72 @@ dk_strategy(struct dk_softc *dksc, struct buf *bp)
blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
bp->b_rawblkno = blkno;
+ return -1;
+}
+
+void
+dk_strategy(struct dk_softc *dksc, struct buf *bp)
+{
+ int error;
+
+ DPRINTF_FOLLOW(("dk_strategy(%s, %p, %p)\n",
+ dksc->sc_xname, dksc, bp));
+
+ if (!(dksc->sc_flags & DKF_INITED)) {
+ DPRINTF_FOLLOW(("dk_strategy: not inited\n"));
+ bp->b_error = ENXIO;
+ biodone(bp);
+ return;
+ }
+
+ error = dk_translate(dksc, bp);
+ if (error >= 0) {
+ biodone(bp);
+ return;
+ }
+
/*
- * Start the unit by calling the start routine
- * provided by the individual driver.
+ * Queue buffer and start unit
*/
- s = splbio();
- bufq_put(dksc->sc_bufq, bp);
- dkd->d_diskstart(dksc->sc_dev);
- splx(s);
- return;
+ dk_start(dksc, bp);
+}
+
+void
+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) {
+
+ disk_busy(&dksc->sc_dkdev);
+ error = dkd->d_diskstart(dksc->sc_dev, bp);
+ if (error == EAGAIN) {
+ 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);
+ }
+ }
+
+ mutex_exit(&dksc->sc_iolock);
}
void
@@ -296,14 +336,54 @@ dk_done(struct dk_softc *dksc, struct buf *bp)
printf("\n");
}
+ mutex_enter(&dksc->sc_iolock);
disk_unbusy(dk, bp->b_bcount - bp->b_resid, (bp->b_flags & B_READ));
+ mutex_exit(&dksc->sc_iolock);
+
#ifdef notyet
rnd_add_uint(&dksc->sc_rnd_source, bp->b_rawblkno);
#endif
+
biodone(bp);
}
int
+dk_discard(struct dk_softc *dksc, dev_t dev, off_t pos, off_t len)
+{
+ const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
+ unsigned secsize = dksc->sc_dkdev.dk_geom.dg_secsize;
+ struct buf tmp, *bp = &tmp;
+ int error;
+
+ DPRINTF_FOLLOW(("dk_discard(%s, %p, 0x"PRIx64", %jd, %jd)\n",
+ dksc->sc_xname, dksc, (intmax_t)pos, (intmax_t)len));
+
+ if (!(dksc->sc_flags & DKF_INITED)) {
+ DPRINTF_FOLLOW(("dk_discard: not inited\n"));
+ return ENXIO;
+ }
+
+ if (secsize == 0 || (pos % secsize) != 0)
+ return EINVAL;
+
+ /* enough data to please the bounds checking code */
+ bp->b_dev = dev;
+ bp->b_blkno = (daddr_t)(pos / secsize);
+ bp->b_bcount = len;
+ bp->b_flags = B_WRITE;
+
+ error = dk_translate(dksc, bp);
+ if (error >= 0)
+ return error;
+
+ error = dkd->d_discard(dksc->sc_dev,
+ (off_t)bp->b_rawblkno * secsize,
+ (off_t)bp->b_bcount);
+
+ return error;
+}
+
+int
dk_size(struct dk_softc *dksc, dev_t dev)
{
const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
@@ -462,12 +542,11 @@ dk_ioctl(struct dk_softc *dksc, dev_t dev,
case DIOCGSTRATEGY:
{
struct disk_strategy *dks = (void *)data;
- int s;
- s = splbio();
+ mutex_enter(&dksc->sc_iolock);
strlcpy(dks->dks_name, bufq_getstrategyname(dksc->sc_bufq),
sizeof(dks->dks_name));
- splx(s);
+ mutex_exit(&dksc->sc_iolock);
dks->dks_paramlen = 0;
return 0;
@@ -478,7 +557,6 @@ dk_ioctl(struct dk_softc *dksc, dev_t dev,
struct disk_strategy *dks = (void *)data;
struct bufq_state *new;
struct bufq_state *old;
- int s;
if (dks->dks_param != NULL) {
return EINVAL;
@@ -489,11 +567,11 @@ dk_ioctl(struct dk_softc *dksc, dev_t dev,
if (error) {
return error;
}
- s = splbio();
+ mutex_enter(&dksc->sc_iolock);
old = dksc->sc_bufq;
bufq_move(new, old);
dksc->sc_bufq = new;
- splx(s);
+ mutex_exit(&dksc->sc_iolock);
bufq_free(old);
return 0;
diff --git a/sys/dev/dkvar.h b/sys/dev/dkvar.h
index e317049bd69..03ad0859b26 100644
--- a/sys/dev/dkvar.h
+++ b/sys/dev/dkvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: dkvar.h,v 1.20 2015/05/02 08:00:08 mlelstv Exp $ */
+/* $NetBSD: dkvar.h,v 1.21 2015/08/16 18:00:03 mlelstv Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -44,6 +44,7 @@ struct dk_softc {
#define DK_XNAME_SIZE 8
char sc_xname[DK_XNAME_SIZE]; /* external name */
struct disk sc_dkdev; /* generic disk info */
+ kmutex_t sc_iolock; /* protects buffer queue */
struct bufq_state *sc_bufq; /* buffer queue */
int sc_dtype; /* disk type */
};
@@ -85,6 +86,8 @@ int dk_open(struct dk_softc *, dev_t,
int dk_close(struct dk_softc *, dev_t,
int, int, struct lwp *);
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 *);
int dk_size(struct dk_softc *, dev_t);
int dk_ioctl(struct dk_softc *, dev_t,
diff --git a/sys/dev/ld.c b/sys/dev/ld.c
index fec58ed6adb..912316f1ea0 100644
--- a/sys/dev/ld.c
+++ b/sys/dev/ld.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ld.c,v 1.88 2015/08/16 17:32:31 mlelstv Exp $ */
+/* $NetBSD: ld.c,v 1.89 2015/08/16 18:00:03 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.88 2015/08/16 17:32:31 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.89 2015/08/16 18:00:03 mlelstv Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -63,7 +63,7 @@ __KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.88 2015/08/16 17:32:31 mlelstv Exp $");
static void ldminphys(struct buf *bp);
static bool ld_suspend(device_t, const pmf_qual_t *);
static bool ld_shutdown(device_t, int);
-static void ld_start(device_t);
+static int ld_diskstart(device_t, struct buf *bp);
static void ld_iosize(device_t, int *);
static int ld_dumpblocks(device_t, void *, daddr_t, int);
static void ld_fake_geometry(struct ld_softc *);
@@ -90,7 +90,7 @@ const struct bdevsw ld_bdevsw = {
.d_dump = lddump,
.d_psize = ldsize,
.d_discard = nodiscard,
- .d_flag = D_DISK
+ .d_flag = D_DISK | D_MPSAFE
};
const struct cdevsw ld_cdevsw = {
@@ -105,7 +105,7 @@ const struct cdevsw ld_cdevsw = {
.d_mmap = nommap,
.d_kqfilter = nokqfilter,
.d_discard = nodiscard,
- .d_flag = D_DISK
+ .d_flag = D_DISK | D_MPSAFE
};
static struct dkdriver lddkdriver = {
@@ -114,7 +114,7 @@ static struct dkdriver lddkdriver = {
.d_strategy = ldstrategy,
.d_iosize = ld_iosize,
.d_minphys = ldminphys,
- .d_diskstart = ld_start,
+ .d_diskstart = ld_diskstart,
.d_dumpblocks = ld_dumpblocks,
.d_lastclose = ld_lastclose
};
@@ -404,55 +404,28 @@ ldstrategy(struct buf *bp)
return dk_strategy(dksc, bp);
}
-static void
-ld_start(device_t dev)
+static int
+ld_diskstart(device_t dev, struct buf *bp)
{
struct ld_softc *sc = device_private(dev);
- struct dk_softc *dksc = &sc->sc_dksc;
- struct buf *bp;
int error;
+ if (sc->sc_queuecnt >= sc->sc_maxqueuecnt)
+ return EAGAIN;
+
mutex_enter(&sc->sc_mutex);
- while (sc->sc_queuecnt < sc->sc_maxqueuecnt) {
- /* See if there is work to do. */
- if ((bp = bufq_peek(dksc->sc_bufq)) == NULL)
- break;
-
- disk_busy(&dksc->sc_dkdev);
- sc->sc_queuecnt++;
-
- if (__predict_true((error = (*sc->sc_start)(sc, bp)) == 0)) {
- /*
- * The back-end is running the job; remove it from
- * the queue.
- */
- (void) bufq_get(dksc->sc_bufq);
- } else {
- disk_unbusy(&dksc->sc_dkdev, 0, (bp->b_flags & B_READ));
- sc->sc_queuecnt--;
- if (error == EAGAIN) {
- /*
- * Temporary resource shortage in the
- * back-end; just defer the job until
- * later.
- *
- * XXX We might consider a watchdog timer
- * XXX to make sure we are kicked into action.
- */
- break;
- } else {
- (void) bufq_get(dksc->sc_bufq);
- bp->b_error = error;
- bp->b_resid = bp->b_bcount;
- mutex_exit(&sc->sc_mutex);
- biodone(bp);
- mutex_enter(&sc->sc_mutex);
- }
- }
+ if (sc->sc_queuecnt >= sc->sc_maxqueuecnt)
+ error = EAGAIN;
+ else {
+ error = (*sc->sc_start)(sc, bp);
+ if (error == 0)
+ sc->sc_queuecnt++;
}
mutex_exit(&sc->sc_mutex);
+
+ return error;
}
void
@@ -469,7 +442,7 @@ lddone(struct ld_softc *sc, struct buf *bp)
cv_broadcast(&sc->sc_drain);
}
mutex_exit(&sc->sc_mutex);
- ld_start(dksc->sc_dev);
+ dk_start(dksc, NULL);
} else
mutex_exit(&sc->sc_mutex);
}