|
@@ -33,6 +33,7 @@
|
|
|
#endif
|
|
|
#include "hw/virtio/virtio-bus.h"
|
|
|
#include "migration/qemu-file-types.h"
|
|
|
+#include "hw/virtio/iothread-vq-mapping.h"
|
|
|
#include "hw/virtio/virtio-access.h"
|
|
|
#include "hw/virtio/virtio-blk-common.h"
|
|
|
#include "qemu/coroutine.h"
|
|
@@ -1423,147 +1424,6 @@ static const BlockDevOps virtio_block_ops = {
|
|
|
.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 */
|
|
|
static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp)
|
|
|
{
|