Skip to content

Commit 1cdaafa

Browse files
mikechristiemstsirkin
authored andcommitted
vhost: replace single worker pointer with xarray
The next patch allows userspace to create multiple workers per device, so this patch replaces the vhost_worker pointer with an xarray so we can store mupltiple workers and look them up. Signed-off-by: Mike Christie <michael.christie@oracle.com> Message-Id: <20230626232307.97930-15-michael.christie@oracle.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
1 parent cef2586 commit 1cdaafa

File tree

2 files changed

+50
-17
lines changed

2 files changed

+50
-17
lines changed

drivers/vhost/vhost.c

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,11 @@ EXPORT_SYMBOL_GPL(vhost_vq_flush);
280280

281281
void vhost_dev_flush(struct vhost_dev *dev)
282282
{
283-
vhost_worker_flush(dev->worker);
283+
struct vhost_worker *worker;
284+
unsigned long i;
285+
286+
xa_for_each(&dev->worker_xa, i, worker)
287+
vhost_worker_flush(worker);
284288
}
285289
EXPORT_SYMBOL_GPL(vhost_dev_flush);
286290

@@ -482,7 +486,6 @@ void vhost_dev_init(struct vhost_dev *dev,
482486
dev->umem = NULL;
483487
dev->iotlb = NULL;
484488
dev->mm = NULL;
485-
dev->worker = NULL;
486489
dev->iov_limit = iov_limit;
487490
dev->weight = weight;
488491
dev->byte_weight = byte_weight;
@@ -492,7 +495,7 @@ void vhost_dev_init(struct vhost_dev *dev,
492495
INIT_LIST_HEAD(&dev->read_list);
493496
INIT_LIST_HEAD(&dev->pending_list);
494497
spin_lock_init(&dev->iotlb_lock);
495-
498+
xa_init_flags(&dev->worker_xa, XA_FLAGS_ALLOC);
496499

497500
for (i = 0; i < dev->nvqs; ++i) {
498501
vq = dev->vqs[i];
@@ -554,22 +557,44 @@ static void vhost_detach_mm(struct vhost_dev *dev)
554557
dev->mm = NULL;
555558
}
556559

557-
static void vhost_worker_free(struct vhost_dev *dev)
560+
static void vhost_worker_destroy(struct vhost_dev *dev,
561+
struct vhost_worker *worker)
562+
{
563+
if (!worker)
564+
return;
565+
566+
WARN_ON(!llist_empty(&worker->work_list));
567+
xa_erase(&dev->worker_xa, worker->id);
568+
vhost_task_stop(worker->vtsk);
569+
kfree(worker);
570+
}
571+
572+
static void vhost_workers_free(struct vhost_dev *dev)
558573
{
559-
if (!dev->worker)
574+
struct vhost_worker *worker;
575+
unsigned long i;
576+
577+
if (!dev->use_worker)
560578
return;
561579

562-
WARN_ON(!llist_empty(&dev->worker->work_list));
563-
vhost_task_stop(dev->worker->vtsk);
564-
kfree(dev->worker);
565-
dev->worker = NULL;
580+
for (i = 0; i < dev->nvqs; i++)
581+
dev->vqs[i]->worker = NULL;
582+
/*
583+
* Free the default worker we created and cleanup workers userspace
584+
* created but couldn't clean up (it forgot or crashed).
585+
*/
586+
xa_for_each(&dev->worker_xa, i, worker)
587+
vhost_worker_destroy(dev, worker);
588+
xa_destroy(&dev->worker_xa);
566589
}
567590

568591
static struct vhost_worker *vhost_worker_create(struct vhost_dev *dev)
569592
{
570593
struct vhost_worker *worker;
571594
struct vhost_task *vtsk;
572595
char name[TASK_COMM_LEN];
596+
int ret;
597+
u32 id;
573598

574599
worker = kzalloc(sizeof(*worker), GFP_KERNEL_ACCOUNT);
575600
if (!worker)
@@ -584,16 +609,18 @@ static struct vhost_worker *vhost_worker_create(struct vhost_dev *dev)
584609
init_llist_head(&worker->work_list);
585610
worker->kcov_handle = kcov_common_handle();
586611
worker->vtsk = vtsk;
587-
/*
588-
* vsock can already try to queue so make sure llist and vtsk are both
589-
* set before vhost_work_queue sees dev->worker is set.
590-
*/
591-
smp_wmb();
592-
dev->worker = worker;
593612

594613
vhost_task_start(vtsk);
614+
615+
ret = xa_alloc(&dev->worker_xa, &id, worker, xa_limit_32b, GFP_KERNEL);
616+
if (ret < 0)
617+
goto stop_worker;
618+
worker->id = id;
619+
595620
return worker;
596621

622+
stop_worker:
623+
vhost_task_stop(vtsk);
597624
free_worker:
598625
kfree(worker);
599626
return NULL;
@@ -650,6 +677,11 @@ long vhost_dev_set_owner(struct vhost_dev *dev)
650677
err = -ENOMEM;
651678
goto err_worker;
652679
}
680+
/*
681+
* vsock can already try to queue so make sure the worker
682+
* is setup before vhost_vq_work_queue sees vq->worker is set.
683+
*/
684+
smp_wmb();
653685

654686
for (i = 0; i < dev->nvqs; i++)
655687
dev->vqs[i]->worker = worker;
@@ -751,7 +783,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
751783
dev->iotlb = NULL;
752784
vhost_clear_msg(dev);
753785
wake_up_interruptible_poll(&dev->wait, EPOLLIN | EPOLLRDNORM);
754-
vhost_worker_free(dev);
786+
vhost_workers_free(dev);
755787
vhost_detach_mm(dev);
756788
}
757789
EXPORT_SYMBOL_GPL(vhost_dev_cleanup);

drivers/vhost/vhost.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct vhost_worker {
3030
struct vhost_task *vtsk;
3131
struct llist_head work_list;
3232
u64 kcov_handle;
33+
u32 id;
3334
};
3435

3536
/* Poll a file (eventfd or socket) */
@@ -159,7 +160,6 @@ struct vhost_dev {
159160
struct vhost_virtqueue **vqs;
160161
int nvqs;
161162
struct eventfd_ctx *log_ctx;
162-
struct vhost_worker *worker;
163163
struct vhost_iotlb *umem;
164164
struct vhost_iotlb *iotlb;
165165
spinlock_t iotlb_lock;
@@ -169,6 +169,7 @@ struct vhost_dev {
169169
int iov_limit;
170170
int weight;
171171
int byte_weight;
172+
struct xarray worker_xa;
172173
bool use_worker;
173174
int (*msg_handler)(struct vhost_dev *dev, u32 asid,
174175
struct vhost_iotlb_msg *msg);

0 commit comments

Comments
 (0)