aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2013-05-31 03:49:41 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2013-05-31 04:21:28 -0400
commitaafc9d158b0039e600fc429246c7bb04a111fb26 (patch)
treea570c77c9cbd92b3b8a7fb7892bab519119dae92
parentd5ddad4168348337d98d6b8f156a3892de444411 (diff)
iscsi-target: Fix iscsit_free_cmd() se_cmd->cmd_kref shutdown handling
With the introduction of target_get_sess_cmd() referencing counting for ISCSI_OP_SCSI_CMD processing with iser-target, iscsit_free_cmd() usage in traditional iscsi-target driver code now needs to be aware of the active I/O shutdown case when a remaining se_cmd->cmd_kref reference may exist after transport_generic_free_cmd() completes, requiring a final target_put_sess_cmd() to release iscsi_cmd descriptor memory. This patch changes iscsit_free_cmd() to invoke __iscsit_free_cmd() before transport_generic_free_cmd() -> target_put_sess_cmd(), and also avoids aquiring the per-connection queue locks for typical fast-path calls during normal ISTATE_REMOVE operation. Also update iscsit_free_cmd() usage throughout iscsi-target to use the new 'bool shutdown' parameter. This patch fixes a regression bug introduced during v3.10-rc1 in commit 3e1c81a95, that was causing the following WARNING to appear: [ 257.235153] ------------[ cut here]------------ [ 257.240314] WARNING: at kernel/softirq.c:160 local_bh_enable_ip+0x3c/0x86() [ 257.248089] Modules linked in: vhost_scsi ib_srpt ib_cm ib_sa ib_mad ib_core tcm_qla2xxx tcm_loop tcm_fc libfc iscsi_target_mod target_core_pscsi target_core_file target_core_iblock target_core_mod configfs ipv6 iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi loop acpi_cpufreq freq_table mperf kvm_intel kvm crc32c_intel button ehci_pci pcspkr joydev i2c_i801 microcode ext3 jbd raid10 raid456 async_pq async_xor xor async_memcpy async_raid6_recov raid6_pq async_tx raid1 raid0 linear igb hwmon i2c_algo_bit i2c_core ptp ata_piix libata qla2xxx uhci_hcd ehci_hcd mlx4_core scsi_transport_fc scsi_tgt pps_core [ 257.308748] CPU: 1 PID: 3295 Comm: iscsi_ttx Not tainted 3.10.0-rc2+ #103 [ 257.316329] Hardware name: Intel Corporation S5520HC/S5520HC, BIOS S5500.86B.01.00.0057.031020111721 03/10/2011 [ 257.327597] ffffffff814c24b7 ffff880458331b58 ffffffff8138eef2 ffff880458331b98 [ 257.335892] ffffffff8102c052 ffff880400000008 0000000000000000 ffff88085bdf0000 [ 257.344191] ffff88085bdf00d8 ffff88085bdf00e0 ffff88085bdf00f8 ffff880458331ba8 [ 257.352488] Call Trace: [ 257.355223] [<ffffffff8138eef2>] dump_stack+0x19/0x1f [ 257.360963] [<ffffffff8102c052>] warn_slowpath_common+0x62/0x7b [ 257.367669] [<ffffffff8102c080>] warn_slowpath_null+0x15/0x17 [ 257.374181] [<ffffffff81032345>] local_bh_enable_ip+0x3c/0x86 [ 257.380697] [<ffffffff813917fd>] _raw_spin_unlock_bh+0x10/0x12 [ 257.387311] [<ffffffffa029069c>] iscsit_free_r2ts_from_list+0x5e/0x67 [iscsi_target_mod] [ 257.396438] [<ffffffffa02906c5>] iscsit_release_cmd+0x20/0x223 [iscsi_target_mod] [ 257.404893] [<ffffffffa02977a4>] lio_release_cmd+0x3a/0x3e [iscsi_target_mod] [ 257.412964] [<ffffffffa01d59a1>] target_release_cmd_kref+0x7a/0x7c [target_core_mod] [ 257.421712] [<ffffffffa01d69bc>] target_put_sess_cmd+0x5f/0x7f [target_core_mod] [ 257.430071] [<ffffffffa01d6d6d>] transport_release_cmd+0x59/0x6f [target_core_mod] [ 257.438625] [<ffffffffa01d6eb4>] transport_put_cmd+0x131/0x140 [target_core_mod] [ 257.446985] [<ffffffffa01d6192>] ? transport_wait_for_tasks+0xfa/0x1d5 [target_core_mod] [ 257.456121] [<ffffffffa01d6f11>] transport_generic_free_cmd+0x4e/0x52 [target_core_mod] [ 257.465159] [<ffffffff81050537>] ? __migrate_task+0x110/0x110 [ 257.471674] [<ffffffffa02904ba>] iscsit_free_cmd+0x46/0x55 [iscsi_target_mod] [ 257.479741] [<ffffffffa0291edb>] iscsit_immediate_queue+0x301/0x353 [iscsi_target_mod] [ 257.488683] [<ffffffffa0292f7e>] iscsi_target_tx_thread+0x1c6/0x2a8 [iscsi_target_mod] [ 257.497623] [<ffffffff81047486>] ? wake_up_bit+0x25/0x25 [ 257.503652] [<ffffffffa0292db8>] ? iscsit_ack_from_expstatsn+0xd5/0xd5 [iscsi_target_mod] [ 257.512882] [<ffffffff81046f89>] kthread+0xb0/0xb8 [ 257.518329] [<ffffffff81046ed9>] ? kthread_freezable_should_stop+0x60/0x60 [ 257.526105] [<ffffffff81396fec>] ret_from_fork+0x7c/0xb0 [ 257.532133] [<ffffffff81046ed9>] ? kthread_freezable_should_stop+0x60/0x60 [ 257.539906] ---[ end trace 5520397d0f2e0800 ]--- Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/target/iscsi/iscsi_target.c12
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.c12
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c50
-rw-r--r--drivers/target/iscsi/iscsi_target_util.h2
4 files changed, 50 insertions, 26 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 262ef1f23b38..d7705e5824fb 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -651,7 +651,7 @@ static int iscsit_add_reject(
651 cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL); 651 cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);
652 if (!cmd->buf_ptr) { 652 if (!cmd->buf_ptr) {
653 pr_err("Unable to allocate memory for cmd->buf_ptr\n"); 653 pr_err("Unable to allocate memory for cmd->buf_ptr\n");
654 iscsit_release_cmd(cmd); 654 iscsit_free_cmd(cmd, false);
655 return -1; 655 return -1;
656 } 656 }
657 657
@@ -697,7 +697,7 @@ int iscsit_add_reject_from_cmd(
697 cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL); 697 cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);
698 if (!cmd->buf_ptr) { 698 if (!cmd->buf_ptr) {
699 pr_err("Unable to allocate memory for cmd->buf_ptr\n"); 699 pr_err("Unable to allocate memory for cmd->buf_ptr\n");
700 iscsit_release_cmd(cmd); 700 iscsit_free_cmd(cmd, false);
701 return -1; 701 return -1;
702 } 702 }
703 703
@@ -1743,7 +1743,7 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
1743 return 0; 1743 return 0;
1744out: 1744out:
1745 if (cmd) 1745 if (cmd)
1746 iscsit_release_cmd(cmd); 1746 iscsit_free_cmd(cmd, false);
1747ping_out: 1747ping_out:
1748 kfree(ping_data); 1748 kfree(ping_data);
1749 return ret; 1749 return ret;
@@ -2251,7 +2251,7 @@ iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
2251 if (conn->conn_state != TARG_CONN_STATE_LOGGED_IN) { 2251 if (conn->conn_state != TARG_CONN_STATE_LOGGED_IN) {
2252 pr_err("Received logout request on connection that" 2252 pr_err("Received logout request on connection that"
2253 " is not in logged in state, ignoring request.\n"); 2253 " is not in logged in state, ignoring request.\n");
2254 iscsit_release_cmd(cmd); 2254 iscsit_free_cmd(cmd, false);
2255 return 0; 2255 return 0;
2256 } 2256 }
2257 2257
@@ -3665,7 +3665,7 @@ iscsit_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state
3665 list_del(&cmd->i_conn_node); 3665 list_del(&cmd->i_conn_node);
3666 spin_unlock_bh(&conn->cmd_lock); 3666 spin_unlock_bh(&conn->cmd_lock);
3667 3667
3668 iscsit_free_cmd(cmd); 3668 iscsit_free_cmd(cmd, false);
3669 break; 3669 break;
3670 case ISTATE_SEND_NOPIN_WANT_RESPONSE: 3670 case ISTATE_SEND_NOPIN_WANT_RESPONSE:
3671 iscsit_mod_nopin_response_timer(conn); 3671 iscsit_mod_nopin_response_timer(conn);
@@ -4122,7 +4122,7 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
4122 4122
4123 iscsit_increment_maxcmdsn(cmd, sess); 4123 iscsit_increment_maxcmdsn(cmd, sess);
4124 4124
4125 iscsit_free_cmd(cmd); 4125 iscsit_free_cmd(cmd, true);
4126 4126
4127 spin_lock_bh(&conn->cmd_lock); 4127 spin_lock_bh(&conn->cmd_lock);
4128 } 4128 }
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c
index ba6091bf93fc..45a5afd5ea13 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.c
+++ b/drivers/target/iscsi/iscsi_target_erl2.c
@@ -143,7 +143,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
143 list_del(&cmd->i_conn_node); 143 list_del(&cmd->i_conn_node);
144 cmd->conn = NULL; 144 cmd->conn = NULL;
145 spin_unlock(&cr->conn_recovery_cmd_lock); 145 spin_unlock(&cr->conn_recovery_cmd_lock);
146 iscsit_free_cmd(cmd); 146 iscsit_free_cmd(cmd, true);
147 spin_lock(&cr->conn_recovery_cmd_lock); 147 spin_lock(&cr->conn_recovery_cmd_lock);
148 } 148 }
149 spin_unlock(&cr->conn_recovery_cmd_lock); 149 spin_unlock(&cr->conn_recovery_cmd_lock);
@@ -165,7 +165,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
165 list_del(&cmd->i_conn_node); 165 list_del(&cmd->i_conn_node);
166 cmd->conn = NULL; 166 cmd->conn = NULL;
167 spin_unlock(&cr->conn_recovery_cmd_lock); 167 spin_unlock(&cr->conn_recovery_cmd_lock);
168 iscsit_free_cmd(cmd); 168 iscsit_free_cmd(cmd, true);
169 spin_lock(&cr->conn_recovery_cmd_lock); 169 spin_lock(&cr->conn_recovery_cmd_lock);
170 } 170 }
171 spin_unlock(&cr->conn_recovery_cmd_lock); 171 spin_unlock(&cr->conn_recovery_cmd_lock);
@@ -248,7 +248,7 @@ void iscsit_discard_cr_cmds_by_expstatsn(
248 iscsit_remove_cmd_from_connection_recovery(cmd, sess); 248 iscsit_remove_cmd_from_connection_recovery(cmd, sess);
249 249
250 spin_unlock(&cr->conn_recovery_cmd_lock); 250 spin_unlock(&cr->conn_recovery_cmd_lock);
251 iscsit_free_cmd(cmd); 251 iscsit_free_cmd(cmd, true);
252 spin_lock(&cr->conn_recovery_cmd_lock); 252 spin_lock(&cr->conn_recovery_cmd_lock);
253 } 253 }
254 spin_unlock(&cr->conn_recovery_cmd_lock); 254 spin_unlock(&cr->conn_recovery_cmd_lock);
@@ -302,7 +302,7 @@ int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn)
302 list_del(&cmd->i_conn_node); 302 list_del(&cmd->i_conn_node);
303 303
304 spin_unlock_bh(&conn->cmd_lock); 304 spin_unlock_bh(&conn->cmd_lock);
305 iscsit_free_cmd(cmd); 305 iscsit_free_cmd(cmd, true);
306 spin_lock_bh(&conn->cmd_lock); 306 spin_lock_bh(&conn->cmd_lock);
307 } 307 }
308 spin_unlock_bh(&conn->cmd_lock); 308 spin_unlock_bh(&conn->cmd_lock);
@@ -355,7 +355,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
355 355
356 list_del(&cmd->i_conn_node); 356 list_del(&cmd->i_conn_node);
357 spin_unlock_bh(&conn->cmd_lock); 357 spin_unlock_bh(&conn->cmd_lock);
358 iscsit_free_cmd(cmd); 358 iscsit_free_cmd(cmd, true);
359 spin_lock_bh(&conn->cmd_lock); 359 spin_lock_bh(&conn->cmd_lock);
360 continue; 360 continue;
361 } 361 }
@@ -375,7 +375,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
375 iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) { 375 iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) {
376 list_del(&cmd->i_conn_node); 376 list_del(&cmd->i_conn_node);
377 spin_unlock_bh(&conn->cmd_lock); 377 spin_unlock_bh(&conn->cmd_lock);
378 iscsit_free_cmd(cmd); 378 iscsit_free_cmd(cmd, true);
379 spin_lock_bh(&conn->cmd_lock); 379 spin_lock_bh(&conn->cmd_lock);
380 continue; 380 continue;
381 } 381 }
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 2cc6c9a3ffb8..08a3bacef0c5 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -676,40 +676,56 @@ void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
676 676
677void iscsit_release_cmd(struct iscsi_cmd *cmd) 677void iscsit_release_cmd(struct iscsi_cmd *cmd)
678{ 678{
679 struct iscsi_conn *conn = cmd->conn;
680
681 iscsit_free_r2ts_from_list(cmd);
682 iscsit_free_all_datain_reqs(cmd);
683
684 kfree(cmd->buf_ptr); 679 kfree(cmd->buf_ptr);
685 kfree(cmd->pdu_list); 680 kfree(cmd->pdu_list);
686 kfree(cmd->seq_list); 681 kfree(cmd->seq_list);
687 kfree(cmd->tmr_req); 682 kfree(cmd->tmr_req);
688 kfree(cmd->iov_data); 683 kfree(cmd->iov_data);
689 684
690 if (conn) { 685 kmem_cache_free(lio_cmd_cache, cmd);
686}
687
688static void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd,
689 bool check_queues)
690{
691 struct iscsi_conn *conn = cmd->conn;
692
693 if (scsi_cmd) {
694 if (cmd->data_direction == DMA_TO_DEVICE) {
695 iscsit_stop_dataout_timer(cmd);
696 iscsit_free_r2ts_from_list(cmd);
697 }
698 if (cmd->data_direction == DMA_FROM_DEVICE)
699 iscsit_free_all_datain_reqs(cmd);
700 }
701
702 if (conn && check_queues) {
691 iscsit_remove_cmd_from_immediate_queue(cmd, conn); 703 iscsit_remove_cmd_from_immediate_queue(cmd, conn);
692 iscsit_remove_cmd_from_response_queue(cmd, conn); 704 iscsit_remove_cmd_from_response_queue(cmd, conn);
693 } 705 }
694
695 kmem_cache_free(lio_cmd_cache, cmd);
696} 706}
697 707
698void iscsit_free_cmd(struct iscsi_cmd *cmd) 708void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
699{ 709{
710 struct se_cmd *se_cmd = NULL;
711 int rc;
700 /* 712 /*
701 * Determine if a struct se_cmd is associated with 713 * Determine if a struct se_cmd is associated with
702 * this struct iscsi_cmd. 714 * this struct iscsi_cmd.
703 */ 715 */
704 switch (cmd->iscsi_opcode) { 716 switch (cmd->iscsi_opcode) {
705 case ISCSI_OP_SCSI_CMD: 717 case ISCSI_OP_SCSI_CMD:
706 if (cmd->data_direction == DMA_TO_DEVICE) 718 se_cmd = &cmd->se_cmd;
707 iscsit_stop_dataout_timer(cmd); 719 __iscsit_free_cmd(cmd, true, shutdown);
708 /* 720 /*
709 * Fallthrough 721 * Fallthrough
710 */ 722 */
711 case ISCSI_OP_SCSI_TMFUNC: 723 case ISCSI_OP_SCSI_TMFUNC:
712 transport_generic_free_cmd(&cmd->se_cmd, 1); 724 rc = transport_generic_free_cmd(&cmd->se_cmd, 1);
725 if (!rc && shutdown && se_cmd && se_cmd->se_sess) {
726 __iscsit_free_cmd(cmd, true, shutdown);
727 target_put_sess_cmd(se_cmd->se_sess, se_cmd);
728 }
713 break; 729 break;
714 case ISCSI_OP_REJECT: 730 case ISCSI_OP_REJECT:
715 /* 731 /*
@@ -718,11 +734,19 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd)
718 * associated cmd->se_cmd needs to be released. 734 * associated cmd->se_cmd needs to be released.
719 */ 735 */
720 if (cmd->se_cmd.se_tfo != NULL) { 736 if (cmd->se_cmd.se_tfo != NULL) {
721 transport_generic_free_cmd(&cmd->se_cmd, 1); 737 se_cmd = &cmd->se_cmd;
738 __iscsit_free_cmd(cmd, true, shutdown);
739
740 rc = transport_generic_free_cmd(&cmd->se_cmd, 1);
741 if (!rc && shutdown && se_cmd->se_sess) {
742 __iscsit_free_cmd(cmd, true, shutdown);
743 target_put_sess_cmd(se_cmd->se_sess, se_cmd);
744 }
722 break; 745 break;
723 } 746 }
724 /* Fall-through */ 747 /* Fall-through */
725 default: 748 default:
749 __iscsit_free_cmd(cmd, false, shutdown);
726 cmd->release_cmd(cmd); 750 cmd->release_cmd(cmd);
727 break; 751 break;
728 } 752 }
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
index 4f8e01a47081..a4422659d049 100644
--- a/drivers/target/iscsi/iscsi_target_util.h
+++ b/drivers/target/iscsi/iscsi_target_util.h
@@ -29,7 +29,7 @@ extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_co
29extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *); 29extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *);
30extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *); 30extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
31extern void iscsit_release_cmd(struct iscsi_cmd *); 31extern void iscsit_release_cmd(struct iscsi_cmd *);
32extern void iscsit_free_cmd(struct iscsi_cmd *); 32extern void iscsit_free_cmd(struct iscsi_cmd *, bool);
33extern int iscsit_check_session_usage_count(struct iscsi_session *); 33extern int iscsit_check_session_usage_count(struct iscsi_session *);
34extern void iscsit_dec_session_usage_count(struct iscsi_session *); 34extern void iscsit_dec_session_usage_count(struct iscsi_session *);
35extern void iscsit_inc_session_usage_count(struct iscsi_session *); 35extern void iscsit_inc_session_usage_count(struct iscsi_session *);