diff options
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/iscsi/cxgbit/cxgbit_cm.c | 23 | ||||
-rw-r--r-- | drivers/target/iscsi/cxgbit/cxgbit_ddp.c | 8 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 33 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_auth.c | 45 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_erl0.c | 15 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_erl1.c | 17 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_erl2.c | 2 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_erl2.h | 2 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_login.c | 151 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_login.h | 2 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_stat.c | 4 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_util.c | 44 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_util.h | 1 | ||||
-rw-r--r-- | drivers/target/target_core_iblock.c | 58 | ||||
-rw-r--r-- | drivers/target/target_core_iblock.h | 1 | ||||
-rw-r--r-- | drivers/target/target_core_sbc.c | 23 | ||||
-rw-r--r-- | drivers/target/target_core_spc.c | 6 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 19 | ||||
-rw-r--r-- | drivers/target/target_core_xcopy.c | 3 |
19 files changed, 239 insertions, 218 deletions
diff --git a/drivers/target/iscsi/cxgbit/cxgbit_cm.c b/drivers/target/iscsi/cxgbit/cxgbit_cm.c index 8de16016b6de..71888b979ab5 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_cm.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_cm.c @@ -598,9 +598,12 @@ out: mutex_unlock(&cdev_list_lock); } +static void __cxgbit_free_conn(struct cxgbit_sock *csk); + void cxgbit_free_np(struct iscsi_np *np) { struct cxgbit_np *cnp = np->np_context; + struct cxgbit_sock *csk, *tmp; cnp->com.state = CSK_STATE_DEAD; if (cnp->com.cdev) @@ -608,6 +611,13 @@ void cxgbit_free_np(struct iscsi_np *np) else cxgbit_free_all_np(cnp); + spin_lock_bh(&cnp->np_accept_lock); + list_for_each_entry_safe(csk, tmp, &cnp->np_accept_list, accept_node) { + list_del_init(&csk->accept_node); + __cxgbit_free_conn(csk); + } + spin_unlock_bh(&cnp->np_accept_lock); + np->np_context = NULL; cxgbit_put_cnp(cnp); } @@ -705,9 +715,9 @@ void cxgbit_abort_conn(struct cxgbit_sock *csk) csk->tid, 600, __func__); } -void cxgbit_free_conn(struct iscsi_conn *conn) +static void __cxgbit_free_conn(struct cxgbit_sock *csk) { - struct cxgbit_sock *csk = conn->context; + struct iscsi_conn *conn = csk->conn; bool release = false; pr_debug("%s: state %d\n", @@ -716,7 +726,7 @@ void cxgbit_free_conn(struct iscsi_conn *conn) spin_lock_bh(&csk->lock); switch (csk->com.state) { case CSK_STATE_ESTABLISHED: - if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) { + if (conn && (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT)) { csk->com.state = CSK_STATE_CLOSING; cxgbit_send_halfclose(csk); } else { @@ -741,6 +751,11 @@ void cxgbit_free_conn(struct iscsi_conn *conn) cxgbit_put_csk(csk); } +void cxgbit_free_conn(struct iscsi_conn *conn) +{ + __cxgbit_free_conn(conn->context); +} + static void cxgbit_set_emss(struct cxgbit_sock *csk, u16 opt) { csk->emss = csk->com.cdev->lldi.mtus[TCPOPT_MSS_G(opt)] - @@ -803,6 +818,7 @@ void _cxgbit_free_csk(struct kref *kref) spin_unlock_bh(&cdev->cskq.lock); cxgbit_free_skb(csk); + cxgbit_put_cnp(csk->cnp); cxgbit_put_cdev(cdev); kfree(csk); @@ -1351,6 +1367,7 @@ cxgbit_pass_accept_req(struct cxgbit_device *cdev, struct sk_buff *skb) goto rel_skb; } + cxgbit_get_cnp(cnp); cxgbit_get_cdev(cdev); spin_lock(&cdev->cskq.lock); diff --git a/drivers/target/iscsi/cxgbit/cxgbit_ddp.c b/drivers/target/iscsi/cxgbit/cxgbit_ddp.c index 768cce0ccb80..76a262674c8d 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_ddp.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_ddp.c @@ -207,8 +207,8 @@ cxgbit_ddp_reserve(struct cxgbit_sock *csk, struct cxgbi_task_tag_info *ttinfo, ret = dma_map_sg(&ppm->pdev->dev, sgl, sgcnt, DMA_FROM_DEVICE); sgl->offset = sg_offset; if (!ret) { - pr_info("%s: 0x%x, xfer %u, sgl %u dma mapping err.\n", - __func__, 0, xferlen, sgcnt); + pr_debug("%s: 0x%x, xfer %u, sgl %u dma mapping err.\n", + __func__, 0, xferlen, sgcnt); goto rel_ppods; } @@ -250,8 +250,8 @@ cxgbit_get_r2t_ttt(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ret = cxgbit_ddp_reserve(csk, ttinfo, cmd->se_cmd.data_length); if (ret < 0) { - pr_info("csk 0x%p, cmd 0x%p, xfer len %u, sgcnt %u no ddp.\n", - csk, cmd, cmd->se_cmd.data_length, ttinfo->nents); + pr_debug("csk 0x%p, cmd 0x%p, xfer len %u, sgcnt %u no ddp.\n", + csk, cmd, cmd->se_cmd.data_length, ttinfo->nents); ttinfo->sgl = NULL; ttinfo->nents = 0; diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 94bad43c41ff..c1d5a173553d 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -1416,7 +1416,8 @@ static void iscsit_do_crypto_hash_buf(struct ahash_request *hash, sg_init_table(sg, ARRAY_SIZE(sg)); sg_set_buf(sg, buf, payload_length); - sg_set_buf(sg + 1, pad_bytes, padding); + if (padding) + sg_set_buf(sg + 1, pad_bytes, padding); ahash_request_set_crypt(hash, sg, data_crc, payload_length + padding); @@ -3910,10 +3911,14 @@ static bool iscsi_target_check_conn_state(struct iscsi_conn *conn) static void iscsit_get_rx_pdu(struct iscsi_conn *conn) { int ret; - u8 buffer[ISCSI_HDR_LEN], opcode; + u8 *buffer, opcode; u32 checksum = 0, digest = 0; struct kvec iov; + buffer = kcalloc(ISCSI_HDR_LEN, sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return; + while (!kthread_should_stop()) { /* * Ensure that both TX and RX per connection kthreads @@ -3921,7 +3926,6 @@ static void iscsit_get_rx_pdu(struct iscsi_conn *conn) */ iscsit_thread_check_cpumask(conn, current, 0); - memset(buffer, 0, ISCSI_HDR_LEN); memset(&iov, 0, sizeof(struct kvec)); iov.iov_base = buffer; @@ -3930,7 +3934,7 @@ static void iscsit_get_rx_pdu(struct iscsi_conn *conn) ret = rx_data(conn, &iov, 1, ISCSI_HDR_LEN); if (ret != ISCSI_HDR_LEN) { iscsit_rx_thread_wait_for_tcp(conn); - return; + break; } if (conn->conn_ops->HeaderDigest) { @@ -3940,7 +3944,7 @@ static void iscsit_get_rx_pdu(struct iscsi_conn *conn) ret = rx_data(conn, &iov, 1, ISCSI_CRC_LEN); if (ret != ISCSI_CRC_LEN) { iscsit_rx_thread_wait_for_tcp(conn); - return; + break; } iscsit_do_crypto_hash_buf(conn->conn_rx_hash, buffer, @@ -3964,7 +3968,7 @@ static void iscsit_get_rx_pdu(struct iscsi_conn *conn) } if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) - return; + break; opcode = buffer[0] & ISCSI_OPCODE_MASK; @@ -3975,13 +3979,15 @@ static void iscsit_get_rx_pdu(struct iscsi_conn *conn) " while in Discovery Session, rejecting.\n", opcode); iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, buffer); - return; + break; } ret = iscsi_target_rx_opcode(conn, buffer); if (ret < 0) - return; + break; } + + kfree(buffer); } int iscsi_target_rx_thread(void *arg) @@ -4208,22 +4214,15 @@ int iscsit_close_connection( crypto_free_ahash(tfm); } - free_cpumask_var(conn->conn_cpumask); - - kfree(conn->conn_ops); - conn->conn_ops = NULL; - if (conn->sock) sock_release(conn->sock); if (conn->conn_transport->iscsit_free_conn) conn->conn_transport->iscsit_free_conn(conn); - iscsit_put_transport(conn->conn_transport); - pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); conn->conn_state = TARG_CONN_STATE_FREE; - kfree(conn); + iscsit_free_conn(conn); spin_lock_bh(&sess->conn_lock); atomic_dec(&sess->nconn); @@ -4356,7 +4355,7 @@ int iscsit_close_session(struct iscsi_session *sess) transport_deregister_session(sess->se_sess); if (sess->sess_ops->ErrorRecoveryLevel == 2) - iscsit_free_connection_recovery_entires(sess); + iscsit_free_connection_recovery_entries(sess); iscsit_free_all_ooo_cmdsns(sess); diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index 9518ffd8b8ba..4e680d753941 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -26,27 +26,6 @@ #include "iscsi_target_nego.h" #include "iscsi_target_auth.h" -static int chap_string_to_hex(unsigned char *dst, unsigned char *src, int len) -{ - int j = DIV_ROUND_UP(len, 2), rc; - - rc = hex2bin(dst, src, j); - if (rc < 0) - pr_debug("CHAP string contains non hex digit symbols\n"); - - dst[j] = '\0'; - return j; -} - -static void chap_binaryhex_to_asciihex(char *dst, char *src, int src_len) -{ - int i; - - for (i = 0; i < src_len; i++) { - sprintf(&dst[i*2], "%02x", (int) src[i] & 0xff); - } -} - static int chap_gen_challenge( struct iscsi_conn *conn, int caller, @@ -62,7 +41,7 @@ static int chap_gen_challenge( ret = get_random_bytes_wait(chap->challenge, CHAP_CHALLENGE_LENGTH); if (unlikely(ret)) return ret; - chap_binaryhex_to_asciihex(challenge_asciihex, chap->challenge, + bin2hex(challenge_asciihex, chap->challenge, CHAP_CHALLENGE_LENGTH); /* * Set CHAP_C, and copy the generated challenge into c_str. @@ -248,9 +227,16 @@ static int chap_server_compute_md5( pr_err("Could not find CHAP_R.\n"); goto out; } + if (strlen(chap_r) != MD5_SIGNATURE_SIZE * 2) { + pr_err("Malformed CHAP_R\n"); + goto out; + } + if (hex2bin(client_digest, chap_r, MD5_SIGNATURE_SIZE) < 0) { + pr_err("Malformed CHAP_R\n"); + goto out; + } pr_debug("[server] Got CHAP_R=%s\n", chap_r); - chap_string_to_hex(client_digest, chap_r, strlen(chap_r)); tfm = crypto_alloc_shash("md5", 0, 0); if (IS_ERR(tfm)) { @@ -294,7 +280,7 @@ static int chap_server_compute_md5( goto out; } - chap_binaryhex_to_asciihex(response, server_digest, MD5_SIGNATURE_SIZE); + bin2hex(response, server_digest, MD5_SIGNATURE_SIZE); pr_debug("[server] MD5 Server Digest: %s\n", response); if (memcmp(server_digest, client_digest, MD5_SIGNATURE_SIZE) != 0) { @@ -349,9 +335,7 @@ static int chap_server_compute_md5( pr_err("Could not find CHAP_C.\n"); goto out; } - pr_debug("[server] Got CHAP_C=%s\n", challenge); - challenge_len = chap_string_to_hex(challenge_binhex, challenge, - strlen(challenge)); + challenge_len = DIV_ROUND_UP(strlen(challenge), 2); if (!challenge_len) { pr_err("Unable to convert incoming challenge\n"); goto out; @@ -360,6 +344,11 @@ static int chap_server_compute_md5( pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n"); goto out; } + if (hex2bin(challenge_binhex, challenge, challenge_len) < 0) { + pr_err("Malformed CHAP_C\n"); + goto out; + } + pr_debug("[server] Got CHAP_C=%s\n", challenge); /* * During mutual authentication, the CHAP_C generated by the * initiator must not match the original CHAP_C generated by @@ -413,7 +402,7 @@ static int chap_server_compute_md5( /* * Convert response from binary hex to ascii hext. */ - chap_binaryhex_to_asciihex(response, digest, MD5_SIGNATURE_SIZE); + bin2hex(response, digest, MD5_SIGNATURE_SIZE); *nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s", response); *nr_out_len += 1; diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index 718fe9a1b709..1193cf884a28 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -770,21 +770,8 @@ void iscsit_handle_time2retain_timeout(struct timer_list *t) pr_err("Time2Retain timer expired for SID: %u, cleaning up" " iSCSI session.\n", sess->sid); - { - struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; - - if (tiqn) { - spin_lock(&tiqn->sess_err_stats.lock); - strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name, - (void *)sess->sess_ops->InitiatorName); - tiqn->sess_err_stats.last_sess_failure_type = - ISCSI_SESS_ERR_CXN_TIMEOUT; - tiqn->sess_err_stats.cxn_timeout_errors++; - atomic_long_inc(&sess->conn_timeout_errors); - spin_unlock(&tiqn->sess_err_stats.lock); - } - } + iscsit_fill_cxn_timeout_err_stats(sess); spin_unlock_bh(&se_tpg->session_lock); iscsit_close_session(sess); } diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index 5efa42b939a1..a211e8154f4c 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -1169,15 +1169,21 @@ void iscsit_handle_dataout_timeout(struct timer_list *t) na = iscsit_tpg_get_node_attrib(sess); if (!sess->sess_ops->ErrorRecoveryLevel) { - pr_debug("Unable to recover from DataOut timeout while" - " in ERL=0.\n"); + pr_err("Unable to recover from DataOut timeout while" + " in ERL=0, closing iSCSI connection for I_T Nexus" + " %s,i,0x%6phN,%s,t,0x%02x\n", + sess->sess_ops->InitiatorName, sess->isid, + sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt); goto failure; } if (++cmd->dataout_timeout_retries == na->dataout_timeout_retries) { - pr_debug("Command ITT: 0x%08x exceeded max retries" - " for DataOUT timeout %u, closing iSCSI connection.\n", - cmd->init_task_tag, na->dataout_timeout_retries); + pr_err("Command ITT: 0x%08x exceeded max retries" + " for DataOUT timeout %u, closing iSCSI connection for" + " I_T Nexus %s,i,0x%6phN,%s,t,0x%02x\n", + cmd->init_task_tag, na->dataout_timeout_retries, + sess->sess_ops->InitiatorName, sess->isid, + sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt); goto failure; } @@ -1224,6 +1230,7 @@ void iscsit_handle_dataout_timeout(struct timer_list *t) failure: spin_unlock_bh(&cmd->dataout_timeout_lock); + iscsit_fill_cxn_timeout_err_stats(sess); iscsit_cause_connection_reinstatement(conn, 0); iscsit_dec_conn_usage_count(conn); } diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c index 8df9c90f3db3..b08b620b1bf0 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.c +++ b/drivers/target/iscsi/iscsi_target_erl2.c @@ -125,7 +125,7 @@ struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry( return NULL; } -void iscsit_free_connection_recovery_entires(struct iscsi_session *sess) +void iscsit_free_connection_recovery_entries(struct iscsi_session *sess) { struct iscsi_cmd *cmd, *cmd_tmp; struct iscsi_conn_recovery *cr, *cr_tmp; diff --git a/drivers/target/iscsi/iscsi_target_erl2.h b/drivers/target/iscsi/iscsi_target_erl2.h index 93e180d68d07..a39b0caf2337 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.h +++ b/drivers/target/iscsi/iscsi_target_erl2.h @@ -13,7 +13,7 @@ extern void iscsit_create_conn_recovery_datain_values(struct iscsi_cmd *, __be32 extern void iscsit_create_conn_recovery_dataout_values(struct iscsi_cmd *); extern struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry( struct iscsi_session *, u16); -extern void iscsit_free_connection_recovery_entires(struct iscsi_session *); +extern void iscsit_free_connection_recovery_entries(struct iscsi_session *); extern int iscsit_remove_active_connection_recovery_entry( struct iscsi_conn_recovery *, struct iscsi_session *); extern int iscsit_remove_cmd_from_connection_recovery(struct iscsi_cmd *, diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 9e74f8bc2963..ae3209efd0e0 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -67,45 +67,10 @@ static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn) goto out_req_buf; } - conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL); - if (!conn->conn_ops) { - pr_err("Unable to allocate memory for" - " struct iscsi_conn_ops.\n"); - goto out_rsp_buf; - } - - init_waitqueue_head(&conn->queues_wq); - INIT_LIST_HEAD(&conn->conn_list); - INIT_LIST_HEAD(&conn->conn_cmd_list); - INIT_LIST_HEAD(&conn->immed_queue_list); - INIT_LIST_HEAD(&conn->response_queue_list); - init_completion(&conn->conn_post_wait_comp); - init_completion(&conn->conn_wait_comp); - init_completion(&conn->conn_wait_rcfr_comp); - init_completion(&conn->conn_waiting_on_uc_comp); - init_completion(&conn->conn_logout_comp); - init_completion(&conn->rx_half_close_comp); - init_completion(&conn->tx_half_close_comp); - init_completion(&conn->rx_login_comp); - spin_lock_init(&conn->cmd_lock); - spin_lock_init(&conn->conn_usage_lock); - spin_lock_init(&conn->immed_queue_lock); - spin_lock_init(&conn->nopin_timer_lock); - spin_lock_init(&conn->response_queue_lock); - spin_lock_init(&conn->state_lock); - - if (!zalloc_cpumask_var(&conn->conn_cpumask, GFP_KERNEL)) { - pr_err("Unable to allocate conn->conn_cpumask\n"); - goto out_conn_ops; - } conn->conn_login = login; return login; -out_conn_ops: - kfree(conn->conn_ops); -out_rsp_buf: - kfree(login->rsp_buf); out_req_buf: kfree(login->req_buf); out_login: @@ -310,11 +275,9 @@ static int iscsi_login_zero_tsih_s1( return -ENOMEM; } - ret = iscsi_login_set_conn_values(sess, conn, pdu->cid); - if (unlikely(ret)) { - kfree(sess); - return ret; - } + if (iscsi_login_set_conn_values(sess, conn, pdu->cid)) + goto free_sess; + sess->init_task_tag = pdu->itt; memcpy(&sess->isid, pdu->isid, 6); sess->exp_cmd_sn = be32_to_cpu(pdu->cmdsn); @@ -615,7 +578,7 @@ int iscsi_login_post_auth_non_zero_tsih( } /* - * Check for any connection recovery entires containing CID. + * Check for any connection recovery entries containing CID. * We use the original ExpStatSN sent in the first login request * to acknowledge commands for the failed connection. * @@ -1149,6 +1112,75 @@ iscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t) return 0; } +static struct iscsi_conn *iscsit_alloc_conn(struct iscsi_np *np) +{ + struct iscsi_conn *conn; + + conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL); + if (!conn) { + pr_err("Could not allocate memory for new connection\n"); + return NULL; + } + pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); + conn->conn_state = TARG_CONN_STATE_FREE; + + init_waitqueue_head(&conn->queues_wq); + INIT_LIST_HEAD(&conn->conn_list); + INIT_LIST_HEAD(&conn->conn_cmd_list); + INIT_LIST_HEAD(&conn->immed_queue_list); + INIT_LIST_HEAD(&conn->response_queue_list); + init_completion(&conn->conn_post_wait_comp); + init_completion(&conn->conn_wait_comp); + init_completion(&conn->conn_wait_rcfr_comp); + init_completion(&conn->conn_waiting_on_uc_comp); + init_completion(&conn->conn_logout_comp); + init_completion(&conn->rx_half_close_comp); + init_completion(&conn->tx_half_close_comp); + init_completion(&conn->rx_login_comp); + spin_lock_init(&conn->cmd_lock); + spin_lock_init(&conn->conn_usage_lock); + spin_lock_init(&conn->immed_queue_lock); + spin_lock_init(&conn->nopin_timer_lock); + spin_lock_init(&conn->response_queue_lock); + spin_lock_init(&conn->state_lock); + + timer_setup(&conn->nopin_response_timer, + iscsit_handle_nopin_response_timeout, 0); + timer_setup(&conn->nopin_timer, iscsit_handle_nopin_timeout, 0); + + if (iscsit_conn_set_transport(conn, np->np_transport) < 0) + goto free_conn; + + conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL); + if (!conn->conn_ops) { + pr_err("Unable to allocate memory for struct iscsi_conn_ops.\n"); + goto put_transport; + } + + if (!zalloc_cpumask_var(&conn->conn_cpumask, GFP_KERNEL)) { + pr_err("Unable to allocate conn->conn_cpumask\n"); + goto free_mask; + } + + return conn; + +free_mask: + free_cpumask_var(conn->conn_cpumask); +put_transport: + iscsit_put_transport(conn->conn_transport); +free_conn: + kfree(conn); + return NULL; +} + +void iscsit_free_conn(struct iscsi_conn *conn) +{ + free_cpumask_var(conn->conn_cpumask); + kfree(conn->conn_ops); + iscsit_put_transport(conn->conn_transport); + kfree(conn); +} + void iscsi_target_login_sess_out(struct iscsi_conn *conn, struct iscsi_np *np, bool zero_tsih, bool new_sess) { @@ -1198,10 +1230,6 @@ old_sess_out: crypto_free_ahash(tfm); } - free_cpumask_var(conn->conn_cpumask); - - kfree(conn->conn_ops); - if (conn->param_list) { iscsi_release_param_list(conn->param_list); conn->param_list = NULL; @@ -1219,8 +1247,7 @@ old_sess_out: if (conn->conn_transport->iscsit_free_conn) conn->conn_transport->iscsit_free_conn(conn); - iscsit_put_transport(conn->conn_transport); - kfree(conn); + iscsit_free_conn(conn); } static int __iscsi_target_login_thread(struct iscsi_np *np) @@ -1250,31 +1277,16 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) } spin_unlock_bh(&np->np_thread_lock); - conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL); + conn = iscsit_alloc_conn(np); if (!conn) { - pr_err("Could not allocate memory for" - " new connection\n"); /* Get another socket */ return 1; } - pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); - conn->conn_state = TARG_CONN_STATE_FREE; - - timer_setup(&conn->nopin_response_timer, - iscsit_handle_nopin_response_timeout, 0); - timer_setup(&conn->nopin_timer, iscsit_handle_nopin_timeout, 0); - - if (iscsit_conn_set_transport(conn, np->np_transport) < 0) { - kfree(conn); - return 1; - } rc = np->np_transport->iscsit_accept_np(np, conn); if (rc == -ENOSYS) { complete(&np->np_restart_comp); - iscsit_put_transport(conn->conn_transport); - kfree(conn); - conn = NULL; + iscsit_free_conn(conn); goto exit; } else if (rc < 0) { spin_lock_bh(&np->np_thread_lock); @@ -1282,17 +1294,13 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; spin_unlock_bh(&np->np_thread_lock); complete(&np->np_restart_comp); - iscsit_put_transport(conn->conn_transport); - kfree(conn); - conn = NULL; + iscsit_free_conn(conn); /* Get another socket */ return 1; } spin_unlock_bh(&np->np_thread_lock); - iscsit_put_transport(conn->conn_transport); - kfree(conn); - conn = NULL; - goto out; + iscsit_free_conn(conn); + return 1; } /* * Perform the remaining iSCSI connection initialization items.. @@ -1442,7 +1450,6 @@ old_sess_out: tpg_np = NULL; } -out: return 1; exit: diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h index 74ac3abc44a0..3b8e3639ff5d 100644 --- a/drivers/target/iscsi/iscsi_target_login.h +++ b/drivers/target/iscsi/iscsi_target_login.h @@ -19,7 +19,7 @@ extern int iscsi_target_setup_login_socket(struct iscsi_np *, extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *); extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *); extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32); -extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *); +extern void iscsit_free_conn(struct iscsi_conn *); extern int iscsit_start_kthreads(struct iscsi_conn *); extern void iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8); extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *, diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c index df0a39811dc2..bb98882bdaa7 100644 --- a/drivers/target/iscsi/iscsi_target_stat.c +++ b/drivers/target/iscsi/iscsi_target_stat.c @@ -328,10 +328,10 @@ static ssize_t iscsi_stat_tgt_attr_fail_intr_name_show(struct config_item *item, { struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item); struct iscsi_login_stats *lstat = &tiqn->login_stats; - unsigned char buf[224]; + unsigned char buf[ISCSI_IQN_LEN]; spin_lock(&lstat->lock); - snprintf(buf, 224, "%s", lstat->last_intr_fail_name[0] ? + snprintf(buf, ISCSI_IQN_LEN, "%s", lstat->last_intr_fail_name[0] ? lstat->last_intr_fail_name : NONE); spin_unlock(&lstat->lock); diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 49be1e41290c..1227872227dc 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -915,6 +915,7 @@ static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response) void iscsit_handle_nopin_response_timeout(struct timer_list *t) { struct iscsi_conn *conn = from_timer(conn, t, nopin_response_timer); + struct iscsi_session *sess = conn->sess; iscsit_inc_conn_usage_count(conn); @@ -925,28 +926,14 @@ void iscsit_handle_nopin_response_timeout(struct timer_list *t) return; } - pr_debug("Did not receive response to NOPIN on CID: %hu on" - " SID: %u, failing connection.\n", conn->cid, - conn->sess->sid); + pr_err("Did not receive response to NOPIN on CID: %hu, failing" + " connection for I_T Nexus %s,i,0x%6phN,%s,t,0x%02x\n", + conn->cid, sess->sess_ops->InitiatorName, sess->isid, + sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt); conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING; spin_unlock_bh(&conn->nopin_timer_lock); - { - struct iscsi_portal_group *tpg = conn->sess->tpg; - struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; - - if (tiqn) { - spin_lock_bh(&tiqn->sess_err_stats.lock); - strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name, - conn->sess->sess_ops->InitiatorName); - tiqn->sess_err_stats.last_sess_failure_type = - ISCSI_SESS_ERR_CXN_TIMEOUT; - tiqn->sess_err_stats.cxn_timeout_errors++; - atomic_long_inc(&conn->sess->conn_timeout_errors); - spin_unlock_bh(&tiqn->sess_err_stats.lock); - } - } - + iscsit_fill_cxn_timeout_err_stats(sess); iscsit_cause_connection_reinstatement(conn, 0); iscsit_dec_conn_usage_count(conn); } @@ -1405,3 +1392,22 @@ struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsi_conn *conn) return tpg->tpg_tiqn; } + +void iscsit_fill_cxn_timeout_err_stats(struct iscsi_session *sess) +{ + struct iscsi_portal_group *tpg = sess->tpg; + struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; + + if (!tiqn) + return; + + spin_lock_bh(&tiqn->sess_err_stats.lock); + strlcpy(tiqn->sess_err_stats.last_sess_fail_rem_name, + sess->sess_ops->InitiatorName, + sizeof(tiqn->sess_err_stats.last_sess_fail_rem_name)); + tiqn->sess_err_stats.last_sess_failure_type = + ISCSI_SESS_ERR_CXN_TIMEOUT; + tiqn->sess_err_stats.cxn_timeout_errors++; + atomic_long_inc(&sess->conn_timeout_errors); + spin_unlock_bh(&tiqn->sess_err_stats.lock); +} diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index d66dfc212624..68e84803b0a1 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -67,5 +67,6 @@ extern int rx_data(struct iscsi_conn *, struct kvec *, int, int); extern int tx_data(struct iscsi_conn *, struct kvec *, int, int); extern void iscsit_collect_login_stats(struct iscsi_conn *, u8, u8); extern struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsi_conn *); +extern void iscsit_fill_cxn_timeout_err_stats(struct iscsi_session *); #endif /*** ISCSI_TARGET_UTIL_H ***/ diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index ce1321a5cb7b..b5ed9c377060 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -514,7 +514,7 @@ iblock_execute_write_same(struct se_cmd *cmd) } /* Always in 512 byte units for Linux/Block */ - block_lba += sg->length >> IBLOCK_LBA_SHIFT; + block_lba += sg->length >> SECTOR_SHIFT; sectors -= 1; } @@ -635,14 +635,15 @@ static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b) } static int -iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio) +iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio, + struct sg_mapping_iter *miter) { struct se_device *dev = cmd->se_dev; struct blk_integrity *bi; struct bio_integrity_payload *bip; struct iblock_dev *ib_dev = IBLOCK_DEV(dev); - struct scatterlist *sg; - int i, rc; + int rc; + size_t resid, len; bi = bdev_get_integrity(ib_dev->ibd_bd); if (!bi) { @@ -650,31 +651,39 @@ iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio) return -ENODEV; } - bip = bio_integrity_alloc(bio, GFP_NOIO, cmd->t_prot_nents); + bip = bio_integrity_alloc(bio, GFP_NOIO, + min_t(unsigned int, cmd->t_prot_nents, BIO_MAX_PAGES)); if (IS_ERR(bip)) { pr_err("Unable to allocate bio_integrity_payload\n"); return PTR_ERR(bip); } - bip->bip_iter.bi_size = (cmd->data_length / dev->dev_attrib.block_size) * - dev->prot_length; - bip->bip_iter.bi_sector = bio->bi_iter.bi_sector; + bip->bip_iter.bi_size = bio_integrity_bytes(bi, bio_sectors(bio)); + bip_set_seed(bip, bio->bi_iter.bi_sector); pr_debug("IBLOCK BIP Size: %u Sector: %llu\n", bip->bip_iter.bi_size, (unsigned long long)bip->bip_iter.bi_sector); - for_each_sg(cmd->t_prot_sg, sg, cmd->t_prot_nents, i) { + resid = bip->bip_iter.bi_size; + while (resid > 0 && sg_miter_next(miter)) { - rc = bio_integrity_add_page(bio, sg_page(sg), sg->length, - sg->offset); - if (rc != sg->length) { + len = min_t(size_t, miter->length, resid); + rc = bio_integrity_add_page(bio, miter->page, len, + offset_in_page(miter->addr)); + if (rc != len) { pr_err("bio_integrity_add_page() failed; %d\n", rc); + sg_miter_stop(miter); return -ENOMEM; } - pr_debug("Added bio integrity page: %p length: %d offset; %d\n", - sg_page(sg), sg->length, sg->offset); + pr_debug("Added bio integrity page: %p length: %zu offset: %lu\n", + miter->page, len, offset_in_page(miter->addr)); + + resid -= len; + if (len < miter->length) + miter->consumed -= miter->length - len; } + sg_miter_stop(miter); return 0; } @@ -686,12 +695,13 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, struct se_device *dev = cmd->se_dev; sector_t block_lba = target_to_linux_sector(dev, cmd->t_task_lba); struct iblock_req *ibr; - struct bio *bio, *bio_start; + struct bio *bio; struct bio_list list; struct scatterlist *sg; u32 sg_num = sgl_nents; unsigned bio_cnt; - int i, op, op_flags = 0; + int i, rc, op, op_flags = 0; + struct sg_mapping_iter prot_miter; if (data_direction == DMA_TO_DEVICE) { struct iblock_dev *ib_dev = IBLOCK_DEV(dev); @@ -726,13 +736,17 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, if (!bio) goto fail_free_ibr; - bio_start = bio; bio_list_init(&list); bio_list_add(&list, bio); refcount_set(&ibr->pending, 2); bio_cnt = 1; + if (cmd->prot_type && dev->dev_attrib.pi_prot_type) + sg_miter_start(&prot_miter, cmd->t_prot_sg, cmd->t_prot_nents, + op == REQ_OP_READ ? SG_MITER_FROM_SG : + SG_MITER_TO_SG); + for_each_sg(sgl, sg, sgl_nents, i) { /* * XXX: if the length the device accepts is shorter than the @@ -741,6 +755,12 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, */ while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset) != sg->length) { + if (cmd->prot_type && dev->dev_attrib.pi_prot_type) { + rc = iblock_alloc_bip(cmd, bio, &prot_miter); + if (rc) + goto fail_put_bios; + } + if (bio_cnt >= IBLOCK_MAX_BIO_PER_TASK) { iblock_submit_bios(&list); bio_cnt = 0; @@ -757,12 +777,12 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, } /* Always in 512 byte units for Linux/Block */ - block_lba += sg->length >> IBLOCK_LBA_SHIFT; + block_lba += sg->length >> SECTOR_SHIFT; sg_num--; } if (cmd->prot_type && dev->dev_attrib.pi_prot_type) { - int rc = iblock_alloc_bip(cmd, bio_start); + rc = iblock_alloc_bip(cmd, bio, &prot_miter); if (rc) goto fail_put_bios; } diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h index 9cc3843404d4..cefc641145b3 100644 --- a/drivers/target/target_core_iblock.h +++ b/drivers/target/target_core_iblock.h @@ -9,7 +9,6 @@ #define IBLOCK_VERSION "4.0" #define IBLOCK_MAX_CDBS 16 -#define IBLOCK_LBA_SHIFT 9 struct iblock_req { refcount_t pending; diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index ebac2b49b9c6..1ac1f7d2e6c9 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -360,6 +360,10 @@ static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success, unsigned int offset; sense_reason_t ret = TCM_NO_SENSE; int i, count; + + if (!success) + return 0; + /* * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command * @@ -425,14 +429,8 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success, struct se_device *dev = cmd->se_dev; sense_reason_t ret = TCM_NO_SENSE; - /* - * Only set SCF_COMPARE_AND_WRITE_POST to force a response fall-through - * within target_complete_ok_work() if the command was successfully - * sent to the backend driver. - */ spin_lock_irq(&cmd->t_state_lock); - if (cmd->transport_state & CMD_T_SENT) { - cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST; + if (success) { *post_ret = 1; if (cmd->scsi_status == SAM_STAT_CHECK_CONDITION) @@ -453,7 +451,8 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes int *post_ret) { struct se_device *dev = cmd->se_dev; - struct scatterlist *write_sg = NULL, *sg; + struct sg_table write_tbl = { }; + struct scatterlist *write_sg, *sg; unsigned char *buf = NULL, *addr; struct sg_mapping_iter m; unsigned int offset = 0, len; @@ -494,14 +493,12 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes goto out; } - write_sg = kmalloc_array(cmd->t_data_nents, sizeof(*write_sg), - GFP_KERNEL); - if (!write_sg) { + if (sg_alloc_table(&write_tbl, cmd->t_data_nents, GFP_KERNEL) < 0) { pr_err("Unable to allocate compare_and_write sg\n"); ret = TCM_OUT_OF_RESOURCES; goto out; } - sg_init_table(write_sg, cmd->t_data_nents); + write_sg = write_tbl.sgl; /* * Setup verify and write data payloads from total NumberLBAs. */ @@ -597,7 +594,7 @@ out: * sbc_compare_and_write() before the original READ I/O submission. */ up(&dev->caw_sem); - kfree(write_sg); + sg_free_table(&write_tbl); kfree(buf); return ret; } diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index cb0461a10808..f459118bc11b 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -636,9 +636,9 @@ spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) /* * The unmap_zeroes_data set means that the underlying device supports - * REQ_DISCARD and has the discard_zeroes_data bit set. This satisfies - * the SBC requirements for LBPRZ, meaning that a subsequent read - * will return zeroes after an UNMAP or WRITE SAME (16) to an LBA + * REQ_OP_DISCARD and has the discard_zeroes_data bit set. This + * satisfies the SBC requirements for LBPRZ, meaning that a subsequent + * read will return zeroes after an UNMAP or WRITE SAME (16) to an LBA * See sbc4r36 6.6.4. */ if (((dev->dev_attrib.emulate_tpu != 0) || diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 86c0156e6c88..4cf33e2cc705 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1778,7 +1778,7 @@ EXPORT_SYMBOL(target_submit_tmr); void transport_generic_request_failure(struct se_cmd *cmd, sense_reason_t sense_reason) { - int ret = 0, post_ret = 0; + int ret = 0; pr_debug("-----[ Storage Engine Exception; sense_reason %d\n", sense_reason); @@ -1789,13 +1789,8 @@ void transport_generic_request_failure(struct se_cmd *cmd, */ transport_complete_task_attr(cmd); - /* - * Handle special case for COMPARE_AND_WRITE failure, where the - * callback is expected to drop the per device ->caw_sem. - */ - if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && - cmd->transport_complete_callback) - cmd->transport_complete_callback(cmd, false, &post_ret); + if (cmd->transport_complete_callback) + cmd->transport_complete_callback(cmd, false, NULL); if (transport_check_aborted_status(cmd, 1)) return; @@ -2012,7 +2007,7 @@ void target_execute_cmd(struct se_cmd *cmd) * Determine if frontend context caller is requesting the stopping of * this command for frontend exceptions. * - * If the received CDB has aleady been aborted stop processing it here. + * If the received CDB has already been aborted stop processing it here. */ spin_lock_irq(&cmd->t_state_lock); if (__transport_check_aborted_status(cmd, 1)) { @@ -2516,7 +2511,7 @@ transport_generic_new_cmd(struct se_cmd *cmd) } /* - * Determine is the TCM fabric module has already allocated physical + * Determine if the TCM fabric module has already allocated physical * memory, and is directly calling transport_generic_map_mem_to_cmd() * beforehand. */ @@ -2754,7 +2749,7 @@ static void target_release_cmd_kref(struct kref *kref) if (se_sess) { spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); list_del_init(&se_cmd->se_cmd_list); - if (list_empty(&se_sess->sess_cmd_list)) + if (se_sess->sess_tearing_down && list_empty(&se_sess->sess_cmd_list)) wake_up(&se_sess->cmd_list_wq); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); } @@ -2907,7 +2902,7 @@ void target_wait_for_sess_cmds(struct se_session *se_sess) spin_lock_irq(&se_sess->sess_cmd_lock); do { - ret = wait_event_interruptible_lock_irq_timeout( + ret = wait_event_lock_irq_timeout( se_sess->cmd_list_wq, list_empty(&se_sess->sess_cmd_list), se_sess->sess_cmd_lock, 180 * HZ); diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 2718a933c0c6..70adcfdca8d1 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -391,7 +391,6 @@ out: struct xcopy_pt_cmd { bool remote_port; struct se_cmd se_cmd; - struct xcopy_op *xcopy_op; struct completion xpt_passthrough_sem; unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER]; }; @@ -596,8 +595,6 @@ static int target_xcopy_setup_pt_cmd( * X-COPY PUSH or X-COPY PULL based upon where the CDB was received. */ target_xcopy_init_pt_lun(se_dev, cmd, remote_port); - - xpt_cmd->xcopy_op = xop; target_xcopy_setup_pt_port(xpt_cmd, xop, remote_port); cmd->tag = 0; |