[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v10 7/8] qmp: add QMP command x-query-virtio-queue-element
From: |
Markus Armbruster |
Subject: |
Re: [PATCH v10 7/8] qmp: add QMP command x-query-virtio-queue-element |
Date: |
Tue, 07 Dec 2021 10:48:03 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) |
Jonah Palmer <jonah.palmer@oracle.com> writes:
> From: Laurent Vivier <lvivier@redhat.com>
>
> This new command shows the information of a VirtQueue element.
>
> Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
> ---
> hw/virtio/virtio-stub.c | 9 +++
> hw/virtio/virtio.c | 154 ++++++++++++++++++++++++++++++++++++++++
> qapi/virtio.json | 183
> ++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 346 insertions(+)
>
> diff --git a/hw/virtio/virtio-stub.c b/hw/virtio/virtio-stub.c
> index 13e5f93..7ddb22c 100644
> --- a/hw/virtio/virtio-stub.c
> +++ b/hw/virtio/virtio-stub.c
> @@ -31,3 +31,12 @@ VirtQueueStatus *qmp_x_query_virtio_queue_status(const
> char *path,
> {
> return qmp_virtio_unsupported(errp);
> }
> +
> +VirtioQueueElement *qmp_x_query_virtio_queue_element(const char *path,
> + uint16_t queue,
> + bool has_index,
> + uint16_t index,
> + Error **errp)
> +{
> + return qmp_virtio_unsupported(errp);
> +}
> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> index 459bfb2..8c6cc27 100644
> --- a/hw/virtio/virtio.c
> +++ b/hw/virtio/virtio.c
> @@ -475,6 +475,19 @@ static inline void vring_used_write(VirtQueue *vq,
> VRingUsedElem *uelem,
> address_space_cache_invalidate(&caches->used, pa, sizeof(VRingUsedElem));
> }
>
> +/* Called within rcu_read_lock(). */
> +static inline uint16_t vring_used_flags(VirtQueue *vq)
> +{
> + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq);
> + hwaddr pa = offsetof(VRingUsed, flags);
> +
> + if (!caches) {
> + return 0;
> + }
> +
> + return virtio_lduw_phys_cached(vq->vdev, &caches->used, pa);
> +}
> +
> /* Called within rcu_read_lock(). */
> static uint16_t vring_used_idx(VirtQueue *vq)
> {
> @@ -4381,6 +4394,147 @@ VirtQueueStatus
> *qmp_x_query_virtio_queue_status(const char *path,
> return status;
> }
>
> +static strList *qmp_decode_vring_desc_flags(uint16_t flags)
> +{
> + strList *list = NULL;
> + strList *node;
> + int i;
> +
> + struct {
> + uint16_t flag;
> + const char *value;
> + } map[] = {
> + { VRING_DESC_F_NEXT, "next" },
> + { VRING_DESC_F_WRITE, "write" },
> + { VRING_DESC_F_INDIRECT, "indirect" },
> + { 1 << VRING_PACKED_DESC_F_AVAIL, "avail" },
> + { 1 << VRING_PACKED_DESC_F_USED, "used" },
> + { 0, "" }
> + };
> +
> + for (i = 0; map[i].flag; i++) {
> + if ((map[i].flag & flags) == 0) {
> + continue;
> + }
> + node = g_malloc0(sizeof(strList));
> + node->value = g_strdup(map[i].value);
> + node->next = list;
> + list = node;
> + }
> +
> + return list;
> +}
> +
> +VirtioQueueElement *qmp_x_query_virtio_queue_element(const char *path,
> + uint16_t queue,
> + bool has_index,
> + uint16_t index,
> + Error **errp)
> +{
> + VirtIODevice *vdev;
> + VirtQueue *vq;
> + VirtioQueueElement *element = NULL;
> +
> + vdev = virtio_device_find(path);
> + if (vdev == NULL) {
> + error_setg(errp, "Path %s is not a VirtIO device", path);
> + return NULL;
> + }
> +
> + if (queue >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, queue)) {
> + error_setg(errp, "Invalid virtqueue number %d", queue);
> + return NULL;
> + }
> + vq = &vdev->vq[queue];
> +
> + if (virtio_vdev_has_feature(vdev, VIRTIO_F_RING_PACKED)) {
> + error_setg(errp, "Packed ring not supported");
> + return NULL;
> + } else {
> + unsigned int head, i, max;
> + VRingMemoryRegionCaches *caches;
> + MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID;
> + MemoryRegionCache *desc_cache;
> + VRingDesc desc;
> + VirtioRingDescList *list = NULL;
> + VirtioRingDescList *node;
> + int rc; int ndescs;
> +
> + RCU_READ_LOCK_GUARD();
> +
> + max = vq->vring.num;
> +
> + if (!has_index) {
> + head = vring_avail_ring(vq, vq->last_avail_idx % vq->vring.num);
> + } else {
> + head = vring_avail_ring(vq, index % vq->vring.num);
> + }
> + i = head;
> +
> + caches = vring_get_region_caches(vq);
> + if (!caches) {
> + error_setg(errp, "Region caches not initialized");
> + return NULL;
> + }
> + if (caches->desc.len < max * sizeof(VRingDesc)) {
> + error_setg(errp, "Cannot map descriptor ring");
> + return NULL;
> + }
> +
> + desc_cache = &caches->desc;
> + vring_split_desc_read(vdev, &desc, desc_cache, i);
> + if (desc.flags & VRING_DESC_F_INDIRECT) {
> + int64_t len;
> + len = address_space_cache_init(&indirect_desc_cache,
> vdev->dma_as,
> + desc.addr, desc.len, false);
> + desc_cache = &indirect_desc_cache;
> + if (len < desc.len) {
> + error_setg(errp, "Cannot map indirect buffer");
> + goto done;
> + }
> +
> + max = desc.len / sizeof(VRingDesc);
> + i = 0;
> + vring_split_desc_read(vdev, &desc, desc_cache, i);
> + }
> +
> + element = g_new0(VirtioQueueElement, 1);
> + element->avail = g_new0(VirtioRingAvail, 1);
> + element->used = g_new0(VirtioRingUsed, 1);
> + element->name = g_strdup(vdev->name);
> + element->index = head;
> + element->avail->flags = vring_avail_flags(vq);
> + element->avail->idx = vring_avail_idx(vq);
> + element->avail->ring = head;
> + element->used->flags = vring_used_flags(vq);
> + element->used->idx = vring_used_idx(vq);
> + ndescs = 0;
> +
> + do {
> + /* A buggy driver may produce an infinite loop */
> + if (ndescs >= max) {
> + break;
> + }
> + node = g_new0(VirtioRingDescList, 1);
> + node->value = g_new0(VirtioRingDesc, 1);
> + node->value->addr = desc.addr;
> + node->value->len = desc.len;
> + node->value->flags = qmp_decode_vring_desc_flags(desc.flags);
> + node->next = list;
> + list = node;
> +
> + ndescs++;
> + rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache,
> + max, &i);
> + } while (rc == VIRTQUEUE_READ_DESC_MORE);
> + element->descs = list;
> +done:
> + address_space_cache_destroy(&indirect_desc_cache);
> + }
> +
> + return element;
> +}
> +
> static const TypeInfo virtio_device_info = {
> .name = TYPE_VIRTIO_DEVICE,
> .parent = TYPE_DEVICE,
> diff --git a/qapi/virtio.json b/qapi/virtio.json
> index 56e56d2..2984e48 100644
> --- a/qapi/virtio.json
> +++ b/qapi/virtio.json
> @@ -654,3 +654,186 @@
> 'data': { 'path': 'str', 'queue': 'uint16' },
> 'returns': 'VirtVhostQueueStatus',
> 'features': [ 'unstable' ] }
> +
> +##
> +# @VirtioRingDesc:
> +#
> +# Information regarding the vring descriptor area
> +#
> +# @addr: Guest physical address of the descriptor area
> +#
> +# @len: Length of the descriptor area
> +#
> +# @flags: List of descriptor flags
> +#
> +# Since: 7.0
> +#
> +##
> +
> +{ 'struct': 'VirtioRingDesc',
> + 'data': { 'addr': 'uint64',
> + 'len': 'uint32',
> + 'flags': [ 'str' ] } }
> +
> +##
> +# @VirtioRingAvail:
> +#
> +# Information regarding the avail vring (a.k.a. driver area)
> +#
> +# @flags: VRingAvail flags
> +#
> +# @idx: VRingAvail index
> +#
> +# @ring: VRingAvail ring[] entry at provided index
> +#
> +# Since: 7.0
> +#
> +##
> +
> +{ 'struct': 'VirtioRingAvail',
> + 'data': { 'flags': 'uint16',
> + 'idx': 'uint16',
> + 'ring': 'uint16' } }
> +
> +##
> +# @VirtioRingUsed:
> +#
> +# Information regarding the used vring (a.k.a. device area)
> +#
> +# @flags: VRingUsed flags
> +#
> +# @idx: VRingUsed index
> +#
> +# Since: 7.0
> +#
> +##
> +
> +{ 'struct': 'VirtioRingUsed',
> + 'data': { 'flags': 'uint16',
> + 'idx': 'uint16' } }
> +
> +##
> +# @VirtioQueueElement:
> +#
> +# Information regarding a VirtQueue's VirtQueueElement including
> +# descriptor, driver, and device areas
> +#
> +# @name: Name of the VirtIODevice that uses this VirtQueue
> +#
> +# @index: Index of the element in the queue
> +#
> +# @descs: List of descriptors (VirtioRingDesc)
> +#
> +# @avail: VRingAvail info
> +#
> +# @used: VRingUsed info
> +#
> +# Since: 7.0
> +#
> +##
> +
> +{ 'struct': 'VirtioQueueElement',
> + 'data': { 'name': 'str',
> + 'index': 'uint32',
> + 'descs': [ 'VirtioRingDesc' ],
> + 'avail': 'VirtioRingAvail',
> + 'used': 'VirtioRingUsed' } }
> +
> +##
> +# @x-query-virtio-queue-element:
> +#
> +# Return the information about a VirtQueue's VirtQueueElement. By
> +# default it looks at the head of the queue (if no index is given)
> +#
> +# @path: VirtIODevice canonical QOM path
> +#
> +# @queue: VirtQueue index to examine
> +#
> +# @index: Index of the element in the queue
Suggest "(default: head of the queue)", and drop "By default it
looks..." above.
> +#
> +# Features:
> +# @unstable: This command is meant for debugging
End with a period for consistency with existing docs, like you did in
v9.
> +#
> +# Returns: VirtioQueueElement information
> +#
> +# Since: 7.0
> +#
> +# Examples:
> +#
> +# 1. Introspect on virtio-net's VirtQueue 0 at index 5
> +#
> +# -> { "execute": "x-query-virtio-queue-element",
> +# "arguments": { "path":
> "/machine/peripheral-anon/device[1]/virtio-backend",
> +# "queue": 0,
> +# "index": 5 }
> +# }
> +# <- { "return": {
> +# "index": 5,
> +# "name": "virtio-net",
> +# "descs": [
> +# { "flags": ["write"], "len": 1536, "addr": 5257305600 }
> +# ],
> +# "avail": {
> +# "idx": 256,
> +# "flags": 0,
> +# "ring": 5
> +# },
> +# "used": {
> +# "idx": 13,
> +# "flags": 0
> +# },
> +# }
> +#
> +# 2. Introspect on virtio-crypto's VirtQueue 1 at head
> +#
> +# -> { "execute": "x-query-virtio-queue-element",
> +# "arguments": { "path": "/machine/peripheral/crypto0/virtio-backend",
> +# "queue": 1 }
> +# }
> +# <- { "return": {
> +# "index": 0,
> +# "name": "virtio-crypto",
> +# "descs": [
> +# { "flags": [], "len": 0, "addr": 8080268923184214134 }
> +# ],
> +# "avail": {
> +# "idx": 280,
> +# "flags": 0,
> +# "ring": 0
> +# },
> +# "used": {
> +# "idx": 280,
> +# "flags": 0
> +# }
> +# }
> +#
> +# 3. Introspect on virtio-scsi's VirtQueue 2 at head
> +#
> +# -> { "execute": "x-query-virtio-queue-element",
> +# "arguments": { "path":
> "/machine/peripheral-anon/device[2]/virtio-backend",
> +# "queue": 2 }
> +# }
> +# <- { "return": {
> +# "index": 19,
> +# "name": "virtio-scsi",
> +# "descs": [
> +# { "flags": ["used", "indirect", "write"], "len": 4099327944,
> +# "addr": 12055409292258155293 }
> +# ],
> +# "avail": {
> +# "idx": 1147,
> +# "flags": 0,
> +# "ring": 19
> +# },
> +# "used": {
> +# "idx": 280,
> +# "flags": 0
> +# }
> +# }
> +#
> +##
> +
> +{ 'command': 'x-query-virtio-queue-element',
> + 'data': { 'path': 'str', 'queue': 'uint16', '*index': 'uint16' },
> + 'returns': 'VirtioQueueElement',
> + 'features': [ 'unstable' ] }
With my doc remarks addressed, QAPI schema
Acked-by: Markus Armbruster <armbru@redhat.com>
One more thing: a brief note in the commit messages on why I made you
use 'str' instead of enums would be nice.
- [PATCH v10 0/8] hmp,qmp: Add commands to introspect virtio devices, Jonah Palmer, 2021/12/06
- [PATCH v10 4/8] qmp: add QMP command x-query-virtio-status, Jonah Palmer, 2021/12/06
- [PATCH v10 3/8] qmp: add QMP command x-query-virtio, Jonah Palmer, 2021/12/06
- [PATCH v10 1/8] virtio: drop name parameter for virtio_init(), Jonah Palmer, 2021/12/06
- [PATCH v10 2/8] virtio: add vhost support for virtio devices, Jonah Palmer, 2021/12/06
- [PATCH v10 7/8] qmp: add QMP command x-query-virtio-queue-element, Jonah Palmer, 2021/12/06
- Re: [PATCH v10 7/8] qmp: add QMP command x-query-virtio-queue-element,
Markus Armbruster <=
- [PATCH v10 6/8] qmp: add QMP commands for virtio/vhost queue-status, Jonah Palmer, 2021/12/06
- [PATCH v10 5/8] qmp: decode feature & status bits in virtio-status, Jonah Palmer, 2021/12/06
- [PATCH v10 8/8] hmp: add virtio commands, Jonah Palmer, 2021/12/06
- Re: [PATCH v10 0/8] hmp, qmp: Add commands to introspect virtio devices, Christian Schoenebeck, 2021/12/06