mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-11 03:24:58 -06:00
virtio: extract iothread-vq-mapping.h API
The code that builds an array of AioContext pointers indexed by the virtqueue is not specific to virtio-blk. virtio-scsi will need to do the same thing, so extract the functions. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Message-ID: <20250311132616.1049687-11-stefanha@redhat.com> Tested-by: Peter Krempa <pkrempa@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
2fa67a7b1d
commit
b50629c335
4 changed files with 178 additions and 141 deletions
|
@ -33,6 +33,7 @@
|
||||||
#endif
|
#endif
|
||||||
#include "hw/virtio/virtio-bus.h"
|
#include "hw/virtio/virtio-bus.h"
|
||||||
#include "migration/qemu-file-types.h"
|
#include "migration/qemu-file-types.h"
|
||||||
|
#include "hw/virtio/iothread-vq-mapping.h"
|
||||||
#include "hw/virtio/virtio-access.h"
|
#include "hw/virtio/virtio-access.h"
|
||||||
#include "hw/virtio/virtio-blk-common.h"
|
#include "hw/virtio/virtio-blk-common.h"
|
||||||
#include "qemu/coroutine.h"
|
#include "qemu/coroutine.h"
|
||||||
|
@ -1423,147 +1424,6 @@ static const BlockDevOps virtio_block_ops = {
|
||||||
.drained_end = virtio_blk_drained_end,
|
.drained_end = virtio_blk_drained_end,
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool
|
|
||||||
iothread_vq_mapping_validate(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* iothread_vq_mapping_apply:
|
|
||||||
* @list: The mapping of virtqueues to IOThreads.
|
|
||||||
* @vq_aio_context: The array of AioContext pointers to fill in.
|
|
||||||
* @num_queues: The length of @vq_aio_context.
|
|
||||||
* @errp: If an error occurs, a pointer to the area to store the error.
|
|
||||||
*
|
|
||||||
* Fill in the AioContext for each virtqueue in the @vq_aio_context array given
|
|
||||||
* the iothread-vq-mapping parameter in @list.
|
|
||||||
*
|
|
||||||
* iothread_vq_mapping_cleanup() must be called to free IOThread object
|
|
||||||
* references after this function returns success.
|
|
||||||
*
|
|
||||||
* Returns: %true on success, %false on failure.
|
|
||||||
**/
|
|
||||||
static bool iothread_vq_mapping_apply(
|
|
||||||
IOThreadVirtQueueMappingList *list,
|
|
||||||
AioContext **vq_aio_context,
|
|
||||||
uint16_t num_queues,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
IOThreadVirtQueueMappingList *node;
|
|
||||||
size_t num_iothreads = 0;
|
|
||||||
size_t cur_iothread = 0;
|
|
||||||
|
|
||||||
if (!iothread_vq_mapping_validate(list, num_queues, errp)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (node = list; node; node = node->next) {
|
|
||||||
num_iothreads++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (node = list; node; node = node->next) {
|
|
||||||
IOThread *iothread = iothread_by_id(node->value->iothread);
|
|
||||||
AioContext *ctx = iothread_get_aio_context(iothread);
|
|
||||||
|
|
||||||
/* Released in virtio_blk_vq_aio_context_cleanup() */
|
|
||||||
object_ref(OBJECT(iothread));
|
|
||||||
|
|
||||||
if (node->value->vqs) {
|
|
||||||
uint16List *vq;
|
|
||||||
|
|
||||||
/* Explicit vq:IOThread assignment */
|
|
||||||
for (vq = node->value->vqs; vq; vq = vq->next) {
|
|
||||||
assert(vq->value < num_queues);
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* iothread_vq_mapping_cleanup:
|
|
||||||
* @list: The mapping of virtqueues to IOThreads.
|
|
||||||
*
|
|
||||||
* Release IOThread object references that were acquired by
|
|
||||||
* iothread_vq_mapping_apply().
|
|
||||||
*/
|
|
||||||
static void iothread_vq_mapping_cleanup(IOThreadVirtQueueMappingList *list)
|
|
||||||
{
|
|
||||||
IOThreadVirtQueueMappingList *node;
|
|
||||||
|
|
||||||
for (node = list; node; node = node->next) {
|
|
||||||
IOThread *iothread = iothread_by_id(node->value->iothread);
|
|
||||||
object_unref(OBJECT(iothread));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Context: BQL held */
|
/* Context: BQL held */
|
||||||
static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp)
|
static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp)
|
||||||
{
|
{
|
||||||
|
|
131
hw/virtio/iothread-vq-mapping.c
Normal file
131
hw/virtio/iothread-vq-mapping.c
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* IOThread Virtqueue Mapping
|
||||||
|
*
|
||||||
|
* Copyright Red Hat, Inc
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "system/iothread.h"
|
||||||
|
#include "hw/virtio/iothread-vq-mapping.h"
|
||||||
|
|
||||||
|
static bool
|
||||||
|
iothread_vq_mapping_validate(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool iothread_vq_mapping_apply(
|
||||||
|
IOThreadVirtQueueMappingList *list,
|
||||||
|
AioContext **vq_aio_context,
|
||||||
|
uint16_t num_queues,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
IOThreadVirtQueueMappingList *node;
|
||||||
|
size_t num_iothreads = 0;
|
||||||
|
size_t cur_iothread = 0;
|
||||||
|
|
||||||
|
if (!iothread_vq_mapping_validate(list, num_queues, errp)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (node = list; node; node = node->next) {
|
||||||
|
num_iothreads++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (node = list; node; node = node->next) {
|
||||||
|
IOThread *iothread = iothread_by_id(node->value->iothread);
|
||||||
|
AioContext *ctx = iothread_get_aio_context(iothread);
|
||||||
|
|
||||||
|
/* Released in virtio_blk_vq_aio_context_cleanup() */
|
||||||
|
object_ref(OBJECT(iothread));
|
||||||
|
|
||||||
|
if (node->value->vqs) {
|
||||||
|
uint16List *vq;
|
||||||
|
|
||||||
|
/* Explicit vq:IOThread assignment */
|
||||||
|
for (vq = node->value->vqs; vq; vq = vq->next) {
|
||||||
|
assert(vq->value < num_queues);
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iothread_vq_mapping_cleanup(IOThreadVirtQueueMappingList *list)
|
||||||
|
{
|
||||||
|
IOThreadVirtQueueMappingList *node;
|
||||||
|
|
||||||
|
for (node = list; node; node = node->next) {
|
||||||
|
IOThread *iothread = iothread_by_id(node->value->iothread);
|
||||||
|
object_unref(OBJECT(iothread));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
system_virtio_ss = ss.source_set()
|
system_virtio_ss = ss.source_set()
|
||||||
system_virtio_ss.add(files('virtio-bus.c'))
|
system_virtio_ss.add(files('virtio-bus.c'))
|
||||||
|
system_virtio_ss.add(files('iothread-vq-mapping.c'))
|
||||||
system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-pci.c'))
|
system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-pci.c'))
|
||||||
system_virtio_ss.add(when: 'CONFIG_VIRTIO_MMIO', if_true: files('virtio-mmio.c'))
|
system_virtio_ss.add(when: 'CONFIG_VIRTIO_MMIO', if_true: files('virtio-mmio.c'))
|
||||||
system_virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c'))
|
system_virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c'))
|
||||||
|
|
45
include/hw/virtio/iothread-vq-mapping.h
Normal file
45
include/hw/virtio/iothread-vq-mapping.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* IOThread Virtqueue Mapping
|
||||||
|
*
|
||||||
|
* Copyright Red Hat, Inc
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HW_VIRTIO_IOTHREAD_VQ_MAPPING_H
|
||||||
|
#define HW_VIRTIO_IOTHREAD_VQ_MAPPING_H
|
||||||
|
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "qapi/qapi-types-virtio.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iothread_vq_mapping_apply:
|
||||||
|
* @list: The mapping of virtqueues to IOThreads.
|
||||||
|
* @vq_aio_context: The array of AioContext pointers to fill in.
|
||||||
|
* @num_queues: The length of @vq_aio_context.
|
||||||
|
* @errp: If an error occurs, a pointer to the area to store the error.
|
||||||
|
*
|
||||||
|
* Fill in the AioContext for each virtqueue in the @vq_aio_context array given
|
||||||
|
* the iothread-vq-mapping parameter in @list.
|
||||||
|
*
|
||||||
|
* iothread_vq_mapping_cleanup() must be called to free IOThread object
|
||||||
|
* references after this function returns success.
|
||||||
|
*
|
||||||
|
* Returns: %true on success, %false on failure.
|
||||||
|
**/
|
||||||
|
bool iothread_vq_mapping_apply(
|
||||||
|
IOThreadVirtQueueMappingList *list,
|
||||||
|
AioContext **vq_aio_context,
|
||||||
|
uint16_t num_queues,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iothread_vq_mapping_cleanup:
|
||||||
|
* @list: The mapping of virtqueues to IOThreads.
|
||||||
|
*
|
||||||
|
* Release IOThread object references that were acquired by
|
||||||
|
* iothread_vq_mapping_apply().
|
||||||
|
*/
|
||||||
|
void iothread_vq_mapping_cleanup(IOThreadVirtQueueMappingList *list);
|
||||||
|
|
||||||
|
#endif /* HW_VIRTIO_IOTHREAD_VQ_MAPPING_H */
|
Loading…
Add table
Add a link
Reference in a new issue