diff options
author | Bart Van Assche <bart.vanassche@sandisk.com> | 2015-10-22 18:57:04 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-11-28 22:33:23 -0500 |
commit | 9ff9d15eddd13ecdd41876c5e1f31ddbb127101c (patch) | |
tree | e35ea2052e32575dd726e0827b4214f80c82d7c4 | |
parent | 057085e522f8bf94c2e691a5b76880f68060f8ba (diff) |
target: Invoke release_cmd() callback without holding a spinlock
This patch fixes the following kernel warning because it avoids that
IRQs are disabled while ft_release_cmd() is invoked (fc_seq_set_resp()
invokes spin_unlock_bh()):
WARNING: CPU: 3 PID: 117 at kernel/softirq.c:150 __local_bh_enable_ip+0xaa/0x110()
Call Trace:
[<ffffffff814f71eb>] dump_stack+0x4f/0x7b
[<ffffffff8105e56a>] warn_slowpath_common+0x8a/0xc0
[<ffffffff8105e65a>] warn_slowpath_null+0x1a/0x20
[<ffffffff81062b2a>] __local_bh_enable_ip+0xaa/0x110
[<ffffffff814ff229>] _raw_spin_unlock_bh+0x39/0x40
[<ffffffffa03a7f94>] fc_seq_set_resp+0xe4/0x100 [libfc]
[<ffffffffa02e604a>] ft_free_cmd+0x4a/0x90 [tcm_fc]
[<ffffffffa02e6972>] ft_release_cmd+0x12/0x20 [tcm_fc]
[<ffffffffa042bd66>] target_release_cmd_kref+0x56/0x90 [target_core_mod]
[<ffffffffa042caf0>] target_put_sess_cmd+0xc0/0x110 [target_core_mod]
[<ffffffffa042cb81>] transport_release_cmd+0x41/0x70 [target_core_mod]
[<ffffffffa042d975>] transport_generic_free_cmd+0x35/0x420 [target_core_mod]
Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
Acked-by: Joern Engel <joern@logfs.org>
Reviewed-by: Andy Grover <agrover@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Sagi Grimberg <sagig@mellanox.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/target/target_core_tmr.c | 7 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 12 |
2 files changed, 12 insertions, 7 deletions
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 5b2820312310..28fb3016370f 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c | |||
@@ -130,6 +130,9 @@ void core_tmr_abort_task( | |||
130 | if (tmr->ref_task_tag != ref_tag) | 130 | if (tmr->ref_task_tag != ref_tag) |
131 | continue; | 131 | continue; |
132 | 132 | ||
133 | if (!kref_get_unless_zero(&se_cmd->cmd_kref)) | ||
134 | continue; | ||
135 | |||
133 | printk("ABORT_TASK: Found referenced %s task_tag: %llu\n", | 136 | printk("ABORT_TASK: Found referenced %s task_tag: %llu\n", |
134 | se_cmd->se_tfo->get_fabric_name(), ref_tag); | 137 | se_cmd->se_tfo->get_fabric_name(), ref_tag); |
135 | 138 | ||
@@ -139,13 +142,15 @@ void core_tmr_abort_task( | |||
139 | " skipping\n", ref_tag); | 142 | " skipping\n", ref_tag); |
140 | spin_unlock(&se_cmd->t_state_lock); | 143 | spin_unlock(&se_cmd->t_state_lock); |
141 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); | 144 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); |
145 | |||
146 | target_put_sess_cmd(se_cmd); | ||
147 | |||
142 | goto out; | 148 | goto out; |
143 | } | 149 | } |
144 | se_cmd->transport_state |= CMD_T_ABORTED; | 150 | se_cmd->transport_state |= CMD_T_ABORTED; |
145 | spin_unlock(&se_cmd->t_state_lock); | 151 | spin_unlock(&se_cmd->t_state_lock); |
146 | 152 | ||
147 | list_del_init(&se_cmd->se_cmd_list); | 153 | list_del_init(&se_cmd->se_cmd_list); |
148 | kref_get(&se_cmd->cmd_kref); | ||
149 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); | 154 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); |
150 | 155 | ||
151 | cancel_work_sync(&se_cmd->work); | 156 | cancel_work_sync(&se_cmd->work); |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 010b8c46f1ef..4fdcee2006d1 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -2509,23 +2509,24 @@ out: | |||
2509 | EXPORT_SYMBOL(target_get_sess_cmd); | 2509 | EXPORT_SYMBOL(target_get_sess_cmd); |
2510 | 2510 | ||
2511 | static void target_release_cmd_kref(struct kref *kref) | 2511 | static void target_release_cmd_kref(struct kref *kref) |
2512 | __releases(&se_cmd->se_sess->sess_cmd_lock) | ||
2513 | { | 2512 | { |
2514 | struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref); | 2513 | struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref); |
2515 | struct se_session *se_sess = se_cmd->se_sess; | 2514 | struct se_session *se_sess = se_cmd->se_sess; |
2515 | unsigned long flags; | ||
2516 | 2516 | ||
2517 | spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); | ||
2517 | if (list_empty(&se_cmd->se_cmd_list)) { | 2518 | if (list_empty(&se_cmd->se_cmd_list)) { |
2518 | spin_unlock(&se_sess->sess_cmd_lock); | 2519 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); |
2519 | se_cmd->se_tfo->release_cmd(se_cmd); | 2520 | se_cmd->se_tfo->release_cmd(se_cmd); |
2520 | return; | 2521 | return; |
2521 | } | 2522 | } |
2522 | if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) { | 2523 | if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) { |
2523 | spin_unlock(&se_sess->sess_cmd_lock); | 2524 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); |
2524 | complete(&se_cmd->cmd_wait_comp); | 2525 | complete(&se_cmd->cmd_wait_comp); |
2525 | return; | 2526 | return; |
2526 | } | 2527 | } |
2527 | list_del(&se_cmd->se_cmd_list); | 2528 | list_del(&se_cmd->se_cmd_list); |
2528 | spin_unlock(&se_sess->sess_cmd_lock); | 2529 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); |
2529 | 2530 | ||
2530 | se_cmd->se_tfo->release_cmd(se_cmd); | 2531 | se_cmd->se_tfo->release_cmd(se_cmd); |
2531 | } | 2532 | } |
@@ -2541,8 +2542,7 @@ int target_put_sess_cmd(struct se_cmd *se_cmd) | |||
2541 | se_cmd->se_tfo->release_cmd(se_cmd); | 2542 | se_cmd->se_tfo->release_cmd(se_cmd); |
2542 | return 1; | 2543 | return 1; |
2543 | } | 2544 | } |
2544 | return kref_put_spinlock_irqsave(&se_cmd->cmd_kref, target_release_cmd_kref, | 2545 | return kref_put(&se_cmd->cmd_kref, target_release_cmd_kref); |
2545 | &se_sess->sess_cmd_lock); | ||
2546 | } | 2546 | } |
2547 | EXPORT_SYMBOL(target_put_sess_cmd); | 2547 | EXPORT_SYMBOL(target_put_sess_cmd); |
2548 | 2548 | ||