hw/virtio: Extract QMP QOM-specific functions to virtio-qmp.c

virtio.c is big enough, extract more QMP related code to virtio-qmp.c.
To do so, expose qmp_find_virtio_device() and declar virtio_list in
the internal virtio-qmp.h header.

Note we have to leave qmp_x_query_virtio_queue_status() and
qmp_x_query_virtio_queue_element(), because they access VirtQueue
internal fields, and VirtQueue is only declared within virtio.c.

Suggested-by: Jonah Palmer <jonah.palmer@oracle.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-Id: <20221222080005.27616-3-philmd@linaro.org>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Philippe Mathieu-Daudé 2022-12-22 09:00:05 +01:00 committed by Michael S. Tsirkin
parent dd92cbb366
commit 9d94c21363
3 changed files with 201 additions and 191 deletions

View File

@ -10,9 +10,14 @@
*/
#include "qemu/osdep.h"
#include "hw/virtio/virtio.h"
#include "virtio-qmp.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-virtio.h"
#include "qapi/qapi-commands-qom.h"
#include "qapi/qmp/qobject.h"
#include "qapi/qmp/qjson.h"
#include "standard-headers/linux/virtio_ids.h"
#include "standard-headers/linux/vhost_types.h"
#include "standard-headers/linux/virtio_blk.h"
@ -657,3 +662,188 @@ VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap)
return features;
}
VirtioInfoList *qmp_x_query_virtio(Error **errp)
{
VirtioInfoList *list = NULL;
VirtioInfoList *node;
VirtIODevice *vdev;
QTAILQ_FOREACH(vdev, &virtio_list, next) {
DeviceState *dev = DEVICE(vdev);
Error *err = NULL;
QObject *obj = qmp_qom_get(dev->canonical_path, "realized", &err);
if (err == NULL) {
GString *is_realized = qobject_to_json_pretty(obj, true);
/* virtio device is NOT realized, remove it from list */
if (!strncmp(is_realized->str, "false", 4)) {
QTAILQ_REMOVE(&virtio_list, vdev, next);
} else {
node = g_new0(VirtioInfoList, 1);
node->value = g_new(VirtioInfo, 1);
node->value->path = g_strdup(dev->canonical_path);
node->value->name = g_strdup(vdev->name);
QAPI_LIST_PREPEND(list, node->value);
}
g_string_free(is_realized, true);
}
qobject_unref(obj);
}
return list;
}
VirtIODevice *qmp_find_virtio_device(const char *path)
{
VirtIODevice *vdev;
QTAILQ_FOREACH(vdev, &virtio_list, next) {
DeviceState *dev = DEVICE(vdev);
if (strcmp(dev->canonical_path, path) != 0) {
continue;
}
Error *err = NULL;
QObject *obj = qmp_qom_get(dev->canonical_path, "realized", &err);
if (err == NULL) {
GString *is_realized = qobject_to_json_pretty(obj, true);
/* virtio device is NOT realized, remove it from list */
if (!strncmp(is_realized->str, "false", 4)) {
g_string_free(is_realized, true);
qobject_unref(obj);
QTAILQ_REMOVE(&virtio_list, vdev, next);
return NULL;
}
g_string_free(is_realized, true);
} else {
/* virtio device doesn't exist in QOM tree */
QTAILQ_REMOVE(&virtio_list, vdev, next);
qobject_unref(obj);
return NULL;
}
/* device exists in QOM tree & is realized */
qobject_unref(obj);
return vdev;
}
return NULL;
}
VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
{
VirtIODevice *vdev;
VirtioStatus *status;
vdev = qmp_find_virtio_device(path);
if (vdev == NULL) {
error_setg(errp, "Path %s is not a VirtIODevice", path);
return NULL;
}
status = g_new0(VirtioStatus, 1);
status->name = g_strdup(vdev->name);
status->device_id = vdev->device_id;
status->vhost_started = vdev->vhost_started;
status->guest_features = qmp_decode_features(vdev->device_id,
vdev->guest_features);
status->host_features = qmp_decode_features(vdev->device_id,
vdev->host_features);
status->backend_features = qmp_decode_features(vdev->device_id,
vdev->backend_features);
switch (vdev->device_endian) {
case VIRTIO_DEVICE_ENDIAN_LITTLE:
status->device_endian = g_strdup("little");
break;
case VIRTIO_DEVICE_ENDIAN_BIG:
status->device_endian = g_strdup("big");
break;
default:
status->device_endian = g_strdup("unknown");
break;
}
status->num_vqs = virtio_get_num_queues(vdev);
status->status = qmp_decode_status(vdev->status);
status->isr = vdev->isr;
status->queue_sel = vdev->queue_sel;
status->vm_running = vdev->vm_running;
status->broken = vdev->broken;
status->disabled = vdev->disabled;
status->use_started = vdev->use_started;
status->started = vdev->started;
status->start_on_kick = vdev->start_on_kick;
status->disable_legacy_check = vdev->disable_legacy_check;
status->bus_name = g_strdup(vdev->bus_name);
status->use_guest_notifier_mask = vdev->use_guest_notifier_mask;
if (vdev->vhost_started) {
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
struct vhost_dev *hdev = vdc->get_vhost(vdev);
status->vhost_dev = g_new0(VhostStatus, 1);
status->vhost_dev->n_mem_sections = hdev->n_mem_sections;
status->vhost_dev->n_tmp_sections = hdev->n_tmp_sections;
status->vhost_dev->nvqs = hdev->nvqs;
status->vhost_dev->vq_index = hdev->vq_index;
status->vhost_dev->features =
qmp_decode_features(vdev->device_id, hdev->features);
status->vhost_dev->acked_features =
qmp_decode_features(vdev->device_id, hdev->acked_features);
status->vhost_dev->backend_features =
qmp_decode_features(vdev->device_id, hdev->backend_features);
status->vhost_dev->protocol_features =
qmp_decode_protocols(hdev->protocol_features);
status->vhost_dev->max_queues = hdev->max_queues;
status->vhost_dev->backend_cap = hdev->backend_cap;
status->vhost_dev->log_enabled = hdev->log_enabled;
status->vhost_dev->log_size = hdev->log_size;
}
return status;
}
VirtVhostQueueStatus *qmp_x_query_virtio_vhost_queue_status(const char *path,
uint16_t queue,
Error **errp)
{
VirtIODevice *vdev;
VirtVhostQueueStatus *status;
vdev = qmp_find_virtio_device(path);
if (vdev == NULL) {
error_setg(errp, "Path %s is not a VirtIODevice", path);
return NULL;
}
if (!vdev->vhost_started) {
error_setg(errp, "Error: vhost device has not started yet");
return NULL;
}
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
struct vhost_dev *hdev = vdc->get_vhost(vdev);
if (queue < hdev->vq_index || queue >= hdev->vq_index + hdev->nvqs) {
error_setg(errp, "Invalid vhost virtqueue number %d", queue);
return NULL;
}
status = g_new0(VirtVhostQueueStatus, 1);
status->name = g_strdup(vdev->name);
status->kick = hdev->vqs[queue].kick;
status->call = hdev->vqs[queue].call;
status->desc = (uintptr_t)hdev->vqs[queue].desc;
status->avail = (uintptr_t)hdev->vqs[queue].avail;
status->used = (uintptr_t)hdev->vqs[queue].used;
status->num = hdev->vqs[queue].num;
status->desc_phys = hdev->vqs[queue].desc_phys;
status->desc_size = hdev->vqs[queue].desc_size;
status->avail_phys = hdev->vqs[queue].avail_phys;
status->avail_size = hdev->vqs[queue].avail_size;
status->used_phys = hdev->vqs[queue].used_phys;
status->used_size = hdev->vqs[queue].used_size;
return status;
}

View File

@ -12,7 +12,16 @@
#define HW_VIRTIO_QMP_H
#include "qapi/qapi-types-virtio.h"
#include "hw/virtio/virtio.h"
#include "qemu/queue.h"
typedef QTAILQ_HEAD(QmpVirtIODeviceList, VirtIODevice) QmpVirtIODeviceList;
/* QAPI list of realized VirtIODevices */
extern QmpVirtIODeviceList virtio_list;
VirtIODevice *qmp_find_virtio_device(const char *path);
VirtioDeviceStatus *qmp_decode_status(uint8_t bitmap);
VhostDeviceProtocols *qmp_decode_protocols(uint64_t bitmap);
VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap);

View File

@ -13,10 +13,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qapi-commands-virtio.h"
#include "qapi/qapi-commands-qom.h"
#include "qapi/qmp/qjson.h"
#include "trace.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
@ -47,8 +44,7 @@
#include "standard-headers/linux/virtio_mem.h"
#include "standard-headers/linux/virtio_vsock.h"
/* QAPI list of realized VirtIODevices */
static QTAILQ_HEAD(, VirtIODevice) virtio_list;
QmpVirtIODeviceList virtio_list;
/*
* Maximum size of virtio device config space
@ -3824,191 +3820,6 @@ bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev)
return virtio_bus_ioeventfd_enabled(vbus);
}
VirtioInfoList *qmp_x_query_virtio(Error **errp)
{
VirtioInfoList *list = NULL;
VirtioInfoList *node;
VirtIODevice *vdev;
QTAILQ_FOREACH(vdev, &virtio_list, next) {
DeviceState *dev = DEVICE(vdev);
Error *err = NULL;
QObject *obj = qmp_qom_get(dev->canonical_path, "realized", &err);
if (err == NULL) {
GString *is_realized = qobject_to_json_pretty(obj, true);
/* virtio device is NOT realized, remove it from list */
if (!strncmp(is_realized->str, "false", 4)) {
QTAILQ_REMOVE(&virtio_list, vdev, next);
} else {
node = g_new0(VirtioInfoList, 1);
node->value = g_new(VirtioInfo, 1);
node->value->path = g_strdup(dev->canonical_path);
node->value->name = g_strdup(vdev->name);
QAPI_LIST_PREPEND(list, node->value);
}
g_string_free(is_realized, true);
}
qobject_unref(obj);
}
return list;
}
static VirtIODevice *qmp_find_virtio_device(const char *path)
{
VirtIODevice *vdev;
QTAILQ_FOREACH(vdev, &virtio_list, next) {
DeviceState *dev = DEVICE(vdev);
if (strcmp(dev->canonical_path, path) != 0) {
continue;
}
Error *err = NULL;
QObject *obj = qmp_qom_get(dev->canonical_path, "realized", &err);
if (err == NULL) {
GString *is_realized = qobject_to_json_pretty(obj, true);
/* virtio device is NOT realized, remove it from list */
if (!strncmp(is_realized->str, "false", 4)) {
g_string_free(is_realized, true);
qobject_unref(obj);
QTAILQ_REMOVE(&virtio_list, vdev, next);
return NULL;
}
g_string_free(is_realized, true);
} else {
/* virtio device doesn't exist in QOM tree */
QTAILQ_REMOVE(&virtio_list, vdev, next);
qobject_unref(obj);
return NULL;
}
/* device exists in QOM tree & is realized */
qobject_unref(obj);
return vdev;
}
return NULL;
}
VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
{
VirtIODevice *vdev;
VirtioStatus *status;
vdev = qmp_find_virtio_device(path);
if (vdev == NULL) {
error_setg(errp, "Path %s is not a VirtIODevice", path);
return NULL;
}
status = g_new0(VirtioStatus, 1);
status->name = g_strdup(vdev->name);
status->device_id = vdev->device_id;
status->vhost_started = vdev->vhost_started;
status->guest_features = qmp_decode_features(vdev->device_id,
vdev->guest_features);
status->host_features = qmp_decode_features(vdev->device_id,
vdev->host_features);
status->backend_features = qmp_decode_features(vdev->device_id,
vdev->backend_features);
switch (vdev->device_endian) {
case VIRTIO_DEVICE_ENDIAN_LITTLE:
status->device_endian = g_strdup("little");
break;
case VIRTIO_DEVICE_ENDIAN_BIG:
status->device_endian = g_strdup("big");
break;
default:
status->device_endian = g_strdup("unknown");
break;
}
status->num_vqs = virtio_get_num_queues(vdev);
status->status = qmp_decode_status(vdev->status);
status->isr = vdev->isr;
status->queue_sel = vdev->queue_sel;
status->vm_running = vdev->vm_running;
status->broken = vdev->broken;
status->disabled = vdev->disabled;
status->use_started = vdev->use_started;
status->started = vdev->started;
status->start_on_kick = vdev->start_on_kick;
status->disable_legacy_check = vdev->disable_legacy_check;
status->bus_name = g_strdup(vdev->bus_name);
status->use_guest_notifier_mask = vdev->use_guest_notifier_mask;
if (vdev->vhost_started) {
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
struct vhost_dev *hdev = vdc->get_vhost(vdev);
status->vhost_dev = g_new0(VhostStatus, 1);
status->vhost_dev->n_mem_sections = hdev->n_mem_sections;
status->vhost_dev->n_tmp_sections = hdev->n_tmp_sections;
status->vhost_dev->nvqs = hdev->nvqs;
status->vhost_dev->vq_index = hdev->vq_index;
status->vhost_dev->features =
qmp_decode_features(vdev->device_id, hdev->features);
status->vhost_dev->acked_features =
qmp_decode_features(vdev->device_id, hdev->acked_features);
status->vhost_dev->backend_features =
qmp_decode_features(vdev->device_id, hdev->backend_features);
status->vhost_dev->protocol_features =
qmp_decode_protocols(hdev->protocol_features);
status->vhost_dev->max_queues = hdev->max_queues;
status->vhost_dev->backend_cap = hdev->backend_cap;
status->vhost_dev->log_enabled = hdev->log_enabled;
status->vhost_dev->log_size = hdev->log_size;
}
return status;
}
VirtVhostQueueStatus *qmp_x_query_virtio_vhost_queue_status(const char *path,
uint16_t queue,
Error **errp)
{
VirtIODevice *vdev;
VirtVhostQueueStatus *status;
vdev = qmp_find_virtio_device(path);
if (vdev == NULL) {
error_setg(errp, "Path %s is not a VirtIODevice", path);
return NULL;
}
if (!vdev->vhost_started) {
error_setg(errp, "Error: vhost device has not started yet");
return NULL;
}
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
struct vhost_dev *hdev = vdc->get_vhost(vdev);
if (queue < hdev->vq_index || queue >= hdev->vq_index + hdev->nvqs) {
error_setg(errp, "Invalid vhost virtqueue number %d", queue);
return NULL;
}
status = g_new0(VirtVhostQueueStatus, 1);
status->name = g_strdup(vdev->name);
status->kick = hdev->vqs[queue].kick;
status->call = hdev->vqs[queue].call;
status->desc = (uintptr_t)hdev->vqs[queue].desc;
status->avail = (uintptr_t)hdev->vqs[queue].avail;
status->used = (uintptr_t)hdev->vqs[queue].used;
status->num = hdev->vqs[queue].num;
status->desc_phys = hdev->vqs[queue].desc_phys;
status->desc_size = hdev->vqs[queue].desc_size;
status->avail_phys = hdev->vqs[queue].avail_phys;
status->avail_size = hdev->vqs[queue].avail_size;
status->used_phys = hdev->vqs[queue].used_phys;
status->used_size = hdev->vqs[queue].used_size;
return status;
}
VirtQueueStatus *qmp_x_query_virtio_queue_status(const char *path,
uint16_t queue,
Error **errp)