Skip to content

Commit 1526d9f

Browse files
mikechristiemartinkpetersen
authored andcommitted
scsi: target: Make state_list per CPU
Do a state_list/execute_task_lock per CPU, so we can do submissions from different CPUs without contention with each other. Note: tcm_fc was passing TARGET_SCF_USE_CPUID, but never set cpuid. The assumption is that it wanted to set the cpuid to the CPU it was submitting from so it will get this behavior with this patch. [mkp: s/printk/pr_err/ + resolve COMPARE AND WRITE patch conflict] Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Himanshu Madhani <[email protected]> Signed-off-by: Mike Christie <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 6f55b06 commit 1526d9f

File tree

5 files changed

+126
-98
lines changed

5 files changed

+126
-98
lines changed

drivers/target/target_core_device.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -721,11 +721,24 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
721721
{
722722
struct se_device *dev;
723723
struct se_lun *xcopy_lun;
724+
int i;
724725

725726
dev = hba->backend->ops->alloc_device(hba, name);
726727
if (!dev)
727728
return NULL;
728729

730+
dev->queues = kcalloc(nr_cpu_ids, sizeof(*dev->queues), GFP_KERNEL);
731+
if (!dev->queues) {
732+
dev->transport->free_device(dev);
733+
return NULL;
734+
}
735+
736+
dev->queue_cnt = nr_cpu_ids;
737+
for (i = 0; i < dev->queue_cnt; i++) {
738+
INIT_LIST_HEAD(&dev->queues[i].state_list);
739+
spin_lock_init(&dev->queues[i].lock);
740+
}
741+
729742
dev->se_hba = hba;
730743
dev->transport = hba->backend->ops;
731744
dev->transport_flags = dev->transport->transport_flags_default;
@@ -735,9 +748,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
735748
INIT_LIST_HEAD(&dev->dev_sep_list);
736749
INIT_LIST_HEAD(&dev->dev_tmr_list);
737750
INIT_LIST_HEAD(&dev->delayed_cmd_list);
738-
INIT_LIST_HEAD(&dev->state_list);
739751
INIT_LIST_HEAD(&dev->qf_cmd_list);
740-
spin_lock_init(&dev->execute_task_lock);
741752
spin_lock_init(&dev->delayed_cmd_lock);
742753
spin_lock_init(&dev->dev_reservation_lock);
743754
spin_lock_init(&dev->se_port_lock);
@@ -1010,6 +1021,7 @@ void target_free_device(struct se_device *dev)
10101021
if (dev->transport->free_prot)
10111022
dev->transport->free_prot(dev);
10121023

1024+
kfree(dev->queues);
10131025
dev->transport->free_device(dev);
10141026
}
10151027

drivers/target/target_core_tmr.c

Lines changed: 87 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -121,57 +121,61 @@ void core_tmr_abort_task(
121121
unsigned long flags;
122122
bool rc;
123123
u64 ref_tag;
124-
125-
spin_lock_irqsave(&dev->execute_task_lock, flags);
126-
list_for_each_entry_safe(se_cmd, next, &dev->state_list, state_list) {
127-
128-
if (se_sess != se_cmd->se_sess)
129-
continue;
130-
131-
/* skip task management functions, including tmr->task_cmd */
132-
if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
133-
continue;
134-
135-
ref_tag = se_cmd->tag;
136-
if (tmr->ref_task_tag != ref_tag)
137-
continue;
138-
139-
printk("ABORT_TASK: Found referenced %s task_tag: %llu\n",
140-
se_cmd->se_tfo->fabric_name, ref_tag);
141-
142-
spin_lock(&se_sess->sess_cmd_lock);
143-
rc = __target_check_io_state(se_cmd, se_sess, 0);
144-
spin_unlock(&se_sess->sess_cmd_lock);
145-
if (!rc)
146-
continue;
147-
148-
list_move_tail(&se_cmd->state_list, &aborted_list);
149-
se_cmd->state_active = false;
150-
151-
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
152-
153-
/*
154-
* Ensure that this ABORT request is visible to the LU RESET
155-
* code.
156-
*/
157-
if (!tmr->tmr_dev)
158-
WARN_ON_ONCE(transport_lookup_tmr_lun(tmr->task_cmd) <
159-
0);
160-
161-
if (dev->transport->tmr_notify)
162-
dev->transport->tmr_notify(dev, TMR_ABORT_TASK,
163-
&aborted_list);
164-
165-
list_del_init(&se_cmd->state_list);
166-
target_put_cmd_and_wait(se_cmd);
167-
168-
printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for"
169-
" ref_tag: %llu\n", ref_tag);
170-
tmr->response = TMR_FUNCTION_COMPLETE;
171-
atomic_long_inc(&dev->aborts_complete);
172-
return;
124+
int i;
125+
126+
for (i = 0; i < dev->queue_cnt; i++) {
127+
spin_lock_irqsave(&dev->queues[i].lock, flags);
128+
list_for_each_entry_safe(se_cmd, next, &dev->queues[i].state_list,
129+
state_list) {
130+
if (se_sess != se_cmd->se_sess)
131+
continue;
132+
133+
/*
134+
* skip task management functions, including
135+
* tmr->task_cmd
136+
*/
137+
if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
138+
continue;
139+
140+
ref_tag = se_cmd->tag;
141+
if (tmr->ref_task_tag != ref_tag)
142+
continue;
143+
144+
pr_err("ABORT_TASK: Found referenced %s task_tag: %llu\n",
145+
se_cmd->se_tfo->fabric_name, ref_tag);
146+
147+
spin_lock(&se_sess->sess_cmd_lock);
148+
rc = __target_check_io_state(se_cmd, se_sess, 0);
149+
spin_unlock(&se_sess->sess_cmd_lock);
150+
if (!rc)
151+
continue;
152+
153+
list_move_tail(&se_cmd->state_list, &aborted_list);
154+
se_cmd->state_active = false;
155+
spin_unlock_irqrestore(&dev->queues[i].lock, flags);
156+
157+
/*
158+
* Ensure that this ABORT request is visible to the LU
159+
* RESET code.
160+
*/
161+
if (!tmr->tmr_dev)
162+
WARN_ON_ONCE(transport_lookup_tmr_lun(tmr->task_cmd) < 0);
163+
164+
if (dev->transport->tmr_notify)
165+
dev->transport->tmr_notify(dev, TMR_ABORT_TASK,
166+
&aborted_list);
167+
168+
list_del_init(&se_cmd->state_list);
169+
target_put_cmd_and_wait(se_cmd);
170+
171+
pr_err("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for ref_tag: %llu\n",
172+
ref_tag);
173+
tmr->response = TMR_FUNCTION_COMPLETE;
174+
atomic_long_inc(&dev->aborts_complete);
175+
return;
176+
}
177+
spin_unlock_irqrestore(&dev->queues[i].lock, flags);
173178
}
174-
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
175179

176180
if (dev->transport->tmr_notify)
177181
dev->transport->tmr_notify(dev, TMR_ABORT_TASK, &aborted_list);
@@ -273,7 +277,7 @@ static void core_tmr_drain_state_list(
273277
struct se_session *sess;
274278
struct se_cmd *cmd, *next;
275279
unsigned long flags;
276-
int rc;
280+
int rc, i;
277281

278282
/*
279283
* Complete outstanding commands with TASK_ABORTED SAM status.
@@ -297,35 +301,39 @@ static void core_tmr_drain_state_list(
297301
* Note that this seems to be independent of TAS (Task Aborted Status)
298302
* in the Control Mode Page.
299303
*/
300-
spin_lock_irqsave(&dev->execute_task_lock, flags);
301-
list_for_each_entry_safe(cmd, next, &dev->state_list, state_list) {
302-
/*
303-
* For PREEMPT_AND_ABORT usage, only process commands
304-
* with a matching reservation key.
305-
*/
306-
if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd))
307-
continue;
308-
309-
/*
310-
* Not aborting PROUT PREEMPT_AND_ABORT CDB..
311-
*/
312-
if (prout_cmd == cmd)
313-
continue;
314-
315-
sess = cmd->se_sess;
316-
if (WARN_ON_ONCE(!sess))
317-
continue;
318-
319-
spin_lock(&sess->sess_cmd_lock);
320-
rc = __target_check_io_state(cmd, tmr_sess, tas);
321-
spin_unlock(&sess->sess_cmd_lock);
322-
if (!rc)
323-
continue;
324-
325-
list_move_tail(&cmd->state_list, &drain_task_list);
326-
cmd->state_active = false;
304+
for (i = 0; i < dev->queue_cnt; i++) {
305+
spin_lock_irqsave(&dev->queues[i].lock, flags);
306+
list_for_each_entry_safe(cmd, next, &dev->queues[i].state_list,
307+
state_list) {
308+
/*
309+
* For PREEMPT_AND_ABORT usage, only process commands
310+
* with a matching reservation key.
311+
*/
312+
if (target_check_cdb_and_preempt(preempt_and_abort_list,
313+
cmd))
314+
continue;
315+
316+
/*
317+
* Not aborting PROUT PREEMPT_AND_ABORT CDB..
318+
*/
319+
if (prout_cmd == cmd)
320+
continue;
321+
322+
sess = cmd->se_sess;
323+
if (WARN_ON_ONCE(!sess))
324+
continue;
325+
326+
spin_lock(&sess->sess_cmd_lock);
327+
rc = __target_check_io_state(cmd, tmr_sess, tas);
328+
spin_unlock(&sess->sess_cmd_lock);
329+
if (!rc)
330+
continue;
331+
332+
list_move_tail(&cmd->state_list, &drain_task_list);
333+
cmd->state_active = false;
334+
}
335+
spin_unlock_irqrestore(&dev->queues[i].lock, flags);
327336
}
328-
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
329337

330338
if (dev->transport->tmr_notify)
331339
dev->transport->tmr_notify(dev, preempt_and_abort_list ?

drivers/target/target_core_transport.c

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -659,12 +659,12 @@ static void target_remove_from_state_list(struct se_cmd *cmd)
659659
if (!dev)
660660
return;
661661

662-
spin_lock_irqsave(&dev->execute_task_lock, flags);
662+
spin_lock_irqsave(&dev->queues[cmd->cpuid].lock, flags);
663663
if (cmd->state_active) {
664664
list_del(&cmd->state_list);
665665
cmd->state_active = false;
666666
}
667-
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
667+
spin_unlock_irqrestore(&dev->queues[cmd->cpuid].lock, flags);
668668
}
669669

670670
/*
@@ -875,10 +875,7 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
875875

876876
INIT_WORK(&cmd->work, success ? target_complete_ok_work :
877877
target_complete_failure_work);
878-
if (cmd->se_cmd_flags & SCF_USE_CPUID)
879-
queue_work_on(cmd->cpuid, target_completion_wq, &cmd->work);
880-
else
881-
queue_work(target_completion_wq, &cmd->work);
878+
queue_work_on(cmd->cpuid, target_completion_wq, &cmd->work);
882879
}
883880
EXPORT_SYMBOL(target_complete_cmd);
884881

@@ -906,12 +903,13 @@ static void target_add_to_state_list(struct se_cmd *cmd)
906903
struct se_device *dev = cmd->se_dev;
907904
unsigned long flags;
908905

909-
spin_lock_irqsave(&dev->execute_task_lock, flags);
906+
spin_lock_irqsave(&dev->queues[cmd->cpuid].lock, flags);
910907
if (!cmd->state_active) {
911-
list_add_tail(&cmd->state_list, &dev->state_list);
908+
list_add_tail(&cmd->state_list,
909+
&dev->queues[cmd->cpuid].state_list);
912910
cmd->state_active = true;
913911
}
914-
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
912+
spin_unlock_irqrestore(&dev->queues[cmd->cpuid].lock, flags);
915913
}
916914

917915
/*
@@ -1399,6 +1397,9 @@ void transport_init_se_cmd(
13991397
cmd->sense_buffer = sense_buffer;
14001398
cmd->orig_fe_lun = unpacked_lun;
14011399

1400+
if (!(cmd->se_cmd_flags & SCF_USE_CPUID))
1401+
cmd->cpuid = smp_processor_id();
1402+
14021403
cmd->state_active = false;
14031404
}
14041405
EXPORT_SYMBOL(transport_init_se_cmd);
@@ -1616,6 +1617,9 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess
16161617
BUG_ON(!se_tpg);
16171618
BUG_ON(se_cmd->se_tfo || se_cmd->se_sess);
16181619
BUG_ON(in_interrupt());
1620+
1621+
if (flags & TARGET_SCF_USE_CPUID)
1622+
se_cmd->se_cmd_flags |= SCF_USE_CPUID;
16191623
/*
16201624
* Initialize se_cmd for target operation. From this point
16211625
* exceptions are handled by sending exception status via
@@ -1625,11 +1629,6 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess
16251629
data_length, data_dir, task_attr, sense,
16261630
unpacked_lun);
16271631

1628-
if (flags & TARGET_SCF_USE_CPUID)
1629-
se_cmd->se_cmd_flags |= SCF_USE_CPUID;
1630-
else
1631-
se_cmd->cpuid = WORK_CPU_UNBOUND;
1632-
16331632
if (flags & TARGET_SCF_UNKNOWN_SIZE)
16341633
se_cmd->unknown_data_length = 1;
16351634
/*

drivers/target/tcm_fc/tfc_cmd.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ static void ft_send_work(struct work_struct *work)
550550
if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb,
551551
&cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
552552
ntohl(fcp->fc_dl), task_attr, data_dir,
553-
TARGET_SCF_ACK_KREF | TARGET_SCF_USE_CPUID))
553+
TARGET_SCF_ACK_KREF))
554554
goto err;
555555

556556
pr_debug("r_ctl %x target_submit_cmd %p\n", fh->fh_r_ctl, cmd);

include/target/target_core_base.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,10 @@ struct se_cmd {
540540
unsigned int t_prot_nents;
541541
sense_reason_t pi_err;
542542
u64 sense_info;
543+
/*
544+
* CPU LIO will execute the cmd on. Defaults to the CPU the cmd is
545+
* initialized on. Drivers can override.
546+
*/
543547
int cpuid;
544548
};
545549

@@ -760,6 +764,11 @@ struct se_dev_stat_grps {
760764
struct config_group scsi_lu_group;
761765
};
762766

767+
struct se_device_queue {
768+
struct list_head state_list;
769+
spinlock_t lock;
770+
};
771+
763772
struct se_device {
764773
/* RELATIVE TARGET PORT IDENTIFER Counter */
765774
u16 dev_rpti_counter;
@@ -792,7 +801,6 @@ struct se_device {
792801
atomic_t dev_qf_count;
793802
u32 export_count;
794803
spinlock_t delayed_cmd_lock;
795-
spinlock_t execute_task_lock;
796804
spinlock_t dev_reservation_lock;
797805
unsigned int dev_reservation_flags;
798806
#define DRF_SPC2_RESERVATIONS 0x00000001
@@ -811,7 +819,6 @@ struct se_device {
811819
struct list_head dev_tmr_list;
812820
struct work_struct qf_work_queue;
813821
struct list_head delayed_cmd_list;
814-
struct list_head state_list;
815822
struct list_head qf_cmd_list;
816823
/* Pointer to associated SE HBA */
817824
struct se_hba *se_hba;
@@ -838,6 +845,8 @@ struct se_device {
838845
/* For se_lun->lun_se_dev RCU read-side critical access */
839846
u32 hba_index;
840847
struct rcu_head rcu_head;
848+
int queue_cnt;
849+
struct se_device_queue *queues;
841850
};
842851

843852
struct se_hba {

0 commit comments

Comments
 (0)