Skip to content

Commit 0f4a943

Browse files
author
Nicholas Bellinger
committed
target: Fix remote-port TMR ABORT + se_cmd fabric stop
To address the bug where fabric driver level shutdown of se_cmd occurs at the same time when TMR CMD_T_ABORTED is happening resulting in a -1 ->cmd_kref, this patch adds a CMD_T_FABRIC_STOP bit that is used to determine when TMR + driver I_T nexus shutdown is happening concurrently. It changes target_sess_cmd_list_set_waiting() to obtain se_cmd->cmd_kref + set CMD_T_FABRIC_STOP, and drop local reference in target_wait_for_sess_cmds() and invoke extra target_put_sess_cmd() during Task Aborted Status (TAS) when necessary. Also, it adds a new target_wait_free_cmd() wrapper around transport_wait_for_tasks() for the special case within transport_generic_free_cmd() to set CMD_T_FABRIC_STOP, and is now aware of CMD_T_ABORTED + CMD_T_TAS status bits to know when an extra transport_put_cmd() during TAS is required. Note transport_generic_free_cmd() is expected to block on cmd->cmd_wait_comp in order to follow what iscsi-target expects during iscsi_conn context se_cmd shutdown. Cc: Quinn Tran <quinn.tran@qlogic.com> Cc: Himanshu Madhani <himanshu.madhani@qlogic.com> Cc: Sagi Grimberg <sagig@mellanox.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Hannes Reinecke <hare@suse.de> Cc: Andy Grover <agrover@redhat.com> Cc: Mike Christie <mchristi@redhat.com> Cc: stable@vger.kernel.org # 3.10+ Signed-off-by: Nicholas Bellinger <nab@daterainc.com>
1 parent ebde1ca commit 0f4a943

File tree

3 files changed

+150
-51
lines changed

3 files changed

+150
-51
lines changed

drivers/target/target_core_tmr.c

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,18 @@ void core_tmr_release_req(struct se_tmr_req *tmr)
7575
kfree(tmr);
7676
}
7777

78-
static void core_tmr_handle_tas_abort(
79-
struct se_session *tmr_sess,
80-
struct se_cmd *cmd,
81-
int tas)
78+
static void core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas)
8279
{
83-
bool remove = true;
80+
unsigned long flags;
81+
bool remove = true, send_tas;
8482
/*
8583
* TASK ABORTED status (TAS) bit support
8684
*/
87-
if (tmr_sess && tmr_sess != cmd->se_sess && tas) {
85+
spin_lock_irqsave(&cmd->t_state_lock, flags);
86+
send_tas = (cmd->transport_state & CMD_T_TAS);
87+
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
88+
89+
if (send_tas) {
8890
remove = false;
8991
transport_send_task_abort(cmd);
9092
}
@@ -107,29 +109,41 @@ static int target_check_cdb_and_preempt(struct list_head *list,
107109
return 1;
108110
}
109111

110-
static bool __target_check_io_state(struct se_cmd *se_cmd)
112+
static bool __target_check_io_state(struct se_cmd *se_cmd,
113+
struct se_session *tmr_sess, int tas)
111114
{
112115
struct se_session *sess = se_cmd->se_sess;
113116

114117
assert_spin_locked(&sess->sess_cmd_lock);
115118
WARN_ON_ONCE(!irqs_disabled());
116119
/*
117120
* If command already reached CMD_T_COMPLETE state within
118-
* target_complete_cmd(), this se_cmd has been passed to
119-
* fabric driver and will not be aborted.
121+
* target_complete_cmd() or CMD_T_FABRIC_STOP due to shutdown,
122+
* this se_cmd has been passed to fabric driver and will
123+
* not be aborted.
120124
*
121125
* Otherwise, obtain a local se_cmd->cmd_kref now for TMR
122126
* ABORT_TASK + LUN_RESET for CMD_T_ABORTED processing as
123127
* long as se_cmd->cmd_kref is still active unless zero.
124128
*/
125129
spin_lock(&se_cmd->t_state_lock);
126-
if (se_cmd->transport_state & CMD_T_COMPLETE) {
127-
pr_debug("Attempted to abort io tag: %llu already complete,"
130+
if (se_cmd->transport_state & (CMD_T_COMPLETE | CMD_T_FABRIC_STOP)) {
131+
pr_debug("Attempted to abort io tag: %llu already complete or"
132+
" fabric stop, skipping\n", se_cmd->tag);
133+
spin_unlock(&se_cmd->t_state_lock);
134+
return false;
135+
}
136+
if (sess->sess_tearing_down || se_cmd->cmd_wait_set) {
137+
pr_debug("Attempted to abort io tag: %llu already shutdown,"
128138
" skipping\n", se_cmd->tag);
129139
spin_unlock(&se_cmd->t_state_lock);
130140
return false;
131141
}
132142
se_cmd->transport_state |= CMD_T_ABORTED;
143+
144+
if ((tmr_sess != se_cmd->se_sess) && tas)
145+
se_cmd->transport_state |= CMD_T_TAS;
146+
133147
spin_unlock(&se_cmd->t_state_lock);
134148

135149
return kref_get_unless_zero(&se_cmd->cmd_kref);
@@ -161,7 +175,7 @@ void core_tmr_abort_task(
161175
printk("ABORT_TASK: Found referenced %s task_tag: %llu\n",
162176
se_cmd->se_tfo->get_fabric_name(), ref_tag);
163177

164-
if (!__target_check_io_state(se_cmd)) {
178+
if (!__target_check_io_state(se_cmd, se_sess, 0)) {
165179
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
166180
target_put_sess_cmd(se_cmd);
167181
goto out;
@@ -230,7 +244,8 @@ static void core_tmr_drain_tmr_list(
230244

231245
spin_lock(&sess->sess_cmd_lock);
232246
spin_lock(&cmd->t_state_lock);
233-
if (!(cmd->transport_state & CMD_T_ACTIVE)) {
247+
if (!(cmd->transport_state & CMD_T_ACTIVE) ||
248+
(cmd->transport_state & CMD_T_FABRIC_STOP)) {
234249
spin_unlock(&cmd->t_state_lock);
235250
spin_unlock(&sess->sess_cmd_lock);
236251
continue;
@@ -240,15 +255,22 @@ static void core_tmr_drain_tmr_list(
240255
spin_unlock(&sess->sess_cmd_lock);
241256
continue;
242257
}
258+
if (sess->sess_tearing_down || cmd->cmd_wait_set) {
259+
spin_unlock(&cmd->t_state_lock);
260+
spin_unlock(&sess->sess_cmd_lock);
261+
continue;
262+
}
243263
cmd->transport_state |= CMD_T_ABORTED;
244264
spin_unlock(&cmd->t_state_lock);
245265

246266
rc = kref_get_unless_zero(&cmd->cmd_kref);
247-
spin_unlock(&sess->sess_cmd_lock);
248267
if (!rc) {
249268
printk("LUN_RESET TMR: non-zero kref_get_unless_zero\n");
269+
spin_unlock(&sess->sess_cmd_lock);
250270
continue;
251271
}
272+
spin_unlock(&sess->sess_cmd_lock);
273+
252274
list_move_tail(&tmr_p->tmr_list, &drain_tmr_list);
253275
}
254276
spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
@@ -325,7 +347,7 @@ static void core_tmr_drain_state_list(
325347
continue;
326348

327349
spin_lock(&sess->sess_cmd_lock);
328-
rc = __target_check_io_state(cmd);
350+
rc = __target_check_io_state(cmd, tmr_sess, tas);
329351
spin_unlock(&sess->sess_cmd_lock);
330352
if (!rc)
331353
continue;
@@ -364,7 +386,7 @@ static void core_tmr_drain_state_list(
364386
cancel_work_sync(&cmd->work);
365387
transport_wait_for_tasks(cmd);
366388

367-
core_tmr_handle_tas_abort(tmr_sess, cmd, tas);
389+
core_tmr_handle_tas_abort(cmd, tas);
368390
target_put_sess_cmd(cmd);
369391
}
370392
}

drivers/target/target_core_transport.c

Lines changed: 110 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2431,18 +2431,33 @@ static void transport_write_pending_qf(struct se_cmd *cmd)
24312431
}
24322432
}
24332433

2434+
static bool
2435+
__transport_wait_for_tasks(struct se_cmd *, bool, bool *, bool *,
2436+
unsigned long *flags);
2437+
2438+
static void target_wait_free_cmd(struct se_cmd *cmd, bool *aborted, bool *tas)
2439+
{
2440+
unsigned long flags;
2441+
2442+
spin_lock_irqsave(&cmd->t_state_lock, flags);
2443+
__transport_wait_for_tasks(cmd, true, aborted, tas, &flags);
2444+
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
2445+
}
2446+
24342447
int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
24352448
{
24362449
int ret = 0;
2450+
bool aborted = false, tas = false;
24372451

24382452
if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) {
24392453
if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
2440-
transport_wait_for_tasks(cmd);
2454+
target_wait_free_cmd(cmd, &aborted, &tas);
24412455

2442-
ret = transport_put_cmd(cmd);
2456+
if (!aborted || tas)
2457+
ret = transport_put_cmd(cmd);
24432458
} else {
24442459
if (wait_for_tasks)
2445-
transport_wait_for_tasks(cmd);
2460+
target_wait_free_cmd(cmd, &aborted, &tas);
24462461
/*
24472462
* Handle WRITE failure case where transport_generic_new_cmd()
24482463
* has already added se_cmd to state_list, but fabric has
@@ -2454,7 +2469,20 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
24542469
if (cmd->se_lun)
24552470
transport_lun_remove_cmd(cmd);
24562471

2457-
ret = transport_put_cmd(cmd);
2472+
if (!aborted || tas)
2473+
ret = transport_put_cmd(cmd);
2474+
}
2475+
/*
2476+
* If the task has been internally aborted due to TMR ABORT_TASK
2477+
* or LUN_RESET, target_core_tmr.c is responsible for performing
2478+
* the remaining calls to target_put_sess_cmd(), and not the
2479+
* callers of this function.
2480+
*/
2481+
if (aborted) {
2482+
pr_debug("Detected CMD_T_ABORTED for ITT: %llu\n", cmd->tag);
2483+
wait_for_completion(&cmd->cmd_wait_comp);
2484+
cmd->se_tfo->release_cmd(cmd);
2485+
ret = 1;
24582486
}
24592487
return ret;
24602488
}
@@ -2509,6 +2537,7 @@ static void target_release_cmd_kref(struct kref *kref)
25092537
struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
25102538
struct se_session *se_sess = se_cmd->se_sess;
25112539
unsigned long flags;
2540+
bool fabric_stop;
25122541

25132542
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
25142543
if (list_empty(&se_cmd->se_cmd_list)) {
@@ -2517,13 +2546,19 @@ static void target_release_cmd_kref(struct kref *kref)
25172546
se_cmd->se_tfo->release_cmd(se_cmd);
25182547
return;
25192548
}
2520-
if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) {
2549+
2550+
spin_lock(&se_cmd->t_state_lock);
2551+
fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP);
2552+
spin_unlock(&se_cmd->t_state_lock);
2553+
2554+
if (se_cmd->cmd_wait_set || fabric_stop) {
2555+
list_del_init(&se_cmd->se_cmd_list);
25212556
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
25222557
target_free_cmd_mem(se_cmd);
25232558
complete(&se_cmd->cmd_wait_comp);
25242559
return;
25252560
}
2526-
list_del(&se_cmd->se_cmd_list);
2561+
list_del_init(&se_cmd->se_cmd_list);
25272562
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
25282563

25292564
target_free_cmd_mem(se_cmd);
@@ -2555,6 +2590,7 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
25552590
{
25562591
struct se_cmd *se_cmd;
25572592
unsigned long flags;
2593+
int rc;
25582594

25592595
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
25602596
if (se_sess->sess_tearing_down) {
@@ -2564,8 +2600,15 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
25642600
se_sess->sess_tearing_down = 1;
25652601
list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list);
25662602

2567-
list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list)
2568-
se_cmd->cmd_wait_set = 1;
2603+
list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) {
2604+
rc = kref_get_unless_zero(&se_cmd->cmd_kref);
2605+
if (rc) {
2606+
se_cmd->cmd_wait_set = 1;
2607+
spin_lock(&se_cmd->t_state_lock);
2608+
se_cmd->transport_state |= CMD_T_FABRIC_STOP;
2609+
spin_unlock(&se_cmd->t_state_lock);
2610+
}
2611+
}
25692612

25702613
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
25712614
}
@@ -2578,15 +2621,25 @@ void target_wait_for_sess_cmds(struct se_session *se_sess)
25782621
{
25792622
struct se_cmd *se_cmd, *tmp_cmd;
25802623
unsigned long flags;
2624+
bool tas;
25812625

25822626
list_for_each_entry_safe(se_cmd, tmp_cmd,
25832627
&se_sess->sess_wait_list, se_cmd_list) {
2584-
list_del(&se_cmd->se_cmd_list);
2628+
list_del_init(&se_cmd->se_cmd_list);
25852629

25862630
pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:"
25872631
" %d\n", se_cmd, se_cmd->t_state,
25882632
se_cmd->se_tfo->get_cmd_state(se_cmd));
25892633

2634+
spin_lock_irqsave(&se_cmd->t_state_lock, flags);
2635+
tas = (se_cmd->transport_state & CMD_T_TAS);
2636+
spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
2637+
2638+
if (!target_put_sess_cmd(se_cmd)) {
2639+
if (tas)
2640+
target_put_sess_cmd(se_cmd);
2641+
}
2642+
25902643
wait_for_completion(&se_cmd->cmd_wait_comp);
25912644
pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d"
25922645
" fabric state: %d\n", se_cmd, se_cmd->t_state,
@@ -2608,53 +2661,75 @@ void transport_clear_lun_ref(struct se_lun *lun)
26082661
wait_for_completion(&lun->lun_ref_comp);
26092662
}
26102663

2611-
/**
2612-
* transport_wait_for_tasks - wait for completion to occur
2613-
* @cmd: command to wait
2614-
*
2615-
* Called from frontend fabric context to wait for storage engine
2616-
* to pause and/or release frontend generated struct se_cmd.
2617-
*/
2618-
bool transport_wait_for_tasks(struct se_cmd *cmd)
2664+
static bool
2665+
__transport_wait_for_tasks(struct se_cmd *cmd, bool fabric_stop,
2666+
bool *aborted, bool *tas, unsigned long *flags)
2667+
__releases(&cmd->t_state_lock)
2668+
__acquires(&cmd->t_state_lock)
26192669
{
2620-
unsigned long flags;
26212670

2622-
spin_lock_irqsave(&cmd->t_state_lock, flags);
2671+
assert_spin_locked(&cmd->t_state_lock);
2672+
WARN_ON_ONCE(!irqs_disabled());
2673+
2674+
if (fabric_stop)
2675+
cmd->transport_state |= CMD_T_FABRIC_STOP;
2676+
2677+
if (cmd->transport_state & CMD_T_ABORTED)
2678+
*aborted = true;
2679+
2680+
if (cmd->transport_state & CMD_T_TAS)
2681+
*tas = true;
2682+
26232683
if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) &&
2624-
!(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) {
2625-
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
2684+
!(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
26262685
return false;
2627-
}
26282686

26292687
if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) &&
2630-
!(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) {
2631-
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
2688+
!(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
26322689
return false;
2633-
}
26342690

2635-
if (!(cmd->transport_state & CMD_T_ACTIVE)) {
2636-
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
2691+
if (!(cmd->transport_state & CMD_T_ACTIVE))
2692+
return false;
2693+
2694+
if (fabric_stop && *aborted)
26372695
return false;
2638-
}
26392696

26402697
cmd->transport_state |= CMD_T_STOP;
26412698

2642-
pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d, t_state: %d, CMD_T_STOP\n",
2643-
cmd, cmd->tag, cmd->se_tfo->get_cmd_state(cmd), cmd->t_state);
2699+
pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d,"
2700+
" t_state: %d, CMD_T_STOP\n", cmd, cmd->tag,
2701+
cmd->se_tfo->get_cmd_state(cmd), cmd->t_state);
26442702

2645-
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
2703+
spin_unlock_irqrestore(&cmd->t_state_lock, *flags);
26462704

26472705
wait_for_completion(&cmd->t_transport_stop_comp);
26482706

2649-
spin_lock_irqsave(&cmd->t_state_lock, flags);
2707+
spin_lock_irqsave(&cmd->t_state_lock, *flags);
26502708
cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP);
26512709

2652-
pr_debug("wait_for_tasks: Stopped wait_for_completion(&cmd->t_transport_stop_comp) for ITT: 0x%08llx\n",
2653-
cmd->tag);
2710+
pr_debug("wait_for_tasks: Stopped wait_for_completion(&cmd->"
2711+
"t_transport_stop_comp) for ITT: 0x%08llx\n", cmd->tag);
26542712

2713+
return true;
2714+
}
2715+
2716+
/**
2717+
* transport_wait_for_tasks - wait for completion to occur
2718+
* @cmd: command to wait
2719+
*
2720+
* Called from frontend fabric context to wait for storage engine
2721+
* to pause and/or release frontend generated struct se_cmd.
2722+
*/
2723+
bool transport_wait_for_tasks(struct se_cmd *cmd)
2724+
{
2725+
unsigned long flags;
2726+
bool ret, aborted = false, tas = false;
2727+
2728+
spin_lock_irqsave(&cmd->t_state_lock, flags);
2729+
ret = __transport_wait_for_tasks(cmd, false, &aborted, &tas, &flags);
26552730
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
26562731

2657-
return true;
2732+
return ret;
26582733
}
26592734
EXPORT_SYMBOL(transport_wait_for_tasks);
26602735

include/target/target_core_base.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@ struct se_cmd {
493493
#define CMD_T_DEV_ACTIVE (1 << 7)
494494
#define CMD_T_REQUEST_STOP (1 << 8)
495495
#define CMD_T_BUSY (1 << 9)
496+
#define CMD_T_TAS (1 << 10)
497+
#define CMD_T_FABRIC_STOP (1 << 11)
496498
spinlock_t t_state_lock;
497499
struct kref cmd_kref;
498500
struct completion t_transport_stop_comp;

0 commit comments

Comments
 (0)