Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: tcm_fc: Handle DDP/SW fc_frame_payload_get failures in ft_recv_write_data target: Fix bug for transport_generic_wait_for_tasks with direct operation target: iscsi_target depends on NET target: Fix WRITE_SAME_16 lba assignment breakage MAINTAINERS: Add target-devel list for drivers/target/ iscsi-target: Fix CONFIG_SMP=n and CONFIG_MODULES=n build failure iscsi-target: Fix snprintf usage with MAX_PORTAL_LEN iscsi-target: Fix uninitialized usage of cmd->pad_bytes iscsi-target: strlen() doesn't count the terminator iscsi-target: Fix NULL dereference on allocation failure
This commit is contained in:
@@ -6319,6 +6319,7 @@ F: include/linux/sysv_fs.h
|
|||||||
TARGET SUBSYSTEM
|
TARGET SUBSYSTEM
|
||||||
M: Nicholas A. Bellinger <nab@linux-iscsi.org>
|
M: Nicholas A. Bellinger <nab@linux-iscsi.org>
|
||||||
L: linux-scsi@vger.kernel.org
|
L: linux-scsi@vger.kernel.org
|
||||||
|
L: target-devel@vger.kernel.org
|
||||||
L: http://groups.google.com/group/linux-iscsi-target-dev
|
L: http://groups.google.com/group/linux-iscsi-target-dev
|
||||||
W: http://www.linux-iscsi.org
|
W: http://www.linux-iscsi.org
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
config ISCSI_TARGET
|
config ISCSI_TARGET
|
||||||
tristate "Linux-iSCSI.org iSCSI Target Mode Stack"
|
tristate "Linux-iSCSI.org iSCSI Target Mode Stack"
|
||||||
|
depends on NET
|
||||||
select CRYPTO
|
select CRYPTO
|
||||||
select CRYPTO_CRC32C
|
select CRYPTO_CRC32C
|
||||||
select CRYPTO_CRC32C_INTEL if X86
|
select CRYPTO_CRC32C_INTEL if X86
|
||||||
|
@@ -120,7 +120,7 @@ struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *buf)
|
|||||||
struct iscsi_tiqn *tiqn = NULL;
|
struct iscsi_tiqn *tiqn = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (strlen(buf) > ISCSI_IQN_LEN) {
|
if (strlen(buf) >= ISCSI_IQN_LEN) {
|
||||||
pr_err("Target IQN exceeds %d bytes\n",
|
pr_err("Target IQN exceeds %d bytes\n",
|
||||||
ISCSI_IQN_LEN);
|
ISCSI_IQN_LEN);
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
@@ -1857,7 +1857,7 @@ static int iscsit_handle_text_cmd(
|
|||||||
char *text_ptr, *text_in;
|
char *text_ptr, *text_in;
|
||||||
int cmdsn_ret, niov = 0, rx_got, rx_size;
|
int cmdsn_ret, niov = 0, rx_got, rx_size;
|
||||||
u32 checksum = 0, data_crc = 0, payload_length;
|
u32 checksum = 0, data_crc = 0, payload_length;
|
||||||
u32 padding = 0, text_length = 0;
|
u32 padding = 0, pad_bytes = 0, text_length = 0;
|
||||||
struct iscsi_cmd *cmd;
|
struct iscsi_cmd *cmd;
|
||||||
struct kvec iov[3];
|
struct kvec iov[3];
|
||||||
struct iscsi_text *hdr;
|
struct iscsi_text *hdr;
|
||||||
@@ -1896,7 +1896,7 @@ static int iscsit_handle_text_cmd(
|
|||||||
|
|
||||||
padding = ((-payload_length) & 3);
|
padding = ((-payload_length) & 3);
|
||||||
if (padding != 0) {
|
if (padding != 0) {
|
||||||
iov[niov].iov_base = cmd->pad_bytes;
|
iov[niov].iov_base = &pad_bytes;
|
||||||
iov[niov++].iov_len = padding;
|
iov[niov++].iov_len = padding;
|
||||||
rx_size += padding;
|
rx_size += padding;
|
||||||
pr_debug("Receiving %u additional bytes"
|
pr_debug("Receiving %u additional bytes"
|
||||||
@@ -1917,7 +1917,7 @@ static int iscsit_handle_text_cmd(
|
|||||||
if (conn->conn_ops->DataDigest) {
|
if (conn->conn_ops->DataDigest) {
|
||||||
iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
|
iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
|
||||||
text_in, text_length,
|
text_in, text_length,
|
||||||
padding, cmd->pad_bytes,
|
padding, (u8 *)&pad_bytes,
|
||||||
(u8 *)&data_crc);
|
(u8 *)&data_crc);
|
||||||
|
|
||||||
if (checksum != data_crc) {
|
if (checksum != data_crc) {
|
||||||
@@ -3468,7 +3468,12 @@ static inline void iscsit_thread_check_cpumask(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define iscsit_thread_get_cpumask(X) ({})
|
|
||||||
|
void iscsit_thread_get_cpumask(struct iscsi_conn *conn)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#define iscsit_thread_check_cpumask(X, Y, Z) ({})
|
#define iscsit_thread_check_cpumask(X, Y, Z) ({})
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
|
@@ -181,7 +181,7 @@ struct se_tpg_np *lio_target_call_addnptotpg(
|
|||||||
return ERR_PTR(-EOVERFLOW);
|
return ERR_PTR(-EOVERFLOW);
|
||||||
}
|
}
|
||||||
memset(buf, 0, MAX_PORTAL_LEN + 1);
|
memset(buf, 0, MAX_PORTAL_LEN + 1);
|
||||||
snprintf(buf, MAX_PORTAL_LEN, "%s", name);
|
snprintf(buf, MAX_PORTAL_LEN + 1, "%s", name);
|
||||||
|
|
||||||
memset(&sockaddr, 0, sizeof(struct __kernel_sockaddr_storage));
|
memset(&sockaddr, 0, sizeof(struct __kernel_sockaddr_storage));
|
||||||
|
|
||||||
|
@@ -978,7 +978,7 @@ struct iscsi_login *iscsi_target_init_negotiation(
|
|||||||
pr_err("Unable to allocate memory for struct iscsi_login.\n");
|
pr_err("Unable to allocate memory for struct iscsi_login.\n");
|
||||||
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
|
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
|
||||||
ISCSI_LOGIN_STATUS_NO_RESOURCES);
|
ISCSI_LOGIN_STATUS_NO_RESOURCES);
|
||||||
goto out;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
login->req = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL);
|
login->req = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL);
|
||||||
|
@@ -1747,6 +1747,8 @@ int transport_generic_handle_cdb(
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(transport_generic_handle_cdb);
|
EXPORT_SYMBOL(transport_generic_handle_cdb);
|
||||||
|
|
||||||
|
static void transport_generic_request_failure(struct se_cmd *,
|
||||||
|
struct se_device *, int, int);
|
||||||
/*
|
/*
|
||||||
* Used by fabric module frontends to queue tasks directly.
|
* Used by fabric module frontends to queue tasks directly.
|
||||||
* Many only be used from process context only
|
* Many only be used from process context only
|
||||||
@@ -1754,6 +1756,8 @@ EXPORT_SYMBOL(transport_generic_handle_cdb);
|
|||||||
int transport_handle_cdb_direct(
|
int transport_handle_cdb_direct(
|
||||||
struct se_cmd *cmd)
|
struct se_cmd *cmd)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!cmd->se_lun) {
|
if (!cmd->se_lun) {
|
||||||
dump_stack();
|
dump_stack();
|
||||||
pr_err("cmd->se_lun is NULL\n");
|
pr_err("cmd->se_lun is NULL\n");
|
||||||
@@ -1765,8 +1769,31 @@ int transport_handle_cdb_direct(
|
|||||||
" from interrupt context\n");
|
" from interrupt context\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
return transport_generic_new_cmd(cmd);
|
* Set TRANSPORT_NEW_CMD state and cmd->t_transport_active=1 following
|
||||||
|
* transport_generic_handle_cdb*() -> transport_add_cmd_to_queue()
|
||||||
|
* in existing usage to ensure that outstanding descriptors are handled
|
||||||
|
* correctly during shutdown via transport_generic_wait_for_tasks()
|
||||||
|
*
|
||||||
|
* Also, we don't take cmd->t_state_lock here as we only expect
|
||||||
|
* this to be called for initial descriptor submission.
|
||||||
|
*/
|
||||||
|
cmd->t_state = TRANSPORT_NEW_CMD;
|
||||||
|
atomic_set(&cmd->t_transport_active, 1);
|
||||||
|
/*
|
||||||
|
* transport_generic_new_cmd() is already handling QUEUE_FULL,
|
||||||
|
* so follow TRANSPORT_NEW_CMD processing thread context usage
|
||||||
|
* and call transport_generic_request_failure() if necessary..
|
||||||
|
*/
|
||||||
|
ret = transport_generic_new_cmd(cmd);
|
||||||
|
if (ret == -EAGAIN)
|
||||||
|
return 0;
|
||||||
|
else if (ret < 0) {
|
||||||
|
cmd->transport_error_status = ret;
|
||||||
|
transport_generic_request_failure(cmd, NULL, 0,
|
||||||
|
(cmd->data_direction != DMA_TO_DEVICE));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(transport_handle_cdb_direct);
|
EXPORT_SYMBOL(transport_handle_cdb_direct);
|
||||||
|
|
||||||
@@ -3324,7 +3351,7 @@ static int transport_generic_cmd_sequencer(
|
|||||||
goto out_invalid_cdb_field;
|
goto out_invalid_cdb_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd->t_task_lba = get_unaligned_be16(&cdb[2]);
|
cmd->t_task_lba = get_unaligned_be64(&cdb[2]);
|
||||||
passthrough = (dev->transport->transport_type ==
|
passthrough = (dev->transport->transport_type ==
|
||||||
TRANSPORT_PLUGIN_PHBA_PDEV);
|
TRANSPORT_PLUGIN_PHBA_PDEV);
|
||||||
/*
|
/*
|
||||||
|
@@ -187,4 +187,9 @@ void ft_dump_cmd(struct ft_cmd *, const char *caller);
|
|||||||
|
|
||||||
ssize_t ft_format_wwn(char *, size_t, u64);
|
ssize_t ft_format_wwn(char *, size_t, u64);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Underlying HW specific helper function
|
||||||
|
*/
|
||||||
|
void ft_invl_hw_context(struct ft_cmd *);
|
||||||
|
|
||||||
#endif /* __TCM_FC_H__ */
|
#endif /* __TCM_FC_H__ */
|
||||||
|
@@ -320,6 +320,7 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg)
|
|||||||
default:
|
default:
|
||||||
pr_debug("%s: unhandled frame r_ctl %x\n",
|
pr_debug("%s: unhandled frame r_ctl %x\n",
|
||||||
__func__, fh->fh_r_ctl);
|
__func__, fh->fh_r_ctl);
|
||||||
|
ft_invl_hw_context(cmd);
|
||||||
fc_frame_free(fp);
|
fc_frame_free(fp);
|
||||||
transport_generic_free_cmd(&cmd->se_cmd, 0, 0);
|
transport_generic_free_cmd(&cmd->se_cmd, 0, 0);
|
||||||
break;
|
break;
|
||||||
|
@@ -213,62 +213,49 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
|
|||||||
if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF))
|
if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF))
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
/*
|
f_ctl = ntoh24(fh->fh_f_ctl);
|
||||||
* Doesn't expect even single byte of payload. Payload
|
ep = fc_seq_exch(seq);
|
||||||
* is expected to be copied directly to user buffers
|
lport = ep->lp;
|
||||||
* due to DDP (Large Rx offload) feature, hence
|
if (cmd->was_ddp_setup) {
|
||||||
* BUG_ON if BUF is non-NULL
|
BUG_ON(!ep);
|
||||||
*/
|
BUG_ON(!lport);
|
||||||
buf = fc_frame_payload_get(fp, 1);
|
|
||||||
if (cmd->was_ddp_setup && buf) {
|
|
||||||
pr_debug("%s: When DDP was setup, not expected to"
|
|
||||||
"receive frame with payload, Payload shall be"
|
|
||||||
"copied directly to buffer instead of coming "
|
|
||||||
"via. legacy receive queues\n", __func__);
|
|
||||||
BUG_ON(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If ft_cmd indicated 'ddp_setup', in that case only the last frame
|
* Doesn't expect payload if DDP is setup. Payload
|
||||||
* should come with 'TSI bit being set'. If 'TSI bit is not set and if
|
* is expected to be copied directly to user buffers
|
||||||
* data frame appears here, means error condition. In both the cases
|
* due to DDP (Large Rx offload),
|
||||||
* release the DDP context (ddp_put) and in error case, as well
|
|
||||||
* initiate error recovery mechanism.
|
|
||||||
*/
|
*/
|
||||||
ep = fc_seq_exch(seq);
|
buf = fc_frame_payload_get(fp, 1);
|
||||||
if (cmd->was_ddp_setup) {
|
if (buf)
|
||||||
BUG_ON(!ep);
|
pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, "
|
||||||
lport = ep->lp;
|
"cmd->sg_cnt 0x%x. DDP was setup"
|
||||||
BUG_ON(!lport);
|
" hence not expected to receive frame with "
|
||||||
}
|
"payload, Frame will be dropped if "
|
||||||
if (cmd->was_ddp_setup && ep->xid != FC_XID_UNKNOWN) {
|
"'Sequence Initiative' bit in f_ctl is "
|
||||||
f_ctl = ntoh24(fh->fh_f_ctl);
|
"not set\n", __func__, ep->xid, f_ctl,
|
||||||
/*
|
cmd->sg, cmd->sg_cnt);
|
||||||
* If TSI bit set in f_ctl, means last write data frame is
|
/*
|
||||||
* received successfully where payload is posted directly
|
* Invalidate HW DDP context if it was setup for respective
|
||||||
* to user buffer and only the last frame's header is posted
|
* command. Invalidation of HW DDP context is requited in both
|
||||||
* in legacy receive queue
|
* situation (success and error).
|
||||||
*/
|
*/
|
||||||
if (f_ctl & FC_FC_SEQ_INIT) { /* TSI bit set in FC frame */
|
ft_invl_hw_context(cmd);
|
||||||
cmd->write_data_len = lport->tt.ddp_done(lport,
|
|
||||||
ep->xid);
|
/*
|
||||||
goto last_frame;
|
* If "Sequence Initiative (TSI)" bit set in f_ctl, means last
|
||||||
} else {
|
* write data frame is received successfully where payload is
|
||||||
/*
|
* posted directly to user buffer and only the last frame's
|
||||||
* Updating the write_data_len may be meaningless at
|
* header is posted in receive queue.
|
||||||
* this point, but just in case if required in future
|
*
|
||||||
* for debugging or any other purpose
|
* If "Sequence Initiative (TSI)" bit is not set, means error
|
||||||
*/
|
* condition w.r.t. DDP, hence drop the packet and let explict
|
||||||
pr_err("%s: Received frame with TSI bit not"
|
* ABORTS from other end of exchange timer trigger the recovery.
|
||||||
" being SET, dropping the frame, "
|
*/
|
||||||
"cmd->sg <%p>, cmd->sg_cnt <0x%x>\n",
|
if (f_ctl & FC_FC_SEQ_INIT)
|
||||||
__func__, cmd->sg, cmd->sg_cnt);
|
goto last_frame;
|
||||||
cmd->write_data_len = lport->tt.ddp_done(lport,
|
else
|
||||||
ep->xid);
|
goto drop;
|
||||||
lport->tt.seq_exch_abort(cmd->seq, 0);
|
|
||||||
goto drop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rel_off = ntohl(fh->fh_parm_offset);
|
rel_off = ntohl(fh->fh_parm_offset);
|
||||||
frame_len = fr_len(fp);
|
frame_len = fr_len(fp);
|
||||||
@@ -331,3 +318,39 @@ last_frame:
|
|||||||
drop:
|
drop:
|
||||||
fc_frame_free(fp);
|
fc_frame_free(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle and cleanup any HW specific resources if
|
||||||
|
* received ABORTS, errors, timeouts.
|
||||||
|
*/
|
||||||
|
void ft_invl_hw_context(struct ft_cmd *cmd)
|
||||||
|
{
|
||||||
|
struct fc_seq *seq = cmd->seq;
|
||||||
|
struct fc_exch *ep = NULL;
|
||||||
|
struct fc_lport *lport = NULL;
|
||||||
|
|
||||||
|
BUG_ON(!cmd);
|
||||||
|
|
||||||
|
/* Cleanup the DDP context in HW if DDP was setup */
|
||||||
|
if (cmd->was_ddp_setup && seq) {
|
||||||
|
ep = fc_seq_exch(seq);
|
||||||
|
if (ep) {
|
||||||
|
lport = ep->lp;
|
||||||
|
if (lport && (ep->xid <= lport->lro_xid))
|
||||||
|
/*
|
||||||
|
* "ddp_done" trigger invalidation of HW
|
||||||
|
* specific DDP context
|
||||||
|
*/
|
||||||
|
cmd->write_data_len = lport->tt.ddp_done(lport,
|
||||||
|
ep->xid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resetting same variable to indicate HW's
|
||||||
|
* DDP context has been invalidated to avoid
|
||||||
|
* re_invalidation of same context (context is
|
||||||
|
* identified using ep->xid)
|
||||||
|
*/
|
||||||
|
cmd->was_ddp_setup = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user