Save context switch per I/O for iSCSI and IOCTL frontends.
Introduce new CTL core KPI ctl_run(), preprocessing I/Os in the caller context instead of scheduling another thread just for that. This call may sleep, that is not acceptable for some frontends like the original CAM/FC one, but iSCSI already has separate sleepable per-connection RX threads, and another thread scheduling is mostly just a waste of time. IOCTL frontend actually waits for the I/O completion in the caller thread, so the use of another thread for this has even less sense. With this change I can measure ~5% IOPS improvement on 4KB iSCSI I/Os to ZFS. MFC after: 1 month
This commit is contained in:
parent
4621c4f2fd
commit
812c9f48a2
@ -258,7 +258,7 @@ point.
|
||||
Here is a roadmap of some of the primary functions in ctl.c. Starting here
|
||||
and following the various leaf functions will show the command flow.
|
||||
|
||||
ctl_queue() This is where commands from the frontend ports come
|
||||
ctl_queue() / ctl_run() This is where commands from the frontend ports come
|
||||
in.
|
||||
|
||||
ctl_queue_sense() This is only used for non-packetized SCSI. i.e.
|
||||
|
@ -513,8 +513,7 @@ static int ctl_scsiio_lun_check(struct ctl_lun *lun,
|
||||
const struct ctl_cmd_entry *entry,
|
||||
struct ctl_scsiio *ctsio);
|
||||
static void ctl_failover_lun(union ctl_io *io);
|
||||
static int ctl_scsiio_precheck(struct ctl_softc *ctl_softc,
|
||||
struct ctl_scsiio *ctsio);
|
||||
static void ctl_scsiio_precheck(struct ctl_scsiio *ctsio);
|
||||
static int ctl_scsiio(struct ctl_scsiio *ctsio);
|
||||
|
||||
static int ctl_target_reset(union ctl_io *io);
|
||||
@ -11437,14 +11436,14 @@ ctl_failover_lun(union ctl_io *rio)
|
||||
mtx_unlock(&lun->lun_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
ctl_scsiio_precheck(struct ctl_softc *softc, struct ctl_scsiio *ctsio)
|
||||
static void
|
||||
ctl_scsiio_precheck(struct ctl_scsiio *ctsio)
|
||||
{
|
||||
struct ctl_softc *softc = CTL_SOFTC(ctsio);
|
||||
struct ctl_lun *lun;
|
||||
const struct ctl_cmd_entry *entry;
|
||||
union ctl_io *bio;
|
||||
uint32_t initidx, targ_lun;
|
||||
int retval = 0;
|
||||
|
||||
lun = NULL;
|
||||
targ_lun = ctsio->io_hdr.nexus.targ_mapped_lun;
|
||||
@ -11482,7 +11481,7 @@ ctl_scsiio_precheck(struct ctl_softc *softc, struct ctl_scsiio *ctsio)
|
||||
if (entry == NULL) {
|
||||
if (lun)
|
||||
mtx_unlock(&lun->lun_lock);
|
||||
return (retval);
|
||||
return;
|
||||
}
|
||||
|
||||
ctsio->io_hdr.flags &= ~CTL_FLAG_DATA_MASK;
|
||||
@ -11499,13 +11498,13 @@ ctl_scsiio_precheck(struct ctl_softc *softc, struct ctl_scsiio *ctsio)
|
||||
if (entry->flags & CTL_CMD_FLAG_OK_ON_NO_LUN) {
|
||||
ctsio->io_hdr.flags |= CTL_FLAG_IS_WAS_ON_RTR;
|
||||
ctl_enqueue_rtr((union ctl_io *)ctsio);
|
||||
return (retval);
|
||||
return;
|
||||
}
|
||||
|
||||
ctl_set_unsupported_lun(ctsio);
|
||||
ctl_done((union ctl_io *)ctsio);
|
||||
CTL_DEBUG_PRINT(("ctl_scsiio_precheck: bailing out due to invalid LUN\n"));
|
||||
return (retval);
|
||||
return;
|
||||
} else {
|
||||
/*
|
||||
* Make sure we support this particular command on this LUN.
|
||||
@ -11515,7 +11514,7 @@ ctl_scsiio_precheck(struct ctl_softc *softc, struct ctl_scsiio *ctsio)
|
||||
mtx_unlock(&lun->lun_lock);
|
||||
ctl_set_invalid_opcode(ctsio);
|
||||
ctl_done((union ctl_io *)ctsio);
|
||||
return (retval);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -11569,14 +11568,14 @@ ctl_scsiio_precheck(struct ctl_softc *softc, struct ctl_scsiio *ctsio)
|
||||
ctsio->io_hdr.status = CTL_SCSI_ERROR | CTL_AUTOSENSE;
|
||||
ctsio->sense_len = sense_len;
|
||||
ctl_done((union ctl_io *)ctsio);
|
||||
return (retval);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctl_scsiio_lun_check(lun, entry, ctsio) != 0) {
|
||||
mtx_unlock(&lun->lun_lock);
|
||||
ctl_done((union ctl_io *)ctsio);
|
||||
return (retval);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -11613,9 +11612,9 @@ ctl_scsiio_precheck(struct ctl_softc *softc, struct ctl_scsiio *ctsio)
|
||||
M_WAITOK)) > CTL_HA_STATUS_SUCCESS) {
|
||||
ctl_set_busy(ctsio);
|
||||
ctl_done((union ctl_io *)ctsio);
|
||||
return (retval);
|
||||
return;
|
||||
}
|
||||
return (retval);
|
||||
return;
|
||||
}
|
||||
|
||||
bio = (union ctl_io *)TAILQ_PREV(&ctsio->io_hdr, ctl_ooaq, ooa_links);
|
||||
@ -11625,7 +11624,7 @@ ctl_scsiio_precheck(struct ctl_softc *softc, struct ctl_scsiio *ctsio)
|
||||
TAILQ_INSERT_TAIL(&bio->io_hdr.blocked_queue, &ctsio->io_hdr,
|
||||
blocked_links);
|
||||
mtx_unlock(&lun->lun_lock);
|
||||
return (retval);
|
||||
break;
|
||||
case CTL_ACTION_PASS:
|
||||
case CTL_ACTION_SKIP:
|
||||
ctsio->io_hdr.flags |= CTL_FLAG_IS_WAS_ON_RTR;
|
||||
@ -11651,7 +11650,6 @@ ctl_scsiio_precheck(struct ctl_softc *softc, struct ctl_scsiio *ctsio)
|
||||
ctl_done((union ctl_io *)ctsio);
|
||||
break;
|
||||
}
|
||||
return (retval);
|
||||
}
|
||||
|
||||
const struct ctl_cmd_entry *
|
||||
@ -13253,6 +13251,41 @@ ctl_queue(union ctl_io *io)
|
||||
return (CTL_RETVAL_COMPLETE);
|
||||
}
|
||||
|
||||
int
|
||||
ctl_run(union ctl_io *io)
|
||||
{
|
||||
struct ctl_port *port = CTL_PORT(io);
|
||||
|
||||
CTL_DEBUG_PRINT(("ctl_run cdb[0]=%02X\n", io->scsiio.cdb[0]));
|
||||
|
||||
#ifdef CTL_TIME_IO
|
||||
io->io_hdr.start_time = time_uptime;
|
||||
getbinuptime(&io->io_hdr.start_bt);
|
||||
#endif /* CTL_TIME_IO */
|
||||
|
||||
/* Map FE-specific LUN ID into global one. */
|
||||
io->io_hdr.nexus.targ_mapped_lun =
|
||||
ctl_lun_map_from_port(port, io->io_hdr.nexus.targ_lun);
|
||||
|
||||
switch (io->io_hdr.io_type) {
|
||||
case CTL_IO_SCSI:
|
||||
if (ctl_debug & CTL_DEBUG_CDB)
|
||||
ctl_io_print(io);
|
||||
ctl_scsiio_precheck(&io->scsiio);
|
||||
break;
|
||||
case CTL_IO_TASK:
|
||||
if (ctl_debug & CTL_DEBUG_CDB)
|
||||
ctl_io_print(io);
|
||||
ctl_run_task(io);
|
||||
break;
|
||||
default:
|
||||
printf("ctl_run: unknown I/O type %d\n", io->io_hdr.io_type);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
return (CTL_RETVAL_COMPLETE);
|
||||
}
|
||||
|
||||
#ifdef CTL_IO_DELAY
|
||||
static void
|
||||
ctl_done_timer_wakeup(void *arg)
|
||||
@ -13384,7 +13417,7 @@ ctl_work_thread(void *arg)
|
||||
if (io->io_hdr.io_type == CTL_IO_TASK)
|
||||
ctl_run_task(io);
|
||||
else
|
||||
ctl_scsiio_precheck(softc, &io->scsiio);
|
||||
ctl_scsiio_precheck(&io->scsiio);
|
||||
continue;
|
||||
}
|
||||
io = (union ctl_io *)STAILQ_FIRST(&thr->rtr_queue);
|
||||
|
@ -310,6 +310,13 @@ void ctl_port_offline(struct ctl_port *fe);
|
||||
*/
|
||||
int ctl_queue(union ctl_io *io);
|
||||
|
||||
/*
|
||||
* This routine starts execution of I/O and task management requests from
|
||||
* the FETD to the CTL layer. May sleep. Returns 0 for success, non-zero
|
||||
* for failure.
|
||||
*/
|
||||
int ctl_run(union ctl_io *io);
|
||||
|
||||
/*
|
||||
* This routine is used if the front end interface doesn't support
|
||||
* autosense (e.g. non-packetized parallel SCSI). This will queue the
|
||||
|
@ -524,7 +524,7 @@ cfi_submit_wait(union ctl_io *io)
|
||||
CTL_DEBUG_PRINT(("cfi_submit_wait\n"));
|
||||
|
||||
/* This shouldn't happen */
|
||||
if ((retval = ctl_queue(io)) != CTL_RETVAL_COMPLETE)
|
||||
if ((retval = ctl_run(io)) != CTL_RETVAL_COMPLETE)
|
||||
return (retval);
|
||||
|
||||
done = 0;
|
||||
|
@ -557,9 +557,9 @@ cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request)
|
||||
io->scsiio.cdb_len = sizeof(bhssc->bhssc_cdb); /* Which is 16. */
|
||||
memcpy(io->scsiio.cdb, bhssc->bhssc_cdb, sizeof(bhssc->bhssc_cdb));
|
||||
refcount_acquire(&cs->cs_outstanding_ctl_pdus);
|
||||
error = ctl_queue(io);
|
||||
error = ctl_run(io);
|
||||
if (error != CTL_RETVAL_COMPLETE) {
|
||||
CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d; "
|
||||
CFISCSI_SESSION_WARN(cs, "ctl_run() failed; error %d; "
|
||||
"dropping connection", error);
|
||||
ctl_free_io(io);
|
||||
refcount_release(&cs->cs_outstanding_ctl_pdus);
|
||||
@ -679,9 +679,9 @@ cfiscsi_pdu_handle_task_request(struct icl_pdu *request)
|
||||
}
|
||||
|
||||
refcount_acquire(&cs->cs_outstanding_ctl_pdus);
|
||||
error = ctl_queue(io);
|
||||
error = ctl_run(io);
|
||||
if (error != CTL_RETVAL_COMPLETE) {
|
||||
CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d; "
|
||||
CFISCSI_SESSION_WARN(cs, "ctl_run() failed; error %d; "
|
||||
"dropping connection", error);
|
||||
ctl_free_io(io);
|
||||
refcount_release(&cs->cs_outstanding_ctl_pdus);
|
||||
@ -1128,9 +1128,9 @@ cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs)
|
||||
io->taskio.task_action = CTL_TASK_I_T_NEXUS_RESET;
|
||||
wait = cs->cs_outstanding_ctl_pdus;
|
||||
refcount_acquire(&cs->cs_outstanding_ctl_pdus);
|
||||
error = ctl_queue(io);
|
||||
error = ctl_run(io);
|
||||
if (error != CTL_RETVAL_COMPLETE) {
|
||||
CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d", error);
|
||||
CFISCSI_SESSION_WARN(cs, "ctl_run() failed; error %d", error);
|
||||
refcount_release(&cs->cs_outstanding_ctl_pdus);
|
||||
ctl_free_io(io);
|
||||
}
|
||||
|
@ -1628,7 +1628,7 @@ tpc_done(union ctl_io *io)
|
||||
io->io_hdr.flags &= ~CTL_FLAG_ABORT;
|
||||
io->io_hdr.flags &= ~CTL_FLAG_SENT_2OTHER_SC;
|
||||
if (tpcl_queue(io, tio->lun) != CTL_RETVAL_COMPLETE) {
|
||||
printf("%s: error returned from ctl_queue()!\n",
|
||||
printf("%s: error returned from tpcl_queue()!\n",
|
||||
__func__);
|
||||
io->io_hdr.status = old_status;
|
||||
} else
|
||||
|
Loading…
Reference in New Issue
Block a user