Micro-optimization: allow target drivers to prealloc scst_cmd + update qla2x00t to use this facility

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@4779 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2013-03-02 00:52:26 +00:00
parent a0ee2a2396
commit ae8e9ef049
6 changed files with 214 additions and 105 deletions

View File

@@ -2453,7 +2453,7 @@ static int q2t_pre_xmit_response(struct q2t_cmd *cmd,
scsi_qla_host_t *ha = tgt->ha;
scsi_qla_host_t *pha = to_qla_parent(ha);
uint16_t full_req_cnt;
struct scst_cmd *scst_cmd = cmd->scst_cmd;
struct scst_cmd *scst_cmd = &cmd->scst_cmd;
TRACE_ENTRY();
@@ -2751,7 +2751,7 @@ static int q2x_xmit_response(struct scst_cmd *scst_cmd)
{
int xmit_type = Q2T_XMIT_DATA, res;
int is_send_status = scst_cmd_get_is_send_status(scst_cmd);
struct q2t_cmd *cmd = (struct q2t_cmd *)scst_cmd_get_tgt_priv(scst_cmd);
struct q2t_cmd *cmd = container_of(scst_cmd, struct q2t_cmd, scst_cmd);
#ifdef CONFIG_SCST_EXTRACHECKS
sBUG_ON(!q2t_has_data(cmd) && !is_send_status);
@@ -3026,7 +3026,7 @@ static int q2t_rdy_to_xfer(struct scst_cmd *scst_cmd)
TRACE(TRACE_SCSI, "qla2x00t: tag=%lld", scst_cmd_get_tag(scst_cmd));
cmd = (struct q2t_cmd *)scst_cmd_get_tgt_priv(scst_cmd);
cmd = container_of(scst_cmd, struct q2t_cmd, scst_cmd);
cmd->bufflen = scst_cmd_get_write_fields(scst_cmd, &cmd->sg,
&cmd->sg_cnt);
cmd->data_direction = scst_cmd_get_data_direction(scst_cmd);
@@ -3100,9 +3100,9 @@ out_unlock:
if (do_tgt_cmd_done) {
if (!ha_locked && !in_interrupt())
scst_tgt_cmd_done(cmd->scst_cmd, SCST_CONTEXT_DIRECT);
scst_tgt_cmd_done(&cmd->scst_cmd, SCST_CONTEXT_DIRECT);
else
scst_tgt_cmd_done(cmd->scst_cmd, SCST_CONTEXT_TASKLET);
scst_tgt_cmd_done(&cmd->scst_cmd, SCST_CONTEXT_TASKLET);
/* !! At this point cmd could be already freed !! */
}
@@ -3177,9 +3177,9 @@ out_unlock:
if (do_tgt_cmd_done) {
if (!ha_locked && !in_interrupt())
scst_tgt_cmd_done(cmd->scst_cmd, SCST_CONTEXT_DIRECT);
scst_tgt_cmd_done(&cmd->scst_cmd, SCST_CONTEXT_DIRECT);
else
scst_tgt_cmd_done(cmd->scst_cmd, SCST_CONTEXT_TASKLET);
scst_tgt_cmd_done(&cmd->scst_cmd, SCST_CONTEXT_TASKLET);
/* !! At this point cmd could be already freed !! */
}
@@ -3206,8 +3206,7 @@ static void q2t_on_free_cmd(struct scst_cmd *scst_cmd)
TRACE(TRACE_SCSI, "qla2x00t: Freeing command %p, tag %lld",
scst_cmd, scst_cmd_get_tag(scst_cmd));
cmd = (struct q2t_cmd *)scst_cmd_get_tgt_priv(scst_cmd);
scst_cmd_set_tgt_priv(scst_cmd, NULL);
cmd = container_of(scst_cmd, struct q2t_cmd, scst_cmd);
q2t_free_cmd(cmd);
@@ -3236,8 +3235,7 @@ static int q2t_prepare_srr_ctio(scsi_qla_host_t *ha, struct q2t_cmd *cmd,
goto out;
}
if (cmd->scst_cmd != NULL)
scst_update_hw_pending_start(cmd->scst_cmd);
scst_update_hw_pending_start(&cmd->scst_cmd);
sc = kzalloc(sizeof(*sc), GFP_ATOMIC);
if (sc != NULL) {
@@ -3410,7 +3408,7 @@ static struct q2t_cmd *q2t_ctio_to_cmd(scsi_qla_host_t *ha, uint32_t handle,
goto out;
}
cmd = (struct q2t_cmd *)scst_cmd_get_tgt_priv(scst_cmd);
cmd = container_of(scst_cmd, struct q2t_cmd, scst_cmd);
TRACE_DBG("Found q2t_cmd %p (tag %d)", cmd, tag);
}
@@ -3455,7 +3453,7 @@ static void q2t_do_ctio_completion(scsi_qla_host_t *ha, uint32_t handle,
goto out;
}
scst_cmd = cmd->scst_cmd;
scst_cmd = &cmd->scst_cmd;
if (cmd->sg_mapped)
q2t_unmap_sg(ha, cmd);
@@ -3565,7 +3563,7 @@ static void q2x_ctio_completion(scsi_qla_host_t *ha, uint32_t handle)
/* pha->hardware_lock supposed to be held on entry */
static int q2x_do_send_cmd_to_scst(struct q2t_cmd *cmd)
{
int res = 0;
int res;
struct q2t_sess *sess = cmd->sess;
uint16_t lun;
atio_entry_t *atio = &cmd->atio.atio2x;
@@ -3576,19 +3574,14 @@ static int q2x_do_send_cmd_to_scst(struct q2t_cmd *cmd)
/* make it be in network byte order */
lun = swab16(le16_to_cpu(atio->lun));
cmd->scst_cmd = scst_rx_cmd(sess->scst_sess, (uint8_t *)&lun,
sizeof(lun), atio->cdb, Q2T_MAX_CDB_LEN,
SCST_ATOMIC);
if (cmd->scst_cmd == NULL) {
PRINT_ERROR("%s", "qla2x00t: scst_rx_cmd() failed");
res = -EFAULT;
res = scst_rx_cmd_prealloced(&cmd->scst_cmd, sess->scst_sess,
(uint8_t *)&lun, sizeof(lun), atio->cdb,
Q2T_MAX_CDB_LEN, SCST_ATOMIC);
if (res != 0)
goto out;
}
cmd->tag = atio->rx_id;
scst_cmd_set_tag(cmd->scst_cmd, cmd->tag);
scst_cmd_set_tgt_priv(cmd->scst_cmd, cmd);
scst_cmd_set_tag(&cmd->scst_cmd, cmd->tag);
if ((atio->execution_codes & (ATIO_EXEC_READ | ATIO_EXEC_WRITE)) ==
(ATIO_EXEC_READ | ATIO_EXEC_WRITE))
@@ -3599,29 +3592,29 @@ static int q2x_do_send_cmd_to_scst(struct q2t_cmd *cmd)
dir = SCST_DATA_WRITE;
else
dir = SCST_DATA_NONE;
scst_cmd_set_expected(cmd->scst_cmd, dir,
scst_cmd_set_expected(&cmd->scst_cmd, dir,
le32_to_cpu(atio->data_length));
switch (atio->task_codes) {
case ATIO_SIMPLE_QUEUE:
scst_cmd_set_queue_type(cmd->scst_cmd, SCST_CMD_QUEUE_SIMPLE);
scst_cmd_set_queue_type(&cmd->scst_cmd, SCST_CMD_QUEUE_SIMPLE);
break;
case ATIO_HEAD_OF_QUEUE:
scst_cmd_set_queue_type(cmd->scst_cmd, SCST_CMD_QUEUE_HEAD_OF_QUEUE);
scst_cmd_set_queue_type(&cmd->scst_cmd, SCST_CMD_QUEUE_HEAD_OF_QUEUE);
break;
case ATIO_ORDERED_QUEUE:
scst_cmd_set_queue_type(cmd->scst_cmd, SCST_CMD_QUEUE_ORDERED);
scst_cmd_set_queue_type(&cmd->scst_cmd, SCST_CMD_QUEUE_ORDERED);
break;
case ATIO_ACA_QUEUE:
scst_cmd_set_queue_type(cmd->scst_cmd, SCST_CMD_QUEUE_ACA);
scst_cmd_set_queue_type(&cmd->scst_cmd, SCST_CMD_QUEUE_ACA);
break;
case ATIO_UNTAGGED:
scst_cmd_set_queue_type(cmd->scst_cmd, SCST_CMD_QUEUE_UNTAGGED);
scst_cmd_set_queue_type(&cmd->scst_cmd, SCST_CMD_QUEUE_UNTAGGED);
break;
default:
PRINT_WARNING("qla2x00t: unknown task code %x, use "
"ORDERED instead", atio->task_codes);
scst_cmd_set_queue_type(cmd->scst_cmd, SCST_CMD_QUEUE_ORDERED);
scst_cmd_set_queue_type(&cmd->scst_cmd, SCST_CMD_QUEUE_ORDERED);
break;
}
@@ -3633,8 +3626,8 @@ static int q2x_do_send_cmd_to_scst(struct q2t_cmd *cmd)
TRACE_DBG("Context %x", context);
TRACE(TRACE_SCSI, "qla2x00t: START Command (tag %d, queue_type %d)",
cmd->tag, scst_cmd_get_queue_type(cmd->scst_cmd));
scst_cmd_init_done(cmd->scst_cmd, context);
cmd->tag, scst_cmd_get_queue_type(&cmd->scst_cmd));
scst_cmd_init_done(&cmd->scst_cmd, context);
out:
TRACE_EXIT_RES(res);
@@ -3644,7 +3637,7 @@ out:
/* pha->hardware_lock supposed to be held on entry */
static int q24_do_send_cmd_to_scst(struct q2t_cmd *cmd)
{
int res = 0;
int res;
struct q2t_sess *sess = cmd->sess;
atio7_entry_t *atio = &cmd->atio.atio7;
scst_data_direction dir;
@@ -3652,20 +3645,15 @@ static int q24_do_send_cmd_to_scst(struct q2t_cmd *cmd)
TRACE_ENTRY();
cmd->scst_cmd = scst_rx_cmd(sess->scst_sess,
res = scst_rx_cmd_prealloced(&cmd->scst_cmd, sess->scst_sess,
(uint8_t *)&atio->fcp_cmnd.lun, sizeof(atio->fcp_cmnd.lun),
atio->fcp_cmnd.cdb, sizeof(atio->fcp_cmnd.cdb) +
atio->fcp_cmnd.add_cdb_len, SCST_ATOMIC);
if (cmd->scst_cmd == NULL) {
PRINT_ERROR("%s", "qla2x00t: scst_rx_cmd() failed");
res = -EFAULT;
if (res != 0)
goto out;
}
cmd->tag = atio->exchange_addr;
scst_cmd_set_tag(cmd->scst_cmd, cmd->tag);
scst_cmd_set_tgt_priv(cmd->scst_cmd, cmd);
scst_cmd_set_tag(&cmd->scst_cmd, cmd->tag);
if (atio->fcp_cmnd.rddata && atio->fcp_cmnd.wrdata)
dir = SCST_DATA_BIDI;
@@ -3675,30 +3663,30 @@ static int q24_do_send_cmd_to_scst(struct q2t_cmd *cmd)
dir = SCST_DATA_WRITE;
else
dir = SCST_DATA_NONE;
scst_cmd_set_expected(cmd->scst_cmd, dir,
scst_cmd_set_expected(&cmd->scst_cmd, dir,
get_unaligned_be32(
&atio->fcp_cmnd.add_cdb[atio->fcp_cmnd.add_cdb_len]));
switch (atio->fcp_cmnd.task_attr) {
case ATIO_SIMPLE_QUEUE:
scst_cmd_set_queue_type(cmd->scst_cmd, SCST_CMD_QUEUE_SIMPLE);
scst_cmd_set_queue_type(&cmd->scst_cmd, SCST_CMD_QUEUE_SIMPLE);
break;
case ATIO_HEAD_OF_QUEUE:
scst_cmd_set_queue_type(cmd->scst_cmd, SCST_CMD_QUEUE_HEAD_OF_QUEUE);
scst_cmd_set_queue_type(&cmd->scst_cmd, SCST_CMD_QUEUE_HEAD_OF_QUEUE);
break;
case ATIO_ORDERED_QUEUE:
scst_cmd_set_queue_type(cmd->scst_cmd, SCST_CMD_QUEUE_ORDERED);
scst_cmd_set_queue_type(&cmd->scst_cmd, SCST_CMD_QUEUE_ORDERED);
break;
case ATIO_ACA_QUEUE:
scst_cmd_set_queue_type(cmd->scst_cmd, SCST_CMD_QUEUE_ACA);
scst_cmd_set_queue_type(&cmd->scst_cmd, SCST_CMD_QUEUE_ACA);
break;
case ATIO_UNTAGGED:
scst_cmd_set_queue_type(cmd->scst_cmd, SCST_CMD_QUEUE_UNTAGGED);
scst_cmd_set_queue_type(&cmd->scst_cmd, SCST_CMD_QUEUE_UNTAGGED);
break;
default:
PRINT_WARNING("qla2x00t: unknown task code %x, use "
"ORDERED instead", atio->fcp_cmnd.task_attr);
scst_cmd_set_queue_type(cmd->scst_cmd, SCST_CMD_QUEUE_ORDERED);
scst_cmd_set_queue_type(&cmd->scst_cmd, SCST_CMD_QUEUE_ORDERED);
break;
}
@@ -3710,8 +3698,8 @@ static int q24_do_send_cmd_to_scst(struct q2t_cmd *cmd)
TRACE_DBG("Context %x", context);
TRACE(TRACE_SCSI, "qla2x00t: START Command %p (tag %d, queue type %x)",
cmd, cmd->tag, scst_cmd_get_queue_type(cmd->scst_cmd));
scst_cmd_init_done(cmd->scst_cmd, context);
cmd, cmd->tag, scst_cmd_get_queue_type(&cmd->scst_cmd));
scst_cmd_init_done(&cmd->scst_cmd, context);
out:
TRACE_EXIT_RES(res);
@@ -4293,9 +4281,9 @@ static void q24_handle_srr(scsi_qla_host_t *ha, struct srr_ctio *sctio,
__q24_xmit_response(cmd, Q2T_XMIT_STATUS);
break;
case SRR_IU_DATA_IN:
cmd->bufflen = scst_cmd_get_adjusted_resp_data_len(cmd->scst_cmd);
cmd->bufflen = scst_cmd_get_adjusted_resp_data_len(&cmd->scst_cmd);
if (q2t_has_data(cmd) &&
(scst_cmd_get_data_direction(cmd->scst_cmd) & SCST_DATA_READ)) {
(scst_cmd_get_data_direction(&cmd->scst_cmd) & SCST_DATA_READ)) {
uint32_t offset;
int xmit_type;
offset = le32_to_cpu(imm->imm.notify_entry24.srr_rel_offs);
@@ -4310,16 +4298,16 @@ static void q24_handle_srr(scsi_qla_host_t *ha, struct srr_ctio *sctio,
PRINT_ERROR("qla2x00t(%ld): SRR for in data for cmd "
"without them (tag %d, SCSI status %d, dir %d),"
" reject", ha->instance, cmd->tag,
scst_cmd_get_status(cmd->scst_cmd),
scst_cmd_get_data_direction(cmd->scst_cmd));
scst_cmd_get_status(&cmd->scst_cmd),
scst_cmd_get_data_direction(&cmd->scst_cmd));
goto out_reject;
}
break;
case SRR_IU_DATA_OUT:
cmd->bufflen = scst_cmd_get_write_fields(cmd->scst_cmd,
cmd->bufflen = scst_cmd_get_write_fields(&cmd->scst_cmd,
&cmd->sg, &cmd->sg_cnt);
if (q2t_has_data(cmd) &&
(scst_cmd_get_data_direction(cmd->scst_cmd) & SCST_DATA_WRITE)) {
(scst_cmd_get_data_direction(&cmd->scst_cmd) & SCST_DATA_WRITE)) {
uint32_t offset;
int xmit_type;
offset = le32_to_cpu(imm->imm.notify_entry24.srr_rel_offs);
@@ -4335,8 +4323,8 @@ static void q24_handle_srr(scsi_qla_host_t *ha, struct srr_ctio *sctio,
PRINT_ERROR("qla2x00t(%ld): SRR for out data for cmd "
"without them (tag %d, SCSI status %d, dir %d),"
" reject", ha->instance, cmd->tag,
scst_cmd_get_status(cmd->scst_cmd),
scst_cmd_get_data_direction(cmd->scst_cmd));
scst_cmd_get_status(&cmd->scst_cmd),
scst_cmd_get_data_direction(&cmd->scst_cmd));
goto out_reject;
}
break;
@@ -4357,7 +4345,7 @@ out_reject:
NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL);
if (cmd->state == Q2T_STATE_NEED_DATA) {
cmd->state = Q2T_STATE_DATA_IN;
scst_rx_data(cmd->scst_cmd, SCST_RX_STATUS_ERROR,
scst_rx_data(&cmd->scst_cmd, SCST_RX_STATUS_ERROR,
SCST_CONTEXT_THREAD);
} else
q24_send_term_exchange(ha, cmd, &cmd->atio.atio7, 1);
@@ -4386,7 +4374,7 @@ static void q2x_handle_srr(scsi_qla_host_t *ha, struct srr_ctio *sctio,
__q2x_xmit_response(cmd, Q2T_XMIT_STATUS);
break;
case SRR_IU_DATA_IN:
cmd->bufflen = scst_cmd_get_adjusted_resp_data_len(cmd->scst_cmd);
cmd->bufflen = scst_cmd_get_adjusted_resp_data_len(&cmd->scst_cmd);
if (q2t_has_data(cmd)) {
uint32_t offset;
int xmit_type;
@@ -4402,12 +4390,12 @@ static void q2x_handle_srr(scsi_qla_host_t *ha, struct srr_ctio *sctio,
PRINT_ERROR("qla2x00t(%ld): SRR for in data for cmd "
"without them (tag %d, SCSI status %d), "
"reject", ha->instance, cmd->tag,
scst_cmd_get_status(cmd->scst_cmd));
scst_cmd_get_status(&cmd->scst_cmd));
goto out_reject;
}
break;
case SRR_IU_DATA_OUT:
cmd->bufflen = scst_cmd_get_write_fields(cmd->scst_cmd,
cmd->bufflen = scst_cmd_get_write_fields(&cmd->scst_cmd,
&cmd->sg, &cmd->sg_cnt);
if (q2t_has_data(cmd)) {
uint32_t offset;
@@ -4425,7 +4413,7 @@ static void q2x_handle_srr(scsi_qla_host_t *ha, struct srr_ctio *sctio,
PRINT_ERROR("qla2x00t(%ld): SRR for out data for cmd "
"without them (tag %d, SCSI status %d), "
"reject", ha->instance, cmd->tag,
scst_cmd_get_status(cmd->scst_cmd));
scst_cmd_get_status(&cmd->scst_cmd));
goto out_reject;
}
break;
@@ -4446,7 +4434,7 @@ out_reject:
NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL);
if (cmd->state == Q2T_STATE_NEED_DATA) {
cmd->state = Q2T_STATE_DATA_IN;
scst_rx_data(cmd->scst_cmd, SCST_RX_STATUS_ERROR,
scst_rx_data(&cmd->scst_cmd, SCST_RX_STATUS_ERROR,
SCST_CONTEXT_THREAD);
} else
q2x_send_term_exchange(ha, cmd, &cmd->atio.atio2x, 1);
@@ -4529,17 +4517,17 @@ restart:
cmd = sctio->cmd;
/* Restore the originals, except bufflen */
cmd->offset = scst_cmd_get_ppl_offset(cmd->scst_cmd);
cmd->offset = scst_cmd_get_ppl_offset(&cmd->scst_cmd);
if (cmd->free_sg) {
kfree(cmd->sg);
cmd->free_sg = 0;
}
cmd->sg = scst_cmd_get_sg(cmd->scst_cmd);
cmd->sg_cnt = scst_cmd_get_sg_cnt(cmd->scst_cmd);
cmd->sg = scst_cmd_get_sg(&cmd->scst_cmd);
cmd->sg_cnt = scst_cmd_get_sg_cnt(&cmd->scst_cmd);
TRACE_MGMT_DBG("SRR cmd %p (scst_cmd %p, tag %d, op %x), "
"sg_cnt=%d, offset=%d", cmd, cmd->scst_cmd,
cmd->tag, cmd->scst_cmd->cdb[0], cmd->sg_cnt,
"sg_cnt=%d, offset=%d", cmd, &cmd->scst_cmd,
cmd->tag, cmd->scst_cmd.cdb[0], cmd->sg_cnt,
cmd->offset);
if (IS_FWI2_CAPABLE(ha))
@@ -5685,7 +5673,7 @@ static void q2t_cleanup_hw_pending_cmd(scsi_qla_host_t *ha, struct q2t_cmd *cmd)
static void q2t_on_hw_pending_cmd_timeout(struct scst_cmd *scst_cmd)
{
struct q2t_cmd *cmd = (struct q2t_cmd *)scst_cmd_get_tgt_priv(scst_cmd);
struct q2t_cmd *cmd = container_of(scst_cmd, struct q2t_cmd, scst_cmd);
struct q2t_tgt *tgt = cmd->tgt;
scsi_qla_host_t *ha = tgt->ha;
scsi_qla_host_t *pha = to_qla_parent(ha);

View File

@@ -196,7 +196,6 @@ struct q2t_sess {
struct q2t_cmd {
struct q2t_sess *sess;
int state;
struct scst_cmd *scst_cmd;
unsigned int conf_compl_supported:1;/* to save extra sess dereferences */
unsigned int sg_mapped:1;
@@ -220,6 +219,8 @@ struct q2t_cmd {
atio7_entry_t atio7;
atio_entry_t atio2x;
} __packed atio;
struct scst_cmd scst_cmd;
};
struct q2t_sess_work_param {

View File

@@ -753,6 +753,13 @@ struct scst_tgt_template {
* Necessary, because for aborted commands xmit_response() could not
* be called. Could be called on IRQ context.
*
* This callback is called when the last reference to cmd is dropped,
* which can be much later after scst_tgt_cmd_done() called by the
* target driver, so it is not recommended that the target driver
* clean hardware or connection related cmd resources in this callback.
* It is recommended to clean them before calling scst_tgt_cmd_done()
* instead.
*
* OPTIONAL
*/
void (*on_free_cmd) (struct scst_cmd *cmd);
@@ -1984,6 +1991,9 @@ struct scst_cmd {
*/
unsigned int finished:1;
/* Set if cmd was pre-alloced by target driver */
unsigned int pre_alloced:1;
/**************************************************************/
/* cmd's async flags */
@@ -2867,7 +2877,10 @@ bool scst_initiator_has_luns(struct scst_tgt *tgt, const char *initiator_name);
struct scst_cmd *scst_rx_cmd(struct scst_session *sess,
const uint8_t *lun, int lun_len, const uint8_t *cdb,
unsigned int cdb_len, int atomic);
unsigned int cdb_len, bool atomic);
int scst_rx_cmd_prealloced(struct scst_cmd *cmd, struct scst_session *sess,
const uint8_t *lun, int lun_len, const uint8_t *cdb,
unsigned int cdb_len, bool atomic);
void scst_cmd_init_done(struct scst_cmd *cmd,
enum scst_exec_context pref_context);

View File

@@ -5273,18 +5273,22 @@ out_err:
}
EXPORT_SYMBOL(scst_cmd_set_ext_cdb);
struct scst_cmd *scst_alloc_cmd(const uint8_t *cdb,
int scst_pre_init_cmd(struct scst_cmd *cmd, const uint8_t *cdb,
unsigned int cdb_len, gfp_t gfp_mask)
{
struct scst_cmd *cmd;
int res;
TRACE_ENTRY();
cmd = kmem_cache_zalloc(scst_cmd_cachep, gfp_mask);
if (cmd == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of scst_cmd failed");
goto out;
#ifdef CONFIG_SCST_EXTRACHECKS
/* cmd supposed to be zeroed */
{
int i;
uint8_t *b = (uint8_t *)cmd;
for (i = 0; i < sizeof(*cmd); i++)
EXTRACHECKS_BUG_ON(b[i] != 0);
}
#endif
cmd->state = SCST_CMD_STATE_INIT_WAIT;
cmd->start_time = jiffies;
@@ -5310,26 +5314,54 @@ struct scst_cmd *scst_alloc_cmd(const uint8_t *cdb,
if (unlikely(cdb_len == 0)) {
PRINT_ERROR("%s", "Wrong CDB len 0, finishing cmd");
goto out_free;
res = -EINVAL;
goto out;
} else if (cdb_len <= SCST_MAX_CDB_SIZE) {
/* Duplicate memcpy to save a branch on the most common path */
memcpy(cmd->cdb, cdb, cdb_len);
} else {
if (unlikely(cdb_len > SCST_MAX_LONG_CDB_SIZE)) {
PRINT_ERROR("Too big CDB (%d), finishing cmd", cdb_len);
goto out_free;
res = -EINVAL;
goto out;
}
cmd->cdb = kmalloc(cdb_len, gfp_mask);
if (unlikely(cmd->cdb == NULL)) {
PRINT_ERROR("Unable to alloc extended CDB (size %d)",
cdb_len);
goto out_free;
res = -ENOMEM;
goto out;
}
memcpy(cmd->cdb, cdb, cdb_len);
}
cmd->cdb_len = cdb_len;
res = 0;
out:
TRACE_EXIT_RES(res);
return res;
}
struct scst_cmd *scst_alloc_cmd(const uint8_t *cdb,
unsigned int cdb_len, gfp_t gfp_mask)
{
struct scst_cmd *cmd;
int rc;
TRACE_ENTRY();
cmd = kmem_cache_zalloc(scst_cmd_cachep, gfp_mask);
if (cmd == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of scst_cmd failed");
goto out;
}
rc = scst_pre_init_cmd(cmd, cdb, cdb_len, gfp_mask);
if (unlikely(rc != 0))
goto out_free;
out:
TRACE_EXIT();
return cmd;
@@ -5342,6 +5374,8 @@ out_free:
static void scst_destroy_cmd(struct scst_cmd *cmd)
{
bool pre_alloced = cmd->pre_alloced;
TRACE_ENTRY();
TRACE_DBG("Destroying cmd %p", cmd);
@@ -5354,7 +5388,20 @@ static void scst_destroy_cmd(struct scst_cmd *cmd)
if (likely(cmd->tgt_dev != NULL))
scst_put(cmd->cpu_cmd_counter);
kmem_cache_free(scst_cmd_cachep, cmd);
EXTRACHECKS_BUG_ON(cmd->pre_alloced && cmd->internal);
if ((cmd->tgtt->on_free_cmd != NULL) && likely(!cmd->internal)) {
TRACE_DBG("Calling target's on_free_cmd(%p)", cmd);
scst_set_cur_start(cmd);
cmd->tgtt->on_free_cmd(cmd);
scst_set_tgt_on_free_time(cmd);
TRACE_DBG("%s", "Target's on_free_cmd() returned");
}
/* At this point cmd can be already freed! */
if (!pre_alloced)
kmem_cache_free(scst_cmd_cachep, cmd);
TRACE_EXIT();
return;
@@ -5383,14 +5430,6 @@ void scst_free_cmd(struct scst_cmd *cmd)
if (!cmd->tgt_i_data_buf_alloced)
scst_check_restore_sg_buff(cmd);
if ((cmd->tgtt->on_free_cmd != NULL) && likely(!cmd->internal)) {
TRACE_DBG("Calling target's on_free_cmd(%p)", cmd);
scst_set_cur_start(cmd);
cmd->tgtt->on_free_cmd(cmd);
scst_set_tgt_on_free_time(cmd);
TRACE_DBG("%s", "Target's on_free_cmd() returned");
}
if (likely(cmd->dev != NULL)) {
struct scst_dev_type *devt = cmd->devt;
if (devt->on_free_cmd != NULL) {

View File

@@ -666,6 +666,8 @@ static inline void scst_sess_put(struct scst_session *sess)
struct scst_cmd *scst_alloc_cmd(const uint8_t *cdb,
unsigned int cdb_len, gfp_t gfp_mask);
int scst_pre_init_cmd(struct scst_cmd *cmd, const uint8_t *cdb,
unsigned int cdb_len, gfp_t gfp_mask);
void scst_free_cmd(struct scst_cmd *cmd);
static inline void __scst_cmd_get(struct scst_cmd *cmd)

View File

@@ -179,6 +179,78 @@ static void scst_check_unblock_dev(struct scst_cmd *cmd)
return;
}
static void __scst_rx_cmd(struct scst_cmd *cmd, struct scst_session *sess,
const uint8_t *lun, int lun_len, gfp_t gfp_mask)
{
TRACE_ENTRY();
cmd->sess = sess;
scst_sess_get(sess);
cmd->tgt = sess->tgt;
cmd->tgtt = sess->tgt->tgtt;
cmd->lun = scst_unpack_lun(lun, lun_len);
if (unlikely(cmd->lun == NO_SUCH_LUN))
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_lun_not_supported));
TRACE_DBG("cmd %p, sess %p", cmd, sess);
TRACE_EXIT();
return;
}
/**
* scst_rx_cmd_prealloced() - notify SCST that new command received
* @cmd: new cmd to initialized
* @sess: SCST session
* @lun: LUN for the command
* @lun_len: length of the LUN in bytes
* @cdb: CDB of the command
* @cdb_len: length of the CDB in bytes
* @atomic: true, if current context is atomic
*
* Description:
* Initializes new prealloced SCST command. Returns 0 on success or
* negative error code otherwise.
*
* Must not be called in parallel with scst_unregister_session() for the
* same session.
*
* Cmd supposed to be zeroed!
*/
int scst_rx_cmd_prealloced(struct scst_cmd *cmd, struct scst_session *sess,
const uint8_t *lun, int lun_len, const uint8_t *cdb,
unsigned int cdb_len, bool atomic)
{
int res;
gfp_t gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
TRACE_ENTRY();
#ifdef CONFIG_SCST_EXTRACHECKS
if (unlikely(sess->shut_phase != SCST_SESS_SPH_READY)) {
PRINT_CRIT_ERROR("%s",
"New cmd while shutting down the session");
sBUG();
}
#endif
res = scst_pre_init_cmd(cmd, cdb, cdb_len, gfp_mask);
if (unlikely(res != 0))
goto out;
__scst_rx_cmd(cmd, sess, lun, lun_len, gfp_mask);
cmd->pre_alloced = 1;
out:
TRACE_EXIT_RES(res);
return res;
}
EXPORT_SYMBOL(scst_rx_cmd_prealloced);
/**
* scst_rx_cmd() - create new command
* @sess: SCST session
@@ -197,9 +269,10 @@ static void scst_check_unblock_dev(struct scst_cmd *cmd)
*/
struct scst_cmd *scst_rx_cmd(struct scst_session *sess,
const uint8_t *lun, int lun_len, const uint8_t *cdb,
unsigned int cdb_len, int atomic)
unsigned int cdb_len, bool atomic)
{
struct scst_cmd *cmd;
gfp_t gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
TRACE_ENTRY();
@@ -211,22 +284,15 @@ struct scst_cmd *scst_rx_cmd(struct scst_session *sess,
}
#endif
cmd = scst_alloc_cmd(cdb, cdb_len, atomic ? GFP_ATOMIC : GFP_KERNEL);
if (unlikely(cmd == NULL))
cmd = scst_alloc_cmd(cdb, cdb_len, gfp_mask);
if (cmd == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of scst_cmd failed");
goto out;
}
cmd->sess = sess;
scst_sess_get(sess);
__scst_rx_cmd(cmd, sess, lun, lun_len, gfp_mask);
cmd->tgt = sess->tgt;
cmd->tgtt = sess->tgt->tgtt;
cmd->lun = scst_unpack_lun(lun, lun_len);
if (unlikely(cmd->lun == NO_SUCH_LUN))
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_lun_not_supported));
TRACE_DBG("cmd %p, sess %p", cmd, sess);
cmd->pre_alloced = 0;
out:
TRACE_EXIT();