diff options
| author | mlelstv <mlelstv@NetBSD.org> | 2015-08-16 18:00:03 +0000 |
|---|---|---|
| committer | mlelstv <mlelstv@NetBSD.org> | 2015-08-16 18:00:03 +0000 |
| commit | 0816f4a9f915c8a6887cb0793bb309ebc4433b89 (patch) | |
| tree | 81601b5094536ba7048473d11e9715ccdda6aca3 /sys/dev | |
| parent | 64fa860da242df5b4f4dc1638e72f5310f6ceecd (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.c | 124 | ||||
| -rw-r--r-- | sys/dev/dksubr.c | 170 | ||||
| -rw-r--r-- | sys/dev/dkvar.h | 5 | ||||
| -rw-r--r-- | sys/dev/ld.c | 67 |
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); } |
