* [PATCH hci-8.1 v3 0/4] vhost-blk: switch from VHOST_SET_NWORKERS to the mainstream worker ioctls
@ 2026-10-28 12:33 Alexander Ivanov
2026-10-28 12:33 ` [PATCH hci-8.1 v3 1/4] vhost-backend: add vhost_set_fork_from_owner op Alexander Ivanov
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Alexander Ivanov @ 2026-10-28 12:33 UTC (permalink / raw)
To: andrey.zhadchenko; +Cc: andrey.drobyshev, svt-core
The kernel drops our VHOST_SET_NWORKERS ioctl in favour of the
mainstream VHOST_NEW_WORKER/VHOST_ATTACH_VRING_WORKER, which vhost-blk
now supports.
Patch 1 wraps VHOST_SET_FORK_FROM_OWNER in a vhost backend op. Patch 2
refuses num-queues above VHOST_BLK_MAX_QUEUES at realize. Patch 3 makes
vhost-blk create its num-threads workers with the mainstream ioctls,
keeping the same worker layout, and fall back to a single thread on a
kernel without them. Patch 4 drops VHOST_SET_NWORKERS from
linux-headers.
v3:
- new patch 1: call VHOST_SET_FORK_FROM_OWNER, VHOST_NEW_WORKER and
VHOST_ATTACH_VRING_WORKER through vhost_ops instead of raw ioctls
- new patch 2: refuse num-queues above VHOST_BLK_MAX_QUEUES at realize
instead of clamping num-threads in patch 3
- patch 3: create each worker right before attaching its first vq
v2:
- patch 1: clamp num-threads to VHOST_BLK_MAX_QUEUES
- patch 1: note in the commit message that our kernel, unlike
mainline, defaults to kthreads
https://virtuozzo.atlassian.net/browse/VSTOR-107537
Alexander Ivanov (4):
vhost-backend: add vhost_set_fork_from_owner op
vhost-blk: reject num-queues above VHOST_BLK_MAX_QUEUES
vhost-blk: create kernel threads with the mainstream worker ioctls
linux-headers: drop VHOST_SET_NWORKERS
hw/block/vhost-blk.c | 105 +++++++++++++++++++++++++-----
hw/virtio/vhost-backend.c | 7 ++
include/hw/virtio/vhost-backend.h | 3 +
linux-headers/linux/vhost.h | 9 ---
4 files changed, 99 insertions(+), 25 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH hci-8.1 v3 1/4] vhost-backend: add vhost_set_fork_from_owner op
2026-10-28 12:33 [PATCH hci-8.1 v3 0/4] vhost-blk: switch from VHOST_SET_NWORKERS to the mainstream worker ioctls Alexander Ivanov
@ 2026-10-28 12:33 ` Alexander Ivanov
2026-10-28 12:36 ` no-reply
2026-10-28 15:30 ` Andrey Drobyshev
2026-10-28 12:33 ` [PATCH hci-8.1 v3 2/4] vhost-blk: reject num-queues above VHOST_BLK_MAX_QUEUES Alexander Ivanov
` (2 subsequent siblings)
3 siblings, 2 replies; 13+ messages in thread
From: Alexander Ivanov @ 2026-10-28 12:33 UTC (permalink / raw)
To: andrey.zhadchenko; +Cc: andrey.drobyshev, svt-core
Wrap VHOST_SET_FORK_FROM_OWNER for the kernel backend next to the
worker ops, so devices switch the vhost worker mode the same way they
create and attach workers.
https://virtuozzo.atlassian.net/browse/VSTOR-107537
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
---
hw/virtio/vhost-backend.c | 7 +++++++
include/hw/virtio/vhost-backend.h | 3 +++
2 files changed, 10 insertions(+)
diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c
index 1447d129630..7f8c731a607 100644
--- a/hw/virtio/vhost-backend.c
+++ b/hw/virtio/vhost-backend.c
@@ -187,6 +187,12 @@ static int vhost_kernel_get_vring_worker(struct vhost_dev *dev,
return vhost_kernel_call(dev, VHOST_GET_VRING_WORKER, worker);
}
+static int vhost_kernel_set_fork_from_owner(struct vhost_dev *dev,
+ uint8_t fork_owner)
+{
+ return vhost_kernel_call(dev, VHOST_SET_FORK_FROM_OWNER, &fork_owner);
+}
+
static int vhost_kernel_set_backend_cap(struct vhost_dev *dev)
{
uint64_t features;
@@ -386,6 +392,7 @@ const VhostOps kernel_ops = {
.vhost_attach_vring_worker = vhost_kernel_attach_vring_worker,
.vhost_new_worker = vhost_kernel_new_worker,
.vhost_free_worker = vhost_kernel_free_worker,
+ .vhost_set_fork_from_owner = vhost_kernel_set_fork_from_owner,
.vhost_set_features_ex = vhost_kernel_set_features,
.vhost_get_features_ex = vhost_kernel_get_features,
.vhost_set_backend_cap = vhost_kernel_set_backend_cap,
diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h
index 18ce5ea9a07..78cd66378ef 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -95,6 +95,8 @@ typedef int (*vhost_new_worker_op)(struct vhost_dev *dev,
struct vhost_worker_state *worker);
typedef int (*vhost_free_worker_op)(struct vhost_dev *dev,
struct vhost_worker_state *worker);
+typedef int (*vhost_set_fork_from_owner_op)(struct vhost_dev *dev,
+ uint8_t fork_owner);
typedef int (*vhost_set_features_ex_op)(struct vhost_dev *dev,
const uint64_t *features);
typedef int (*vhost_get_features_ex_op)(struct vhost_dev *dev,
@@ -190,6 +192,7 @@ typedef struct VhostOps {
vhost_free_worker_op vhost_free_worker;
vhost_get_vring_worker_op vhost_get_vring_worker;
vhost_attach_vring_worker_op vhost_attach_vring_worker;
+ vhost_set_fork_from_owner_op vhost_set_fork_from_owner;
vhost_set_features_ex_op vhost_set_features_ex;
vhost_get_features_ex_op vhost_get_features_ex;
vhost_set_features_op vhost_set_features;
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH hci-8.1 v3 2/4] vhost-blk: reject num-queues above VHOST_BLK_MAX_QUEUES
2026-10-28 12:33 [PATCH hci-8.1 v3 0/4] vhost-blk: switch from VHOST_SET_NWORKERS to the mainstream worker ioctls Alexander Ivanov
2026-10-28 12:33 ` [PATCH hci-8.1 v3 1/4] vhost-backend: add vhost_set_fork_from_owner op Alexander Ivanov
@ 2026-10-28 12:33 ` Alexander Ivanov
2026-10-28 12:35 ` no-reply
2026-10-28 15:31 ` Andrey Drobyshev
2026-10-28 12:33 ` [PATCH hci-8.1 v3 3/4] vhost-blk: create kernel threads with the mainstream worker ioctls Alexander Ivanov
2026-10-28 12:33 ` [PATCH hci-8.1 v3 4/4] linux-headers: drop VHOST_SET_NWORKERS Alexander Ivanov
3 siblings, 2 replies; 13+ messages in thread
From: Alexander Ivanov @ 2026-10-28 12:33 UTC (permalink / raw)
To: andrey.zhadchenko; +Cc: andrey.drobyshev, svt-core
Only the automatic num-queues value is capped at VHOST_BLK_MAX_QUEUES,
an explicit one is taken as is. The kernel vhost-blk device has that
many virtqueues and fails VHOST_SET_VRING_NUM on any vq beyond them,
so such a device realizes fine and then never starts. Refuse it at
realize instead.
https://virtuozzo.atlassian.net/browse/VSTOR-107537
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
---
hw/block/vhost-blk.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/hw/block/vhost-blk.c b/hw/block/vhost-blk.c
index abddff02c6d..8a015d54fa7 100644
--- a/hw/block/vhost-blk.c
+++ b/hw/block/vhost-blk.c
@@ -598,8 +598,9 @@ static void vhost_blk_device_realize(DeviceState *dev, Error **errp)
VHOST_BLK_MAX_QUEUES);
}
- if (!conf->num_queues) {
- error_setg(errp, "vhost-blk: num-queues property must be larger than 0");
+ if (!conf->num_queues || conf->num_queues > VHOST_BLK_MAX_QUEUES) {
+ error_setg(errp, "vhost-blk: invalid num-queues property (%" PRIu16 "), "
+ "must be 1-%d", conf->num_queues, VHOST_BLK_MAX_QUEUES);
return;
}
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH hci-8.1 v3 3/4] vhost-blk: create kernel threads with the mainstream worker ioctls
2026-10-28 12:33 [PATCH hci-8.1 v3 0/4] vhost-blk: switch from VHOST_SET_NWORKERS to the mainstream worker ioctls Alexander Ivanov
2026-10-28 12:33 ` [PATCH hci-8.1 v3 1/4] vhost-backend: add vhost_set_fork_from_owner op Alexander Ivanov
2026-10-28 12:33 ` [PATCH hci-8.1 v3 2/4] vhost-blk: reject num-queues above VHOST_BLK_MAX_QUEUES Alexander Ivanov
@ 2026-10-28 12:33 ` Alexander Ivanov
2026-10-28 12:38 ` no-reply
2026-10-28 15:31 ` Andrey Drobyshev
2026-10-28 12:33 ` [PATCH hci-8.1 v3 4/4] linux-headers: drop VHOST_SET_NWORKERS Alexander Ivanov
3 siblings, 2 replies; 13+ messages in thread
From: Alexander Ivanov @ 2026-10-28 12:33 UTC (permalink / raw)
To: andrey.zhadchenko; +Cc: andrey.drobyshev, svt-core
num-threads was passed to our own VHOST_SET_NWORKERS kernel ioctl. The
kernel drops it with the revert of "drivers/vhost: add ioctl to
increase the number of workers" in favour of the mainstream worker
ioctls, which vhost-blk now supports. Create num-threads - 1 workers
with VHOST_NEW_WORKER and attach them to the virtqueues round-robin
with VHOST_ATTACH_VRING_WORKER, the layout VHOST_SET_NWORKERS produced.
Our kernel, unlike mainline, defaults to kthread mode, where
VHOST_NEW_WORKER fails with -EFAULT rather than -ENOTTY. So switch the
device to vhost_task mode with VHOST_SET_FORK_FROM_OWNER before
VHOST_SET_OWNER. With num-threads=1 nothing changes: no worker ioctls,
kthread mode.
Released vz10 kernels have VHOST_SET_FORK_FROM_OWNER, but their
vhost-blk does not handle the worker ioctls and fails VHOST_NEW_WORKER
with -ENOTTY. On such a kernel, or one without
VHOST_SET_FORK_FROM_OWNER, warn and run a single thread rather than
fail to start vhost-blk.
https://virtuozzo.atlassian.net/browse/VSTOR-107537
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
---
hw/block/vhost-blk.c | 100 +++++++++++++++++++++++++++++++++++++------
1 file changed, 86 insertions(+), 14 deletions(-)
diff --git a/hw/block/vhost-blk.c b/hw/block/vhost-blk.c
index 8a015d54fa7..cc05eb057df 100644
--- a/hw/block/vhost-blk.c
+++ b/hw/block/vhost-blk.c
@@ -33,9 +33,60 @@
#include "migration/cpr.h"
#include "system/runstate.h"
+/*
+ * Spread the virtqueues round-robin over nworkers kernel threads. Thread 0 is
+ * the default worker VHOST_SET_OWNER created; vq 0 and every nworkers-th vq
+ * after it stay on it.
+ */
+static int vhost_blk_set_workers(struct vhost_dev *hdev, int nworkers)
+{
+ uint32_t ids[VHOST_BLK_MAX_QUEUES];
+ int i, ret;
+
+ assert(nworkers <= ARRAY_SIZE(ids));
+
+ for (i = 1; i < hdev->nvqs; i++) {
+ int w = i % nworkers;
+ struct vhost_vring_worker vq_worker = { .index = i };
+
+ if (w == 0) {
+ continue;
+ }
+
+ /* vq i < nworkers is the first user of thread i: create it here */
+ if (i < nworkers) {
+ struct vhost_worker_state worker = { };
+
+ ret = hdev->vhost_ops->vhost_new_worker(hdev, &worker);
+ if (ret == -ENOTTY) {
+ /* vhost-blk predating worker ioctls, fails on vq 1 only */
+ warn_report_once("vhost-blk: kernel does not support worker "
+ "ioctls, using a single kernel thread");
+ return 0;
+ } else if (ret < 0) {
+ error_report("vhost-blk: unable to create kernel thread: %s",
+ strerror(-ret));
+ return ret;
+ }
+ ids[w] = worker.worker_id;
+ }
+
+ vq_worker.worker_id = ids[w];
+ ret = hdev->vhost_ops->vhost_attach_vring_worker(hdev, &vq_worker);
+ if (ret < 0) {
+ error_report("vhost-blk: unable to attach kernel thread to "
+ "queue %d: %s", i, strerror(-ret));
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int vhost_blk_start(VirtIODevice *vdev)
{
VHostBlk *s = VHOST_BLK(vdev);
+ struct vhost_dev *hdev = &s->dev;
struct vhost_vring_file backend;
int ret, i, nworkers;
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
@@ -51,15 +102,36 @@ static int vhost_blk_start(VirtIODevice *vdev)
return 0;
}
+ nworkers = MIN(s->conf.num_threads, hdev->nvqs);
+ if (nworkers > 1) {
+ /*
+ * VHOST_NEW_WORKER needs vhost_task mode; our kernel defaults to
+ * kthreads and VHOST_RESET_OWNER brings that default back, so ask
+ * on every start. Must precede VHOST_SET_OWNER.
+ */
+ ret = hdev->vhost_ops->vhost_set_fork_from_owner(hdev,
+ VHOST_FORK_OWNER_TASK);
+ if (ret == -ENOTTY) {
+ warn_report_once("vhost-blk: kernel does not support vhost tasks, "
+ "using a single kernel thread");
+ nworkers = 1;
+ } else if (ret < 0) {
+ error_report("vhost-blk: unable to set vhost task mode: %s",
+ strerror(-ret));
+ return ret;
+ }
+ }
+
if (ioctl(s->vhostfd, VHOST_SET_OWNER, NULL)) {
error_report("vhost-blk: unable to set owner");
return -ENOSYS;
}
- nworkers = s->conf.num_threads;
- if (nworkers != 1 && ioctl(s->vhostfd, VHOST_SET_NWORKERS, &nworkers)) {
- error_report("vhost-blk: unable to set number of kernel threads");
- return -EINVAL;
+ if (nworkers > 1) {
+ ret = vhost_blk_set_workers(hdev, nworkers);
+ if (ret < 0) {
+ return ret;
+ }
}
if (s->conf.serial) {
@@ -70,22 +142,22 @@ static int vhost_blk_start(VirtIODevice *vdev)
}
}
- ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true);
+ ret = k->set_guest_notifiers(qbus->parent, hdev->nvqs, true);
if (ret < 0) {
error_report("vhost-blk: unable to bind guest notifiers");
return ret;
}
- ret = vhost_dev_enable_notifiers(&s->dev, vdev);
+ ret = vhost_dev_enable_notifiers(hdev, vdev);
if (ret < 0) {
error_report("vhost-blk: unable to enable dev notifiers: %s",
strerror(errno));
goto err_set;
}
- s->dev.acked_features = vdev->guest_features & s->dev.features;
+ hdev->acked_features = vdev->guest_features & hdev->features;
- ret = vhost_dev_start(&s->dev, vdev, false);
+ ret = vhost_dev_start(hdev, vdev, false);
if (ret < 0) {
error_report("vhost-blk: unable to start vhost dev");
goto err_disable;
@@ -100,11 +172,11 @@ static int vhost_blk_start(VirtIODevice *vdev)
goto err_stop;
}
- for (i = 0; i < s->dev.nvqs; i++) {
- vhost_virtqueue_mask(&s->dev, vdev, i, false);
+ for (i = 0; i < hdev->nvqs; i++) {
+ vhost_virtqueue_mask(hdev, vdev, i, false);
}
- for (i = 0; i < s->dev.nvqs; i++) {
+ for (i = 0; i < hdev->nvqs; i++) {
event_notifier_set(virtio_queue_get_host_notifier(virtio_get_queue(vdev, i)));
}
@@ -113,11 +185,11 @@ static int vhost_blk_start(VirtIODevice *vdev)
return 0;
err_stop:
- vhost_dev_stop(&s->dev, vdev, false);
+ vhost_dev_stop(hdev, vdev, false);
err_disable:
- vhost_dev_disable_notifiers(&s->dev, vdev);
+ vhost_dev_disable_notifiers(hdev, vdev);
err_set:
- ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
+ ret = k->set_guest_notifiers(qbus->parent, hdev->nvqs, false);
if (ret < 0) {
error_report("vhost-blk: unable to unbind guest notifiers");
}
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH hci-8.1 v3 4/4] linux-headers: drop VHOST_SET_NWORKERS
2026-10-28 12:33 [PATCH hci-8.1 v3 0/4] vhost-blk: switch from VHOST_SET_NWORKERS to the mainstream worker ioctls Alexander Ivanov
` (2 preceding siblings ...)
2026-10-28 12:33 ` [PATCH hci-8.1 v3 3/4] vhost-blk: create kernel threads with the mainstream worker ioctls Alexander Ivanov
@ 2026-10-28 12:33 ` Alexander Ivanov
2026-10-28 12:36 ` no-reply
2026-10-28 15:31 ` Andrey Drobyshev
3 siblings, 2 replies; 13+ messages in thread
From: Alexander Ivanov @ 2026-10-28 12:33 UTC (permalink / raw)
To: andrey.zhadchenko; +Cc: andrey.drobyshev, svt-core
vhost-blk no longer uses it, and the kernel drops the ioctl.
https://virtuozzo.atlassian.net/browse/VSTOR-107537
Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
---
linux-headers/linux/vhost.h | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h
index baad06412d4..b6eb628d973 100644
--- a/linux-headers/linux/vhost.h
+++ b/linux-headers/linux/vhost.h
@@ -102,15 +102,6 @@
#define VHOST_GET_VRING_WORKER _IOWR(VHOST_VIRTIO, 0x16, \
struct vhost_vring_worker)
-/* Set number of vhost workers
- * Currently number of vhost workers can only be increased.
- * All workers are freed upon reset.
- * If the value is too big it is silently truncated to the maximum number of
- * supported vhost workers
- * Even if the error is returned it is possible that some workers were created
- */
-#define VHOST_SET_NWORKERS _IOW(VHOST_VIRTIO, 0x1F, int)
-
/* The following ioctls use eventfd file descriptors to signal and poll
* for events. */
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH hci-8.1 v3 2/4] vhost-blk: reject num-queues above VHOST_BLK_MAX_QUEUES
2026-10-28 12:33 ` [PATCH hci-8.1 v3 2/4] vhost-blk: reject num-queues above VHOST_BLK_MAX_QUEUES Alexander Ivanov
@ 2026-10-28 12:35 ` no-reply
2026-10-28 15:31 ` Andrey Drobyshev
1 sibling, 0 replies; 13+ messages in thread
From: no-reply @ 2026-10-28 12:35 UTC (permalink / raw)
To: Alexander Ivanov, andrey.zhadchenko; +Cc: andrey.drobyshev, svt-core
> Only the automatic num-queues value is capped at VHOST_BLK_MAX_QUEUES,
> an explicit one is taken as is. The kernel vhost-blk device has that
> many virtqueues and fails VHOST_SET_VRING_NUM on any vq beyond them,
> so such a device realizes fine and then never starts. Refuse it at
> realize instead.
>
> https://virtuozzo.atlassian.net/browse/VSTOR-107537
>
> Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261028123333.3145676-1-alexander.ivanov@virtuozzo.com?part=2
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH hci-8.1 v3 1/4] vhost-backend: add vhost_set_fork_from_owner op
2026-10-28 12:33 ` [PATCH hci-8.1 v3 1/4] vhost-backend: add vhost_set_fork_from_owner op Alexander Ivanov
@ 2026-10-28 12:36 ` no-reply
2026-10-28 15:30 ` Andrey Drobyshev
1 sibling, 0 replies; 13+ messages in thread
From: no-reply @ 2026-10-28 12:36 UTC (permalink / raw)
To: andrey.zhadchenko, Alexander Ivanov; +Cc: andrey.drobyshev, svt-core
> Wrap VHOST_SET_FORK_FROM_OWNER for the kernel backend next to the
> worker ops, so devices switch the vhost worker mode the same way they
> create and attach workers.
>
> https://virtuozzo.atlassian.net/browse/VSTOR-107537
>
> Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261028123333.3145676-1-alexander.ivanov@virtuozzo.com?part=1
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH hci-8.1 v3 4/4] linux-headers: drop VHOST_SET_NWORKERS
2026-10-28 12:33 ` [PATCH hci-8.1 v3 4/4] linux-headers: drop VHOST_SET_NWORKERS Alexander Ivanov
@ 2026-10-28 12:36 ` no-reply
2026-10-28 15:31 ` Andrey Drobyshev
1 sibling, 0 replies; 13+ messages in thread
From: no-reply @ 2026-10-28 12:36 UTC (permalink / raw)
To: andrey.zhadchenko, Alexander Ivanov; +Cc: svt-core, andrey.drobyshev
> vhost-blk no longer uses it, and the kernel drops the ioctl.
>
> https://virtuozzo.atlassian.net/browse/VSTOR-107537
>
> Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261028123333.3145676-1-alexander.ivanov@virtuozzo.com?part=4
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH hci-8.1 v3 3/4] vhost-blk: create kernel threads with the mainstream worker ioctls
2026-10-28 12:33 ` [PATCH hci-8.1 v3 3/4] vhost-blk: create kernel threads with the mainstream worker ioctls Alexander Ivanov
@ 2026-10-28 12:38 ` no-reply
2026-10-28 15:31 ` Andrey Drobyshev
1 sibling, 0 replies; 13+ messages in thread
From: no-reply @ 2026-10-28 12:38 UTC (permalink / raw)
To: Alexander Ivanov, andrey.zhadchenko; +Cc: andrey.drobyshev, svt-core
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] vhost-blk: single-thread fallback only handles -ENOTTY from unknown vhost ioctls
- [Low] vhost-blk: ENOTTY worker fallback leaves device in vhost_task mode
- [Low] vhost-blk: num-threads=0 silently accepted as a single kernel thread
--
commit bce7b559a829ea8e18f3184e167eeedc9027e77f
Author: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
vhost-blk: create kernel threads with the mainstream worker ioctls
This patch replaces the VHOST_SET_NWORKERS ioctl with VHOST_NEW_WORKER and
VHOST_ATTACH_VRING_WORKER. It creates num-threads - 1 workers and attaches
them to the virtqueues round-robin. It also switches the device to
vhost_task mode with VHOST_SET_FORK_FROM_OWNER before VHOST_SET_OWNER. If
the kernel lacks these ioctls, it warns and runs a single thread.
Link: https://virtuozzo.atlassian.net/browse/VSTOR-107537
> diff --git a/hw/block/vhost-blk.c b/hw/block/vhost-blk.c
> --- a/hw/block/vhost-blk.c
> +++ b/hw/block/vhost-blk.c
[ ... ]
> +static int vhost_blk_set_workers(struct vhost_dev *hdev, int nworkers)
> +{
[ ... ]
> + ret = hdev->vhost_ops->vhost_new_worker(hdev, &worker);
> + if (ret == -ENOTTY) {
> + /* vhost-blk predating worker ioctls, fails on vq 1 only */
> + warn_report_once("vhost-blk: kernel does not support worker "
> + "ioctls, using a single kernel thread");
> + return 0;
> + } else if (ret < 0) {
> + error_report("vhost-blk: unable to create kernel thread: %s",
> + strerror(-ret));
> + return ret;
> + }
[Severity: Medium]
Is -ENOTTY the only errno an older kernel can return here? The fallback to
a single thread is taken only for an exact -ENOTTY from
vhost_blk_set_workers()->vhost_new_worker(). Any other errno goes through
error_report() and fails vhost_blk_start().
The same applies in vhost_blk_start() to the result of
vhost_set_fork_from_owner():
ret = hdev->vhost_ops->vhost_set_fork_from_owner(hdev,
VHOST_FORK_OWNER_TASK);
if (ret == -ENOTTY) {
...
nworkers = 1;
} else if (ret < 0) {
error_report("vhost-blk: unable to set vhost task mode: %s", ...);
return ret;
Both go through vhost_kernel_call(), which returns the raw -errno from
ioctl().
The comment in vhost_kernel_set_features() says that for unknown vhost
ioctls the kernel interprets the argument as a virtio queue id and most
likely errors out validating that id, instead of reporting an unknown
operation.
If VHOST_SET_FORK_FROM_OWNER falls through to the vring ioctl handler on a
kernel without it, could the result be -ENOBUFS instead of -ENOTTY? In that
case the commit message promise to "warn and run a single thread rather than
fail to start vhost-blk" would not hold when num-threads > 1.
The commit message also notes that VHOST_NEW_WORKER fails with -EFAULT in
kthread mode, so the errno is not uniform across kernel configurations.
I couldn't check the kernel side, so this is based on the in-tree comment.
> + }
> +
> + return 0;
> +}
[ ... ]
> + nworkers = MIN(s->conf.num_threads, hdev->nvqs);
> + if (nworkers > 1) {
[Severity: Low]
If num-threads is 0, nworkers becomes 0 here, so both nworkers > 1 blocks
are skipped. Doesn't vhost_blk_start() then silently run a single kthread
with no diagnostic?
The old code passed num_threads to VHOST_SET_NWORKERS whenever it was not 1,
and failed with -EINVAL if that ioctl failed. vhost_blk_device_realize()
validates num_queues but not num_threads, and the num-threads property is a
DEFINE_PROP_UINT16 with a default of 1 and no range check.
Should num-threads=0 be rejected at realize time, or is the silent fallback
intended? The commit message doesn't mention this change in behaviour.
> + /*
> + * VHOST_NEW_WORKER needs vhost_task mode; our kernel defaults to
> + * kthreads and VHOST_RESET_OWNER brings that default back, so ask
> + * on every start. Must precede VHOST_SET_OWNER.
> + */
> + ret = hdev->vhost_ops->vhost_set_fork_from_owner(hdev,
> + VHOST_FORK_OWNER_TASK);
[Severity: Low]
On a released vz10 kernel that has VHOST_SET_FORK_FROM_OWNER but whose
vhost-blk lacks the worker ioctls, this call succeeds and switches the
device to vhost_task mode. Later, vhost_blk_set_workers() gets -ENOTTY from
vhost_new_worker() on vq 1, warns, and returns 0.
Does anything restore VHOST_FORK_OWNER_KTHREAD on that path? The fallback
then runs one thread in vhost_task mode, while num-threads=1 runs one thread
in kthread mode.
The commit message says "With num-threads=1 nothing changes: no worker
ioctls, kthread mode", but the fallback case isn't described as differing
from it. Is that difference intended?
I couldn't confirm from this tree whether task mode matters for vhost-blk on
those kernels.
> + if (ret == -ENOTTY) {
> + warn_report_once("vhost-blk: kernel does not support vhost tasks, "
> + "using a single kernel thread");
> + nworkers = 1;
> + } else if (ret < 0) {
[ ... ]
--
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261028123333.3145676-1-alexander.ivanov@virtuozzo.com?part=3
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH hci-8.1 v3 1/4] vhost-backend: add vhost_set_fork_from_owner op
2026-10-28 12:33 ` [PATCH hci-8.1 v3 1/4] vhost-backend: add vhost_set_fork_from_owner op Alexander Ivanov
2026-10-28 12:36 ` no-reply
@ 2026-10-28 15:30 ` Andrey Drobyshev
1 sibling, 0 replies; 13+ messages in thread
From: Andrey Drobyshev @ 2026-10-28 15:30 UTC (permalink / raw)
To: Alexander Ivanov, andrey.zhadchenko; +Cc: svt-core
On 10/28/26 2:33 PM, Alexander Ivanov wrote:
> Wrap VHOST_SET_FORK_FROM_OWNER for the kernel backend next to the
> worker ops, so devices switch the vhost worker mode the same way they
> create and attach workers.
>
> https://virtuozzo.atlassian.net/browse/VSTOR-107537
>
> Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
> ---
> [...]
Reviewed-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH hci-8.1 v3 2/4] vhost-blk: reject num-queues above VHOST_BLK_MAX_QUEUES
2026-10-28 12:33 ` [PATCH hci-8.1 v3 2/4] vhost-blk: reject num-queues above VHOST_BLK_MAX_QUEUES Alexander Ivanov
2026-10-28 12:35 ` no-reply
@ 2026-10-28 15:31 ` Andrey Drobyshev
1 sibling, 0 replies; 13+ messages in thread
From: Andrey Drobyshev @ 2026-10-28 15:31 UTC (permalink / raw)
To: Alexander Ivanov, andrey.zhadchenko; +Cc: svt-core
On 10/28/26 2:33 PM, Alexander Ivanov wrote:
> Only the automatic num-queues value is capped at VHOST_BLK_MAX_QUEUES,
> an explicit one is taken as is. The kernel vhost-blk device has that
> many virtqueues and fails VHOST_SET_VRING_NUM on any vq beyond them,
> so such a device realizes fine and then never starts.
This claim isn't quite accurate:
> -device vhost-blk-pci,devpath=/dev/loop0,num-queues=33
> qemu-system-x86_64: vhost_set_vring_call failed: No buffer space available (105)
> qemu-system-x86_64: vhost-blk: vhost initialization failed: No buffer space available
So realize doesn't even work. Just adjust the commit message.
> Refuse it at realize instead.
>
> https://virtuozzo.atlassian.net/browse/VSTOR-107537
>
Let's also add the 'Fixes: 0ff3cb5ff28f ("...")' tag here.
> Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
> ---
> [...]
With that:
Reviewed-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH hci-8.1 v3 4/4] linux-headers: drop VHOST_SET_NWORKERS
2026-10-28 12:33 ` [PATCH hci-8.1 v3 4/4] linux-headers: drop VHOST_SET_NWORKERS Alexander Ivanov
2026-10-28 12:36 ` no-reply
@ 2026-10-28 15:31 ` Andrey Drobyshev
1 sibling, 0 replies; 13+ messages in thread
From: Andrey Drobyshev @ 2026-10-28 15:31 UTC (permalink / raw)
To: Alexander Ivanov, andrey.zhadchenko; +Cc: svt-core
On 10/28/26 2:33 PM, Alexander Ivanov wrote:
> vhost-blk no longer uses it, and the kernel drops the ioctl.
>
> https://virtuozzo.atlassian.net/browse/VSTOR-107537
>
> Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
> ---
> [...]
Reviewed-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH hci-8.1 v3 3/4] vhost-blk: create kernel threads with the mainstream worker ioctls
2026-10-28 12:33 ` [PATCH hci-8.1 v3 3/4] vhost-blk: create kernel threads with the mainstream worker ioctls Alexander Ivanov
2026-10-28 12:38 ` no-reply
@ 2026-10-28 15:31 ` Andrey Drobyshev
1 sibling, 0 replies; 13+ messages in thread
From: Andrey Drobyshev @ 2026-10-28 15:31 UTC (permalink / raw)
To: Alexander Ivanov, andrey.zhadchenko; +Cc: svt-core
On 10/28/26 2:33 PM, Alexander Ivanov wrote:
> num-threads was passed to our own VHOST_SET_NWORKERS kernel ioctl. The
> kernel drops it with the revert of "drivers/vhost: add ioctl to
> increase the number of workers" in favour of the mainstream worker
> ioctls, which vhost-blk now supports. Create num-threads - 1 workers
> with VHOST_NEW_WORKER and attach them to the virtqueues round-robin
> with VHOST_ATTACH_VRING_WORKER, the layout VHOST_SET_NWORKERS produced.
>
> Our kernel, unlike mainline, defaults to kthread mode, where
> VHOST_NEW_WORKER fails with -EFAULT rather than -ENOTTY. So switch the
> device to vhost_task mode with VHOST_SET_FORK_FROM_OWNER before
> VHOST_SET_OWNER. With num-threads=1 nothing changes: no worker ioctls,
> kthread mode.
>
> Released vz10 kernels have VHOST_SET_FORK_FROM_OWNER, but their
> vhost-blk does not handle the worker ioctls and fails VHOST_NEW_WORKER
> with -ENOTTY. On such a kernel, or one without
> VHOST_SET_FORK_FROM_OWNER, warn and run a single thread rather than
> fail to start vhost-blk.
>
> https://virtuozzo.atlassian.net/browse/VSTOR-107537
>
> Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
> ---
> hw/block/vhost-blk.c | 100 +++++++++++++++++++++++++++++++++++++------
> 1 file changed, 86 insertions(+), 14 deletions(-)
>
> diff --git a/hw/block/vhost-blk.c b/hw/block/vhost-blk.c
> index 8a015d54fa7..cc05eb057df 100644
> --- a/hw/block/vhost-blk.c
> +++ b/hw/block/vhost-blk.c
> @@ -33,9 +33,60 @@
> #include "migration/cpr.h"
> #include "system/runstate.h"
>
> +/*
> + * Spread the virtqueues round-robin over nworkers kernel threads. Thread 0 is
> + * the default worker VHOST_SET_OWNER created; vq 0 and every nworkers-th vq
> + * after it stay on it.
> + */
> +static int vhost_blk_set_workers(struct vhost_dev *hdev, int nworkers)
> +{
> + uint32_t ids[VHOST_BLK_MAX_QUEUES];
> + int i, ret;
> +
> + assert(nworkers <= ARRAY_SIZE(ids));
> +
> + for (i = 1; i < hdev->nvqs; i++) {
> + int w = i % nworkers;
> + struct vhost_vring_worker vq_worker = { .index = i };
> +
> + if (w == 0) {
> + continue;
> + }
> +
> + /* vq i < nworkers is the first user of thread i: create it here */
> + if (i < nworkers) {
> + struct vhost_worker_state worker = { };
> +
> + ret = hdev->vhost_ops->vhost_new_worker(hdev, &worker);
> + if (ret == -ENOTTY) {
> + /* vhost-blk predating worker ioctls, fails on vq 1 only */
> + warn_report_once("vhost-blk: kernel does not support worker "
> + "ioctls, using a single kernel thread");
> + return 0;
AFAIU Sashiko is right about failure not always being indicated by
-ENOTTY. We might get EPERM, ENOBUFS, EINVAL, EFAULT.
Maybe let's just stop keying on exact error:
> ret = hdev->vhost_ops->vhost_set_fork_from_owner(hdev, VHOST_FORK_OWNER_TASK);
> if (ret < 0) {
> warn_report_once("vhost-blk: unable to use multiple kernel threads: %s",
> strerror(-ret));
> nworkers = 1;
> }
And the same for vhost_new_worker() inside the loop.
@Andrey Zhadchenko can you confirm that's the right error-handling
approach here?
> + } else if (ret < 0) {
> + error_report("vhost-blk: unable to create kernel thread: %s",
> + strerror(-ret));
> + return ret;
> + }
> + ids[w] = worker.worker_id;
> + }
> +
> + vq_worker.worker_id = ids[w];
> + ret = hdev->vhost_ops->vhost_attach_vring_worker(hdev, &vq_worker);
> + if (ret < 0) {
> + error_report("vhost-blk: unable to attach kernel thread to "
> + "queue %d: %s", i, strerror(-ret));
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> static int vhost_blk_start(VirtIODevice *vdev)
> {
> VHostBlk *s = VHOST_BLK(vdev);
> + struct vhost_dev *hdev = &s->dev;
> struct vhost_vring_file backend;
> int ret, i, nworkers;
> BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
> @@ -51,15 +102,36 @@ static int vhost_blk_start(VirtIODevice *vdev)
> return 0;
> }
>
> + nworkers = MIN(s->conf.num_threads, hdev->nvqs);
> + if (nworkers > 1) {
> + /*
> + * VHOST_NEW_WORKER needs vhost_task mode; our kernel defaults to
> + * kthreads and VHOST_RESET_OWNER brings that default back, so ask
> + * on every start. Must precede VHOST_SET_OWNER.
> + */
> + ret = hdev->vhost_ops->vhost_set_fork_from_owner(hdev,
> + VHOST_FORK_OWNER_TASK);
> + if (ret == -ENOTTY) {
> + warn_report_once("vhost-blk: kernel does not support vhost tasks, "
> + "using a single kernel thread");
> + nworkers = 1;
> + } else if (ret < 0) {
> + error_report("vhost-blk: unable to set vhost task mode: %s",
> + strerror(-ret));
> + return ret;
> + }
> + }
> +
> if (ioctl(s->vhostfd, VHOST_SET_OWNER, NULL)) {
> error_report("vhost-blk: unable to set owner");
> return -ENOSYS;
> }
>
> - nworkers = s->conf.num_threads;
> - if (nworkers != 1 && ioctl(s->vhostfd, VHOST_SET_NWORKERS, &nworkers)) {
> - error_report("vhost-blk: unable to set number of kernel threads");
> - return -EINVAL;
> + if (nworkers > 1) {
> + ret = vhost_blk_set_workers(hdev, nworkers);
> + if (ret < 0) {
> + return ret;
> + }
> }
>
> if (s->conf.serial) {
> @@ -70,22 +142,22 @@ static int vhost_blk_start(VirtIODevice *vdev)
> }
> }
>
> - ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true);
> + ret = k->set_guest_notifiers(qbus->parent, hdev->nvqs, true);
Nit: these s->dev -> hdev replacements generally don't belong here as
they aren't part of the changing logic. Split it into another patch
(maybe covering stop()/reset() as well?) and add 'Fixes: ...' tag, so I
can squash it during the next rebase keeping only the meaningful history.
Andrey
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-10-28 15:31 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-28 12:33 [PATCH hci-8.1 v3 0/4] vhost-blk: switch from VHOST_SET_NWORKERS to the mainstream worker ioctls Alexander Ivanov
2026-10-28 12:33 ` [PATCH hci-8.1 v3 1/4] vhost-backend: add vhost_set_fork_from_owner op Alexander Ivanov
2026-10-28 12:36 ` no-reply
2026-10-28 15:30 ` Andrey Drobyshev
2026-10-28 12:33 ` [PATCH hci-8.1 v3 2/4] vhost-blk: reject num-queues above VHOST_BLK_MAX_QUEUES Alexander Ivanov
2026-10-28 12:35 ` no-reply
2026-10-28 15:31 ` Andrey Drobyshev
2026-10-28 12:33 ` [PATCH hci-8.1 v3 3/4] vhost-blk: create kernel threads with the mainstream worker ioctls Alexander Ivanov
2026-10-28 12:38 ` no-reply
2026-10-28 15:31 ` Andrey Drobyshev
2026-10-28 12:33 ` [PATCH hci-8.1 v3 4/4] linux-headers: drop VHOST_SET_NWORKERS Alexander Ivanov
2026-10-28 12:36 ` no-reply
2026-10-28 15:31 ` Andrey Drobyshev
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.