Commit 9d6064a347a8e15451cbdf6286542d402c9da24c
Committed by
Nicholas Bellinger
1 parent
703d641d87
Exists in
master
and in
20 other branches
tcm_vhost: Use llist for cmd completion list
This drops the cmd completion list spin lock and makes the cmd completion queue lock-less. Signed-off-by: Asias He <asias@redhat.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Showing 2 changed files with 14 additions and 34 deletions Side-by-side Diff
drivers/vhost/tcm_vhost.c
... | ... | @@ -47,6 +47,7 @@ |
47 | 47 | #include <linux/vhost.h> |
48 | 48 | #include <linux/virtio_net.h> /* TODO vhost.h currently depends on this */ |
49 | 49 | #include <linux/virtio_scsi.h> |
50 | +#include <linux/llist.h> | |
50 | 51 | |
51 | 52 | #include "vhost.c" |
52 | 53 | #include "vhost.h" |
... | ... | @@ -64,8 +65,7 @@ |
64 | 65 | struct vhost_virtqueue vqs[3]; |
65 | 66 | |
66 | 67 | struct vhost_work vs_completion_work; /* cmd completion work item */ |
67 | - struct list_head vs_completion_list; /* cmd completion queue */ | |
68 | - spinlock_t vs_completion_lock; /* protects s_completion_list */ | |
68 | + struct llist_head vs_completion_list; /* cmd completion queue */ | |
69 | 69 | }; |
70 | 70 | |
71 | 71 | /* Local pointer to allocated TCM configfs fabric module */ |
... | ... | @@ -301,9 +301,7 @@ |
301 | 301 | { |
302 | 302 | struct vhost_scsi *vs = tv_cmd->tvc_vhost; |
303 | 303 | |
304 | - spin_lock_bh(&vs->vs_completion_lock); | |
305 | - list_add_tail(&tv_cmd->tvc_completion_list, &vs->vs_completion_list); | |
306 | - spin_unlock_bh(&vs->vs_completion_lock); | |
304 | + llist_add(&tv_cmd->tvc_completion_list, &vs->vs_completion_list); | |
307 | 305 | |
308 | 306 | vhost_work_queue(&vs->dev, &vs->vs_completion_work); |
309 | 307 | } |
... | ... | @@ -347,27 +345,6 @@ |
347 | 345 | kfree(tv_cmd); |
348 | 346 | } |
349 | 347 | |
350 | -/* Dequeue a command from the completion list */ | |
351 | -static struct tcm_vhost_cmd *vhost_scsi_get_cmd_from_completion( | |
352 | - struct vhost_scsi *vs) | |
353 | -{ | |
354 | - struct tcm_vhost_cmd *tv_cmd = NULL; | |
355 | - | |
356 | - spin_lock_bh(&vs->vs_completion_lock); | |
357 | - if (list_empty(&vs->vs_completion_list)) { | |
358 | - spin_unlock_bh(&vs->vs_completion_lock); | |
359 | - return NULL; | |
360 | - } | |
361 | - | |
362 | - list_for_each_entry(tv_cmd, &vs->vs_completion_list, | |
363 | - tvc_completion_list) { | |
364 | - list_del(&tv_cmd->tvc_completion_list); | |
365 | - break; | |
366 | - } | |
367 | - spin_unlock_bh(&vs->vs_completion_lock); | |
368 | - return tv_cmd; | |
369 | -} | |
370 | - | |
371 | 348 | /* Fill in status and signal that we are done processing this command |
372 | 349 | * |
373 | 350 | * This is scheduled in the vhost work queue so we are called with the owner |
374 | 351 | |
375 | 352 | |
... | ... | @@ -377,12 +354,18 @@ |
377 | 354 | { |
378 | 355 | struct vhost_scsi *vs = container_of(work, struct vhost_scsi, |
379 | 356 | vs_completion_work); |
357 | + struct virtio_scsi_cmd_resp v_rsp; | |
380 | 358 | struct tcm_vhost_cmd *tv_cmd; |
359 | + struct llist_node *llnode; | |
360 | + struct se_cmd *se_cmd; | |
361 | + int ret; | |
381 | 362 | |
382 | - while ((tv_cmd = vhost_scsi_get_cmd_from_completion(vs))) { | |
383 | - struct virtio_scsi_cmd_resp v_rsp; | |
384 | - struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd; | |
385 | - int ret; | |
363 | + llnode = llist_del_all(&vs->vs_completion_list); | |
364 | + while (llnode) { | |
365 | + tv_cmd = llist_entry(llnode, struct tcm_vhost_cmd, | |
366 | + tvc_completion_list); | |
367 | + llnode = llist_next(llnode); | |
368 | + se_cmd = &tv_cmd->tvc_se_cmd; | |
386 | 369 | |
387 | 370 | pr_debug("%s tv_cmd %p resid %u status %#02x\n", __func__, |
388 | 371 | tv_cmd, se_cmd->residual_count, se_cmd->scsi_status); |
... | ... | @@ -426,7 +409,6 @@ |
426 | 409 | pr_err("Unable to allocate struct tcm_vhost_cmd\n"); |
427 | 410 | return ERR_PTR(-ENOMEM); |
428 | 411 | } |
429 | - INIT_LIST_HEAD(&tv_cmd->tvc_completion_list); | |
430 | 412 | tv_cmd->tvc_tag = v_req->tag; |
431 | 413 | tv_cmd->tvc_task_attr = v_req->task_attr; |
432 | 414 | tv_cmd->tvc_exp_data_len = exp_data_len; |
... | ... | @@ -857,8 +839,6 @@ |
857 | 839 | return -ENOMEM; |
858 | 840 | |
859 | 841 | vhost_work_init(&s->vs_completion_work, vhost_scsi_complete_cmd_work); |
860 | - INIT_LIST_HEAD(&s->vs_completion_list); | |
861 | - spin_lock_init(&s->vs_completion_lock); | |
862 | 842 | |
863 | 843 | s->vqs[VHOST_SCSI_VQ_CTL].handle_kick = vhost_scsi_ctl_handle_kick; |
864 | 844 | s->vqs[VHOST_SCSI_VQ_EVT].handle_kick = vhost_scsi_evt_handle_kick; |
drivers/vhost/tcm_vhost.h
... | ... | @@ -34,7 +34,7 @@ |
34 | 34 | /* Sense buffer that will be mapped into outgoing status */ |
35 | 35 | unsigned char tvc_sense_buf[TRANSPORT_SENSE_BUFFER]; |
36 | 36 | /* Completed commands list, serviced from vhost worker thread */ |
37 | - struct list_head tvc_completion_list; | |
37 | + struct llist_node tvc_completion_list; | |
38 | 38 | }; |
39 | 39 | |
40 | 40 | struct tcm_vhost_nexus { |