Skip to content

Commit

Permalink
scsi: target: core: Add workqueue based cmd submission
Browse files Browse the repository at this point in the history
loop and vhost/scsi do their target cmd submission from driver
workqueues. This allows them to avoid an issue where the backend may block
waiting for resources like tags/requests, mem/locks, etc and that ends up
blocking their entire submission path and for the case of vhost-scsi both
the submission and completion path.

This patch adds a helper drivers can use to submit from a LIO workqueue.
This code will then be extended in the next patches to fix the plugging of
backend devices.

We are only converting vhost/loop initially, but the workqueue based
submission will work for other drivers and have similar benefits where the
main target loops will not end up blocking one some backend resource.

Link: https://lore.kernel.org/r/20210227170006.5077-17-michael.christie@oracle.com
Tested-by: Laurence Oberman <loberman@redhat.com>
Reviewed-by: Bodo Stroesser <bostroesser@gmail.com>
Signed-off-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
  • Loading branch information
Mike Christie authored and Martin K. Petersen committed Mar 4, 2021
1 parent 0869419 commit eb44ce8
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 4 deletions.
10 changes: 8 additions & 2 deletions drivers/target/target_core_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -735,8 +735,14 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)

dev->queue_cnt = nr_cpu_ids;
for (i = 0; i < dev->queue_cnt; i++) {
INIT_LIST_HEAD(&dev->queues[i].state_list);
spin_lock_init(&dev->queues[i].lock);
struct se_device_queue *q;

q = &dev->queues[i];
INIT_LIST_HEAD(&q->state_list);
spin_lock_init(&q->lock);

init_llist_head(&q->sq.cmd_list);
INIT_WORK(&q->sq.work, target_queued_submit_work);
}

dev->se_hba = hba;
Expand Down
1 change: 1 addition & 0 deletions drivers/target/target_core_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ void target_qf_do_work(struct work_struct *work);
bool target_check_wce(struct se_device *dev);
bool target_check_fua(struct se_device *dev);
void __target_execute_cmd(struct se_cmd *, bool);
void target_queued_submit_work(struct work_struct *work);

/* target_core_stat.c */
void target_stat_setup_dev_default_groups(struct se_device *);
Expand Down
42 changes: 41 additions & 1 deletion drivers/target/target_core_transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <trace/events/target.h>

static struct workqueue_struct *target_completion_wq;
static struct workqueue_struct *target_submission_wq;
static struct kmem_cache *se_sess_cache;
struct kmem_cache *se_ua_cache;
struct kmem_cache *t10_pr_reg_cache;
Expand Down Expand Up @@ -129,8 +130,15 @@ int init_se_kmem_caches(void)
if (!target_completion_wq)
goto out_free_lba_map_mem_cache;

target_submission_wq = alloc_workqueue("target_submission",
WQ_MEM_RECLAIM, 0);
if (!target_submission_wq)
goto out_free_completion_wq;

return 0;

out_free_completion_wq:
destroy_workqueue(target_completion_wq);
out_free_lba_map_mem_cache:
kmem_cache_destroy(t10_alua_lba_map_mem_cache);
out_free_lba_map_cache:
Expand All @@ -153,6 +161,7 @@ int init_se_kmem_caches(void)

void release_se_kmem_caches(void)
{
destroy_workqueue(target_submission_wq);
destroy_workqueue(target_completion_wq);
kmem_cache_destroy(se_sess_cache);
kmem_cache_destroy(se_ua_cache);
Expand Down Expand Up @@ -1382,7 +1391,6 @@ void __target_init_cmd(
{
INIT_LIST_HEAD(&cmd->se_delayed_node);
INIT_LIST_HEAD(&cmd->se_qf_node);
INIT_LIST_HEAD(&cmd->se_cmd_list);
INIT_LIST_HEAD(&cmd->state_list);
init_completion(&cmd->t_transport_stop_comp);
cmd->free_compl = NULL;
Expand Down Expand Up @@ -1799,6 +1807,38 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
}
EXPORT_SYMBOL(target_submit_cmd);

void target_queued_submit_work(struct work_struct *work)
{
struct se_cmd_queue *sq = container_of(work, struct se_cmd_queue, work);
struct se_cmd *se_cmd, *next_cmd;
struct llist_node *cmd_list;

cmd_list = llist_del_all(&sq->cmd_list);
if (!cmd_list)
/* Previous call took what we were queued to submit */
return;

cmd_list = llist_reverse_order(cmd_list);
llist_for_each_entry_safe(se_cmd, next_cmd, cmd_list, se_cmd_list)
target_submit(se_cmd);
}

/**
* target_queue_submission - queue the cmd to run on the LIO workqueue
* @se_cmd: command descriptor to submit
*/
void target_queue_submission(struct se_cmd *se_cmd)
{
struct se_device *se_dev = se_cmd->se_dev;
int cpu = se_cmd->cpuid;
struct se_cmd_queue *sq;

sq = &se_dev->queues[cpu].sq;
llist_add(&se_cmd->se_cmd_list, &sq->cmd_list);
queue_work_on(cpu, target_submission_wq, &sq->work);
}
EXPORT_SYMBOL_GPL(target_queue_submission);

static void target_complete_tmr_failure(struct work_struct *work)
{
struct se_cmd *se_cmd = container_of(work, struct se_cmd, work);
Expand Down
8 changes: 7 additions & 1 deletion include/target/target_core_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ struct se_cmd {
/* Only used for internal passthrough and legacy TCM fabric modules */
struct se_session *se_sess;
struct se_tmr_req *se_tmr_req;
struct list_head se_cmd_list;
struct llist_node se_cmd_list;
struct completion *free_compl;
struct completion *abrt_compl;
const struct target_core_fabric_ops *se_tfo;
Expand Down Expand Up @@ -765,9 +765,15 @@ struct se_dev_stat_grps {
struct config_group scsi_lu_group;
};

struct se_cmd_queue {
struct llist_head cmd_list;
struct work_struct work;
};

struct se_device_queue {
struct list_head state_list;
spinlock_t lock;
struct se_cmd_queue sq;
};

struct se_device {
Expand Down
2 changes: 2 additions & 0 deletions include/target/target_core_fabric.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ sense_reason_t target_cmd_init_cdb(struct se_cmd *se_cmd, unsigned char *cdb,
sense_reason_t target_cmd_parse_cdb(struct se_cmd *);
void target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *,
unsigned char *, u64, u32, int, int, int);
void target_queue_submission(struct se_cmd *se_cmd);

int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
unsigned char *sense, u64 unpacked_lun,
void *fabric_tmr_ptr, unsigned char tm_type,
Expand Down

0 comments on commit eb44ce8

Please sign in to comment.