* [PATCH v4 0/4] virtio-blk: add iothread-vq-mapping parameter
@ 2023-12-20 13:47 Stefan Hajnoczi
2023-12-20 13:47 ` [PATCH v4 1/4] qdev-properties: alias all object class properties Stefan Hajnoczi
` (4 more replies)
0 siblings, 5 replies; 12+ messages in thread
From: Stefan Hajnoczi @ 2023-12-20 13:47 UTC (permalink / raw)
To: qemu-devel
Cc: Michal Privoznik, Kevin Wolf, Hanna Reitz, qemu-block,
Michael S. Tsirkin, Daniel P. Berrangé, Stefan Hajnoczi,
Michael Roth, Eduardo Habkost, Eric Blake, Markus Armbruster,
Paolo Bonzini
v4:
- Use DummyVirtioForceArrays naming in QAPI schema [Markus]
v3:
- Rebased onto Kevin's block branch
- Add StringOutputVisitor "<omitted>" patch to fix "info qtree" crash
- Fix QAPI schema formatting [Markus]
- Eliminate unnecessary local variable in get_iothread_vq_mapping_list() [Markus]
virtio-blk and virtio-scsi devices need a way to specify the mapping between
IOThreads and virtqueues. At the moment all virtqueues are assigned to a single
IOThread or the main loop. This single thread can be a CPU bottleneck, so it is
necessary to allow finer-grained assignment to spread the load. With this
series applied, "pidstat -t 1" shows that guests with -smp 2 or higher are able
to exploit multiple IOThreads.
This series introduces command-line syntax for the new iothread-vq-mapping
property is as follows:
--device '{"driver":"virtio-blk-pci","iothread-vq-mapping":[{"iothread":"iothread0","vqs":[0,1,2]},...]},...'
IOThreads are specified by name and virtqueues are specified by 0-based
index.
It will be common to simply assign virtqueues round-robin across a set
of IOThreads. A convenient syntax that does not require specifying
individual virtqueue indices is available:
--device '{"driver":"virtio-blk-pci","iothread-vq-mapping":[{"iothread":"iothread0"},{"iothread":"iothread1"},...]},...'
There is no way to reassign virtqueues at runtime and I expect that to be a
very rare requirement.
Note that JSON --device syntax is required for the iothread-vq-mapping
parameter because it's non-scalar.
Based-on: 81e69329d6a4018f4b37d15b6fc845fbe585a93b (https://repo.or.cz/qemu/kevin.git block)
Stefan Hajnoczi (4):
qdev-properties: alias all object class properties
string-output-visitor: show structs as "<omitted>"
qdev: add IOThreadVirtQueueMappingList property type
virtio-blk: add iothread-vq-mapping parameter
qapi/virtio.json | 29 +++++
hw/block/dataplane/virtio-blk.h | 3 +
include/hw/qdev-properties-system.h | 5 +
include/hw/virtio/virtio-blk.h | 2 +
include/qapi/string-output-visitor.h | 6 +-
hw/block/dataplane/virtio-blk.c | 155 ++++++++++++++++++++-------
hw/block/virtio-blk.c | 92 +++++++++++++---
hw/core/qdev-properties-system.c | 46 ++++++++
hw/core/qdev-properties.c | 18 ++--
qapi/string-output-visitor.c | 16 +++
10 files changed, 311 insertions(+), 61 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v4 1/4] qdev-properties: alias all object class properties
2023-12-20 13:47 [PATCH v4 0/4] virtio-blk: add iothread-vq-mapping parameter Stefan Hajnoczi
@ 2023-12-20 13:47 ` Stefan Hajnoczi
2023-12-21 12:39 ` Kevin Wolf
2023-12-20 13:47 ` [PATCH v4 2/4] string-output-visitor: show structs as "<omitted>" Stefan Hajnoczi
` (3 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Stefan Hajnoczi @ 2023-12-20 13:47 UTC (permalink / raw)
To: qemu-devel
Cc: Michal Privoznik, Kevin Wolf, Hanna Reitz, qemu-block,
Michael S. Tsirkin, Daniel P. Berrangé, Stefan Hajnoczi,
Michael Roth, Eduardo Habkost, Eric Blake, Markus Armbruster,
Paolo Bonzini
qdev_alias_all_properties() aliases a DeviceState's qdev properties onto
an Object. This is used for VirtioPCIProxy types so that --device
virtio-blk-pci has properties of its embedded --device virtio-blk-device
object.
Currently this function is implemented using qdev properties. Change the
function to use QOM object class properties instead. This works because
qdev properties create QOM object class properties, but it also catches
any QOM object class-only properties that have no qdev properties.
This change ensures that properties of devices are shown with --device
foo,\? even if they are QOM object class properties.
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
hw/core/qdev-properties.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 840006e953..7d6fa726fd 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -1076,16 +1076,18 @@ void device_class_set_props(DeviceClass *dc, Property *props)
void qdev_alias_all_properties(DeviceState *target, Object *source)
{
ObjectClass *class;
- Property *prop;
+ ObjectPropertyIterator iter;
+ ObjectProperty *prop;
class = object_get_class(OBJECT(target));
- do {
- DeviceClass *dc = DEVICE_CLASS(class);
- for (prop = dc->props_; prop && prop->name; prop++) {
- object_property_add_alias(source, prop->name,
- OBJECT(target), prop->name);
+ object_class_property_iter_init(&iter, class);
+ while ((prop = object_property_iter_next(&iter))) {
+ if (object_property_find(source, prop->name)) {
+ continue; /* skip duplicate properties */
}
- class = object_class_get_parent(class);
- } while (class != object_class_by_name(TYPE_DEVICE));
+
+ object_property_add_alias(source, prop->name,
+ OBJECT(target), prop->name);
+ }
}
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v4 2/4] string-output-visitor: show structs as "<omitted>"
2023-12-20 13:47 [PATCH v4 0/4] virtio-blk: add iothread-vq-mapping parameter Stefan Hajnoczi
2023-12-20 13:47 ` [PATCH v4 1/4] qdev-properties: alias all object class properties Stefan Hajnoczi
@ 2023-12-20 13:47 ` Stefan Hajnoczi
2023-12-20 13:47 ` [PATCH v4 3/4] qdev: add IOThreadVirtQueueMappingList property type Stefan Hajnoczi
` (2 subsequent siblings)
4 siblings, 0 replies; 12+ messages in thread
From: Stefan Hajnoczi @ 2023-12-20 13:47 UTC (permalink / raw)
To: qemu-devel
Cc: Michal Privoznik, Kevin Wolf, Hanna Reitz, qemu-block,
Michael S. Tsirkin, Daniel P. Berrangé, Stefan Hajnoczi,
Michael Roth, Eduardo Habkost, Eric Blake, Markus Armbruster,
Paolo Bonzini
StringOutputVisitor crashes when it visits a struct because
->start_struct() is NULL.
Show "<omitted>" instead of crashing. This is necessary because the
virtio-blk-pci iothread-vq-mapping parameter that I'd like to introduce
soon is a list of IOThreadMapping structs.
This patch is a quick fix to solve the crash, but the long-term solution
is replacing StringOutputVisitor with something that can handle the full
gamut of values in QEMU.
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
include/qapi/string-output-visitor.h | 6 +++---
qapi/string-output-visitor.c | 16 ++++++++++++++++
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/include/qapi/string-output-visitor.h b/include/qapi/string-output-visitor.h
index 268dfe9986..b1ee473b30 100644
--- a/include/qapi/string-output-visitor.h
+++ b/include/qapi/string-output-visitor.h
@@ -26,9 +26,9 @@ typedef struct StringOutputVisitor StringOutputVisitor;
* If everything else succeeds, pass @result to visit_complete() to
* collect the result of the visit.
*
- * The string output visitor does not implement support for visiting
- * QAPI structs, alternates, null, or arbitrary QTypes. It also
- * requires a non-null list argument to visit_start_list().
+ * The string output visitor does not implement support for alternates, null,
+ * or arbitrary QTypes. Struct fields are not shown. It also requires a
+ * non-null list argument to visit_start_list().
*/
Visitor *string_output_visitor_new(bool human, char **result);
diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c
index c0cb72dbe4..f0c1dea89e 100644
--- a/qapi/string-output-visitor.c
+++ b/qapi/string-output-visitor.c
@@ -292,6 +292,20 @@ static bool print_type_null(Visitor *v, const char *name, QNull **obj,
return true;
}
+static bool start_struct(Visitor *v, const char *name, void **obj,
+ size_t size, Error **errp)
+{
+ return true;
+}
+
+static void end_struct(Visitor *v, void **obj)
+{
+ StringOutputVisitor *sov = to_sov(v);
+
+ /* TODO actually print struct fields */
+ string_output_set(sov, g_strdup("<omitted>"));
+}
+
static bool
start_list(Visitor *v, const char *name, GenericList **list, size_t size,
Error **errp)
@@ -379,6 +393,8 @@ Visitor *string_output_visitor_new(bool human, char **result)
v->visitor.type_str = print_type_str;
v->visitor.type_number = print_type_number;
v->visitor.type_null = print_type_null;
+ v->visitor.start_struct = start_struct;
+ v->visitor.end_struct = end_struct;
v->visitor.start_list = start_list;
v->visitor.next_list = next_list;
v->visitor.end_list = end_list;
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v4 3/4] qdev: add IOThreadVirtQueueMappingList property type
2023-12-20 13:47 [PATCH v4 0/4] virtio-blk: add iothread-vq-mapping parameter Stefan Hajnoczi
2023-12-20 13:47 ` [PATCH v4 1/4] qdev-properties: alias all object class properties Stefan Hajnoczi
2023-12-20 13:47 ` [PATCH v4 2/4] string-output-visitor: show structs as "<omitted>" Stefan Hajnoczi
@ 2023-12-20 13:47 ` Stefan Hajnoczi
2023-12-20 13:47 ` [PATCH v4 4/4] virtio-blk: add iothread-vq-mapping parameter Stefan Hajnoczi
2023-12-21 21:07 ` [PATCH v4 0/4] " Kevin Wolf
4 siblings, 0 replies; 12+ messages in thread
From: Stefan Hajnoczi @ 2023-12-20 13:47 UTC (permalink / raw)
To: qemu-devel
Cc: Michal Privoznik, Kevin Wolf, Hanna Reitz, qemu-block,
Michael S. Tsirkin, Daniel P. Berrangé, Stefan Hajnoczi,
Michael Roth, Eduardo Habkost, Eric Blake, Markus Armbruster,
Paolo Bonzini
virtio-blk and virtio-scsi devices will need a way to specify the
mapping between IOThreads and virtqueues. At the moment all virtqueues
are assigned to a single IOThread or the main loop. This single thread
can be a CPU bottleneck, so it is necessary to allow finer-grained
assignment to spread the load.
Introduce DEFINE_PROP_IOTHREAD_VQ_MAPPING_LIST() so devices can take a
parameter that maps virtqueues to IOThreads. The command-line syntax for
this new property is as follows:
--device '{"driver":"foo","iothread-vq-mapping":[{"iothread":"iothread0","vqs":[0,1,2]},...]}'
IOThreads are specified by name and virtqueues are specified by 0-based
index.
It will be common to simply assign virtqueues round-robin across a set
of IOThreads. A convenient syntax that does not require specifying
individual virtqueue indices is available:
--device '{"driver":"foo","iothread-vq-mapping":[{"iothread":"iothread0"},{"iothread":"iothread1"},...]}'
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
qapi/virtio.json | 29 ++++++++++++++++++
include/hw/qdev-properties-system.h | 5 ++++
hw/core/qdev-properties-system.c | 46 +++++++++++++++++++++++++++++
3 files changed, 80 insertions(+)
diff --git a/qapi/virtio.json b/qapi/virtio.json
index e6dcee7b83..19c7c36e36 100644
--- a/qapi/virtio.json
+++ b/qapi/virtio.json
@@ -928,3 +928,32 @@
'data': { 'path': 'str', 'queue': 'uint16', '*index': 'uint16' },
'returns': 'VirtioQueueElement',
'features': [ 'unstable' ] }
+
+##
+# @IOThreadVirtQueueMapping:
+#
+# Describes the subset of virtqueues assigned to an IOThread.
+#
+# @iothread: the id of IOThread object
+#
+# @vqs: an optional array of virtqueue indices that will be handled by this
+# IOThread. When absent, virtqueues are assigned round-robin across all
+# IOThreadVirtQueueMappings provided. Either all IOThreadVirtQueueMappings
+# must have @vqs or none of them must have it.
+#
+# Since: 9.0
+##
+
+{ 'struct': 'IOThreadVirtQueueMapping',
+ 'data': { 'iothread': 'str', '*vqs': ['uint16'] } }
+
+##
+# @DummyVirtioForceArrays:
+#
+# Not used by QMP; hack to let us use IOThreadVirtQueueMappingList internally
+#
+# Since: 9.0
+##
+
+{ 'struct': 'DummyVirtioForceArrays',
+ 'data': { 'unused-iothread-vq-mapping': ['IOThreadVirtQueueMapping'] } }
diff --git a/include/hw/qdev-properties-system.h b/include/hw/qdev-properties-system.h
index 91f7a2452d..06c359c190 100644
--- a/include/hw/qdev-properties-system.h
+++ b/include/hw/qdev-properties-system.h
@@ -24,6 +24,7 @@ extern const PropertyInfo qdev_prop_off_auto_pcibar;
extern const PropertyInfo qdev_prop_pcie_link_speed;
extern const PropertyInfo qdev_prop_pcie_link_width;
extern const PropertyInfo qdev_prop_cpus390entitlement;
+extern const PropertyInfo qdev_prop_iothread_vq_mapping_list;
#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
@@ -82,4 +83,8 @@ extern const PropertyInfo qdev_prop_cpus390entitlement;
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_cpus390entitlement, \
CpuS390Entitlement)
+#define DEFINE_PROP_IOTHREAD_VQ_MAPPING_LIST(_name, _state, _field) \
+ DEFINE_PROP(_name, _state, _field, qdev_prop_iothread_vq_mapping_list, \
+ IOThreadVirtQueueMappingList *)
+
#endif
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 73cced4626..1a396521d5 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -18,6 +18,7 @@
#include "qapi/qapi-types-block.h"
#include "qapi/qapi-types-machine.h"
#include "qapi/qapi-types-migration.h"
+#include "qapi/qapi-visit-virtio.h"
#include "qapi/qmp/qerror.h"
#include "qemu/ctype.h"
#include "qemu/cutils.h"
@@ -1160,3 +1161,48 @@ const PropertyInfo qdev_prop_cpus390entitlement = {
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
};
+
+/* --- IOThreadVirtQueueMappingList --- */
+
+static void get_iothread_vq_mapping_list(Object *obj, Visitor *v,
+ const char *name, void *opaque, Error **errp)
+{
+ IOThreadVirtQueueMappingList **prop_ptr =
+ object_field_prop_ptr(obj, opaque);
+
+ visit_type_IOThreadVirtQueueMappingList(v, name, prop_ptr, errp);
+}
+
+static void set_iothread_vq_mapping_list(Object *obj, Visitor *v,
+ const char *name, void *opaque, Error **errp)
+{
+ IOThreadVirtQueueMappingList **prop_ptr =
+ object_field_prop_ptr(obj, opaque);
+ IOThreadVirtQueueMappingList *list;
+
+ if (!visit_type_IOThreadVirtQueueMappingList(v, name, &list, errp)) {
+ return;
+ }
+
+ qapi_free_IOThreadVirtQueueMappingList(*prop_ptr);
+ *prop_ptr = list;
+}
+
+static void release_iothread_vq_mapping_list(Object *obj,
+ const char *name, void *opaque)
+{
+ IOThreadVirtQueueMappingList **prop_ptr =
+ object_field_prop_ptr(obj, opaque);
+
+ qapi_free_IOThreadVirtQueueMappingList(*prop_ptr);
+ *prop_ptr = NULL;
+}
+
+const PropertyInfo qdev_prop_iothread_vq_mapping_list = {
+ .name = "IOThreadVirtQueueMappingList",
+ .description = "IOThread virtqueue mapping list [{\"iothread\":\"<id>\", "
+ "\"vqs\":[1,2,3,...]},...]",
+ .get = get_iothread_vq_mapping_list,
+ .set = set_iothread_vq_mapping_list,
+ .release = release_iothread_vq_mapping_list,
+};
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v4 4/4] virtio-blk: add iothread-vq-mapping parameter
2023-12-20 13:47 [PATCH v4 0/4] virtio-blk: add iothread-vq-mapping parameter Stefan Hajnoczi
` (2 preceding siblings ...)
2023-12-20 13:47 ` [PATCH v4 3/4] qdev: add IOThreadVirtQueueMappingList property type Stefan Hajnoczi
@ 2023-12-20 13:47 ` Stefan Hajnoczi
2023-12-21 13:10 ` Kevin Wolf
2023-12-21 13:40 ` Kevin Wolf
2023-12-21 21:07 ` [PATCH v4 0/4] " Kevin Wolf
4 siblings, 2 replies; 12+ messages in thread
From: Stefan Hajnoczi @ 2023-12-20 13:47 UTC (permalink / raw)
To: qemu-devel
Cc: Michal Privoznik, Kevin Wolf, Hanna Reitz, qemu-block,
Michael S. Tsirkin, Daniel P. Berrangé, Stefan Hajnoczi,
Michael Roth, Eduardo Habkost, Eric Blake, Markus Armbruster,
Paolo Bonzini
Add the iothread-vq-mapping parameter to assign virtqueues to IOThreads.
Store the vq:AioContext mapping in the new struct
VirtIOBlockDataPlane->vq_aio_context[] field and refactor the code to
use the per-vq AioContext instead of the BlockDriverState's AioContext.
Reimplement --device virtio-blk-pci,iothread= and non-IOThread mode by
assigning all virtqueues to the IOThread and main loop's AioContext in
vq_aio_context[], respectively.
The comment in struct VirtIOBlockDataPlane about EventNotifiers is
stale. Remove it.
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
hw/block/dataplane/virtio-blk.h | 3 +
include/hw/virtio/virtio-blk.h | 2 +
hw/block/dataplane/virtio-blk.c | 155 ++++++++++++++++++++++++--------
hw/block/virtio-blk.c | 92 ++++++++++++++++---
4 files changed, 202 insertions(+), 50 deletions(-)
diff --git a/hw/block/dataplane/virtio-blk.h b/hw/block/dataplane/virtio-blk.h
index 5e18bb99ae..1a806fe447 100644
--- a/hw/block/dataplane/virtio-blk.h
+++ b/hw/block/dataplane/virtio-blk.h
@@ -28,4 +28,7 @@ void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s, VirtQueue *vq);
int virtio_blk_data_plane_start(VirtIODevice *vdev);
void virtio_blk_data_plane_stop(VirtIODevice *vdev);
+void virtio_blk_data_plane_detach(VirtIOBlockDataPlane *s);
+void virtio_blk_data_plane_attach(VirtIOBlockDataPlane *s);
+
#endif /* HW_DATAPLANE_VIRTIO_BLK_H */
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
index 9881009c22..5e4091e4da 100644
--- a/include/hw/virtio/virtio-blk.h
+++ b/include/hw/virtio/virtio-blk.h
@@ -21,6 +21,7 @@
#include "sysemu/block-backend.h"
#include "sysemu/block-ram-registrar.h"
#include "qom/object.h"
+#include "qapi/qapi-types-virtio.h"
#define TYPE_VIRTIO_BLK "virtio-blk-device"
OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBlock, VIRTIO_BLK)
@@ -37,6 +38,7 @@ struct VirtIOBlkConf
{
BlockConf conf;
IOThread *iothread;
+ IOThreadVirtQueueMappingList *iothread_vq_mapping_list;
char *serial;
uint32_t request_merging;
uint16_t num_queues;
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index 7bbbd981ad..6debd4401e 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -32,13 +32,11 @@ struct VirtIOBlockDataPlane {
VirtIOBlkConf *conf;
VirtIODevice *vdev;
- /* Note that these EventNotifiers are assigned by value. This is
- * fine as long as you do not call event_notifier_cleanup on them
- * (because you don't own the file descriptor or handle; you just
- * use it).
+ /*
+ * The AioContext for each virtqueue. The BlockDriverState will use the
+ * first element as its AioContext.
*/
- IOThread *iothread;
- AioContext *ctx;
+ AioContext **vq_aio_context;
};
/* Raise an interrupt to signal guest, if necessary */
@@ -47,6 +45,45 @@ void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s, VirtQueue *vq)
virtio_notify_irqfd(s->vdev, vq);
}
+/* Generate vq:AioContext mappings from a validated iothread-vq-mapping list */
+static void
+apply_vq_mapping(IOThreadVirtQueueMappingList *iothread_vq_mapping_list,
+ AioContext **vq_aio_context, uint16_t num_queues)
+{
+ IOThreadVirtQueueMappingList *node;
+ size_t num_iothreads = 0;
+ size_t cur_iothread = 0;
+
+ for (node = iothread_vq_mapping_list; node; node = node->next) {
+ num_iothreads++;
+ }
+
+ for (node = iothread_vq_mapping_list; node; node = node->next) {
+ IOThread *iothread = iothread_by_id(node->value->iothread);
+ AioContext *ctx = iothread_get_aio_context(iothread);
+
+ /* Released in virtio_blk_data_plane_destroy() */
+ object_ref(OBJECT(iothread));
+
+ if (node->value->vqs) {
+ uint16List *vq;
+
+ /* Explicit vq:IOThread assignment */
+ for (vq = node->value->vqs; vq; vq = vq->next) {
+ vq_aio_context[vq->value] = ctx;
+ }
+ } else {
+ /* Round-robin vq:IOThread assignment */
+ for (unsigned i = cur_iothread; i < num_queues;
+ i += num_iothreads) {
+ vq_aio_context[i] = ctx;
+ }
+ }
+
+ cur_iothread++;
+ }
+}
+
/* Context: QEMU global mutex held */
bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
VirtIOBlockDataPlane **dataplane,
@@ -58,7 +95,7 @@ bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
*dataplane = NULL;
- if (conf->iothread) {
+ if (conf->iothread || conf->iothread_vq_mapping_list) {
if (!k->set_guest_notifiers || !k->ioeventfd_assign) {
error_setg(errp,
"device is incompatible with iothread "
@@ -86,13 +123,24 @@ bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
s = g_new0(VirtIOBlockDataPlane, 1);
s->vdev = vdev;
s->conf = conf;
+ s->vq_aio_context = g_new(AioContext *, conf->num_queues);
- if (conf->iothread) {
- s->iothread = conf->iothread;
- object_ref(OBJECT(s->iothread));
- s->ctx = iothread_get_aio_context(s->iothread);
+ if (conf->iothread_vq_mapping_list) {
+ apply_vq_mapping(conf->iothread_vq_mapping_list, s->vq_aio_context,
+ conf->num_queues);
+ } else if (conf->iothread) {
+ AioContext *ctx = iothread_get_aio_context(conf->iothread);
+ for (unsigned i = 0; i < conf->num_queues; i++) {
+ s->vq_aio_context[i] = ctx;
+ }
+
+ /* Released in virtio_blk_data_plane_destroy() */
+ object_ref(OBJECT(conf->iothread));
} else {
- s->ctx = qemu_get_aio_context();
+ AioContext *ctx = qemu_get_aio_context();
+ for (unsigned i = 0; i < conf->num_queues; i++) {
+ s->vq_aio_context[i] = ctx;
+ }
}
*dataplane = s;
@@ -104,6 +152,7 @@ bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
{
VirtIOBlock *vblk;
+ VirtIOBlkConf *conf = s->conf;
if (!s) {
return;
@@ -111,9 +160,21 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
vblk = VIRTIO_BLK(s->vdev);
assert(!vblk->dataplane_started);
- if (s->iothread) {
- object_unref(OBJECT(s->iothread));
+
+ if (conf->iothread_vq_mapping_list) {
+ IOThreadVirtQueueMappingList *node;
+
+ for (node = conf->iothread_vq_mapping_list; node; node = node->next) {
+ IOThread *iothread = iothread_by_id(node->value->iothread);
+ object_unref(OBJECT(iothread));
+ }
}
+
+ if (conf->iothread) {
+ object_unref(OBJECT(conf->iothread));
+ }
+
+ g_free(s->vq_aio_context);
g_free(s);
}
@@ -177,19 +238,13 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
trace_virtio_blk_data_plane_start(s);
- r = blk_set_aio_context(s->conf->conf.blk, s->ctx, &local_err);
+ r = blk_set_aio_context(s->conf->conf.blk, s->vq_aio_context[0],
+ &local_err);
if (r < 0) {
error_report_err(local_err);
goto fail_aio_context;
}
- /* Kick right away to begin processing requests already in vring */
- for (i = 0; i < nvqs; i++) {
- VirtQueue *vq = virtio_get_queue(s->vdev, i);
-
- event_notifier_set(virtio_queue_get_host_notifier(vq));
- }
-
/*
* These fields must be visible to the IOThread when it processes the
* virtqueue, otherwise it will think dataplane has not started yet.
@@ -206,8 +261,12 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
if (!blk_in_drain(s->conf->conf.blk)) {
for (i = 0; i < nvqs; i++) {
VirtQueue *vq = virtio_get_queue(s->vdev, i);
+ AioContext *ctx = s->vq_aio_context[i];
- virtio_queue_aio_attach_host_notifier(vq, s->ctx);
+ /* Kick right away to begin processing requests already in vring */
+ event_notifier_set(virtio_queue_get_host_notifier(vq));
+
+ virtio_queue_aio_attach_host_notifier(vq, ctx);
}
}
return 0;
@@ -236,23 +295,18 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
*
* Context: BH in IOThread
*/
-static void virtio_blk_data_plane_stop_bh(void *opaque)
+static void virtio_blk_data_plane_stop_vq_bh(void *opaque)
{
- VirtIOBlockDataPlane *s = opaque;
- unsigned i;
+ VirtQueue *vq = opaque;
+ EventNotifier *host_notifier = virtio_queue_get_host_notifier(vq);
- for (i = 0; i < s->conf->num_queues; i++) {
- VirtQueue *vq = virtio_get_queue(s->vdev, i);
- EventNotifier *host_notifier = virtio_queue_get_host_notifier(vq);
+ virtio_queue_aio_detach_host_notifier(vq, qemu_get_current_aio_context());
- virtio_queue_aio_detach_host_notifier(vq, s->ctx);
-
- /*
- * Test and clear notifier after disabling event, in case poll callback
- * didn't have time to run.
- */
- virtio_queue_host_notifier_read(host_notifier);
- }
+ /*
+ * Test and clear notifier after disabling event, in case poll callback
+ * didn't have time to run.
+ */
+ virtio_queue_host_notifier_read(host_notifier);
}
/* Context: QEMU global mutex held */
@@ -279,7 +333,12 @@ void virtio_blk_data_plane_stop(VirtIODevice *vdev)
trace_virtio_blk_data_plane_stop(s);
if (!blk_in_drain(s->conf->conf.blk)) {
- aio_wait_bh_oneshot(s->ctx, virtio_blk_data_plane_stop_bh, s);
+ for (i = 0; i < nvqs; i++) {
+ VirtQueue *vq = virtio_get_queue(s->vdev, i);
+ AioContext *ctx = s->vq_aio_context[i];
+
+ aio_wait_bh_oneshot(ctx, virtio_blk_data_plane_stop_vq_bh, vq);
+ }
}
/*
@@ -322,3 +381,23 @@ void virtio_blk_data_plane_stop(VirtIODevice *vdev)
s->stopping = false;
}
+
+void virtio_blk_data_plane_detach(VirtIOBlockDataPlane *s)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(s->vdev);
+
+ for (uint16_t i = 0; i < s->conf->num_queues; i++) {
+ VirtQueue *vq = virtio_get_queue(vdev, i);
+ virtio_queue_aio_detach_host_notifier(vq, s->vq_aio_context[i]);
+ }
+}
+
+void virtio_blk_data_plane_attach(VirtIOBlockDataPlane *s)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(s->vdev);
+
+ for (uint16_t i = 0; i < s->conf->num_queues; i++) {
+ VirtQueue *vq = virtio_get_queue(vdev, i);
+ virtio_queue_aio_attach_host_notifier(vq, s->vq_aio_context[i]);
+ }
+}
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index ec9ed09a6a..46e73b2c96 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -1151,6 +1151,7 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
return;
}
}
+
virtio_blk_handle_vq(s, vq);
}
@@ -1463,6 +1464,68 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
return 0;
}
+static bool
+validate_iothread_vq_mapping_list(IOThreadVirtQueueMappingList *list,
+ uint16_t num_queues, Error **errp)
+{
+ g_autofree unsigned long *vqs = bitmap_new(num_queues);
+ g_autoptr(GHashTable) iothreads =
+ g_hash_table_new(g_str_hash, g_str_equal);
+
+ for (IOThreadVirtQueueMappingList *node = list; node; node = node->next) {
+ const char *name = node->value->iothread;
+ uint16List *vq;
+
+ if (!iothread_by_id(name)) {
+ error_setg(errp, "IOThread \"%s\" object does not exist", name);
+ return false;
+ }
+
+ if (!g_hash_table_add(iothreads, (gpointer)name)) {
+ error_setg(errp,
+ "duplicate IOThread name \"%s\" in iothread-vq-mapping",
+ name);
+ return false;
+ }
+
+ if (node != list) {
+ if (!!node->value->vqs != !!list->value->vqs) {
+ error_setg(errp, "either all items in iothread-vq-mapping "
+ "must have vqs or none of them must have it");
+ return false;
+ }
+ }
+
+ for (vq = node->value->vqs; vq; vq = vq->next) {
+ if (vq->value >= num_queues) {
+ error_setg(errp, "vq index %u for IOThread \"%s\" must be "
+ "less than num_queues %u in iothread-vq-mapping",
+ vq->value, name, num_queues);
+ return false;
+ }
+
+ if (test_and_set_bit(vq->value, vqs)) {
+ error_setg(errp, "cannot assign vq %u to IOThread \"%s\" "
+ "because it is already assigned", vq->value, name);
+ return false;
+ }
+ }
+ }
+
+ if (list->value->vqs) {
+ for (uint16_t i = 0; i < num_queues; i++) {
+ if (!test_bit(i, vqs)) {
+ error_setg(errp,
+ "missing vq %u IOThread assignment in iothread-vq-mapping",
+ i);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
static void virtio_resize_cb(void *opaque)
{
VirtIODevice *vdev = opaque;
@@ -1487,34 +1550,24 @@ static void virtio_blk_resize(void *opaque)
static void virtio_blk_drained_begin(void *opaque)
{
VirtIOBlock *s = opaque;
- VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
- AioContext *ctx = blk_get_aio_context(s->conf.conf.blk);
if (!s->dataplane || !s->dataplane_started) {
return;
}
- for (uint16_t i = 0; i < s->conf.num_queues; i++) {
- VirtQueue *vq = virtio_get_queue(vdev, i);
- virtio_queue_aio_detach_host_notifier(vq, ctx);
- }
+ virtio_blk_data_plane_detach(s->dataplane);
}
/* Resume virtqueue ioeventfd processing after drain */
static void virtio_blk_drained_end(void *opaque)
{
VirtIOBlock *s = opaque;
- VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
- AioContext *ctx = blk_get_aio_context(s->conf.conf.blk);
if (!s->dataplane || !s->dataplane_started) {
return;
}
- for (uint16_t i = 0; i < s->conf.num_queues; i++) {
- VirtQueue *vq = virtio_get_queue(vdev, i);
- virtio_queue_aio_attach_host_notifier(vq, ctx);
- }
+ virtio_blk_data_plane_attach(s->dataplane);
}
static const BlockDevOps virtio_block_ops = {
@@ -1600,6 +1653,19 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
return;
}
+ if (conf->iothread_vq_mapping_list) {
+ if (conf->iothread) {
+ error_setg(errp, "iothread and iothread-vq-mapping properties "
+ "cannot be set at the same time");
+ return;
+ }
+
+ if (!validate_iothread_vq_mapping_list(conf->iothread_vq_mapping_list,
+ conf->num_queues, errp)) {
+ return;
+ }
+ }
+
s->config_size = virtio_get_config_size(&virtio_blk_cfg_size_params,
s->host_features);
virtio_init(vdev, VIRTIO_ID_BLOCK, s->config_size);
@@ -1702,6 +1768,8 @@ static Property virtio_blk_properties[] = {
DEFINE_PROP_BOOL("seg-max-adjust", VirtIOBlock, conf.seg_max_adjust, true),
DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD,
IOThread *),
+ DEFINE_PROP_IOTHREAD_VQ_MAPPING_LIST("iothread-vq-mapping", VirtIOBlock,
+ conf.iothread_vq_mapping_list),
DEFINE_PROP_BIT64("discard", VirtIOBlock, host_features,
VIRTIO_BLK_F_DISCARD, true),
DEFINE_PROP_BOOL("report-discard-granularity", VirtIOBlock,
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v4 1/4] qdev-properties: alias all object class properties
2023-12-20 13:47 ` [PATCH v4 1/4] qdev-properties: alias all object class properties Stefan Hajnoczi
@ 2023-12-21 12:39 ` Kevin Wolf
2023-12-21 15:47 ` Stefan Hajnoczi
0 siblings, 1 reply; 12+ messages in thread
From: Kevin Wolf @ 2023-12-21 12:39 UTC (permalink / raw)
To: Stefan Hajnoczi
Cc: qemu-devel, Michal Privoznik, Hanna Reitz, qemu-block,
Michael S. Tsirkin, Daniel P. Berrangé, Michael Roth,
Eduardo Habkost, Eric Blake, Markus Armbruster, Paolo Bonzini
Am 20.12.2023 um 14:47 hat Stefan Hajnoczi geschrieben:
> qdev_alias_all_properties() aliases a DeviceState's qdev properties onto
> an Object. This is used for VirtioPCIProxy types so that --device
> virtio-blk-pci has properties of its embedded --device virtio-blk-device
> object.
>
> Currently this function is implemented using qdev properties. Change the
> function to use QOM object class properties instead. This works because
> qdev properties create QOM object class properties, but it also catches
> any QOM object class-only properties that have no qdev properties.
>
> This change ensures that properties of devices are shown with --device
> foo,\? even if they are QOM object class properties.
>
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
We should also update the comment to refer to properties in general
rather than just qdev properties. I can squash in the following hunk.
Kevin
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 25743a29a0..09aa04ca1e 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -230,8 +230,8 @@ void qdev_property_add_static(DeviceState *dev, Property *prop);
* @target: Device which has properties to be aliased
* @source: Object to add alias properties to
*
- * Add alias properties to the @source object for all qdev properties on
- * the @target DeviceState.
+ * Add alias properties to the @source object for all properties on the @target
+ * DeviceState.
*
* This is useful when @target is an internal implementation object
* owned by @source, and you want to expose all the properties of that
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v4 4/4] virtio-blk: add iothread-vq-mapping parameter
2023-12-20 13:47 ` [PATCH v4 4/4] virtio-blk: add iothread-vq-mapping parameter Stefan Hajnoczi
@ 2023-12-21 13:10 ` Kevin Wolf
2024-01-18 21:28 ` Stefan Hajnoczi
2023-12-21 13:40 ` Kevin Wolf
1 sibling, 1 reply; 12+ messages in thread
From: Kevin Wolf @ 2023-12-21 13:10 UTC (permalink / raw)
To: Stefan Hajnoczi
Cc: qemu-devel, Michal Privoznik, Hanna Reitz, qemu-block,
Michael S. Tsirkin, Daniel P. Berrangé, Michael Roth,
Eduardo Habkost, Eric Blake, Markus Armbruster, Paolo Bonzini
Am 20.12.2023 um 14:47 hat Stefan Hajnoczi geschrieben:
> Add the iothread-vq-mapping parameter to assign virtqueues to IOThreads.
> Store the vq:AioContext mapping in the new struct
> VirtIOBlockDataPlane->vq_aio_context[] field and refactor the code to
> use the per-vq AioContext instead of the BlockDriverState's AioContext.
>
> Reimplement --device virtio-blk-pci,iothread= and non-IOThread mode by
> assigning all virtqueues to the IOThread and main loop's AioContext in
> vq_aio_context[], respectively.
>
> The comment in struct VirtIOBlockDataPlane about EventNotifiers is
> stale. Remove it.
>
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
I'm looking at virtio_blk_dma_restart_cb/bh(). It seems to run all
queued requests in the iothread of the first vq, but when the requests
complete, they will push the result to their original vq.
Do we know that the dataplane isn't started and won't be started until
the requests complete? (I wouldn't expect so, because then moving to the
AioContext of the BlockBackend wouldn't have been necessary either.) Or
is there another reason why this is safe?
Kevin
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 4/4] virtio-blk: add iothread-vq-mapping parameter
2023-12-20 13:47 ` [PATCH v4 4/4] virtio-blk: add iothread-vq-mapping parameter Stefan Hajnoczi
2023-12-21 13:10 ` Kevin Wolf
@ 2023-12-21 13:40 ` Kevin Wolf
2024-01-19 13:41 ` Stefan Hajnoczi
1 sibling, 1 reply; 12+ messages in thread
From: Kevin Wolf @ 2023-12-21 13:40 UTC (permalink / raw)
To: Stefan Hajnoczi
Cc: qemu-devel, Michal Privoznik, Hanna Reitz, qemu-block,
Michael S. Tsirkin, Daniel P. Berrangé, Michael Roth,
Eduardo Habkost, Eric Blake, Markus Armbruster, Paolo Bonzini
Am 20.12.2023 um 14:47 hat Stefan Hajnoczi geschrieben:
> Add the iothread-vq-mapping parameter to assign virtqueues to IOThreads.
> Store the vq:AioContext mapping in the new struct
> VirtIOBlockDataPlane->vq_aio_context[] field and refactor the code to
> use the per-vq AioContext instead of the BlockDriverState's AioContext.
>
> Reimplement --device virtio-blk-pci,iothread= and non-IOThread mode by
> assigning all virtqueues to the IOThread and main loop's AioContext in
> vq_aio_context[], respectively.
>
> The comment in struct VirtIOBlockDataPlane about EventNotifiers is
> stale. Remove it.
>
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> @@ -177,19 +238,13 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
>
> trace_virtio_blk_data_plane_start(s);
>
> - r = blk_set_aio_context(s->conf->conf.blk, s->ctx, &local_err);
> + r = blk_set_aio_context(s->conf->conf.blk, s->vq_aio_context[0],
> + &local_err);
> if (r < 0) {
> error_report_err(local_err);
> goto fail_aio_context;
> }
This doesn't really have to be an error any more, we'll just submit I/O
from any thread we want no matter what the home AioContext of the
BlockBackend is.
So the only effect the blk_set_aio_context() has is that other users of
the image try to submit their requests from the same iothread as the
first virtqueue in the hope that this performs a bit better (maybe less
lock contention or whatever the idea was?)
> - /* Kick right away to begin processing requests already in vring */
> - for (i = 0; i < nvqs; i++) {
> - VirtQueue *vq = virtio_get_queue(s->vdev, i);
> -
> - event_notifier_set(virtio_queue_get_host_notifier(vq));
> - }
> -
> /*
> * These fields must be visible to the IOThread when it processes the
> * virtqueue, otherwise it will think dataplane has not started yet.
> @@ -206,8 +261,12 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
> if (!blk_in_drain(s->conf->conf.blk)) {
> for (i = 0; i < nvqs; i++) {
> VirtQueue *vq = virtio_get_queue(s->vdev, i);
> + AioContext *ctx = s->vq_aio_context[i];
>
> - virtio_queue_aio_attach_host_notifier(vq, s->ctx);
> + /* Kick right away to begin processing requests already in vring */
> + event_notifier_set(virtio_queue_get_host_notifier(vq));
The old code did this also for blk_in_drain() == true. Why don't we need
it there any more? Should the 'if' move inside the loop just around
attaching the notifier?
> + virtio_queue_aio_attach_host_notifier(vq, ctx);
> }
> }
> return 0;
Kevin
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 1/4] qdev-properties: alias all object class properties
2023-12-21 12:39 ` Kevin Wolf
@ 2023-12-21 15:47 ` Stefan Hajnoczi
0 siblings, 0 replies; 12+ messages in thread
From: Stefan Hajnoczi @ 2023-12-21 15:47 UTC (permalink / raw)
To: Kevin Wolf
Cc: qemu-devel, Michal Privoznik, Hanna Reitz, qemu-block,
Michael S. Tsirkin, Daniel P. Berrangé, Michael Roth,
Eduardo Habkost, Eric Blake, Markus Armbruster, Paolo Bonzini
[-- Attachment #1: Type: text/plain, Size: 1880 bytes --]
On Thu, Dec 21, 2023 at 01:39:48PM +0100, Kevin Wolf wrote:
> Am 20.12.2023 um 14:47 hat Stefan Hajnoczi geschrieben:
> > qdev_alias_all_properties() aliases a DeviceState's qdev properties onto
> > an Object. This is used for VirtioPCIProxy types so that --device
> > virtio-blk-pci has properties of its embedded --device virtio-blk-device
> > object.
> >
> > Currently this function is implemented using qdev properties. Change the
> > function to use QOM object class properties instead. This works because
> > qdev properties create QOM object class properties, but it also catches
> > any QOM object class-only properties that have no qdev properties.
> >
> > This change ensures that properties of devices are shown with --device
> > foo,\? even if they are QOM object class properties.
> >
> > Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
>
> Reviewed-by: Kevin Wolf <kwolf@redhat.com>
>
> We should also update the comment to refer to properties in general
> rather than just qdev properties. I can squash in the following hunk.
Please go ahead. Thank you!
Stefan
> diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
> index 25743a29a0..09aa04ca1e 100644
> --- a/include/hw/qdev-properties.h
> +++ b/include/hw/qdev-properties.h
> @@ -230,8 +230,8 @@ void qdev_property_add_static(DeviceState *dev, Property *prop);
> * @target: Device which has properties to be aliased
> * @source: Object to add alias properties to
> *
> - * Add alias properties to the @source object for all qdev properties on
> - * the @target DeviceState.
> + * Add alias properties to the @source object for all properties on the @target
> + * DeviceState.
> *
> * This is useful when @target is an internal implementation object
> * owned by @source, and you want to expose all the properties of that
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 0/4] virtio-blk: add iothread-vq-mapping parameter
2023-12-20 13:47 [PATCH v4 0/4] virtio-blk: add iothread-vq-mapping parameter Stefan Hajnoczi
` (3 preceding siblings ...)
2023-12-20 13:47 ` [PATCH v4 4/4] virtio-blk: add iothread-vq-mapping parameter Stefan Hajnoczi
@ 2023-12-21 21:07 ` Kevin Wolf
4 siblings, 0 replies; 12+ messages in thread
From: Kevin Wolf @ 2023-12-21 21:07 UTC (permalink / raw)
To: Stefan Hajnoczi
Cc: qemu-devel, Michal Privoznik, Hanna Reitz, qemu-block,
Michael S. Tsirkin, Daniel P. Berrangé, Michael Roth,
Eduardo Habkost, Eric Blake, Markus Armbruster, Paolo Bonzini
Am 20.12.2023 um 14:47 hat Stefan Hajnoczi geschrieben:
> v4:
> - Use DummyVirtioForceArrays naming in QAPI schema [Markus]
> v3:
> - Rebased onto Kevin's block branch
> - Add StringOutputVisitor "<omitted>" patch to fix "info qtree" crash
> - Fix QAPI schema formatting [Markus]
> - Eliminate unnecessary local variable in get_iothread_vq_mapping_list() [Markus]
>
> virtio-blk and virtio-scsi devices need a way to specify the mapping between
> IOThreads and virtqueues. At the moment all virtqueues are assigned to a single
> IOThread or the main loop. This single thread can be a CPU bottleneck, so it is
> necessary to allow finer-grained assignment to spread the load. With this
> series applied, "pidstat -t 1" shows that guests with -smp 2 or higher are able
> to exploit multiple IOThreads.
>
> This series introduces command-line syntax for the new iothread-vq-mapping
> property is as follows:
>
> --device '{"driver":"virtio-blk-pci","iothread-vq-mapping":[{"iothread":"iothread0","vqs":[0,1,2]},...]},...'
>
> IOThreads are specified by name and virtqueues are specified by 0-based
> index.
>
> It will be common to simply assign virtqueues round-robin across a set
> of IOThreads. A convenient syntax that does not require specifying
> individual virtqueue indices is available:
>
> --device '{"driver":"virtio-blk-pci","iothread-vq-mapping":[{"iothread":"iothread0"},{"iothread":"iothread1"},...]},...'
>
> There is no way to reassign virtqueues at runtime and I expect that to be a
> very rare requirement.
>
> Note that JSON --device syntax is required for the iothread-vq-mapping
> parameter because it's non-scalar.
>
> Based-on: 81e69329d6a4018f4b37d15b6fc845fbe585a93b (https://repo.or.cz/qemu/kevin.git block)
Thanks, applied to the block branch. We agreed off-list that the
remaining problems can be fixed in follow-up patches.
Kevin
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 4/4] virtio-blk: add iothread-vq-mapping parameter
2023-12-21 13:10 ` Kevin Wolf
@ 2024-01-18 21:28 ` Stefan Hajnoczi
0 siblings, 0 replies; 12+ messages in thread
From: Stefan Hajnoczi @ 2024-01-18 21:28 UTC (permalink / raw)
To: Kevin Wolf
Cc: qemu-devel, Michal Privoznik, Hanna Reitz, qemu-block,
Michael S. Tsirkin, Daniel P. Berrangé, Michael Roth,
Eduardo Habkost, Eric Blake, Markus Armbruster, Paolo Bonzini
[-- Attachment #1: Type: text/plain, Size: 1346 bytes --]
On Thu, Dec 21, 2023 at 02:10:20PM +0100, Kevin Wolf wrote:
> Am 20.12.2023 um 14:47 hat Stefan Hajnoczi geschrieben:
> > Add the iothread-vq-mapping parameter to assign virtqueues to IOThreads.
> > Store the vq:AioContext mapping in the new struct
> > VirtIOBlockDataPlane->vq_aio_context[] field and refactor the code to
> > use the per-vq AioContext instead of the BlockDriverState's AioContext.
> >
> > Reimplement --device virtio-blk-pci,iothread= and non-IOThread mode by
> > assigning all virtqueues to the IOThread and main loop's AioContext in
> > vq_aio_context[], respectively.
> >
> > The comment in struct VirtIOBlockDataPlane about EventNotifiers is
> > stale. Remove it.
> >
> > Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
>
> I'm looking at virtio_blk_dma_restart_cb/bh(). It seems to run all
> queued requests in the iothread of the first vq, but when the requests
> complete, they will push the result to their original vq.
>
> Do we know that the dataplane isn't started and won't be started until
> the requests complete? (I wouldn't expect so, because then moving to the
> AioContext of the BlockBackend wouldn't have been necessary either.) Or
> is there another reason why this is safe?
You are right. I overlooked this. I'll send a patch to make s->rq
multi-queue safe.
Stefan
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 4/4] virtio-blk: add iothread-vq-mapping parameter
2023-12-21 13:40 ` Kevin Wolf
@ 2024-01-19 13:41 ` Stefan Hajnoczi
0 siblings, 0 replies; 12+ messages in thread
From: Stefan Hajnoczi @ 2024-01-19 13:41 UTC (permalink / raw)
To: Kevin Wolf
Cc: qemu-devel, Michal Privoznik, Hanna Reitz, qemu-block,
Michael S. Tsirkin, Daniel P. Berrangé, Michael Roth,
Eduardo Habkost, Eric Blake, Markus Armbruster, Paolo Bonzini
[-- Attachment #1: Type: text/plain, Size: 2927 bytes --]
On Thu, Dec 21, 2023 at 02:40:19PM +0100, Kevin Wolf wrote:
> Am 20.12.2023 um 14:47 hat Stefan Hajnoczi geschrieben:
> > Add the iothread-vq-mapping parameter to assign virtqueues to IOThreads.
> > Store the vq:AioContext mapping in the new struct
> > VirtIOBlockDataPlane->vq_aio_context[] field and refactor the code to
> > use the per-vq AioContext instead of the BlockDriverState's AioContext.
> >
> > Reimplement --device virtio-blk-pci,iothread= and non-IOThread mode by
> > assigning all virtqueues to the IOThread and main loop's AioContext in
> > vq_aio_context[], respectively.
> >
> > The comment in struct VirtIOBlockDataPlane about EventNotifiers is
> > stale. Remove it.
> >
> > Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
>
> > @@ -177,19 +238,13 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
> >
> > trace_virtio_blk_data_plane_start(s);
> >
> > - r = blk_set_aio_context(s->conf->conf.blk, s->ctx, &local_err);
> > + r = blk_set_aio_context(s->conf->conf.blk, s->vq_aio_context[0],
> > + &local_err);
> > if (r < 0) {
> > error_report_err(local_err);
> > goto fail_aio_context;
> > }
>
> This doesn't really have to be an error any more, we'll just submit I/O
> from any thread we want no matter what the home AioContext of the
> BlockBackend is.
>
> So the only effect the blk_set_aio_context() has is that other users of
> the image try to submit their requests from the same iothread as the
> first virtqueue in the hope that this performs a bit better (maybe less
> lock contention or whatever the idea was?)
Yes, I'll change this.
> > - /* Kick right away to begin processing requests already in vring */
> > - for (i = 0; i < nvqs; i++) {
> > - VirtQueue *vq = virtio_get_queue(s->vdev, i);
> > -
> > - event_notifier_set(virtio_queue_get_host_notifier(vq));
> > - }
> > -
> > /*
> > * These fields must be visible to the IOThread when it processes the
> > * virtqueue, otherwise it will think dataplane has not started yet.
> > @@ -206,8 +261,12 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
> > if (!blk_in_drain(s->conf->conf.blk)) {
> > for (i = 0; i < nvqs; i++) {
> > VirtQueue *vq = virtio_get_queue(s->vdev, i);
> > + AioContext *ctx = s->vq_aio_context[i];
> >
> > - virtio_queue_aio_attach_host_notifier(vq, s->ctx);
> > + /* Kick right away to begin processing requests already in vring */
> > + event_notifier_set(virtio_queue_get_host_notifier(vq));
>
> The old code did this also for blk_in_drain() == true. Why don't we need
> it there any more? Should the 'if' move inside the loop just around
> attaching the notifier?
The answer is I'm not 100% sure. Your suggestion is safer, I'll do that.
Stefan
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2024-01-19 13:59 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-20 13:47 [PATCH v4 0/4] virtio-blk: add iothread-vq-mapping parameter Stefan Hajnoczi
2023-12-20 13:47 ` [PATCH v4 1/4] qdev-properties: alias all object class properties Stefan Hajnoczi
2023-12-21 12:39 ` Kevin Wolf
2023-12-21 15:47 ` Stefan Hajnoczi
2023-12-20 13:47 ` [PATCH v4 2/4] string-output-visitor: show structs as "<omitted>" Stefan Hajnoczi
2023-12-20 13:47 ` [PATCH v4 3/4] qdev: add IOThreadVirtQueueMappingList property type Stefan Hajnoczi
2023-12-20 13:47 ` [PATCH v4 4/4] virtio-blk: add iothread-vq-mapping parameter Stefan Hajnoczi
2023-12-21 13:10 ` Kevin Wolf
2024-01-18 21:28 ` Stefan Hajnoczi
2023-12-21 13:40 ` Kevin Wolf
2024-01-19 13:41 ` Stefan Hajnoczi
2023-12-21 21:07 ` [PATCH v4 0/4] " Kevin Wolf
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).