@@ -280,7 +280,11 @@ EXPORT_SYMBOL_GPL(vhost_vq_flush);
280280
281281void 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}
285289EXPORT_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
568591static 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 );
597624free_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}
757789EXPORT_SYMBOL_GPL (vhost_dev_cleanup );
0 commit comments