version 1.91.2.1, 2016/07/20 23:47:56 |
version 1.91.2.2, 2017/01/07 08:56:31 |
Line 86 struct dkwedge_softc { |
|
Line 86 struct dkwedge_softc { |
|
struct bufq_state *sc_bufq; /* buffer queue */ |
struct bufq_state *sc_bufq; /* buffer queue */ |
struct callout sc_restart_ch; /* callout to restart I/O */ |
struct callout sc_restart_ch; /* callout to restart I/O */ |
|
|
|
kmutex_t sc_iolock; |
|
kcondvar_t sc_dkdrn; |
u_int sc_iopend; /* I/Os pending */ |
u_int sc_iopend; /* I/Os pending */ |
int sc_flags; /* flags (splbio) */ |
int sc_flags; /* flags (sc_iolock) */ |
}; |
}; |
|
|
#define DK_F_WAIT_DRAIN 0x0001 /* waiting for I/O to drain */ |
#define DK_F_WAIT_DRAIN 0x0001 /* waiting for I/O to drain */ |
Line 123 const struct bdevsw dk_bdevsw = { |
|
Line 125 const struct bdevsw dk_bdevsw = { |
|
.d_dump = dkdump, |
.d_dump = dkdump, |
.d_psize = dksize, |
.d_psize = dksize, |
.d_discard = dkdiscard, |
.d_discard = dkdiscard, |
.d_flag = D_DISK |
.d_flag = D_DISK | D_MPSAFE |
}; |
}; |
|
|
const struct cdevsw dk_cdevsw = { |
const struct cdevsw dk_cdevsw = { |
Line 138 const struct cdevsw dk_cdevsw = { |
|
Line 140 const struct cdevsw dk_cdevsw = { |
|
.d_mmap = nommap, |
.d_mmap = nommap, |
.d_kqfilter = nokqfilter, |
.d_kqfilter = nokqfilter, |
.d_discard = dkdiscard, |
.d_discard = dkdiscard, |
.d_flag = D_DISK |
.d_flag = D_DISK | D_MPSAFE |
}; |
}; |
|
|
static struct dkwedge_softc **dkwedges; |
static struct dkwedge_softc **dkwedges; |
Line 185 CFATTACH_DECL3_NEW(dk, 0, |
|
Line 187 CFATTACH_DECL3_NEW(dk, 0, |
|
* dkwedge_wait_drain: |
* dkwedge_wait_drain: |
* |
* |
* Wait for I/O on the wedge to drain. |
* Wait for I/O on the wedge to drain. |
* NOTE: Must be called at splbio()! |
|
*/ |
*/ |
static void |
static void |
dkwedge_wait_drain(struct dkwedge_softc *sc) |
dkwedge_wait_drain(struct dkwedge_softc *sc) |
{ |
{ |
|
|
|
mutex_enter(&sc->sc_iolock); |
while (sc->sc_iopend != 0) { |
while (sc->sc_iopend != 0) { |
sc->sc_flags |= DK_F_WAIT_DRAIN; |
sc->sc_flags |= DK_F_WAIT_DRAIN; |
(void) tsleep(&sc->sc_iopend, PRIBIO, "dkdrn", 0); |
cv_wait(&sc->sc_dkdrn, &sc->sc_iolock); |
} |
} |
|
mutex_exit(&sc->sc_iolock); |
} |
} |
|
|
/* |
/* |
Line 325 dkwedge_add(struct dkwedge_info *dkw) |
|
Line 328 dkwedge_add(struct dkwedge_info *dkw) |
|
callout_init(&sc->sc_restart_ch, 0); |
callout_init(&sc->sc_restart_ch, 0); |
callout_setfunc(&sc->sc_restart_ch, dkrestart, sc); |
callout_setfunc(&sc->sc_restart_ch, dkrestart, sc); |
|
|
|
mutex_init(&sc->sc_iolock, MUTEX_DEFAULT, IPL_BIO); |
|
cv_init(&sc->sc_dkdrn, "dkdrn"); |
|
|
/* |
/* |
* Wedge will be added; increment the wedge count for the parent. |
* Wedge will be added; increment the wedge count for the parent. |
* Only allow this to happend if RAW_PART is the only thing open. |
* Only allow this to happend if RAW_PART is the only thing open. |
Line 363 dkwedge_add(struct dkwedge_info *dkw) |
|
Line 369 dkwedge_add(struct dkwedge_info *dkw) |
|
} |
} |
mutex_exit(&pdk->dk_openlock); |
mutex_exit(&pdk->dk_openlock); |
if (error) { |
if (error) { |
|
cv_destroy(&sc->sc_dkdrn); |
|
mutex_destroy(&sc->sc_iolock); |
bufq_free(sc->sc_bufq); |
bufq_free(sc->sc_bufq); |
free(sc, M_DKWEDGE); |
free(sc, M_DKWEDGE); |
return (error); |
return (error); |
Line 416 dkwedge_add(struct dkwedge_info *dkw) |
|
Line 424 dkwedge_add(struct dkwedge_info *dkw) |
|
LIST_REMOVE(sc, sc_plink); |
LIST_REMOVE(sc, sc_plink); |
mutex_exit(&pdk->dk_openlock); |
mutex_exit(&pdk->dk_openlock); |
|
|
|
cv_destroy(&sc->sc_dkdrn); |
|
mutex_destroy(&sc->sc_iolock); |
bufq_free(sc->sc_bufq); |
bufq_free(sc->sc_bufq); |
free(sc, M_DKWEDGE); |
free(sc, M_DKWEDGE); |
return (error); |
return (error); |
Line 442 dkwedge_add(struct dkwedge_info *dkw) |
|
Line 452 dkwedge_add(struct dkwedge_info *dkw) |
|
LIST_REMOVE(sc, sc_plink); |
LIST_REMOVE(sc, sc_plink); |
mutex_exit(&pdk->dk_openlock); |
mutex_exit(&pdk->dk_openlock); |
|
|
|
cv_destroy(&sc->sc_dkdrn); |
|
mutex_destroy(&sc->sc_iolock); |
bufq_free(sc->sc_bufq); |
bufq_free(sc->sc_bufq); |
free(sc, M_DKWEDGE); |
free(sc, M_DKWEDGE); |
return (ENOMEM); |
return (ENOMEM); |
Line 568 dkwedge_detach(device_t self, int flags) |
|
Line 580 dkwedge_detach(device_t self, int flags) |
|
{ |
{ |
struct dkwedge_softc *sc = NULL; |
struct dkwedge_softc *sc = NULL; |
u_int unit; |
u_int unit; |
int bmaj, cmaj, rc, s; |
int bmaj, cmaj, rc; |
|
|
rw_enter(&dkwedges_lock, RW_WRITER); |
rw_enter(&dkwedges_lock, RW_WRITER); |
for (unit = 0; unit < ndkwedges; unit++) { |
for (unit = 0; unit < ndkwedges; unit++) { |
Line 600 dkwedge_detach(device_t self, int flags) |
|
Line 612 dkwedge_detach(device_t self, int flags) |
|
* state of the wedge is not RUNNING. Once we've done |
* state of the wedge is not RUNNING. Once we've done |
* that, wait for any other pending I/O to complete. |
* that, wait for any other pending I/O to complete. |
*/ |
*/ |
s = splbio(); |
|
dkstart(sc); |
dkstart(sc); |
dkwedge_wait_drain(sc); |
dkwedge_wait_drain(sc); |
splx(s); |
|
|
|
/* Nuke the vnodes for any open instances. */ |
/* Nuke the vnodes for any open instances. */ |
vdevgone(bmaj, unit, unit, VBLK); |
vdevgone(bmaj, unit, unit, VBLK); |
Line 635 dkwedge_detach(device_t self, int flags) |
|
Line 645 dkwedge_detach(device_t self, int flags) |
|
sc->sc_state = DKW_STATE_DEAD; |
sc->sc_state = DKW_STATE_DEAD; |
rw_exit(&dkwedges_lock); |
rw_exit(&dkwedges_lock); |
|
|
|
mutex_destroy(&sc->sc_iolock); |
|
cv_destroy(&sc->sc_dkdrn); |
|
|
free(sc, M_DKWEDGE); |
free(sc, M_DKWEDGE); |
|
|
return 0; |
return 0; |
Line 1206 dkstrategy(struct buf *bp) |
|
Line 1219 dkstrategy(struct buf *bp) |
|
{ |
{ |
struct dkwedge_softc *sc = dkwedge_lookup(bp->b_dev); |
struct dkwedge_softc *sc = dkwedge_lookup(bp->b_dev); |
uint64_t p_size, p_offset; |
uint64_t p_size, p_offset; |
int s; |
|
|
|
if (sc == NULL) { |
if (sc == NULL) { |
bp->b_error = ENODEV; |
bp->b_error = ENODEV; |
Line 1234 dkstrategy(struct buf *bp) |
|
Line 1246 dkstrategy(struct buf *bp) |
|
bp->b_rawblkno = bp->b_blkno + p_offset; |
bp->b_rawblkno = bp->b_blkno + p_offset; |
|
|
/* Place it in the queue and start I/O on the unit. */ |
/* Place it in the queue and start I/O on the unit. */ |
s = splbio(); |
mutex_enter(&sc->sc_iolock); |
sc->sc_iopend++; |
sc->sc_iopend++; |
bufq_put(sc->sc_bufq, bp); |
bufq_put(sc->sc_bufq, bp); |
|
mutex_exit(&sc->sc_iolock); |
|
|
dkstart(sc); |
dkstart(sc); |
splx(s); |
|
return; |
return; |
|
|
done: |
done: |
Line 1250 dkstrategy(struct buf *bp) |
|
Line 1263 dkstrategy(struct buf *bp) |
|
* dkstart: |
* dkstart: |
* |
* |
* Start I/O that has been enqueued on the wedge. |
* Start I/O that has been enqueued on the wedge. |
* NOTE: Must be called at splbio()! |
|
*/ |
*/ |
static void |
static void |
dkstart(struct dkwedge_softc *sc) |
dkstart(struct dkwedge_softc *sc) |
Line 1258 dkstart(struct dkwedge_softc *sc) |
|
Line 1270 dkstart(struct dkwedge_softc *sc) |
|
struct vnode *vp; |
struct vnode *vp; |
struct buf *bp, *nbp; |
struct buf *bp, *nbp; |
|
|
|
mutex_enter(&sc->sc_iolock); |
|
|
/* Do as much work as has been enqueued. */ |
/* Do as much work as has been enqueued. */ |
while ((bp = bufq_peek(sc->sc_bufq)) != NULL) { |
while ((bp = bufq_peek(sc->sc_bufq)) != NULL) { |
|
|
if (sc->sc_state != DKW_STATE_RUNNING) { |
if (sc->sc_state != DKW_STATE_RUNNING) { |
(void) bufq_get(sc->sc_bufq); |
(void) bufq_get(sc->sc_bufq); |
if (sc->sc_iopend-- == 1 && |
if (sc->sc_iopend-- == 1 && |
(sc->sc_flags & DK_F_WAIT_DRAIN) != 0) { |
(sc->sc_flags & DK_F_WAIT_DRAIN) != 0) { |
sc->sc_flags &= ~DK_F_WAIT_DRAIN; |
sc->sc_flags &= ~DK_F_WAIT_DRAIN; |
wakeup(&sc->sc_iopend); |
cv_broadcast(&sc->sc_dkdrn); |
} |
} |
|
mutex_exit(&sc->sc_iolock); |
bp->b_error = ENXIO; |
bp->b_error = ENXIO; |
bp->b_resid = bp->b_bcount; |
bp->b_resid = bp->b_bcount; |
biodone(bp); |
biodone(bp); |
|
mutex_enter(&sc->sc_iolock); |
|
continue; |
} |
} |
|
|
/* Instrumentation. */ |
/* fetch an I/O buf with sc_iolock dropped */ |
disk_busy(&sc->sc_dk); |
mutex_exit(&sc->sc_iolock); |
|
|
nbp = getiobuf(sc->sc_parent->dk_rawvp, false); |
nbp = getiobuf(sc->sc_parent->dk_rawvp, false); |
|
mutex_enter(&sc->sc_iolock); |
if (nbp == NULL) { |
if (nbp == NULL) { |
/* |
/* |
* No resources to run this request; leave the |
* No resources to run this request; leave the |
* buffer queued up, and schedule a timer to |
* buffer queued up, and schedule a timer to |
* restart the queue in 1/2 a second. |
* restart the queue in 1/2 a second. |
*/ |
*/ |
disk_unbusy(&sc->sc_dk, 0, bp->b_flags & B_READ); |
|
callout_schedule(&sc->sc_restart_ch, hz / 2); |
callout_schedule(&sc->sc_restart_ch, hz / 2); |
return; |
break; |
} |
} |
|
|
(void) bufq_get(sc->sc_bufq); |
/* |
|
* fetch buf, this can fail if another thread |
|
* has already processed the queue, it can also |
|
* return a completely different buf. |
|
*/ |
|
bp = bufq_get(sc->sc_bufq); |
|
if (bp == NULL) { |
|
mutex_exit(&sc->sc_iolock); |
|
putiobuf(nbp); |
|
mutex_enter(&sc->sc_iolock); |
|
continue; |
|
} |
|
|
|
/* Instrumentation. */ |
|
disk_busy(&sc->sc_dk); |
|
|
|
/* release lock for VOP_STRATEGY */ |
|
mutex_exit(&sc->sc_iolock); |
|
|
nbp->b_data = bp->b_data; |
nbp->b_data = bp->b_data; |
nbp->b_flags = bp->b_flags; |
nbp->b_flags = bp->b_flags; |
Line 1308 dkstart(struct dkwedge_softc *sc) |
|
Line 1342 dkstart(struct dkwedge_softc *sc) |
|
mutex_exit(vp->v_interlock); |
mutex_exit(vp->v_interlock); |
} |
} |
VOP_STRATEGY(vp, nbp); |
VOP_STRATEGY(vp, nbp); |
|
|
|
mutex_enter(&sc->sc_iolock); |
} |
} |
|
|
|
mutex_exit(&sc->sc_iolock); |
} |
} |
|
|
/* |
/* |
Line 1322 dkiodone(struct buf *bp) |
|
Line 1360 dkiodone(struct buf *bp) |
|
struct buf *obp = bp->b_private; |
struct buf *obp = bp->b_private; |
struct dkwedge_softc *sc = dkwedge_lookup(obp->b_dev); |
struct dkwedge_softc *sc = dkwedge_lookup(obp->b_dev); |
|
|
int s = splbio(); |
|
|
|
if (bp->b_error != 0) |
if (bp->b_error != 0) |
obp->b_error = bp->b_error; |
obp->b_error = bp->b_error; |
obp->b_resid = bp->b_resid; |
obp->b_resid = bp->b_resid; |
putiobuf(bp); |
putiobuf(bp); |
|
|
|
mutex_enter(&sc->sc_iolock); |
if (sc->sc_iopend-- == 1 && (sc->sc_flags & DK_F_WAIT_DRAIN) != 0) { |
if (sc->sc_iopend-- == 1 && (sc->sc_flags & DK_F_WAIT_DRAIN) != 0) { |
sc->sc_flags &= ~DK_F_WAIT_DRAIN; |
sc->sc_flags &= ~DK_F_WAIT_DRAIN; |
wakeup(&sc->sc_iopend); |
cv_broadcast(&sc->sc_dkdrn); |
} |
} |
|
|
disk_unbusy(&sc->sc_dk, obp->b_bcount - obp->b_resid, |
disk_unbusy(&sc->sc_dk, obp->b_bcount - obp->b_resid, |
obp->b_flags & B_READ); |
obp->b_flags & B_READ); |
|
mutex_exit(&sc->sc_iolock); |
|
|
biodone(obp); |
biodone(obp); |
|
|
/* Kick the queue in case there is more work we can do. */ |
/* Kick the queue in case there is more work we can do. */ |
dkstart(sc); |
dkstart(sc); |
splx(s); |
|
} |
} |
|
|
/* |
/* |
|
|
dkrestart(void *v) |
dkrestart(void *v) |
{ |
{ |
struct dkwedge_softc *sc = v; |
struct dkwedge_softc *sc = v; |
int s; |
|
|
|
s = splbio(); |
|
dkstart(sc); |
dkstart(sc); |
splx(s); |
|
} |
} |
|
|
/* |
/* |