virtualization.lists.linux-foundation.org archive mirror
 help / color / mirror / Atom feed
* vhost: Fix vhost_task regressions in 6.4-rc
@ 2023-06-07 19:23 Mike Christie
  2023-06-07 19:23 ` [PATCH 1/2] vhost: Fix crash during early vhost_transport_send_pkt calls Mike Christie
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Mike Christie @ 2023-06-07 19:23 UTC (permalink / raw)
  To: stefanha, jasowang, mst, sgarzare, virtualization

The following patches were made over Linus's tree which contains a
vhost change missing in mst's vhost branch. These patches fix two
issues caused by the vhost_task patches:
1. I was setting dev->worker too early and this caused crashes when
vsock would queue work before VHOST_SET_OWNER.

2. The patch that Linus's tree contains which vhost does not yet
have converted vhost_tasks to use CLONE_THREAD. That required a
change to how we set the task state, but I completely messed up
and moved when we set ourself to interruptible too late.



_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] vhost: Fix crash during early vhost_transport_send_pkt calls
  2023-06-07 19:23 vhost: Fix vhost_task regressions in 6.4-rc Mike Christie
@ 2023-06-07 19:23 ` Mike Christie
  2023-06-08  8:39   ` Stefano Garzarella
  2023-06-07 19:23 ` [PATCH 2/2] vhost: Fix worker hangs due to missed wake up calls Mike Christie
  2023-06-07 20:22 ` vhost: Fix vhost_task regressions in 6.4-rc Michael S. Tsirkin
  2 siblings, 1 reply; 7+ messages in thread
From: Mike Christie @ 2023-06-07 19:23 UTC (permalink / raw)
  To: stefanha, jasowang, mst, sgarzare, virtualization

If userspace does VHOST_VSOCK_SET_GUEST_CID before VHOST_SET_OWNER we
can race where:
1. thread0 calls vhost_transport_send_pkt -> vhost_work_queue
2. thread1 does VHOST_SET_OWNER which calls vhost_worker_create.
3. vhost_worker_create will set the dev->worker pointer before setting
the worker->vtsk pointer.
4. thread0's vhost_work_queue will see the dev->worker pointer is
set and try to call vhost_task_wake using not yet set worker->vtsk
pointer.
5. We then crash since vtsk is NULL.

Before commit 6e890c5d5021 ("vhost: use vhost_tasks for worker
threads"), we only had the worker pointer so we could just check it to
see if VHOST_SET_OWNER has been done. After that commit we have the
vhost_worker and vhost_task pointer, so we can now hit the bug above.

This patch embeds the vhost_worker in the vhost_dev and moves the work
list initialization back to vhost_dev_init, so we can just check the
worker.vtsk pointer to check if VHOST_SET_OWNER has been done like
before.

Fixes: 6e890c5d5021 ("vhost: use vhost_tasks for worker threads")
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/vhost/vhost.c | 50 +++++++++++++++----------------------------
 drivers/vhost/vhost.h |  2 +-
 2 files changed, 18 insertions(+), 34 deletions(-)

diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 074273020849..7a9f93eae225 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -235,7 +235,7 @@ void vhost_dev_flush(struct vhost_dev *dev)
 {
 	struct vhost_flush_struct flush;
 
-	if (dev->worker) {
+	if (dev->worker.vtsk) {
 		init_completion(&flush.wait_event);
 		vhost_work_init(&flush.work, vhost_flush_work);
 
@@ -247,7 +247,7 @@ EXPORT_SYMBOL_GPL(vhost_dev_flush);
 
 void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
 {
-	if (!dev->worker)
+	if (!dev->worker.vtsk)
 		return;
 
 	if (!test_and_set_bit(VHOST_WORK_QUEUED, &work->flags)) {
@@ -255,8 +255,8 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
 		 * sure it was not in the list.
 		 * test_and_set_bit() implies a memory barrier.
 		 */
-		llist_add(&work->node, &dev->worker->work_list);
-		vhost_task_wake(dev->worker->vtsk);
+		llist_add(&work->node, &dev->worker.work_list);
+		vhost_task_wake(dev->worker.vtsk);
 	}
 }
 EXPORT_SYMBOL_GPL(vhost_work_queue);
@@ -264,7 +264,7 @@ EXPORT_SYMBOL_GPL(vhost_work_queue);
 /* A lockless hint for busy polling code to exit the loop */
 bool vhost_has_work(struct vhost_dev *dev)
 {
-	return dev->worker && !llist_empty(&dev->worker->work_list);
+	return !llist_empty(&dev->worker.work_list);
 }
 EXPORT_SYMBOL_GPL(vhost_has_work);
 
@@ -456,7 +456,8 @@ void vhost_dev_init(struct vhost_dev *dev,
 	dev->umem = NULL;
 	dev->iotlb = NULL;
 	dev->mm = NULL;
-	dev->worker = NULL;
+	memset(&dev->worker, 0, sizeof(dev->worker));
+	init_llist_head(&dev->worker.work_list);
 	dev->iov_limit = iov_limit;
 	dev->weight = weight;
 	dev->byte_weight = byte_weight;
@@ -530,47 +531,30 @@ static void vhost_detach_mm(struct vhost_dev *dev)
 
 static void vhost_worker_free(struct vhost_dev *dev)
 {
-	struct vhost_worker *worker = dev->worker;
-
-	if (!worker)
+	if (!dev->worker.vtsk)
 		return;
 
-	dev->worker = NULL;
-	WARN_ON(!llist_empty(&worker->work_list));
-	vhost_task_stop(worker->vtsk);
-	kfree(worker);
+	WARN_ON(!llist_empty(&dev->worker.work_list));
+	vhost_task_stop(dev->worker.vtsk);
+	dev->worker.kcov_handle = 0;
+	dev->worker.vtsk = NULL;
 }
 
 static int vhost_worker_create(struct vhost_dev *dev)
 {
-	struct vhost_worker *worker;
 	struct vhost_task *vtsk;
 	char name[TASK_COMM_LEN];
-	int ret;
-
-	worker = kzalloc(sizeof(*worker), GFP_KERNEL_ACCOUNT);
-	if (!worker)
-		return -ENOMEM;
 
-	dev->worker = worker;
-	worker->kcov_handle = kcov_common_handle();
-	init_llist_head(&worker->work_list);
 	snprintf(name, sizeof(name), "vhost-%d", current->pid);
 
-	vtsk = vhost_task_create(vhost_worker, worker, name);
-	if (!vtsk) {
-		ret = -ENOMEM;
-		goto free_worker;
-	}
+	vtsk = vhost_task_create(vhost_worker, &dev->worker, name);
+	if (!vtsk)
+		return -ENOMEM;
 
-	worker->vtsk = vtsk;
+	dev->worker.kcov_handle = kcov_common_handle();
+	dev->worker.vtsk = vtsk;
 	vhost_task_start(vtsk);
 	return 0;
-
-free_worker:
-	kfree(worker);
-	dev->worker = NULL;
-	return ret;
 }
 
 /* Caller should have device mutex */
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index 0308638cdeee..305ec8593d46 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -154,7 +154,7 @@ struct vhost_dev {
 	struct vhost_virtqueue **vqs;
 	int nvqs;
 	struct eventfd_ctx *log_ctx;
-	struct vhost_worker *worker;
+	struct vhost_worker worker;
 	struct vhost_iotlb *umem;
 	struct vhost_iotlb *iotlb;
 	spinlock_t iotlb_lock;
-- 
2.25.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] vhost: Fix worker hangs due to missed wake up calls
  2023-06-07 19:23 vhost: Fix vhost_task regressions in 6.4-rc Mike Christie
  2023-06-07 19:23 ` [PATCH 1/2] vhost: Fix crash during early vhost_transport_send_pkt calls Mike Christie
@ 2023-06-07 19:23 ` Mike Christie
  2023-06-07 20:22 ` vhost: Fix vhost_task regressions in 6.4-rc Michael S. Tsirkin
  2 siblings, 0 replies; 7+ messages in thread
From: Mike Christie @ 2023-06-07 19:23 UTC (permalink / raw)
  To: stefanha, jasowang, mst, sgarzare, virtualization

We can race where we have added work to the work_list, but
vhost_task_fn has passed that check but not yet set us into
TASK_INTERRUPTIBLE. wake_up_process will see us in TASK_RUNNING and
just return.

This bug was intoduced in commit f9010dbdce91 ("fork, vhost: Use
CLONE_THREAD to fix freezer/ps regression") when I moved the setting
of TASK_INTERRUPTIBLE to simplfy the code and avoid get_signal from
logging warnings about being in the wrong state. This moves the setting
of TASK_INTERRUPTIBLE back to before we test if we need to stop the
task to avoid a possible race there as well. We then have vhost_worker
set TASK_RUNNING if it finds work similar to before.

Fixes: f9010dbdce91 ("fork, vhost: Use CLONE_THREAD to fix freezer/ps regression")
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/vhost/vhost.c |  2 ++
 kernel/vhost_task.c   | 16 +++++++++-------
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 7a9f93eae225..b2722d29e069 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -341,6 +341,8 @@ static bool vhost_worker(void *data)
 
 	node = llist_del_all(&worker->work_list);
 	if (node) {
+		__set_current_state(TASK_RUNNING);
+
 		node = llist_reverse_order(node);
 		/* make sure flag is seen after deletion */
 		smp_wmb();
diff --git a/kernel/vhost_task.c b/kernel/vhost_task.c
index f80d5c51ae67..da35e5b7f047 100644
--- a/kernel/vhost_task.c
+++ b/kernel/vhost_task.c
@@ -28,10 +28,6 @@ static int vhost_task_fn(void *data)
 	for (;;) {
 		bool did_work;
 
-		/* mb paired w/ vhost_task_stop */
-		if (test_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags))
-			break;
-
 		if (!dead && signal_pending(current)) {
 			struct ksignal ksig;
 			/*
@@ -48,11 +44,17 @@ static int vhost_task_fn(void *data)
 				clear_thread_flag(TIF_SIGPENDING);
 		}
 
+		/* mb paired w/ vhost_task_stop */
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		if (test_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags)) {
+			__set_current_state(TASK_RUNNING);
+			break;
+		}
+
 		did_work = vtsk->fn(vtsk->data);
-		if (!did_work) {
-			set_current_state(TASK_INTERRUPTIBLE);
+		if (!did_work)
 			schedule();
-		}
 	}
 
 	complete(&vtsk->exited);
-- 
2.25.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: vhost: Fix vhost_task regressions in 6.4-rc
  2023-06-07 19:23 vhost: Fix vhost_task regressions in 6.4-rc Mike Christie
  2023-06-07 19:23 ` [PATCH 1/2] vhost: Fix crash during early vhost_transport_send_pkt calls Mike Christie
  2023-06-07 19:23 ` [PATCH 2/2] vhost: Fix worker hangs due to missed wake up calls Mike Christie
@ 2023-06-07 20:22 ` Michael S. Tsirkin
  2023-06-08  0:38   ` Mike Christie
  2 siblings, 1 reply; 7+ messages in thread
From: Michael S. Tsirkin @ 2023-06-07 20:22 UTC (permalink / raw)
  To: Mike Christie; +Cc: virtualization, stefanha

On Wed, Jun 07, 2023 at 02:23:36PM -0500, Mike Christie wrote:
> The following patches were made over Linus's tree which contains a
> vhost change missing in mst's vhost branch. These patches fix two
> issues caused by the vhost_task patches:
> 1. I was setting dev->worker too early and this caused crashes when
> vsock would queue work before VHOST_SET_OWNER.
> 
> 2. The patch that Linus's tree contains which vhost does not yet
> have converted vhost_tasks to use CLONE_THREAD. That required a
> change to how we set the task state, but I completely messed up
> and moved when we set ourself to interruptible too late.
> 

Right. and that's in rc5 yes?

-- 
MST

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: vhost: Fix vhost_task regressions in 6.4-rc
  2023-06-07 20:22 ` vhost: Fix vhost_task regressions in 6.4-rc Michael S. Tsirkin
@ 2023-06-08  0:38   ` Mike Christie
  0 siblings, 0 replies; 7+ messages in thread
From: Mike Christie @ 2023-06-08  0:38 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: virtualization, stefanha

On 6/7/23 3:22 PM, Michael S. Tsirkin wrote:
> On Wed, Jun 07, 2023 at 02:23:36PM -0500, Mike Christie wrote:
>> The following patches were made over Linus's tree which contains a
>> vhost change missing in mst's vhost branch. These patches fix two
>> issues caused by the vhost_task patches:
>> 1. I was setting dev->worker too early and this caused crashes when
>> vsock would queue work before VHOST_SET_OWNER.
>>
>> 2. The patch that Linus's tree contains which vhost does not yet
>> have converted vhost_tasks to use CLONE_THREAD. That required a
>> change to how we set the task state, but I completely messed up
>> and moved when we set ourself to interruptible too late.
>>
> 
> Right. and that's in rc5 yes?
> 

Yes.
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] vhost: Fix crash during early vhost_transport_send_pkt calls
  2023-06-07 19:23 ` [PATCH 1/2] vhost: Fix crash during early vhost_transport_send_pkt calls Mike Christie
@ 2023-06-08  8:39   ` Stefano Garzarella
  2023-06-08 15:11     ` Michael S. Tsirkin
  0 siblings, 1 reply; 7+ messages in thread
From: Stefano Garzarella @ 2023-06-08  8:39 UTC (permalink / raw)
  To: Mike Christie; +Cc: virtualization, stefanha, mst

On Wed, Jun 07, 2023 at 02:23:37PM -0500, Mike Christie wrote:
>If userspace does VHOST_VSOCK_SET_GUEST_CID before VHOST_SET_OWNER we
>can race where:
>1. thread0 calls vhost_transport_send_pkt -> vhost_work_queue
>2. thread1 does VHOST_SET_OWNER which calls vhost_worker_create.
>3. vhost_worker_create will set the dev->worker pointer before setting
>the worker->vtsk pointer.
>4. thread0's vhost_work_queue will see the dev->worker pointer is
>set and try to call vhost_task_wake using not yet set worker->vtsk
>pointer.
>5. We then crash since vtsk is NULL.
>
>Before commit 6e890c5d5021 ("vhost: use vhost_tasks for worker
>threads"), we only had the worker pointer so we could just check it to
>see if VHOST_SET_OWNER has been done. After that commit we have the
>vhost_worker and vhost_task pointer, so we can now hit the bug above.
>
>This patch embeds the vhost_worker in the vhost_dev and moves the work
>list initialization back to vhost_dev_init, so we can just check the
>worker.vtsk pointer to check if VHOST_SET_OWNER has been done like
>before.
>

We should add:

Reported-by: syzbot+d0d442c22fa8db45ff0e@syzkaller.appspotmail.com

Michael, can it be added when apply?

>Fixes: 6e890c5d5021 ("vhost: use vhost_tasks for worker threads")
>Signed-off-by: Mike Christie <michael.christie@oracle.com>
>---
> drivers/vhost/vhost.c | 50 +++++++++++++++----------------------------
> drivers/vhost/vhost.h |  2 +-
> 2 files changed, 18 insertions(+), 34 deletions(-)
>
>diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
>index 074273020849..7a9f93eae225 100644
>--- a/drivers/vhost/vhost.c
>+++ b/drivers/vhost/vhost.c
>@@ -235,7 +235,7 @@ void vhost_dev_flush(struct vhost_dev *dev)
> {
> 	struct vhost_flush_struct flush;
>
>-	if (dev->worker) {
>+	if (dev->worker.vtsk) {
> 		init_completion(&flush.wait_event);
> 		vhost_work_init(&flush.work, vhost_flush_work);
>
>@@ -247,7 +247,7 @@ EXPORT_SYMBOL_GPL(vhost_dev_flush);
>
> void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
> {
>-	if (!dev->worker)
>+	if (!dev->worker.vtsk)
> 		return;
>
> 	if (!test_and_set_bit(VHOST_WORK_QUEUED, &work->flags)) {
>@@ -255,8 +255,8 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
> 		 * sure it was not in the list.
> 		 * test_and_set_bit() implies a memory barrier.
> 		 */
>-		llist_add(&work->node, &dev->worker->work_list);
>-		vhost_task_wake(dev->worker->vtsk);
>+		llist_add(&work->node, &dev->worker.work_list);
>+		vhost_task_wake(dev->worker.vtsk);
> 	}
> }
> EXPORT_SYMBOL_GPL(vhost_work_queue);
>@@ -264,7 +264,7 @@ EXPORT_SYMBOL_GPL(vhost_work_queue);
> /* A lockless hint for busy polling code to exit the loop */
> bool vhost_has_work(struct vhost_dev *dev)
> {
>-	return dev->worker && !llist_empty(&dev->worker->work_list);
>+	return !llist_empty(&dev->worker.work_list);
> }
> EXPORT_SYMBOL_GPL(vhost_has_work);
>
>@@ -456,7 +456,8 @@ void vhost_dev_init(struct vhost_dev *dev,
> 	dev->umem = NULL;
> 	dev->iotlb = NULL;
> 	dev->mm = NULL;
>-	dev->worker = NULL;
>+	memset(&dev->worker, 0, sizeof(dev->worker));
>+	init_llist_head(&dev->worker.work_list);
> 	dev->iov_limit = iov_limit;
> 	dev->weight = weight;
> 	dev->byte_weight = byte_weight;
>@@ -530,47 +531,30 @@ static void vhost_detach_mm(struct vhost_dev *dev)
>
> static void vhost_worker_free(struct vhost_dev *dev)
> {
>-	struct vhost_worker *worker = dev->worker;
>-
>-	if (!worker)
>+	if (!dev->worker.vtsk)
> 		return;
>
>-	dev->worker = NULL;
>-	WARN_ON(!llist_empty(&worker->work_list));
>-	vhost_task_stop(worker->vtsk);
>-	kfree(worker);
>+	WARN_ON(!llist_empty(&dev->worker.work_list));
>+	vhost_task_stop(dev->worker.vtsk);
>+	dev->worker.kcov_handle = 0;
>+	dev->worker.vtsk = NULL;
> }
>
> static int vhost_worker_create(struct vhost_dev *dev)
> {
>-	struct vhost_worker *worker;
> 	struct vhost_task *vtsk;
> 	char name[TASK_COMM_LEN];
>-	int ret;
>-
>-	worker = kzalloc(sizeof(*worker), GFP_KERNEL_ACCOUNT);
>-	if (!worker)
>-		return -ENOMEM;
>
>-	dev->worker = worker;
>-	worker->kcov_handle = kcov_common_handle();
>-	init_llist_head(&worker->work_list);
> 	snprintf(name, sizeof(name), "vhost-%d", current->pid);
>
>-	vtsk = vhost_task_create(vhost_worker, worker, name);
>-	if (!vtsk) {
>-		ret = -ENOMEM;
>-		goto free_worker;
>-	}
>+	vtsk = vhost_task_create(vhost_worker, &dev->worker, name);
>+	if (!vtsk)
>+		return -ENOMEM;
>
>-	worker->vtsk = vtsk;
>+	dev->worker.kcov_handle = kcov_common_handle();
>+	dev->worker.vtsk = vtsk;

Okay, I think we are safe for now for the problem I highlighted in v1:

Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>

Thanks,
Stefano

> 	vhost_task_start(vtsk);
> 	return 0;
>-
>-free_worker:
>-	kfree(worker);
>-	dev->worker = NULL;
>-	return ret;
> }
>
> /* Caller should have device mutex */
>diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
>index 0308638cdeee..305ec8593d46 100644
>--- a/drivers/vhost/vhost.h
>+++ b/drivers/vhost/vhost.h
>@@ -154,7 +154,7 @@ struct vhost_dev {
> 	struct vhost_virtqueue **vqs;
> 	int nvqs;
> 	struct eventfd_ctx *log_ctx;
>-	struct vhost_worker *worker;
>+	struct vhost_worker worker;
> 	struct vhost_iotlb *umem;
> 	struct vhost_iotlb *iotlb;
> 	spinlock_t iotlb_lock;
>-- 
>2.25.1
>

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] vhost: Fix crash during early vhost_transport_send_pkt calls
  2023-06-08  8:39   ` Stefano Garzarella
@ 2023-06-08 15:11     ` Michael S. Tsirkin
  0 siblings, 0 replies; 7+ messages in thread
From: Michael S. Tsirkin @ 2023-06-08 15:11 UTC (permalink / raw)
  To: Stefano Garzarella; +Cc: stefanha, virtualization

On Thu, Jun 08, 2023 at 10:39:41AM +0200, Stefano Garzarella wrote:
> On Wed, Jun 07, 2023 at 02:23:37PM -0500, Mike Christie wrote:
> > If userspace does VHOST_VSOCK_SET_GUEST_CID before VHOST_SET_OWNER we
> > can race where:
> > 1. thread0 calls vhost_transport_send_pkt -> vhost_work_queue
> > 2. thread1 does VHOST_SET_OWNER which calls vhost_worker_create.
> > 3. vhost_worker_create will set the dev->worker pointer before setting
> > the worker->vtsk pointer.
> > 4. thread0's vhost_work_queue will see the dev->worker pointer is
> > set and try to call vhost_task_wake using not yet set worker->vtsk
> > pointer.
> > 5. We then crash since vtsk is NULL.
> > 
> > Before commit 6e890c5d5021 ("vhost: use vhost_tasks for worker
> > threads"), we only had the worker pointer so we could just check it to
> > see if VHOST_SET_OWNER has been done. After that commit we have the
> > vhost_worker and vhost_task pointer, so we can now hit the bug above.
> > 
> > This patch embeds the vhost_worker in the vhost_dev and moves the work
> > list initialization back to vhost_dev_init, so we can just check the
> > worker.vtsk pointer to check if VHOST_SET_OWNER has been done like
> > before.
> > 
> 
> We should add:
> 
> Reported-by: syzbot+d0d442c22fa8db45ff0e@syzkaller.appspotmail.com
> 
> Michael, can it be added when apply?

will do, thanks!

> > Fixes: 6e890c5d5021 ("vhost: use vhost_tasks for worker threads")
> > Signed-off-by: Mike Christie <michael.christie@oracle.com>
> > ---
> > drivers/vhost/vhost.c | 50 +++++++++++++++----------------------------
> > drivers/vhost/vhost.h |  2 +-
> > 2 files changed, 18 insertions(+), 34 deletions(-)
> > 
> > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> > index 074273020849..7a9f93eae225 100644
> > --- a/drivers/vhost/vhost.c
> > +++ b/drivers/vhost/vhost.c
> > @@ -235,7 +235,7 @@ void vhost_dev_flush(struct vhost_dev *dev)
> > {
> > 	struct vhost_flush_struct flush;
> > 
> > -	if (dev->worker) {
> > +	if (dev->worker.vtsk) {
> > 		init_completion(&flush.wait_event);
> > 		vhost_work_init(&flush.work, vhost_flush_work);
> > 
> > @@ -247,7 +247,7 @@ EXPORT_SYMBOL_GPL(vhost_dev_flush);
> > 
> > void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
> > {
> > -	if (!dev->worker)
> > +	if (!dev->worker.vtsk)
> > 		return;
> > 
> > 	if (!test_and_set_bit(VHOST_WORK_QUEUED, &work->flags)) {
> > @@ -255,8 +255,8 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
> > 		 * sure it was not in the list.
> > 		 * test_and_set_bit() implies a memory barrier.
> > 		 */
> > -		llist_add(&work->node, &dev->worker->work_list);
> > -		vhost_task_wake(dev->worker->vtsk);
> > +		llist_add(&work->node, &dev->worker.work_list);
> > +		vhost_task_wake(dev->worker.vtsk);
> > 	}
> > }
> > EXPORT_SYMBOL_GPL(vhost_work_queue);
> > @@ -264,7 +264,7 @@ EXPORT_SYMBOL_GPL(vhost_work_queue);
> > /* A lockless hint for busy polling code to exit the loop */
> > bool vhost_has_work(struct vhost_dev *dev)
> > {
> > -	return dev->worker && !llist_empty(&dev->worker->work_list);
> > +	return !llist_empty(&dev->worker.work_list);
> > }
> > EXPORT_SYMBOL_GPL(vhost_has_work);
> > 
> > @@ -456,7 +456,8 @@ void vhost_dev_init(struct vhost_dev *dev,
> > 	dev->umem = NULL;
> > 	dev->iotlb = NULL;
> > 	dev->mm = NULL;
> > -	dev->worker = NULL;
> > +	memset(&dev->worker, 0, sizeof(dev->worker));
> > +	init_llist_head(&dev->worker.work_list);
> > 	dev->iov_limit = iov_limit;
> > 	dev->weight = weight;
> > 	dev->byte_weight = byte_weight;
> > @@ -530,47 +531,30 @@ static void vhost_detach_mm(struct vhost_dev *dev)
> > 
> > static void vhost_worker_free(struct vhost_dev *dev)
> > {
> > -	struct vhost_worker *worker = dev->worker;
> > -
> > -	if (!worker)
> > +	if (!dev->worker.vtsk)
> > 		return;
> > 
> > -	dev->worker = NULL;
> > -	WARN_ON(!llist_empty(&worker->work_list));
> > -	vhost_task_stop(worker->vtsk);
> > -	kfree(worker);
> > +	WARN_ON(!llist_empty(&dev->worker.work_list));
> > +	vhost_task_stop(dev->worker.vtsk);
> > +	dev->worker.kcov_handle = 0;
> > +	dev->worker.vtsk = NULL;
> > }
> > 
> > static int vhost_worker_create(struct vhost_dev *dev)
> > {
> > -	struct vhost_worker *worker;
> > 	struct vhost_task *vtsk;
> > 	char name[TASK_COMM_LEN];
> > -	int ret;
> > -
> > -	worker = kzalloc(sizeof(*worker), GFP_KERNEL_ACCOUNT);
> > -	if (!worker)
> > -		return -ENOMEM;
> > 
> > -	dev->worker = worker;
> > -	worker->kcov_handle = kcov_common_handle();
> > -	init_llist_head(&worker->work_list);
> > 	snprintf(name, sizeof(name), "vhost-%d", current->pid);
> > 
> > -	vtsk = vhost_task_create(vhost_worker, worker, name);
> > -	if (!vtsk) {
> > -		ret = -ENOMEM;
> > -		goto free_worker;
> > -	}
> > +	vtsk = vhost_task_create(vhost_worker, &dev->worker, name);
> > +	if (!vtsk)
> > +		return -ENOMEM;
> > 
> > -	worker->vtsk = vtsk;
> > +	dev->worker.kcov_handle = kcov_common_handle();
> > +	dev->worker.vtsk = vtsk;
> 
> Okay, I think we are safe for now for the problem I highlighted in v1:
> 
> Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
> 
> Thanks,
> Stefano
> 
> > 	vhost_task_start(vtsk);
> > 	return 0;
> > -
> > -free_worker:
> > -	kfree(worker);
> > -	dev->worker = NULL;
> > -	return ret;
> > }
> > 
> > /* Caller should have device mutex */
> > diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
> > index 0308638cdeee..305ec8593d46 100644
> > --- a/drivers/vhost/vhost.h
> > +++ b/drivers/vhost/vhost.h
> > @@ -154,7 +154,7 @@ struct vhost_dev {
> > 	struct vhost_virtqueue **vqs;
> > 	int nvqs;
> > 	struct eventfd_ctx *log_ctx;
> > -	struct vhost_worker *worker;
> > +	struct vhost_worker worker;
> > 	struct vhost_iotlb *umem;
> > 	struct vhost_iotlb *iotlb;
> > 	spinlock_t iotlb_lock;
> > -- 
> > 2.25.1
> > 

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2023-06-08 15:11 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-06-07 19:23 vhost: Fix vhost_task regressions in 6.4-rc Mike Christie
2023-06-07 19:23 ` [PATCH 1/2] vhost: Fix crash during early vhost_transport_send_pkt calls Mike Christie
2023-06-08  8:39   ` Stefano Garzarella
2023-06-08 15:11     ` Michael S. Tsirkin
2023-06-07 19:23 ` [PATCH 2/2] vhost: Fix worker hangs due to missed wake up calls Mike Christie
2023-06-07 20:22 ` vhost: Fix vhost_task regressions in 6.4-rc Michael S. Tsirkin
2023-06-08  0:38   ` Mike Christie

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).