* [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22
@ 2024-07-23 7:02 Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 01/25] qga: drop blocking of guest-get-memory-block-size command Konstantin Kostiuk
` (25 more replies)
0 siblings, 26 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
The following changes since commit 23fa74974d8c96bc95cbecc0d4e2d90f984939f6:
Merge tag 'pull-target-arm-20240718' of https://git.linaro.org/people/pmaydell/qemu-arm into staging (2024-07-19 07:02:17 +1000)
are available in the Git repository at:
https://github.com/kostyanf14/qemu.git tags/qga-pull-2024-07-23
for you to fetch changes up to 8e326d36dd16b91d9abc4963b5f75b8f637c2312:
qga/linux: Add new api 'guest-network-get-route' (2024-07-23 09:49:07 +0300)
----------------------------------------------------------------
qga-pull-2024-07-23
v1->v2:
Fix clang build failure of qga/linux: Add new api 'guest-network-get-route'
----------------------------------------------------------------
Daniel P. Berrangé (22):
qga: drop blocking of guest-get-memory-block-size command
qga: move linux vcpu command impls to commands-linux.c
qga: move linux suspend command impls to commands-linux.c
qga: move linux fs/disk command impls to commands-linux.c
qga: move linux disk/cpu stats command impls to commands-linux.c
qga: move linux memory block command impls to commands-linux.c
qga: move CONFIG_FSFREEZE/TRIM to be meson defined options
qga: conditionalize schema for commands unsupported on Windows
qga: conditionalize schema for commands unsupported on non-Linux POSIX
qga: conditionalize schema for commands requiring getifaddrs
qga: conditionalize schema for commands requiring linux/win32
qga: conditionalize schema for commands only supported on Windows
qga: conditionalize schema for commands requiring fsfreeze
qga: conditionalize schema for commands requiring fstrim
qga: conditionalize schema for commands requiring libudev
qga: conditionalize schema for commands requiring utmpx
qga: conditionalize schema for commands not supported on other UNIX
qga: don't disable fsfreeze commands if vss_init fails
qga: move declare of QGAConfig struct to top of file
qga: remove pointless 'blockrpcs_key' variable
qga: allow configuration file path via the cli
qga: centralize logic for disabling/enabling commands
Dehan Meng (1):
qga/linux: Add new api 'guest-network-get-route'
Thomas Lamprecht (1):
guest-agent: document allow-rpcs in config file section
Zhao Liu (1):
qga/commands-posix: Make ga_wait_child() return boolean
docs/interop/qemu-ga.rst | 20 +
meson.build | 16 +
qga/commands-bsd.c | 24 -
qga/commands-common.h | 9 -
qga/commands-linux.c | 1938 +++++++++++++++++++++++++++++++++++++
qga/commands-posix.c | 2383 ++++------------------------------------------
qga/commands-win32.c | 78 +-
qga/main.c | 224 ++---
qga/qapi-schema.json | 226 ++++-
9 files changed, 2452 insertions(+), 2466 deletions(-)
--
2.45.2
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PULL v2 01/25] qga: drop blocking of guest-get-memory-block-size command
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 02/25] qga: move linux vcpu command impls to commands-linux.c Konstantin Kostiuk
` (24 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
This command has never existed in tree, since it was renamed to
guest-get-memory-block-info before being merged.
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20240712132459.3974109-2-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-posix.c | 2 +-
qga/commands-win32.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 7f05996495..76af98ba32 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -3099,7 +3099,7 @@ GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
"guest-suspend-disk", "guest-suspend-ram",
"guest-suspend-hybrid", "guest-get-vcpus", "guest-set-vcpus",
"guest-get-memory-blocks", "guest-set-memory-blocks",
- "guest-get-memory-block-size", "guest-get-memory-block-info",
+ "guest-get-memory-block-info",
NULL};
char **p = (char **)list;
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 0d1b836e87..9fe670d5b4 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -1995,7 +1995,7 @@ GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
"guest-suspend-hybrid",
"guest-set-vcpus",
"guest-get-memory-blocks", "guest-set-memory-blocks",
- "guest-get-memory-block-size", "guest-get-memory-block-info",
+ "guest-get-memory-block-info",
NULL};
char **p = (char **)list_unsupported;
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 02/25] qga: move linux vcpu command impls to commands-linux.c
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 01/25] qga: drop blocking of guest-get-memory-block-size command Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 03/25] qga: move linux suspend " Konstantin Kostiuk
` (23 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
The qmp_guest_set_vcpus and qmp_guest_get_vcpus command impls in
commands-posix.c are surrounded by '#ifdef __linux__' so should
instead live in commands-linux.c
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-ID: <20240712132459.3974109-3-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-linux.c | 141 +++++++++++++++++++++++++++++++++++++++++++
qga/commands-posix.c | 139 ------------------------------------------
2 files changed, 141 insertions(+), 139 deletions(-)
diff --git a/qga/commands-linux.c b/qga/commands-linux.c
index 214e408fcd..78580ac39d 100644
--- a/qga/commands-linux.c
+++ b/qga/commands-linux.c
@@ -13,6 +13,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "qga-qapi-commands.h"
#include "commands-common.h"
#include "cutils.h"
#include <mntent.h>
@@ -284,3 +285,143 @@ int qmp_guest_fsfreeze_do_thaw(Error **errp)
return i;
}
#endif /* CONFIG_FSFREEZE */
+
+/* Transfer online/offline status between @vcpu and the guest system.
+ *
+ * On input either @errp or *@errp must be NULL.
+ *
+ * In system-to-@vcpu direction, the following @vcpu fields are accessed:
+ * - R: vcpu->logical_id
+ * - W: vcpu->online
+ * - W: vcpu->can_offline
+ *
+ * In @vcpu-to-system direction, the following @vcpu fields are accessed:
+ * - R: vcpu->logical_id
+ * - R: vcpu->online
+ *
+ * Written members remain unmodified on error.
+ */
+static void transfer_vcpu(GuestLogicalProcessor *vcpu, bool sys2vcpu,
+ char *dirpath, Error **errp)
+{
+ int fd;
+ int res;
+ int dirfd;
+ static const char fn[] = "online";
+
+ dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
+ if (dirfd == -1) {
+ error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
+ return;
+ }
+
+ fd = openat(dirfd, fn, sys2vcpu ? O_RDONLY : O_RDWR);
+ if (fd == -1) {
+ if (errno != ENOENT) {
+ error_setg_errno(errp, errno, "open(\"%s/%s\")", dirpath, fn);
+ } else if (sys2vcpu) {
+ vcpu->online = true;
+ vcpu->can_offline = false;
+ } else if (!vcpu->online) {
+ error_setg(errp, "logical processor #%" PRId64 " can't be "
+ "offlined", vcpu->logical_id);
+ } /* otherwise pretend successful re-onlining */
+ } else {
+ unsigned char status;
+
+ res = pread(fd, &status, 1, 0);
+ if (res == -1) {
+ error_setg_errno(errp, errno, "pread(\"%s/%s\")", dirpath, fn);
+ } else if (res == 0) {
+ error_setg(errp, "pread(\"%s/%s\"): unexpected EOF", dirpath,
+ fn);
+ } else if (sys2vcpu) {
+ vcpu->online = (status != '0');
+ vcpu->can_offline = true;
+ } else if (vcpu->online != (status != '0')) {
+ status = '0' + vcpu->online;
+ if (pwrite(fd, &status, 1, 0) == -1) {
+ error_setg_errno(errp, errno, "pwrite(\"%s/%s\")", dirpath,
+ fn);
+ }
+ } /* otherwise pretend successful re-(on|off)-lining */
+
+ res = close(fd);
+ g_assert(res == 0);
+ }
+
+ res = close(dirfd);
+ g_assert(res == 0);
+}
+
+GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
+{
+ GuestLogicalProcessorList *head, **tail;
+ const char *cpu_dir = "/sys/devices/system/cpu";
+ const gchar *line;
+ g_autoptr(GDir) cpu_gdir = NULL;
+ Error *local_err = NULL;
+
+ head = NULL;
+ tail = &head;
+ cpu_gdir = g_dir_open(cpu_dir, 0, NULL);
+
+ if (cpu_gdir == NULL) {
+ error_setg_errno(errp, errno, "failed to list entries: %s", cpu_dir);
+ return NULL;
+ }
+
+ while (local_err == NULL && (line = g_dir_read_name(cpu_gdir)) != NULL) {
+ GuestLogicalProcessor *vcpu;
+ int64_t id;
+ if (sscanf(line, "cpu%" PRId64, &id)) {
+ g_autofree char *path = g_strdup_printf("/sys/devices/system/cpu/"
+ "cpu%" PRId64 "/", id);
+ vcpu = g_malloc0(sizeof *vcpu);
+ vcpu->logical_id = id;
+ vcpu->has_can_offline = true; /* lolspeak ftw */
+ transfer_vcpu(vcpu, true, path, &local_err);
+ QAPI_LIST_APPEND(tail, vcpu);
+ }
+ }
+
+ if (local_err == NULL) {
+ /* there's no guest with zero VCPUs */
+ g_assert(head != NULL);
+ return head;
+ }
+
+ qapi_free_GuestLogicalProcessorList(head);
+ error_propagate(errp, local_err);
+ return NULL;
+}
+
+int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
+{
+ int64_t processed;
+ Error *local_err = NULL;
+
+ processed = 0;
+ while (vcpus != NULL) {
+ char *path = g_strdup_printf("/sys/devices/system/cpu/cpu%" PRId64 "/",
+ vcpus->value->logical_id);
+
+ transfer_vcpu(vcpus->value, false, path, &local_err);
+ g_free(path);
+ if (local_err != NULL) {
+ break;
+ }
+ ++processed;
+ vcpus = vcpus->next;
+ }
+
+ if (local_err != NULL) {
+ if (processed == 0) {
+ error_propagate(errp, local_err);
+ } else {
+ error_free(local_err);
+ }
+ }
+
+ return processed;
+}
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 76af98ba32..a8ef41f175 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -2003,145 +2003,6 @@ void qmp_guest_suspend_hybrid(Error **errp)
guest_suspend(SUSPEND_MODE_HYBRID, errp);
}
-/* Transfer online/offline status between @vcpu and the guest system.
- *
- * On input either @errp or *@errp must be NULL.
- *
- * In system-to-@vcpu direction, the following @vcpu fields are accessed:
- * - R: vcpu->logical_id
- * - W: vcpu->online
- * - W: vcpu->can_offline
- *
- * In @vcpu-to-system direction, the following @vcpu fields are accessed:
- * - R: vcpu->logical_id
- * - R: vcpu->online
- *
- * Written members remain unmodified on error.
- */
-static void transfer_vcpu(GuestLogicalProcessor *vcpu, bool sys2vcpu,
- char *dirpath, Error **errp)
-{
- int fd;
- int res;
- int dirfd;
- static const char fn[] = "online";
-
- dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
- if (dirfd == -1) {
- error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
- return;
- }
-
- fd = openat(dirfd, fn, sys2vcpu ? O_RDONLY : O_RDWR);
- if (fd == -1) {
- if (errno != ENOENT) {
- error_setg_errno(errp, errno, "open(\"%s/%s\")", dirpath, fn);
- } else if (sys2vcpu) {
- vcpu->online = true;
- vcpu->can_offline = false;
- } else if (!vcpu->online) {
- error_setg(errp, "logical processor #%" PRId64 " can't be "
- "offlined", vcpu->logical_id);
- } /* otherwise pretend successful re-onlining */
- } else {
- unsigned char status;
-
- res = pread(fd, &status, 1, 0);
- if (res == -1) {
- error_setg_errno(errp, errno, "pread(\"%s/%s\")", dirpath, fn);
- } else if (res == 0) {
- error_setg(errp, "pread(\"%s/%s\"): unexpected EOF", dirpath,
- fn);
- } else if (sys2vcpu) {
- vcpu->online = (status != '0');
- vcpu->can_offline = true;
- } else if (vcpu->online != (status != '0')) {
- status = '0' + vcpu->online;
- if (pwrite(fd, &status, 1, 0) == -1) {
- error_setg_errno(errp, errno, "pwrite(\"%s/%s\")", dirpath,
- fn);
- }
- } /* otherwise pretend successful re-(on|off)-lining */
-
- res = close(fd);
- g_assert(res == 0);
- }
-
- res = close(dirfd);
- g_assert(res == 0);
-}
-
-GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
-{
- GuestLogicalProcessorList *head, **tail;
- const char *cpu_dir = "/sys/devices/system/cpu";
- const gchar *line;
- g_autoptr(GDir) cpu_gdir = NULL;
- Error *local_err = NULL;
-
- head = NULL;
- tail = &head;
- cpu_gdir = g_dir_open(cpu_dir, 0, NULL);
-
- if (cpu_gdir == NULL) {
- error_setg_errno(errp, errno, "failed to list entries: %s", cpu_dir);
- return NULL;
- }
-
- while (local_err == NULL && (line = g_dir_read_name(cpu_gdir)) != NULL) {
- GuestLogicalProcessor *vcpu;
- int64_t id;
- if (sscanf(line, "cpu%" PRId64, &id)) {
- g_autofree char *path = g_strdup_printf("/sys/devices/system/cpu/"
- "cpu%" PRId64 "/", id);
- vcpu = g_malloc0(sizeof *vcpu);
- vcpu->logical_id = id;
- vcpu->has_can_offline = true; /* lolspeak ftw */
- transfer_vcpu(vcpu, true, path, &local_err);
- QAPI_LIST_APPEND(tail, vcpu);
- }
- }
-
- if (local_err == NULL) {
- /* there's no guest with zero VCPUs */
- g_assert(head != NULL);
- return head;
- }
-
- qapi_free_GuestLogicalProcessorList(head);
- error_propagate(errp, local_err);
- return NULL;
-}
-
-int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
-{
- int64_t processed;
- Error *local_err = NULL;
-
- processed = 0;
- while (vcpus != NULL) {
- char *path = g_strdup_printf("/sys/devices/system/cpu/cpu%" PRId64 "/",
- vcpus->value->logical_id);
-
- transfer_vcpu(vcpus->value, false, path, &local_err);
- g_free(path);
- if (local_err != NULL) {
- break;
- }
- ++processed;
- vcpus = vcpus->next;
- }
-
- if (local_err != NULL) {
- if (processed == 0) {
- error_propagate(errp, local_err);
- } else {
- error_free(local_err);
- }
- }
-
- return processed;
-}
#endif /* __linux__ */
#if defined(__linux__) || defined(__FreeBSD__)
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 03/25] qga: move linux suspend command impls to commands-linux.c
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 01/25] qga: drop blocking of guest-get-memory-block-size command Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 02/25] qga: move linux vcpu command impls to commands-linux.c Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 04/25] qga: move linux fs/disk " Konstantin Kostiuk
` (22 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
The qmp_guest_suspend_{disk,ram,hybrid} command impls in
commands-posix.c are surrounded by '#ifdef __linux__' so should
instead live in commands-linux.c
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-ID: <20240712132459.3974109-4-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-linux.c | 265 +++++++++++++++++++++++++++++++++++++++++++
qga/commands-posix.c | 265 -------------------------------------------
2 files changed, 265 insertions(+), 265 deletions(-)
diff --git a/qga/commands-linux.c b/qga/commands-linux.c
index 78580ac39d..3fabf54882 100644
--- a/qga/commands-linux.c
+++ b/qga/commands-linux.c
@@ -286,6 +286,271 @@ int qmp_guest_fsfreeze_do_thaw(Error **errp)
}
#endif /* CONFIG_FSFREEZE */
+
+#define LINUX_SYS_STATE_FILE "/sys/power/state"
+#define SUSPEND_SUPPORTED 0
+#define SUSPEND_NOT_SUPPORTED 1
+
+typedef enum {
+ SUSPEND_MODE_DISK = 0,
+ SUSPEND_MODE_RAM = 1,
+ SUSPEND_MODE_HYBRID = 2,
+} SuspendMode;
+
+/*
+ * Executes a command in a child process using g_spawn_sync,
+ * returning an int >= 0 representing the exit status of the
+ * process.
+ *
+ * If the program wasn't found in path, returns -1.
+ *
+ * If a problem happened when creating the child process,
+ * returns -1 and errp is set.
+ */
+static int run_process_child(const char *command[], Error **errp)
+{
+ int exit_status, spawn_flag;
+ GError *g_err = NULL;
+ bool success;
+
+ spawn_flag = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL |
+ G_SPAWN_STDERR_TO_DEV_NULL;
+
+ success = g_spawn_sync(NULL, (char **)command, NULL, spawn_flag,
+ NULL, NULL, NULL, NULL,
+ &exit_status, &g_err);
+
+ if (success) {
+ return WEXITSTATUS(exit_status);
+ }
+
+ if (g_err && (g_err->code != G_SPAWN_ERROR_NOENT)) {
+ error_setg(errp, "failed to create child process, error '%s'",
+ g_err->message);
+ }
+
+ g_error_free(g_err);
+ return -1;
+}
+
+static bool systemd_supports_mode(SuspendMode mode, Error **errp)
+{
+ const char *systemctl_args[3] = {"systemd-hibernate", "systemd-suspend",
+ "systemd-hybrid-sleep"};
+ const char *cmd[4] = {"systemctl", "status", systemctl_args[mode], NULL};
+ int status;
+
+ status = run_process_child(cmd, errp);
+
+ /*
+ * systemctl status uses LSB return codes so we can expect
+ * status > 0 and be ok. To assert if the guest has support
+ * for the selected suspend mode, status should be < 4. 4 is
+ * the code for unknown service status, the return value when
+ * the service does not exist. A common value is status = 3
+ * (program is not running).
+ */
+ if (status > 0 && status < 4) {
+ return true;
+ }
+
+ return false;
+}
+
+static void systemd_suspend(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ const char *systemctl_args[3] = {"hibernate", "suspend", "hybrid-sleep"};
+ const char *cmd[3] = {"systemctl", systemctl_args[mode], NULL};
+ int status;
+
+ status = run_process_child(cmd, &local_err);
+
+ if (status == 0) {
+ return;
+ }
+
+ if ((status == -1) && !local_err) {
+ error_setg(errp, "the helper program 'systemctl %s' was not found",
+ systemctl_args[mode]);
+ return;
+ }
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ } else {
+ error_setg(errp, "the helper program 'systemctl %s' returned an "
+ "unexpected exit status code (%d)",
+ systemctl_args[mode], status);
+ }
+}
+
+static bool pmutils_supports_mode(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ const char *pmutils_args[3] = {"--hibernate", "--suspend",
+ "--suspend-hybrid"};
+ const char *cmd[3] = {"pm-is-supported", pmutils_args[mode], NULL};
+ int status;
+
+ status = run_process_child(cmd, &local_err);
+
+ if (status == SUSPEND_SUPPORTED) {
+ return true;
+ }
+
+ if ((status == -1) && !local_err) {
+ return false;
+ }
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ } else {
+ error_setg(errp,
+ "the helper program '%s' returned an unexpected exit"
+ " status code (%d)", "pm-is-supported", status);
+ }
+
+ return false;
+}
+
+static void pmutils_suspend(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ const char *pmutils_binaries[3] = {"pm-hibernate", "pm-suspend",
+ "pm-suspend-hybrid"};
+ const char *cmd[2] = {pmutils_binaries[mode], NULL};
+ int status;
+
+ status = run_process_child(cmd, &local_err);
+
+ if (status == 0) {
+ return;
+ }
+
+ if ((status == -1) && !local_err) {
+ error_setg(errp, "the helper program '%s' was not found",
+ pmutils_binaries[mode]);
+ return;
+ }
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ } else {
+ error_setg(errp,
+ "the helper program '%s' returned an unexpected exit"
+ " status code (%d)", pmutils_binaries[mode], status);
+ }
+}
+
+static bool linux_sys_state_supports_mode(SuspendMode mode, Error **errp)
+{
+ const char *sysfile_strs[3] = {"disk", "mem", NULL};
+ const char *sysfile_str = sysfile_strs[mode];
+ char buf[32]; /* hopefully big enough */
+ int fd;
+ ssize_t ret;
+
+ if (!sysfile_str) {
+ error_setg(errp, "unknown guest suspend mode");
+ return false;
+ }
+
+ fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
+ if (fd < 0) {
+ return false;
+ }
+
+ ret = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+ if (ret <= 0) {
+ return false;
+ }
+ buf[ret] = '\0';
+
+ if (strstr(buf, sysfile_str)) {
+ return true;
+ }
+ return false;
+}
+
+static void linux_sys_state_suspend(SuspendMode mode, Error **errp)
+{
+ g_autoptr(GError) local_gerr = NULL;
+ const char *sysfile_strs[3] = {"disk", "mem", NULL};
+ const char *sysfile_str = sysfile_strs[mode];
+
+ if (!sysfile_str) {
+ error_setg(errp, "unknown guest suspend mode");
+ return;
+ }
+
+ if (!g_file_set_contents(LINUX_SYS_STATE_FILE, sysfile_str,
+ -1, &local_gerr)) {
+ error_setg(errp, "suspend: cannot write to '%s': %s",
+ LINUX_SYS_STATE_FILE, local_gerr->message);
+ return;
+ }
+}
+
+static void guest_suspend(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ bool mode_supported = false;
+
+ if (systemd_supports_mode(mode, &local_err)) {
+ mode_supported = true;
+ systemd_suspend(mode, &local_err);
+
+ if (!local_err) {
+ return;
+ }
+ }
+
+ error_free(local_err);
+ local_err = NULL;
+
+ if (pmutils_supports_mode(mode, &local_err)) {
+ mode_supported = true;
+ pmutils_suspend(mode, &local_err);
+
+ if (!local_err) {
+ return;
+ }
+ }
+
+ error_free(local_err);
+ local_err = NULL;
+
+ if (linux_sys_state_supports_mode(mode, &local_err)) {
+ mode_supported = true;
+ linux_sys_state_suspend(mode, &local_err);
+ }
+
+ if (!mode_supported) {
+ error_free(local_err);
+ error_setg(errp,
+ "the requested suspend mode is not supported by the guest");
+ } else {
+ error_propagate(errp, local_err);
+ }
+}
+
+void qmp_guest_suspend_disk(Error **errp)
+{
+ guest_suspend(SUSPEND_MODE_DISK, errp);
+}
+
+void qmp_guest_suspend_ram(Error **errp)
+{
+ guest_suspend(SUSPEND_MODE_RAM, errp);
+}
+
+void qmp_guest_suspend_hybrid(Error **errp)
+{
+ guest_suspend(SUSPEND_MODE_HYBRID, errp);
+}
+
/* Transfer online/offline status between @vcpu and the guest system.
*
* On input either @errp or *@errp must be NULL.
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index a8ef41f175..ef21da63be 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1738,271 +1738,6 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
}
#endif /* CONFIG_FSTRIM */
-
-#define LINUX_SYS_STATE_FILE "/sys/power/state"
-#define SUSPEND_SUPPORTED 0
-#define SUSPEND_NOT_SUPPORTED 1
-
-typedef enum {
- SUSPEND_MODE_DISK = 0,
- SUSPEND_MODE_RAM = 1,
- SUSPEND_MODE_HYBRID = 2,
-} SuspendMode;
-
-/*
- * Executes a command in a child process using g_spawn_sync,
- * returning an int >= 0 representing the exit status of the
- * process.
- *
- * If the program wasn't found in path, returns -1.
- *
- * If a problem happened when creating the child process,
- * returns -1 and errp is set.
- */
-static int run_process_child(const char *command[], Error **errp)
-{
- int exit_status, spawn_flag;
- GError *g_err = NULL;
- bool success;
-
- spawn_flag = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL |
- G_SPAWN_STDERR_TO_DEV_NULL;
-
- success = g_spawn_sync(NULL, (char **)command, NULL, spawn_flag,
- NULL, NULL, NULL, NULL,
- &exit_status, &g_err);
-
- if (success) {
- return WEXITSTATUS(exit_status);
- }
-
- if (g_err && (g_err->code != G_SPAWN_ERROR_NOENT)) {
- error_setg(errp, "failed to create child process, error '%s'",
- g_err->message);
- }
-
- g_error_free(g_err);
- return -1;
-}
-
-static bool systemd_supports_mode(SuspendMode mode, Error **errp)
-{
- const char *systemctl_args[3] = {"systemd-hibernate", "systemd-suspend",
- "systemd-hybrid-sleep"};
- const char *cmd[4] = {"systemctl", "status", systemctl_args[mode], NULL};
- int status;
-
- status = run_process_child(cmd, errp);
-
- /*
- * systemctl status uses LSB return codes so we can expect
- * status > 0 and be ok. To assert if the guest has support
- * for the selected suspend mode, status should be < 4. 4 is
- * the code for unknown service status, the return value when
- * the service does not exist. A common value is status = 3
- * (program is not running).
- */
- if (status > 0 && status < 4) {
- return true;
- }
-
- return false;
-}
-
-static void systemd_suspend(SuspendMode mode, Error **errp)
-{
- Error *local_err = NULL;
- const char *systemctl_args[3] = {"hibernate", "suspend", "hybrid-sleep"};
- const char *cmd[3] = {"systemctl", systemctl_args[mode], NULL};
- int status;
-
- status = run_process_child(cmd, &local_err);
-
- if (status == 0) {
- return;
- }
-
- if ((status == -1) && !local_err) {
- error_setg(errp, "the helper program 'systemctl %s' was not found",
- systemctl_args[mode]);
- return;
- }
-
- if (local_err) {
- error_propagate(errp, local_err);
- } else {
- error_setg(errp, "the helper program 'systemctl %s' returned an "
- "unexpected exit status code (%d)",
- systemctl_args[mode], status);
- }
-}
-
-static bool pmutils_supports_mode(SuspendMode mode, Error **errp)
-{
- Error *local_err = NULL;
- const char *pmutils_args[3] = {"--hibernate", "--suspend",
- "--suspend-hybrid"};
- const char *cmd[3] = {"pm-is-supported", pmutils_args[mode], NULL};
- int status;
-
- status = run_process_child(cmd, &local_err);
-
- if (status == SUSPEND_SUPPORTED) {
- return true;
- }
-
- if ((status == -1) && !local_err) {
- return false;
- }
-
- if (local_err) {
- error_propagate(errp, local_err);
- } else {
- error_setg(errp,
- "the helper program '%s' returned an unexpected exit"
- " status code (%d)", "pm-is-supported", status);
- }
-
- return false;
-}
-
-static void pmutils_suspend(SuspendMode mode, Error **errp)
-{
- Error *local_err = NULL;
- const char *pmutils_binaries[3] = {"pm-hibernate", "pm-suspend",
- "pm-suspend-hybrid"};
- const char *cmd[2] = {pmutils_binaries[mode], NULL};
- int status;
-
- status = run_process_child(cmd, &local_err);
-
- if (status == 0) {
- return;
- }
-
- if ((status == -1) && !local_err) {
- error_setg(errp, "the helper program '%s' was not found",
- pmutils_binaries[mode]);
- return;
- }
-
- if (local_err) {
- error_propagate(errp, local_err);
- } else {
- error_setg(errp,
- "the helper program '%s' returned an unexpected exit"
- " status code (%d)", pmutils_binaries[mode], status);
- }
-}
-
-static bool linux_sys_state_supports_mode(SuspendMode mode, Error **errp)
-{
- const char *sysfile_strs[3] = {"disk", "mem", NULL};
- const char *sysfile_str = sysfile_strs[mode];
- char buf[32]; /* hopefully big enough */
- int fd;
- ssize_t ret;
-
- if (!sysfile_str) {
- error_setg(errp, "unknown guest suspend mode");
- return false;
- }
-
- fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
- if (fd < 0) {
- return false;
- }
-
- ret = read(fd, buf, sizeof(buf) - 1);
- close(fd);
- if (ret <= 0) {
- return false;
- }
- buf[ret] = '\0';
-
- if (strstr(buf, sysfile_str)) {
- return true;
- }
- return false;
-}
-
-static void linux_sys_state_suspend(SuspendMode mode, Error **errp)
-{
- g_autoptr(GError) local_gerr = NULL;
- const char *sysfile_strs[3] = {"disk", "mem", NULL};
- const char *sysfile_str = sysfile_strs[mode];
-
- if (!sysfile_str) {
- error_setg(errp, "unknown guest suspend mode");
- return;
- }
-
- if (!g_file_set_contents(LINUX_SYS_STATE_FILE, sysfile_str,
- -1, &local_gerr)) {
- error_setg(errp, "suspend: cannot write to '%s': %s",
- LINUX_SYS_STATE_FILE, local_gerr->message);
- return;
- }
-}
-
-static void guest_suspend(SuspendMode mode, Error **errp)
-{
- Error *local_err = NULL;
- bool mode_supported = false;
-
- if (systemd_supports_mode(mode, &local_err)) {
- mode_supported = true;
- systemd_suspend(mode, &local_err);
-
- if (!local_err) {
- return;
- }
- }
-
- error_free(local_err);
- local_err = NULL;
-
- if (pmutils_supports_mode(mode, &local_err)) {
- mode_supported = true;
- pmutils_suspend(mode, &local_err);
-
- if (!local_err) {
- return;
- }
- }
-
- error_free(local_err);
- local_err = NULL;
-
- if (linux_sys_state_supports_mode(mode, &local_err)) {
- mode_supported = true;
- linux_sys_state_suspend(mode, &local_err);
- }
-
- if (!mode_supported) {
- error_free(local_err);
- error_setg(errp,
- "the requested suspend mode is not supported by the guest");
- } else {
- error_propagate(errp, local_err);
- }
-}
-
-void qmp_guest_suspend_disk(Error **errp)
-{
- guest_suspend(SUSPEND_MODE_DISK, errp);
-}
-
-void qmp_guest_suspend_ram(Error **errp)
-{
- guest_suspend(SUSPEND_MODE_RAM, errp);
-}
-
-void qmp_guest_suspend_hybrid(Error **errp)
-{
- guest_suspend(SUSPEND_MODE_HYBRID, errp);
-}
-
#endif /* __linux__ */
#if defined(__linux__) || defined(__FreeBSD__)
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 04/25] qga: move linux fs/disk command impls to commands-linux.c
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (2 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 03/25] qga: move linux suspend " Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 05/25] qga: move linux disk/cpu stats " Konstantin Kostiuk
` (21 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
The qmp_guest_{fstrim, get_fsinfo, get_disks} command impls in
commands-posix.c are surrounded by '#ifdef __linux__' so should
instead live in commands-linux.c
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-ID: <20240712132459.3974109-5-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-linux.c | 904 ++++++++++++++++++++++++++++++++++++++++++
qga/commands-posix.c | 909 -------------------------------------------
2 files changed, 904 insertions(+), 909 deletions(-)
diff --git a/qga/commands-linux.c b/qga/commands-linux.c
index 3fabf54882..084e6c9e85 100644
--- a/qga/commands-linux.c
+++ b/qga/commands-linux.c
@@ -14,10 +14,21 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qga-qapi-commands.h"
+#include "qapi/error.h"
+#include "qapi/qmp/qerror.h"
#include "commands-common.h"
#include "cutils.h"
#include <mntent.h>
#include <sys/ioctl.h>
+#include <mntent.h>
+#include <linux/nvme_ioctl.h>
+#include "block/nvme.h"
+
+#ifdef CONFIG_LIBUDEV
+#include <libudev.h>
+#endif
+
+#include <sys/statvfs.h>
#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
static int dev_major_minor(const char *devpath,
@@ -286,6 +297,899 @@ int qmp_guest_fsfreeze_do_thaw(Error **errp)
}
#endif /* CONFIG_FSFREEZE */
+#if defined(CONFIG_FSFREEZE)
+
+static char *get_pci_driver(char const *syspath, int pathlen, Error **errp)
+{
+ char *path;
+ char *dpath;
+ char *driver = NULL;
+ char buf[PATH_MAX];
+ ssize_t len;
+
+ path = g_strndup(syspath, pathlen);
+ dpath = g_strdup_printf("%s/driver", path);
+ len = readlink(dpath, buf, sizeof(buf) - 1);
+ if (len != -1) {
+ buf[len] = 0;
+ driver = g_path_get_basename(buf);
+ }
+ g_free(dpath);
+ g_free(path);
+ return driver;
+}
+
+static int compare_uint(const void *_a, const void *_b)
+{
+ unsigned int a = *(unsigned int *)_a;
+ unsigned int b = *(unsigned int *)_b;
+
+ return a < b ? -1 : a > b ? 1 : 0;
+}
+
+/* Walk the specified sysfs and build a sorted list of host or ata numbers */
+static int build_hosts(char const *syspath, char const *host, bool ata,
+ unsigned int *hosts, int hosts_max, Error **errp)
+{
+ char *path;
+ DIR *dir;
+ struct dirent *entry;
+ int i = 0;
+
+ path = g_strndup(syspath, host - syspath);
+ dir = opendir(path);
+ if (!dir) {
+ error_setg_errno(errp, errno, "opendir(\"%s\")", path);
+ g_free(path);
+ return -1;
+ }
+
+ while (i < hosts_max) {
+ entry = readdir(dir);
+ if (!entry) {
+ break;
+ }
+ if (ata && sscanf(entry->d_name, "ata%d", hosts + i) == 1) {
+ ++i;
+ } else if (!ata && sscanf(entry->d_name, "host%d", hosts + i) == 1) {
+ ++i;
+ }
+ }
+
+ qsort(hosts, i, sizeof(hosts[0]), compare_uint);
+
+ g_free(path);
+ closedir(dir);
+ return i;
+}
+
+/*
+ * Store disk device info for devices on the PCI bus.
+ * Returns true if information has been stored, or false for failure.
+ */
+static bool build_guest_fsinfo_for_pci_dev(char const *syspath,
+ GuestDiskAddress *disk,
+ Error **errp)
+{
+ unsigned int pci[4], host, hosts[8], tgt[3];
+ int i, nhosts = 0, pcilen;
+ GuestPCIAddress *pciaddr = disk->pci_controller;
+ bool has_ata = false, has_host = false, has_tgt = false;
+ char *p, *q, *driver = NULL;
+ bool ret = false;
+
+ p = strstr(syspath, "/devices/pci");
+ if (!p || sscanf(p + 12, "%*x:%*x/%x:%x:%x.%x%n",
+ pci, pci + 1, pci + 2, pci + 3, &pcilen) < 4) {
+ g_debug("only pci device is supported: sysfs path '%s'", syspath);
+ return false;
+ }
+
+ p += 12 + pcilen;
+ while (true) {
+ driver = get_pci_driver(syspath, p - syspath, errp);
+ if (driver && (g_str_equal(driver, "ata_piix") ||
+ g_str_equal(driver, "sym53c8xx") ||
+ g_str_equal(driver, "virtio-pci") ||
+ g_str_equal(driver, "ahci") ||
+ g_str_equal(driver, "nvme") ||
+ g_str_equal(driver, "xhci_hcd") ||
+ g_str_equal(driver, "ehci-pci"))) {
+ break;
+ }
+
+ g_free(driver);
+ if (sscanf(p, "/%x:%x:%x.%x%n",
+ pci, pci + 1, pci + 2, pci + 3, &pcilen) == 4) {
+ p += pcilen;
+ continue;
+ }
+
+ g_debug("unsupported driver or sysfs path '%s'", syspath);
+ return false;
+ }
+
+ p = strstr(syspath, "/target");
+ if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u",
+ tgt, tgt + 1, tgt + 2) == 3) {
+ has_tgt = true;
+ }
+
+ p = strstr(syspath, "/ata");
+ if (p) {
+ q = p + 4;
+ has_ata = true;
+ } else {
+ p = strstr(syspath, "/host");
+ q = p + 5;
+ }
+ if (p && sscanf(q, "%u", &host) == 1) {
+ has_host = true;
+ nhosts = build_hosts(syspath, p, has_ata, hosts,
+ ARRAY_SIZE(hosts), errp);
+ if (nhosts < 0) {
+ goto cleanup;
+ }
+ }
+
+ pciaddr->domain = pci[0];
+ pciaddr->bus = pci[1];
+ pciaddr->slot = pci[2];
+ pciaddr->function = pci[3];
+
+ if (strcmp(driver, "ata_piix") == 0) {
+ /* a host per ide bus, target*:0:<unit>:0 */
+ if (!has_host || !has_tgt) {
+ g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ for (i = 0; i < nhosts; i++) {
+ if (host == hosts[i]) {
+ disk->bus_type = GUEST_DISK_BUS_TYPE_IDE;
+ disk->bus = i;
+ disk->unit = tgt[1];
+ break;
+ }
+ }
+ if (i >= nhosts) {
+ g_debug("no host for '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ } else if (strcmp(driver, "sym53c8xx") == 0) {
+ /* scsi(LSI Logic): target*:0:<unit>:0 */
+ if (!has_tgt) {
+ g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
+ disk->unit = tgt[1];
+ } else if (strcmp(driver, "virtio-pci") == 0) {
+ if (has_tgt) {
+ /* virtio-scsi: target*:0:0:<unit> */
+ disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
+ disk->unit = tgt[2];
+ } else {
+ /* virtio-blk: 1 disk per 1 device */
+ disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO;
+ }
+ } else if (strcmp(driver, "ahci") == 0) {
+ /* ahci: 1 host per 1 unit */
+ if (!has_host || !has_tgt) {
+ g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ for (i = 0; i < nhosts; i++) {
+ if (host == hosts[i]) {
+ disk->unit = i;
+ disk->bus_type = GUEST_DISK_BUS_TYPE_SATA;
+ break;
+ }
+ }
+ if (i >= nhosts) {
+ g_debug("no host for '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ } else if (strcmp(driver, "nvme") == 0) {
+ disk->bus_type = GUEST_DISK_BUS_TYPE_NVME;
+ } else if (strcmp(driver, "ehci-pci") == 0 || strcmp(driver, "xhci_hcd") == 0) {
+ disk->bus_type = GUEST_DISK_BUS_TYPE_USB;
+ } else {
+ g_debug("unknown driver '%s' (sysfs path '%s')", driver, syspath);
+ goto cleanup;
+ }
+
+ ret = true;
+
+cleanup:
+ g_free(driver);
+ return ret;
+}
+
+/*
+ * Store disk device info for non-PCI virtio devices (for example s390x
+ * channel I/O devices). Returns true if information has been stored, or
+ * false for failure.
+ */
+static bool build_guest_fsinfo_for_nonpci_virtio(char const *syspath,
+ GuestDiskAddress *disk,
+ Error **errp)
+{
+ unsigned int tgt[3];
+ char *p;
+
+ if (!strstr(syspath, "/virtio") || !strstr(syspath, "/block")) {
+ g_debug("Unsupported virtio device '%s'", syspath);
+ return false;
+ }
+
+ p = strstr(syspath, "/target");
+ if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u",
+ &tgt[0], &tgt[1], &tgt[2]) == 3) {
+ /* virtio-scsi: target*:0:<target>:<unit> */
+ disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
+ disk->bus = tgt[0];
+ disk->target = tgt[1];
+ disk->unit = tgt[2];
+ } else {
+ /* virtio-blk: 1 disk per 1 device */
+ disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO;
+ }
+
+ return true;
+}
+
+/*
+ * Store disk device info for CCW devices (s390x channel I/O devices).
+ * Returns true if information has been stored, or false for failure.
+ */
+static bool build_guest_fsinfo_for_ccw_dev(char const *syspath,
+ GuestDiskAddress *disk,
+ Error **errp)
+{
+ unsigned int cssid, ssid, subchno, devno;
+ char *p;
+
+ p = strstr(syspath, "/devices/css");
+ if (!p || sscanf(p + 12, "%*x/%x.%x.%x/%*x.%*x.%x/",
+ &cssid, &ssid, &subchno, &devno) < 4) {
+ g_debug("could not parse ccw device sysfs path: %s", syspath);
+ return false;
+ }
+
+ disk->ccw_address = g_new0(GuestCCWAddress, 1);
+ disk->ccw_address->cssid = cssid;
+ disk->ccw_address->ssid = ssid;
+ disk->ccw_address->subchno = subchno;
+ disk->ccw_address->devno = devno;
+
+ if (strstr(p, "/virtio")) {
+ build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp);
+ }
+
+ return true;
+}
+
+/* Store disk device info specified by @sysfs into @fs */
+static void build_guest_fsinfo_for_real_device(char const *syspath,
+ GuestFilesystemInfo *fs,
+ Error **errp)
+{
+ GuestDiskAddress *disk;
+ GuestPCIAddress *pciaddr;
+ bool has_hwinf;
+#ifdef CONFIG_LIBUDEV
+ struct udev *udev = NULL;
+ struct udev_device *udevice = NULL;
+#endif
+
+ pciaddr = g_new0(GuestPCIAddress, 1);
+ pciaddr->domain = -1; /* -1 means field is invalid */
+ pciaddr->bus = -1;
+ pciaddr->slot = -1;
+ pciaddr->function = -1;
+
+ disk = g_new0(GuestDiskAddress, 1);
+ disk->pci_controller = pciaddr;
+ disk->bus_type = GUEST_DISK_BUS_TYPE_UNKNOWN;
+
+#ifdef CONFIG_LIBUDEV
+ udev = udev_new();
+ udevice = udev_device_new_from_syspath(udev, syspath);
+ if (udev == NULL || udevice == NULL) {
+ g_debug("failed to query udev");
+ } else {
+ const char *devnode, *serial;
+ devnode = udev_device_get_devnode(udevice);
+ if (devnode != NULL) {
+ disk->dev = g_strdup(devnode);
+ }
+ serial = udev_device_get_property_value(udevice, "ID_SERIAL");
+ if (serial != NULL && *serial != 0) {
+ disk->serial = g_strdup(serial);
+ }
+ }
+
+ udev_unref(udev);
+ udev_device_unref(udevice);
+#endif
+
+ if (strstr(syspath, "/devices/pci")) {
+ has_hwinf = build_guest_fsinfo_for_pci_dev(syspath, disk, errp);
+ } else if (strstr(syspath, "/devices/css")) {
+ has_hwinf = build_guest_fsinfo_for_ccw_dev(syspath, disk, errp);
+ } else if (strstr(syspath, "/virtio")) {
+ has_hwinf = build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp);
+ } else {
+ g_debug("Unsupported device type for '%s'", syspath);
+ has_hwinf = false;
+ }
+
+ if (has_hwinf || disk->dev || disk->serial) {
+ QAPI_LIST_PREPEND(fs->disk, disk);
+ } else {
+ qapi_free_GuestDiskAddress(disk);
+ }
+}
+
+static void build_guest_fsinfo_for_device(char const *devpath,
+ GuestFilesystemInfo *fs,
+ Error **errp);
+
+/* Store a list of slave devices of virtual volume specified by @syspath into
+ * @fs */
+static void build_guest_fsinfo_for_virtual_device(char const *syspath,
+ GuestFilesystemInfo *fs,
+ Error **errp)
+{
+ Error *err = NULL;
+ DIR *dir;
+ char *dirpath;
+ struct dirent *entry;
+
+ dirpath = g_strdup_printf("%s/slaves", syspath);
+ dir = opendir(dirpath);
+ if (!dir) {
+ if (errno != ENOENT) {
+ error_setg_errno(errp, errno, "opendir(\"%s\")", dirpath);
+ }
+ g_free(dirpath);
+ return;
+ }
+
+ for (;;) {
+ errno = 0;
+ entry = readdir(dir);
+ if (entry == NULL) {
+ if (errno) {
+ error_setg_errno(errp, errno, "readdir(\"%s\")", dirpath);
+ }
+ break;
+ }
+
+ if (entry->d_type == DT_LNK) {
+ char *path;
+
+ g_debug(" slave device '%s'", entry->d_name);
+ path = g_strdup_printf("%s/slaves/%s", syspath, entry->d_name);
+ build_guest_fsinfo_for_device(path, fs, &err);
+ g_free(path);
+
+ if (err) {
+ error_propagate(errp, err);
+ break;
+ }
+ }
+ }
+
+ g_free(dirpath);
+ closedir(dir);
+}
+
+static bool is_disk_virtual(const char *devpath, Error **errp)
+{
+ g_autofree char *syspath = realpath(devpath, NULL);
+
+ if (!syspath) {
+ error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
+ return false;
+ }
+ return strstr(syspath, "/devices/virtual/block/") != NULL;
+}
+
+/* Dispatch to functions for virtual/real device */
+static void build_guest_fsinfo_for_device(char const *devpath,
+ GuestFilesystemInfo *fs,
+ Error **errp)
+{
+ ERRP_GUARD();
+ g_autofree char *syspath = NULL;
+ bool is_virtual = false;
+
+ syspath = realpath(devpath, NULL);
+ if (!syspath) {
+ if (errno != ENOENT) {
+ error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
+ return;
+ }
+
+ /* ENOENT: This devpath may not exist because of container config */
+ if (!fs->name) {
+ fs->name = g_path_get_basename(devpath);
+ }
+ return;
+ }
+
+ if (!fs->name) {
+ fs->name = g_path_get_basename(syspath);
+ }
+
+ g_debug(" parse sysfs path '%s'", syspath);
+ is_virtual = is_disk_virtual(syspath, errp);
+ if (*errp != NULL) {
+ return;
+ }
+ if (is_virtual) {
+ build_guest_fsinfo_for_virtual_device(syspath, fs, errp);
+ } else {
+ build_guest_fsinfo_for_real_device(syspath, fs, errp);
+ }
+}
+
+#ifdef CONFIG_LIBUDEV
+
+/*
+ * Wrapper around build_guest_fsinfo_for_device() for getting just
+ * the disk address.
+ */
+static GuestDiskAddress *get_disk_address(const char *syspath, Error **errp)
+{
+ g_autoptr(GuestFilesystemInfo) fs = NULL;
+
+ fs = g_new0(GuestFilesystemInfo, 1);
+ build_guest_fsinfo_for_device(syspath, fs, errp);
+ if (fs->disk != NULL) {
+ return g_steal_pointer(&fs->disk->value);
+ }
+ return NULL;
+}
+
+static char *get_alias_for_syspath(const char *syspath)
+{
+ struct udev *udev = NULL;
+ struct udev_device *udevice = NULL;
+ char *ret = NULL;
+
+ udev = udev_new();
+ if (udev == NULL) {
+ g_debug("failed to query udev");
+ goto out;
+ }
+ udevice = udev_device_new_from_syspath(udev, syspath);
+ if (udevice == NULL) {
+ g_debug("failed to query udev for path: %s", syspath);
+ goto out;
+ } else {
+ const char *alias = udev_device_get_property_value(
+ udevice, "DM_NAME");
+ /*
+ * NULL means there was an error and empty string means there is no
+ * alias. In case of no alias we return NULL instead of empty string.
+ */
+ if (alias == NULL) {
+ g_debug("failed to query udev for device alias for: %s",
+ syspath);
+ } else if (*alias != 0) {
+ ret = g_strdup(alias);
+ }
+ }
+
+out:
+ udev_unref(udev);
+ udev_device_unref(udevice);
+ return ret;
+}
+
+static char *get_device_for_syspath(const char *syspath)
+{
+ struct udev *udev = NULL;
+ struct udev_device *udevice = NULL;
+ char *ret = NULL;
+
+ udev = udev_new();
+ if (udev == NULL) {
+ g_debug("failed to query udev");
+ goto out;
+ }
+ udevice = udev_device_new_from_syspath(udev, syspath);
+ if (udevice == NULL) {
+ g_debug("failed to query udev for path: %s", syspath);
+ goto out;
+ } else {
+ ret = g_strdup(udev_device_get_devnode(udevice));
+ }
+
+out:
+ udev_unref(udev);
+ udev_device_unref(udevice);
+ return ret;
+}
+
+static void get_disk_deps(const char *disk_dir, GuestDiskInfo *disk)
+{
+ g_autofree char *deps_dir = NULL;
+ const gchar *dep;
+ GDir *dp_deps = NULL;
+
+ /* List dependent disks */
+ deps_dir = g_strdup_printf("%s/slaves", disk_dir);
+ g_debug(" listing entries in: %s", deps_dir);
+ dp_deps = g_dir_open(deps_dir, 0, NULL);
+ if (dp_deps == NULL) {
+ g_debug("failed to list entries in %s", deps_dir);
+ return;
+ }
+ disk->has_dependencies = true;
+ while ((dep = g_dir_read_name(dp_deps)) != NULL) {
+ g_autofree char *dep_dir = NULL;
+ char *dev_name;
+
+ /* Add dependent disks */
+ dep_dir = g_strdup_printf("%s/%s", deps_dir, dep);
+ dev_name = get_device_for_syspath(dep_dir);
+ if (dev_name != NULL) {
+ g_debug(" adding dependent device: %s", dev_name);
+ QAPI_LIST_PREPEND(disk->dependencies, dev_name);
+ }
+ }
+ g_dir_close(dp_deps);
+}
+
+/*
+ * Detect partitions subdirectory, name is "<disk_name><number>" or
+ * "<disk_name>p<number>"
+ *
+ * @disk_name -- last component of /sys path (e.g. sda)
+ * @disk_dir -- sys path of the disk (e.g. /sys/block/sda)
+ * @disk_dev -- device node of the disk (e.g. /dev/sda)
+ */
+static GuestDiskInfoList *get_disk_partitions(
+ GuestDiskInfoList *list,
+ const char *disk_name, const char *disk_dir,
+ const char *disk_dev)
+{
+ GuestDiskInfoList *ret = list;
+ struct dirent *de_disk;
+ DIR *dp_disk = NULL;
+ size_t len = strlen(disk_name);
+
+ dp_disk = opendir(disk_dir);
+ while ((de_disk = readdir(dp_disk)) != NULL) {
+ g_autofree char *partition_dir = NULL;
+ char *dev_name;
+ GuestDiskInfo *partition;
+
+ if (!(de_disk->d_type & DT_DIR)) {
+ continue;
+ }
+
+ if (!(strncmp(disk_name, de_disk->d_name, len) == 0 &&
+ ((*(de_disk->d_name + len) == 'p' &&
+ isdigit(*(de_disk->d_name + len + 1))) ||
+ isdigit(*(de_disk->d_name + len))))) {
+ continue;
+ }
+
+ partition_dir = g_strdup_printf("%s/%s",
+ disk_dir, de_disk->d_name);
+ dev_name = get_device_for_syspath(partition_dir);
+ if (dev_name == NULL) {
+ g_debug("Failed to get device name for syspath: %s",
+ disk_dir);
+ continue;
+ }
+ partition = g_new0(GuestDiskInfo, 1);
+ partition->name = dev_name;
+ partition->partition = true;
+ partition->has_dependencies = true;
+ /* Add parent disk as dependent for easier tracking of hierarchy */
+ QAPI_LIST_PREPEND(partition->dependencies, g_strdup(disk_dev));
+
+ QAPI_LIST_PREPEND(ret, partition);
+ }
+ closedir(dp_disk);
+
+ return ret;
+}
+
+static void get_nvme_smart(GuestDiskInfo *disk)
+{
+ int fd;
+ GuestNVMeSmart *smart;
+ NvmeSmartLog log = {0};
+ struct nvme_admin_cmd cmd = {
+ .opcode = NVME_ADM_CMD_GET_LOG_PAGE,
+ .nsid = NVME_NSID_BROADCAST,
+ .addr = (uintptr_t)&log,
+ .data_len = sizeof(log),
+ .cdw10 = NVME_LOG_SMART_INFO | (1 << 15) /* RAE bit */
+ | (((sizeof(log) >> 2) - 1) << 16)
+ };
+
+ fd = qga_open_cloexec(disk->name, O_RDONLY, 0);
+ if (fd == -1) {
+ g_debug("Failed to open device: %s: %s", disk->name, g_strerror(errno));
+ return;
+ }
+
+ if (ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd)) {
+ g_debug("Failed to get smart: %s: %s", disk->name, g_strerror(errno));
+ close(fd);
+ return;
+ }
+
+ disk->smart = g_new0(GuestDiskSmart, 1);
+ disk->smart->type = GUEST_DISK_BUS_TYPE_NVME;
+
+ smart = &disk->smart->u.nvme;
+ smart->critical_warning = log.critical_warning;
+ smart->temperature = lduw_le_p(&log.temperature); /* unaligned field */
+ smart->available_spare = log.available_spare;
+ smart->available_spare_threshold = log.available_spare_threshold;
+ smart->percentage_used = log.percentage_used;
+ smart->data_units_read_lo = le64_to_cpu(log.data_units_read[0]);
+ smart->data_units_read_hi = le64_to_cpu(log.data_units_read[1]);
+ smart->data_units_written_lo = le64_to_cpu(log.data_units_written[0]);
+ smart->data_units_written_hi = le64_to_cpu(log.data_units_written[1]);
+ smart->host_read_commands_lo = le64_to_cpu(log.host_read_commands[0]);
+ smart->host_read_commands_hi = le64_to_cpu(log.host_read_commands[1]);
+ smart->host_write_commands_lo = le64_to_cpu(log.host_write_commands[0]);
+ smart->host_write_commands_hi = le64_to_cpu(log.host_write_commands[1]);
+ smart->controller_busy_time_lo = le64_to_cpu(log.controller_busy_time[0]);
+ smart->controller_busy_time_hi = le64_to_cpu(log.controller_busy_time[1]);
+ smart->power_cycles_lo = le64_to_cpu(log.power_cycles[0]);
+ smart->power_cycles_hi = le64_to_cpu(log.power_cycles[1]);
+ smart->power_on_hours_lo = le64_to_cpu(log.power_on_hours[0]);
+ smart->power_on_hours_hi = le64_to_cpu(log.power_on_hours[1]);
+ smart->unsafe_shutdowns_lo = le64_to_cpu(log.unsafe_shutdowns[0]);
+ smart->unsafe_shutdowns_hi = le64_to_cpu(log.unsafe_shutdowns[1]);
+ smart->media_errors_lo = le64_to_cpu(log.media_errors[0]);
+ smart->media_errors_hi = le64_to_cpu(log.media_errors[1]);
+ smart->number_of_error_log_entries_lo =
+ le64_to_cpu(log.number_of_error_log_entries[0]);
+ smart->number_of_error_log_entries_hi =
+ le64_to_cpu(log.number_of_error_log_entries[1]);
+
+ close(fd);
+}
+
+static void get_disk_smart(GuestDiskInfo *disk)
+{
+ if (disk->address
+ && (disk->address->bus_type == GUEST_DISK_BUS_TYPE_NVME)) {
+ get_nvme_smart(disk);
+ }
+}
+
+GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
+{
+ GuestDiskInfoList *ret = NULL;
+ GuestDiskInfo *disk;
+ DIR *dp = NULL;
+ struct dirent *de = NULL;
+
+ g_debug("listing /sys/block directory");
+ dp = opendir("/sys/block");
+ if (dp == NULL) {
+ error_setg_errno(errp, errno, "Can't open directory \"/sys/block\"");
+ return NULL;
+ }
+ while ((de = readdir(dp)) != NULL) {
+ g_autofree char *disk_dir = NULL, *line = NULL,
+ *size_path = NULL;
+ char *dev_name;
+ Error *local_err = NULL;
+ if (de->d_type != DT_LNK) {
+ g_debug(" skipping entry: %s", de->d_name);
+ continue;
+ }
+
+ /* Check size and skip zero-sized disks */
+ g_debug(" checking disk size");
+ size_path = g_strdup_printf("/sys/block/%s/size", de->d_name);
+ if (!g_file_get_contents(size_path, &line, NULL, NULL)) {
+ g_debug(" failed to read disk size");
+ continue;
+ }
+ if (g_strcmp0(line, "0\n") == 0) {
+ g_debug(" skipping zero-sized disk");
+ continue;
+ }
+
+ g_debug(" adding %s", de->d_name);
+ disk_dir = g_strdup_printf("/sys/block/%s", de->d_name);
+ dev_name = get_device_for_syspath(disk_dir);
+ if (dev_name == NULL) {
+ g_debug("Failed to get device name for syspath: %s",
+ disk_dir);
+ continue;
+ }
+ disk = g_new0(GuestDiskInfo, 1);
+ disk->name = dev_name;
+ disk->partition = false;
+ disk->alias = get_alias_for_syspath(disk_dir);
+ QAPI_LIST_PREPEND(ret, disk);
+
+ /* Get address for non-virtual devices */
+ bool is_virtual = is_disk_virtual(disk_dir, &local_err);
+ if (local_err != NULL) {
+ g_debug(" failed to check disk path, ignoring error: %s",
+ error_get_pretty(local_err));
+ error_free(local_err);
+ local_err = NULL;
+ /* Don't try to get the address */
+ is_virtual = true;
+ }
+ if (!is_virtual) {
+ disk->address = get_disk_address(disk_dir, &local_err);
+ if (local_err != NULL) {
+ g_debug(" failed to get device info, ignoring error: %s",
+ error_get_pretty(local_err));
+ error_free(local_err);
+ local_err = NULL;
+ }
+ }
+
+ get_disk_deps(disk_dir, disk);
+ get_disk_smart(disk);
+ ret = get_disk_partitions(ret, de->d_name, disk_dir, dev_name);
+ }
+
+ closedir(dp);
+
+ return ret;
+}
+
+#else
+
+GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
+{
+ error_setg(errp, QERR_UNSUPPORTED);
+ return NULL;
+}
+
+#endif
+
+/* Return a list of the disk device(s)' info which @mount lies on */
+static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount,
+ Error **errp)
+{
+ GuestFilesystemInfo *fs = g_malloc0(sizeof(*fs));
+ struct statvfs buf;
+ unsigned long used, nonroot_total, fr_size;
+ char *devpath = g_strdup_printf("/sys/dev/block/%u:%u",
+ mount->devmajor, mount->devminor);
+
+ fs->mountpoint = g_strdup(mount->dirname);
+ fs->type = g_strdup(mount->devtype);
+ build_guest_fsinfo_for_device(devpath, fs, errp);
+
+ if (statvfs(fs->mountpoint, &buf) == 0) {
+ fr_size = buf.f_frsize;
+ used = buf.f_blocks - buf.f_bfree;
+ nonroot_total = used + buf.f_bavail;
+ fs->used_bytes = used * fr_size;
+ fs->total_bytes = nonroot_total * fr_size;
+ fs->total_bytes_privileged = buf.f_blocks * fr_size;
+
+ fs->has_total_bytes = true;
+ fs->has_total_bytes_privileged = true;
+ fs->has_used_bytes = true;
+ }
+
+ g_free(devpath);
+
+ return fs;
+}
+
+GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
+{
+ FsMountList mounts;
+ struct FsMount *mount;
+ GuestFilesystemInfoList *ret = NULL;
+ Error *local_err = NULL;
+
+ QTAILQ_INIT(&mounts);
+ if (!build_fs_mount_list(&mounts, &local_err)) {
+ error_propagate(errp, local_err);
+ return NULL;
+ }
+
+ QTAILQ_FOREACH(mount, &mounts, next) {
+ g_debug("Building guest fsinfo for '%s'", mount->dirname);
+
+ QAPI_LIST_PREPEND(ret, build_guest_fsinfo(mount, &local_err));
+ if (local_err) {
+ error_propagate(errp, local_err);
+ qapi_free_GuestFilesystemInfoList(ret);
+ ret = NULL;
+ break;
+ }
+ }
+
+ free_fs_mount_list(&mounts);
+ return ret;
+}
+#endif /* CONFIG_FSFREEZE */
+
+#if defined(CONFIG_FSTRIM)
+/*
+ * Walk list of mounted file systems in the guest, and trim them.
+ */
+GuestFilesystemTrimResponse *
+qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
+{
+ GuestFilesystemTrimResponse *response;
+ GuestFilesystemTrimResult *result;
+ int ret = 0;
+ FsMountList mounts;
+ struct FsMount *mount;
+ int fd;
+ struct fstrim_range r;
+
+ slog("guest-fstrim called");
+
+ QTAILQ_INIT(&mounts);
+ if (!build_fs_mount_list(&mounts, errp)) {
+ return NULL;
+ }
+
+ response = g_malloc0(sizeof(*response));
+
+ QTAILQ_FOREACH(mount, &mounts, next) {
+ result = g_malloc0(sizeof(*result));
+ result->path = g_strdup(mount->dirname);
+
+ QAPI_LIST_PREPEND(response->paths, result);
+
+ fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0);
+ if (fd == -1) {
+ result->error = g_strdup_printf("failed to open: %s",
+ strerror(errno));
+ continue;
+ }
+
+ /* We try to cull filesystems we know won't work in advance, but other
+ * filesystems may not implement fstrim for less obvious reasons.
+ * These will report EOPNOTSUPP; while in some other cases ENOTTY
+ * will be reported (e.g. CD-ROMs).
+ * Any other error means an unexpected error.
+ */
+ r.start = 0;
+ r.len = -1;
+ r.minlen = has_minimum ? minimum : 0;
+ ret = ioctl(fd, FITRIM, &r);
+ if (ret == -1) {
+ if (errno == ENOTTY || errno == EOPNOTSUPP) {
+ result->error = g_strdup("trim not supported");
+ } else {
+ result->error = g_strdup_printf("failed to trim: %s",
+ strerror(errno));
+ }
+ close(fd);
+ continue;
+ }
+
+ result->has_minimum = true;
+ result->minimum = r.minlen;
+ result->has_trimmed = true;
+ result->trimmed = r.len;
+ close(fd);
+ }
+
+ free_fs_mount_list(&mounts);
+ return response;
+}
+#endif /* CONFIG_FSTRIM */
#define LINUX_SYS_STATE_FILE "/sys/power/state"
#define SUSPEND_SUPPORTED 0
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index ef21da63be..98aafc45f3 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -24,23 +24,12 @@
#include "qemu/base64.h"
#include "qemu/cutils.h"
#include "commands-common.h"
-#include "block/nvme.h"
#include "cutils.h"
#ifdef HAVE_UTMPX
#include <utmpx.h>
#endif
-#if defined(__linux__)
-#include <mntent.h>
-#include <sys/statvfs.h>
-#include <linux/nvme_ioctl.h>
-
-#ifdef CONFIG_LIBUDEV
-#include <libudev.h>
-#endif
-#endif
-
#ifdef HAVE_GETIFADDRS
#include <arpa/inet.h>
#include <sys/socket.h>
@@ -842,904 +831,6 @@ static void guest_fsfreeze_cleanup(void)
}
#endif
-/* linux-specific implementations. avoid this if at all possible. */
-#if defined(__linux__)
-#if defined(CONFIG_FSFREEZE)
-
-static char *get_pci_driver(char const *syspath, int pathlen, Error **errp)
-{
- char *path;
- char *dpath;
- char *driver = NULL;
- char buf[PATH_MAX];
- ssize_t len;
-
- path = g_strndup(syspath, pathlen);
- dpath = g_strdup_printf("%s/driver", path);
- len = readlink(dpath, buf, sizeof(buf) - 1);
- if (len != -1) {
- buf[len] = 0;
- driver = g_path_get_basename(buf);
- }
- g_free(dpath);
- g_free(path);
- return driver;
-}
-
-static int compare_uint(const void *_a, const void *_b)
-{
- unsigned int a = *(unsigned int *)_a;
- unsigned int b = *(unsigned int *)_b;
-
- return a < b ? -1 : a > b ? 1 : 0;
-}
-
-/* Walk the specified sysfs and build a sorted list of host or ata numbers */
-static int build_hosts(char const *syspath, char const *host, bool ata,
- unsigned int *hosts, int hosts_max, Error **errp)
-{
- char *path;
- DIR *dir;
- struct dirent *entry;
- int i = 0;
-
- path = g_strndup(syspath, host - syspath);
- dir = opendir(path);
- if (!dir) {
- error_setg_errno(errp, errno, "opendir(\"%s\")", path);
- g_free(path);
- return -1;
- }
-
- while (i < hosts_max) {
- entry = readdir(dir);
- if (!entry) {
- break;
- }
- if (ata && sscanf(entry->d_name, "ata%d", hosts + i) == 1) {
- ++i;
- } else if (!ata && sscanf(entry->d_name, "host%d", hosts + i) == 1) {
- ++i;
- }
- }
-
- qsort(hosts, i, sizeof(hosts[0]), compare_uint);
-
- g_free(path);
- closedir(dir);
- return i;
-}
-
-/*
- * Store disk device info for devices on the PCI bus.
- * Returns true if information has been stored, or false for failure.
- */
-static bool build_guest_fsinfo_for_pci_dev(char const *syspath,
- GuestDiskAddress *disk,
- Error **errp)
-{
- unsigned int pci[4], host, hosts[8], tgt[3];
- int i, nhosts = 0, pcilen;
- GuestPCIAddress *pciaddr = disk->pci_controller;
- bool has_ata = false, has_host = false, has_tgt = false;
- char *p, *q, *driver = NULL;
- bool ret = false;
-
- p = strstr(syspath, "/devices/pci");
- if (!p || sscanf(p + 12, "%*x:%*x/%x:%x:%x.%x%n",
- pci, pci + 1, pci + 2, pci + 3, &pcilen) < 4) {
- g_debug("only pci device is supported: sysfs path '%s'", syspath);
- return false;
- }
-
- p += 12 + pcilen;
- while (true) {
- driver = get_pci_driver(syspath, p - syspath, errp);
- if (driver && (g_str_equal(driver, "ata_piix") ||
- g_str_equal(driver, "sym53c8xx") ||
- g_str_equal(driver, "virtio-pci") ||
- g_str_equal(driver, "ahci") ||
- g_str_equal(driver, "nvme") ||
- g_str_equal(driver, "xhci_hcd") ||
- g_str_equal(driver, "ehci-pci"))) {
- break;
- }
-
- g_free(driver);
- if (sscanf(p, "/%x:%x:%x.%x%n",
- pci, pci + 1, pci + 2, pci + 3, &pcilen) == 4) {
- p += pcilen;
- continue;
- }
-
- g_debug("unsupported driver or sysfs path '%s'", syspath);
- return false;
- }
-
- p = strstr(syspath, "/target");
- if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u",
- tgt, tgt + 1, tgt + 2) == 3) {
- has_tgt = true;
- }
-
- p = strstr(syspath, "/ata");
- if (p) {
- q = p + 4;
- has_ata = true;
- } else {
- p = strstr(syspath, "/host");
- q = p + 5;
- }
- if (p && sscanf(q, "%u", &host) == 1) {
- has_host = true;
- nhosts = build_hosts(syspath, p, has_ata, hosts,
- ARRAY_SIZE(hosts), errp);
- if (nhosts < 0) {
- goto cleanup;
- }
- }
-
- pciaddr->domain = pci[0];
- pciaddr->bus = pci[1];
- pciaddr->slot = pci[2];
- pciaddr->function = pci[3];
-
- if (strcmp(driver, "ata_piix") == 0) {
- /* a host per ide bus, target*:0:<unit>:0 */
- if (!has_host || !has_tgt) {
- g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
- goto cleanup;
- }
- for (i = 0; i < nhosts; i++) {
- if (host == hosts[i]) {
- disk->bus_type = GUEST_DISK_BUS_TYPE_IDE;
- disk->bus = i;
- disk->unit = tgt[1];
- break;
- }
- }
- if (i >= nhosts) {
- g_debug("no host for '%s' (driver '%s')", syspath, driver);
- goto cleanup;
- }
- } else if (strcmp(driver, "sym53c8xx") == 0) {
- /* scsi(LSI Logic): target*:0:<unit>:0 */
- if (!has_tgt) {
- g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
- goto cleanup;
- }
- disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
- disk->unit = tgt[1];
- } else if (strcmp(driver, "virtio-pci") == 0) {
- if (has_tgt) {
- /* virtio-scsi: target*:0:0:<unit> */
- disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
- disk->unit = tgt[2];
- } else {
- /* virtio-blk: 1 disk per 1 device */
- disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO;
- }
- } else if (strcmp(driver, "ahci") == 0) {
- /* ahci: 1 host per 1 unit */
- if (!has_host || !has_tgt) {
- g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
- goto cleanup;
- }
- for (i = 0; i < nhosts; i++) {
- if (host == hosts[i]) {
- disk->unit = i;
- disk->bus_type = GUEST_DISK_BUS_TYPE_SATA;
- break;
- }
- }
- if (i >= nhosts) {
- g_debug("no host for '%s' (driver '%s')", syspath, driver);
- goto cleanup;
- }
- } else if (strcmp(driver, "nvme") == 0) {
- disk->bus_type = GUEST_DISK_BUS_TYPE_NVME;
- } else if (strcmp(driver, "ehci-pci") == 0 || strcmp(driver, "xhci_hcd") == 0) {
- disk->bus_type = GUEST_DISK_BUS_TYPE_USB;
- } else {
- g_debug("unknown driver '%s' (sysfs path '%s')", driver, syspath);
- goto cleanup;
- }
-
- ret = true;
-
-cleanup:
- g_free(driver);
- return ret;
-}
-
-/*
- * Store disk device info for non-PCI virtio devices (for example s390x
- * channel I/O devices). Returns true if information has been stored, or
- * false for failure.
- */
-static bool build_guest_fsinfo_for_nonpci_virtio(char const *syspath,
- GuestDiskAddress *disk,
- Error **errp)
-{
- unsigned int tgt[3];
- char *p;
-
- if (!strstr(syspath, "/virtio") || !strstr(syspath, "/block")) {
- g_debug("Unsupported virtio device '%s'", syspath);
- return false;
- }
-
- p = strstr(syspath, "/target");
- if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u",
- &tgt[0], &tgt[1], &tgt[2]) == 3) {
- /* virtio-scsi: target*:0:<target>:<unit> */
- disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
- disk->bus = tgt[0];
- disk->target = tgt[1];
- disk->unit = tgt[2];
- } else {
- /* virtio-blk: 1 disk per 1 device */
- disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO;
- }
-
- return true;
-}
-
-/*
- * Store disk device info for CCW devices (s390x channel I/O devices).
- * Returns true if information has been stored, or false for failure.
- */
-static bool build_guest_fsinfo_for_ccw_dev(char const *syspath,
- GuestDiskAddress *disk,
- Error **errp)
-{
- unsigned int cssid, ssid, subchno, devno;
- char *p;
-
- p = strstr(syspath, "/devices/css");
- if (!p || sscanf(p + 12, "%*x/%x.%x.%x/%*x.%*x.%x/",
- &cssid, &ssid, &subchno, &devno) < 4) {
- g_debug("could not parse ccw device sysfs path: %s", syspath);
- return false;
- }
-
- disk->ccw_address = g_new0(GuestCCWAddress, 1);
- disk->ccw_address->cssid = cssid;
- disk->ccw_address->ssid = ssid;
- disk->ccw_address->subchno = subchno;
- disk->ccw_address->devno = devno;
-
- if (strstr(p, "/virtio")) {
- build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp);
- }
-
- return true;
-}
-
-/* Store disk device info specified by @sysfs into @fs */
-static void build_guest_fsinfo_for_real_device(char const *syspath,
- GuestFilesystemInfo *fs,
- Error **errp)
-{
- GuestDiskAddress *disk;
- GuestPCIAddress *pciaddr;
- bool has_hwinf;
-#ifdef CONFIG_LIBUDEV
- struct udev *udev = NULL;
- struct udev_device *udevice = NULL;
-#endif
-
- pciaddr = g_new0(GuestPCIAddress, 1);
- pciaddr->domain = -1; /* -1 means field is invalid */
- pciaddr->bus = -1;
- pciaddr->slot = -1;
- pciaddr->function = -1;
-
- disk = g_new0(GuestDiskAddress, 1);
- disk->pci_controller = pciaddr;
- disk->bus_type = GUEST_DISK_BUS_TYPE_UNKNOWN;
-
-#ifdef CONFIG_LIBUDEV
- udev = udev_new();
- udevice = udev_device_new_from_syspath(udev, syspath);
- if (udev == NULL || udevice == NULL) {
- g_debug("failed to query udev");
- } else {
- const char *devnode, *serial;
- devnode = udev_device_get_devnode(udevice);
- if (devnode != NULL) {
- disk->dev = g_strdup(devnode);
- }
- serial = udev_device_get_property_value(udevice, "ID_SERIAL");
- if (serial != NULL && *serial != 0) {
- disk->serial = g_strdup(serial);
- }
- }
-
- udev_unref(udev);
- udev_device_unref(udevice);
-#endif
-
- if (strstr(syspath, "/devices/pci")) {
- has_hwinf = build_guest_fsinfo_for_pci_dev(syspath, disk, errp);
- } else if (strstr(syspath, "/devices/css")) {
- has_hwinf = build_guest_fsinfo_for_ccw_dev(syspath, disk, errp);
- } else if (strstr(syspath, "/virtio")) {
- has_hwinf = build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp);
- } else {
- g_debug("Unsupported device type for '%s'", syspath);
- has_hwinf = false;
- }
-
- if (has_hwinf || disk->dev || disk->serial) {
- QAPI_LIST_PREPEND(fs->disk, disk);
- } else {
- qapi_free_GuestDiskAddress(disk);
- }
-}
-
-static void build_guest_fsinfo_for_device(char const *devpath,
- GuestFilesystemInfo *fs,
- Error **errp);
-
-/* Store a list of slave devices of virtual volume specified by @syspath into
- * @fs */
-static void build_guest_fsinfo_for_virtual_device(char const *syspath,
- GuestFilesystemInfo *fs,
- Error **errp)
-{
- Error *err = NULL;
- DIR *dir;
- char *dirpath;
- struct dirent *entry;
-
- dirpath = g_strdup_printf("%s/slaves", syspath);
- dir = opendir(dirpath);
- if (!dir) {
- if (errno != ENOENT) {
- error_setg_errno(errp, errno, "opendir(\"%s\")", dirpath);
- }
- g_free(dirpath);
- return;
- }
-
- for (;;) {
- errno = 0;
- entry = readdir(dir);
- if (entry == NULL) {
- if (errno) {
- error_setg_errno(errp, errno, "readdir(\"%s\")", dirpath);
- }
- break;
- }
-
- if (entry->d_type == DT_LNK) {
- char *path;
-
- g_debug(" slave device '%s'", entry->d_name);
- path = g_strdup_printf("%s/slaves/%s", syspath, entry->d_name);
- build_guest_fsinfo_for_device(path, fs, &err);
- g_free(path);
-
- if (err) {
- error_propagate(errp, err);
- break;
- }
- }
- }
-
- g_free(dirpath);
- closedir(dir);
-}
-
-static bool is_disk_virtual(const char *devpath, Error **errp)
-{
- g_autofree char *syspath = realpath(devpath, NULL);
-
- if (!syspath) {
- error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
- return false;
- }
- return strstr(syspath, "/devices/virtual/block/") != NULL;
-}
-
-/* Dispatch to functions for virtual/real device */
-static void build_guest_fsinfo_for_device(char const *devpath,
- GuestFilesystemInfo *fs,
- Error **errp)
-{
- ERRP_GUARD();
- g_autofree char *syspath = NULL;
- bool is_virtual = false;
-
- syspath = realpath(devpath, NULL);
- if (!syspath) {
- if (errno != ENOENT) {
- error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
- return;
- }
-
- /* ENOENT: This devpath may not exist because of container config */
- if (!fs->name) {
- fs->name = g_path_get_basename(devpath);
- }
- return;
- }
-
- if (!fs->name) {
- fs->name = g_path_get_basename(syspath);
- }
-
- g_debug(" parse sysfs path '%s'", syspath);
- is_virtual = is_disk_virtual(syspath, errp);
- if (*errp != NULL) {
- return;
- }
- if (is_virtual) {
- build_guest_fsinfo_for_virtual_device(syspath, fs, errp);
- } else {
- build_guest_fsinfo_for_real_device(syspath, fs, errp);
- }
-}
-
-#ifdef CONFIG_LIBUDEV
-
-/*
- * Wrapper around build_guest_fsinfo_for_device() for getting just
- * the disk address.
- */
-static GuestDiskAddress *get_disk_address(const char *syspath, Error **errp)
-{
- g_autoptr(GuestFilesystemInfo) fs = NULL;
-
- fs = g_new0(GuestFilesystemInfo, 1);
- build_guest_fsinfo_for_device(syspath, fs, errp);
- if (fs->disk != NULL) {
- return g_steal_pointer(&fs->disk->value);
- }
- return NULL;
-}
-
-static char *get_alias_for_syspath(const char *syspath)
-{
- struct udev *udev = NULL;
- struct udev_device *udevice = NULL;
- char *ret = NULL;
-
- udev = udev_new();
- if (udev == NULL) {
- g_debug("failed to query udev");
- goto out;
- }
- udevice = udev_device_new_from_syspath(udev, syspath);
- if (udevice == NULL) {
- g_debug("failed to query udev for path: %s", syspath);
- goto out;
- } else {
- const char *alias = udev_device_get_property_value(
- udevice, "DM_NAME");
- /*
- * NULL means there was an error and empty string means there is no
- * alias. In case of no alias we return NULL instead of empty string.
- */
- if (alias == NULL) {
- g_debug("failed to query udev for device alias for: %s",
- syspath);
- } else if (*alias != 0) {
- ret = g_strdup(alias);
- }
- }
-
-out:
- udev_unref(udev);
- udev_device_unref(udevice);
- return ret;
-}
-
-static char *get_device_for_syspath(const char *syspath)
-{
- struct udev *udev = NULL;
- struct udev_device *udevice = NULL;
- char *ret = NULL;
-
- udev = udev_new();
- if (udev == NULL) {
- g_debug("failed to query udev");
- goto out;
- }
- udevice = udev_device_new_from_syspath(udev, syspath);
- if (udevice == NULL) {
- g_debug("failed to query udev for path: %s", syspath);
- goto out;
- } else {
- ret = g_strdup(udev_device_get_devnode(udevice));
- }
-
-out:
- udev_unref(udev);
- udev_device_unref(udevice);
- return ret;
-}
-
-static void get_disk_deps(const char *disk_dir, GuestDiskInfo *disk)
-{
- g_autofree char *deps_dir = NULL;
- const gchar *dep;
- GDir *dp_deps = NULL;
-
- /* List dependent disks */
- deps_dir = g_strdup_printf("%s/slaves", disk_dir);
- g_debug(" listing entries in: %s", deps_dir);
- dp_deps = g_dir_open(deps_dir, 0, NULL);
- if (dp_deps == NULL) {
- g_debug("failed to list entries in %s", deps_dir);
- return;
- }
- disk->has_dependencies = true;
- while ((dep = g_dir_read_name(dp_deps)) != NULL) {
- g_autofree char *dep_dir = NULL;
- char *dev_name;
-
- /* Add dependent disks */
- dep_dir = g_strdup_printf("%s/%s", deps_dir, dep);
- dev_name = get_device_for_syspath(dep_dir);
- if (dev_name != NULL) {
- g_debug(" adding dependent device: %s", dev_name);
- QAPI_LIST_PREPEND(disk->dependencies, dev_name);
- }
- }
- g_dir_close(dp_deps);
-}
-
-/*
- * Detect partitions subdirectory, name is "<disk_name><number>" or
- * "<disk_name>p<number>"
- *
- * @disk_name -- last component of /sys path (e.g. sda)
- * @disk_dir -- sys path of the disk (e.g. /sys/block/sda)
- * @disk_dev -- device node of the disk (e.g. /dev/sda)
- */
-static GuestDiskInfoList *get_disk_partitions(
- GuestDiskInfoList *list,
- const char *disk_name, const char *disk_dir,
- const char *disk_dev)
-{
- GuestDiskInfoList *ret = list;
- struct dirent *de_disk;
- DIR *dp_disk = NULL;
- size_t len = strlen(disk_name);
-
- dp_disk = opendir(disk_dir);
- while ((de_disk = readdir(dp_disk)) != NULL) {
- g_autofree char *partition_dir = NULL;
- char *dev_name;
- GuestDiskInfo *partition;
-
- if (!(de_disk->d_type & DT_DIR)) {
- continue;
- }
-
- if (!(strncmp(disk_name, de_disk->d_name, len) == 0 &&
- ((*(de_disk->d_name + len) == 'p' &&
- isdigit(*(de_disk->d_name + len + 1))) ||
- isdigit(*(de_disk->d_name + len))))) {
- continue;
- }
-
- partition_dir = g_strdup_printf("%s/%s",
- disk_dir, de_disk->d_name);
- dev_name = get_device_for_syspath(partition_dir);
- if (dev_name == NULL) {
- g_debug("Failed to get device name for syspath: %s",
- disk_dir);
- continue;
- }
- partition = g_new0(GuestDiskInfo, 1);
- partition->name = dev_name;
- partition->partition = true;
- partition->has_dependencies = true;
- /* Add parent disk as dependent for easier tracking of hierarchy */
- QAPI_LIST_PREPEND(partition->dependencies, g_strdup(disk_dev));
-
- QAPI_LIST_PREPEND(ret, partition);
- }
- closedir(dp_disk);
-
- return ret;
-}
-
-static void get_nvme_smart(GuestDiskInfo *disk)
-{
- int fd;
- GuestNVMeSmart *smart;
- NvmeSmartLog log = {0};
- struct nvme_admin_cmd cmd = {
- .opcode = NVME_ADM_CMD_GET_LOG_PAGE,
- .nsid = NVME_NSID_BROADCAST,
- .addr = (uintptr_t)&log,
- .data_len = sizeof(log),
- .cdw10 = NVME_LOG_SMART_INFO | (1 << 15) /* RAE bit */
- | (((sizeof(log) >> 2) - 1) << 16)
- };
-
- fd = qga_open_cloexec(disk->name, O_RDONLY, 0);
- if (fd == -1) {
- g_debug("Failed to open device: %s: %s", disk->name, g_strerror(errno));
- return;
- }
-
- if (ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd)) {
- g_debug("Failed to get smart: %s: %s", disk->name, g_strerror(errno));
- close(fd);
- return;
- }
-
- disk->smart = g_new0(GuestDiskSmart, 1);
- disk->smart->type = GUEST_DISK_BUS_TYPE_NVME;
-
- smart = &disk->smart->u.nvme;
- smart->critical_warning = log.critical_warning;
- smart->temperature = lduw_le_p(&log.temperature); /* unaligned field */
- smart->available_spare = log.available_spare;
- smart->available_spare_threshold = log.available_spare_threshold;
- smart->percentage_used = log.percentage_used;
- smart->data_units_read_lo = le64_to_cpu(log.data_units_read[0]);
- smart->data_units_read_hi = le64_to_cpu(log.data_units_read[1]);
- smart->data_units_written_lo = le64_to_cpu(log.data_units_written[0]);
- smart->data_units_written_hi = le64_to_cpu(log.data_units_written[1]);
- smart->host_read_commands_lo = le64_to_cpu(log.host_read_commands[0]);
- smart->host_read_commands_hi = le64_to_cpu(log.host_read_commands[1]);
- smart->host_write_commands_lo = le64_to_cpu(log.host_write_commands[0]);
- smart->host_write_commands_hi = le64_to_cpu(log.host_write_commands[1]);
- smart->controller_busy_time_lo = le64_to_cpu(log.controller_busy_time[0]);
- smart->controller_busy_time_hi = le64_to_cpu(log.controller_busy_time[1]);
- smart->power_cycles_lo = le64_to_cpu(log.power_cycles[0]);
- smart->power_cycles_hi = le64_to_cpu(log.power_cycles[1]);
- smart->power_on_hours_lo = le64_to_cpu(log.power_on_hours[0]);
- smart->power_on_hours_hi = le64_to_cpu(log.power_on_hours[1]);
- smart->unsafe_shutdowns_lo = le64_to_cpu(log.unsafe_shutdowns[0]);
- smart->unsafe_shutdowns_hi = le64_to_cpu(log.unsafe_shutdowns[1]);
- smart->media_errors_lo = le64_to_cpu(log.media_errors[0]);
- smart->media_errors_hi = le64_to_cpu(log.media_errors[1]);
- smart->number_of_error_log_entries_lo =
- le64_to_cpu(log.number_of_error_log_entries[0]);
- smart->number_of_error_log_entries_hi =
- le64_to_cpu(log.number_of_error_log_entries[1]);
-
- close(fd);
-}
-
-static void get_disk_smart(GuestDiskInfo *disk)
-{
- if (disk->address
- && (disk->address->bus_type == GUEST_DISK_BUS_TYPE_NVME)) {
- get_nvme_smart(disk);
- }
-}
-
-GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
-{
- GuestDiskInfoList *ret = NULL;
- GuestDiskInfo *disk;
- DIR *dp = NULL;
- struct dirent *de = NULL;
-
- g_debug("listing /sys/block directory");
- dp = opendir("/sys/block");
- if (dp == NULL) {
- error_setg_errno(errp, errno, "Can't open directory \"/sys/block\"");
- return NULL;
- }
- while ((de = readdir(dp)) != NULL) {
- g_autofree char *disk_dir = NULL, *line = NULL,
- *size_path = NULL;
- char *dev_name;
- Error *local_err = NULL;
- if (de->d_type != DT_LNK) {
- g_debug(" skipping entry: %s", de->d_name);
- continue;
- }
-
- /* Check size and skip zero-sized disks */
- g_debug(" checking disk size");
- size_path = g_strdup_printf("/sys/block/%s/size", de->d_name);
- if (!g_file_get_contents(size_path, &line, NULL, NULL)) {
- g_debug(" failed to read disk size");
- continue;
- }
- if (g_strcmp0(line, "0\n") == 0) {
- g_debug(" skipping zero-sized disk");
- continue;
- }
-
- g_debug(" adding %s", de->d_name);
- disk_dir = g_strdup_printf("/sys/block/%s", de->d_name);
- dev_name = get_device_for_syspath(disk_dir);
- if (dev_name == NULL) {
- g_debug("Failed to get device name for syspath: %s",
- disk_dir);
- continue;
- }
- disk = g_new0(GuestDiskInfo, 1);
- disk->name = dev_name;
- disk->partition = false;
- disk->alias = get_alias_for_syspath(disk_dir);
- QAPI_LIST_PREPEND(ret, disk);
-
- /* Get address for non-virtual devices */
- bool is_virtual = is_disk_virtual(disk_dir, &local_err);
- if (local_err != NULL) {
- g_debug(" failed to check disk path, ignoring error: %s",
- error_get_pretty(local_err));
- error_free(local_err);
- local_err = NULL;
- /* Don't try to get the address */
- is_virtual = true;
- }
- if (!is_virtual) {
- disk->address = get_disk_address(disk_dir, &local_err);
- if (local_err != NULL) {
- g_debug(" failed to get device info, ignoring error: %s",
- error_get_pretty(local_err));
- error_free(local_err);
- local_err = NULL;
- }
- }
-
- get_disk_deps(disk_dir, disk);
- get_disk_smart(disk);
- ret = get_disk_partitions(ret, de->d_name, disk_dir, dev_name);
- }
-
- closedir(dp);
-
- return ret;
-}
-
-#else
-
-GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-#endif
-
-/* Return a list of the disk device(s)' info which @mount lies on */
-static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount,
- Error **errp)
-{
- GuestFilesystemInfo *fs = g_malloc0(sizeof(*fs));
- struct statvfs buf;
- unsigned long used, nonroot_total, fr_size;
- char *devpath = g_strdup_printf("/sys/dev/block/%u:%u",
- mount->devmajor, mount->devminor);
-
- fs->mountpoint = g_strdup(mount->dirname);
- fs->type = g_strdup(mount->devtype);
- build_guest_fsinfo_for_device(devpath, fs, errp);
-
- if (statvfs(fs->mountpoint, &buf) == 0) {
- fr_size = buf.f_frsize;
- used = buf.f_blocks - buf.f_bfree;
- nonroot_total = used + buf.f_bavail;
- fs->used_bytes = used * fr_size;
- fs->total_bytes = nonroot_total * fr_size;
- fs->total_bytes_privileged = buf.f_blocks * fr_size;
-
- fs->has_total_bytes = true;
- fs->has_total_bytes_privileged = true;
- fs->has_used_bytes = true;
- }
-
- g_free(devpath);
-
- return fs;
-}
-
-GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
-{
- FsMountList mounts;
- struct FsMount *mount;
- GuestFilesystemInfoList *ret = NULL;
- Error *local_err = NULL;
-
- QTAILQ_INIT(&mounts);
- if (!build_fs_mount_list(&mounts, &local_err)) {
- error_propagate(errp, local_err);
- return NULL;
- }
-
- QTAILQ_FOREACH(mount, &mounts, next) {
- g_debug("Building guest fsinfo for '%s'", mount->dirname);
-
- QAPI_LIST_PREPEND(ret, build_guest_fsinfo(mount, &local_err));
- if (local_err) {
- error_propagate(errp, local_err);
- qapi_free_GuestFilesystemInfoList(ret);
- ret = NULL;
- break;
- }
- }
-
- free_fs_mount_list(&mounts);
- return ret;
-}
-#endif /* CONFIG_FSFREEZE */
-
-#if defined(CONFIG_FSTRIM)
-/*
- * Walk list of mounted file systems in the guest, and trim them.
- */
-GuestFilesystemTrimResponse *
-qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
-{
- GuestFilesystemTrimResponse *response;
- GuestFilesystemTrimResult *result;
- int ret = 0;
- FsMountList mounts;
- struct FsMount *mount;
- int fd;
- struct fstrim_range r;
-
- slog("guest-fstrim called");
-
- QTAILQ_INIT(&mounts);
- if (!build_fs_mount_list(&mounts, errp)) {
- return NULL;
- }
-
- response = g_malloc0(sizeof(*response));
-
- QTAILQ_FOREACH(mount, &mounts, next) {
- result = g_malloc0(sizeof(*result));
- result->path = g_strdup(mount->dirname);
-
- QAPI_LIST_PREPEND(response->paths, result);
-
- fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0);
- if (fd == -1) {
- result->error = g_strdup_printf("failed to open: %s",
- strerror(errno));
- continue;
- }
-
- /* We try to cull filesystems we know won't work in advance, but other
- * filesystems may not implement fstrim for less obvious reasons.
- * These will report EOPNOTSUPP; while in some other cases ENOTTY
- * will be reported (e.g. CD-ROMs).
- * Any other error means an unexpected error.
- */
- r.start = 0;
- r.len = -1;
- r.minlen = has_minimum ? minimum : 0;
- ret = ioctl(fd, FITRIM, &r);
- if (ret == -1) {
- if (errno == ENOTTY || errno == EOPNOTSUPP) {
- result->error = g_strdup("trim not supported");
- } else {
- result->error = g_strdup_printf("failed to trim: %s",
- strerror(errno));
- }
- close(fd);
- continue;
- }
-
- result->has_minimum = true;
- result->minimum = r.minlen;
- result->has_trimmed = true;
- result->trimmed = r.len;
- close(fd);
- }
-
- free_fs_mount_list(&mounts);
- return response;
-}
-#endif /* CONFIG_FSTRIM */
-
-#endif /* __linux__ */
-
#if defined(__linux__) || defined(__FreeBSD__)
void qmp_guest_set_user_password(const char *username,
const char *password,
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 05/25] qga: move linux disk/cpu stats command impls to commands-linux.c
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (3 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 04/25] qga: move linux fs/disk " Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 06/25] qga: move linux memory block " Konstantin Kostiuk
` (20 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
The qmp_guest_{diskstats,cpustats} command impls in
commands-posix.c are surrounded by '#ifdef __linux__' so should
instead live in commands-linux.c
This also removes a "#ifdef CONFIG_LINUX" that was nested inside
a "#ifdef __linux__".
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Message-ID: <20240712132459.3974109-6-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-linux.c | 195 ++++++++++++++++++++++++++++++++++++++++++
qga/commands-posix.c | 199 -------------------------------------------
2 files changed, 195 insertions(+), 199 deletions(-)
diff --git a/qga/commands-linux.c b/qga/commands-linux.c
index 084e6c9e85..c0e8bd4062 100644
--- a/qga/commands-linux.c
+++ b/qga/commands-linux.c
@@ -1594,3 +1594,198 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
return processed;
}
+
+#define MAX_NAME_LEN 128
+static GuestDiskStatsInfoList *guest_get_diskstats(Error **errp)
+{
+ GuestDiskStatsInfoList *head = NULL, **tail = &head;
+ const char *diskstats = "/proc/diskstats";
+ FILE *fp;
+ size_t n;
+ char *line = NULL;
+
+ fp = fopen(diskstats, "r");
+ if (fp == NULL) {
+ error_setg_errno(errp, errno, "open(\"%s\")", diskstats);
+ return NULL;
+ }
+
+ while (getline(&line, &n, fp) != -1) {
+ g_autofree GuestDiskStatsInfo *diskstatinfo = NULL;
+ g_autofree GuestDiskStats *diskstat = NULL;
+ char dev_name[MAX_NAME_LEN];
+ unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks, dc_ticks, fl_ticks;
+ unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios;
+ unsigned long wr_merges, rd_sec_or_wr_ios, wr_sec;
+ unsigned long dc_ios, dc_merges, dc_sec, fl_ios;
+ unsigned int major, minor;
+ int i;
+
+ i = sscanf(line, "%u %u %s %lu %lu %lu"
+ "%lu %lu %lu %lu %u %u %u %u"
+ "%lu %lu %lu %u %lu %u",
+ &major, &minor, dev_name,
+ &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios,
+ &rd_ticks_or_wr_sec, &wr_ios, &wr_merges, &wr_sec,
+ &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks,
+ &dc_ios, &dc_merges, &dc_sec, &dc_ticks,
+ &fl_ios, &fl_ticks);
+
+ if (i < 7) {
+ continue;
+ }
+
+ diskstatinfo = g_new0(GuestDiskStatsInfo, 1);
+ diskstatinfo->name = g_strdup(dev_name);
+ diskstatinfo->major = major;
+ diskstatinfo->minor = minor;
+
+ diskstat = g_new0(GuestDiskStats, 1);
+ if (i == 7) {
+ diskstat->has_read_ios = true;
+ diskstat->read_ios = rd_ios;
+ diskstat->has_read_sectors = true;
+ diskstat->read_sectors = rd_merges_or_rd_sec;
+ diskstat->has_write_ios = true;
+ diskstat->write_ios = rd_sec_or_wr_ios;
+ diskstat->has_write_sectors = true;
+ diskstat->write_sectors = rd_ticks_or_wr_sec;
+ }
+ if (i >= 14) {
+ diskstat->has_read_ios = true;
+ diskstat->read_ios = rd_ios;
+ diskstat->has_read_sectors = true;
+ diskstat->read_sectors = rd_sec_or_wr_ios;
+ diskstat->has_read_merges = true;
+ diskstat->read_merges = rd_merges_or_rd_sec;
+ diskstat->has_read_ticks = true;
+ diskstat->read_ticks = rd_ticks_or_wr_sec;
+ diskstat->has_write_ios = true;
+ diskstat->write_ios = wr_ios;
+ diskstat->has_write_sectors = true;
+ diskstat->write_sectors = wr_sec;
+ diskstat->has_write_merges = true;
+ diskstat->write_merges = wr_merges;
+ diskstat->has_write_ticks = true;
+ diskstat->write_ticks = wr_ticks;
+ diskstat->has_ios_pgr = true;
+ diskstat->ios_pgr = ios_pgr;
+ diskstat->has_total_ticks = true;
+ diskstat->total_ticks = tot_ticks;
+ diskstat->has_weight_ticks = true;
+ diskstat->weight_ticks = rq_ticks;
+ }
+ if (i >= 18) {
+ diskstat->has_discard_ios = true;
+ diskstat->discard_ios = dc_ios;
+ diskstat->has_discard_merges = true;
+ diskstat->discard_merges = dc_merges;
+ diskstat->has_discard_sectors = true;
+ diskstat->discard_sectors = dc_sec;
+ diskstat->has_discard_ticks = true;
+ diskstat->discard_ticks = dc_ticks;
+ }
+ if (i >= 20) {
+ diskstat->has_flush_ios = true;
+ diskstat->flush_ios = fl_ios;
+ diskstat->has_flush_ticks = true;
+ diskstat->flush_ticks = fl_ticks;
+ }
+
+ diskstatinfo->stats = g_steal_pointer(&diskstat);
+ QAPI_LIST_APPEND(tail, diskstatinfo);
+ diskstatinfo = NULL;
+ }
+ free(line);
+ fclose(fp);
+ return head;
+}
+
+GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
+{
+ return guest_get_diskstats(errp);
+}
+
+GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
+{
+ GuestCpuStatsList *head = NULL, **tail = &head;
+ const char *cpustats = "/proc/stat";
+ int clk_tck = sysconf(_SC_CLK_TCK);
+ FILE *fp;
+ size_t n;
+ char *line = NULL;
+
+ fp = fopen(cpustats, "r");
+ if (fp == NULL) {
+ error_setg_errno(errp, errno, "open(\"%s\")", cpustats);
+ return NULL;
+ }
+
+ while (getline(&line, &n, fp) != -1) {
+ GuestCpuStats *cpustat = NULL;
+ GuestLinuxCpuStats *linuxcpustat;
+ int i;
+ unsigned long user, system, idle, iowait, irq, softirq, steal, guest;
+ unsigned long nice, guest_nice;
+ char name[64];
+
+ i = sscanf(line, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+ name, &user, &nice, &system, &idle, &iowait, &irq, &softirq,
+ &steal, &guest, &guest_nice);
+
+ /* drop "cpu 1 2 3 ...", get "cpuX 1 2 3 ..." only */
+ if ((i == EOF) || strncmp(name, "cpu", 3) || (name[3] == '\0')) {
+ continue;
+ }
+
+ if (i < 5) {
+ slog("Parsing cpu stat from %s failed, see \"man proc\"", cpustats);
+ break;
+ }
+
+ cpustat = g_new0(GuestCpuStats, 1);
+ cpustat->type = GUEST_CPU_STATS_TYPE_LINUX;
+
+ linuxcpustat = &cpustat->u.q_linux;
+ linuxcpustat->cpu = atoi(&name[3]);
+ linuxcpustat->user = user * 1000 / clk_tck;
+ linuxcpustat->nice = nice * 1000 / clk_tck;
+ linuxcpustat->system = system * 1000 / clk_tck;
+ linuxcpustat->idle = idle * 1000 / clk_tck;
+
+ if (i > 5) {
+ linuxcpustat->has_iowait = true;
+ linuxcpustat->iowait = iowait * 1000 / clk_tck;
+ }
+
+ if (i > 6) {
+ linuxcpustat->has_irq = true;
+ linuxcpustat->irq = irq * 1000 / clk_tck;
+ linuxcpustat->has_softirq = true;
+ linuxcpustat->softirq = softirq * 1000 / clk_tck;
+ }
+
+ if (i > 8) {
+ linuxcpustat->has_steal = true;
+ linuxcpustat->steal = steal * 1000 / clk_tck;
+ }
+
+ if (i > 9) {
+ linuxcpustat->has_guest = true;
+ linuxcpustat->guest = guest * 1000 / clk_tck;
+ }
+
+ if (i > 10) {
+ linuxcpustat->has_guest = true;
+ linuxcpustat->guest = guest * 1000 / clk_tck;
+ linuxcpustat->has_guestnice = true;
+ linuxcpustat->guestnice = guest_nice * 1000 / clk_tck;
+ }
+
+ QAPI_LIST_APPEND(tail, cpustat);
+ }
+
+ free(line);
+ fclose(fp);
+ return head;
+}
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 98aafc45f3..5da60e65ab 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1195,205 +1195,6 @@ GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
return info;
}
-#define MAX_NAME_LEN 128
-static GuestDiskStatsInfoList *guest_get_diskstats(Error **errp)
-{
-#ifdef CONFIG_LINUX
- GuestDiskStatsInfoList *head = NULL, **tail = &head;
- const char *diskstats = "/proc/diskstats";
- FILE *fp;
- size_t n;
- char *line = NULL;
-
- fp = fopen(diskstats, "r");
- if (fp == NULL) {
- error_setg_errno(errp, errno, "open(\"%s\")", diskstats);
- return NULL;
- }
-
- while (getline(&line, &n, fp) != -1) {
- g_autofree GuestDiskStatsInfo *diskstatinfo = NULL;
- g_autofree GuestDiskStats *diskstat = NULL;
- char dev_name[MAX_NAME_LEN];
- unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks, dc_ticks, fl_ticks;
- unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios;
- unsigned long wr_merges, rd_sec_or_wr_ios, wr_sec;
- unsigned long dc_ios, dc_merges, dc_sec, fl_ios;
- unsigned int major, minor;
- int i;
-
- i = sscanf(line, "%u %u %s %lu %lu %lu"
- "%lu %lu %lu %lu %u %u %u %u"
- "%lu %lu %lu %u %lu %u",
- &major, &minor, dev_name,
- &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios,
- &rd_ticks_or_wr_sec, &wr_ios, &wr_merges, &wr_sec,
- &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks,
- &dc_ios, &dc_merges, &dc_sec, &dc_ticks,
- &fl_ios, &fl_ticks);
-
- if (i < 7) {
- continue;
- }
-
- diskstatinfo = g_new0(GuestDiskStatsInfo, 1);
- diskstatinfo->name = g_strdup(dev_name);
- diskstatinfo->major = major;
- diskstatinfo->minor = minor;
-
- diskstat = g_new0(GuestDiskStats, 1);
- if (i == 7) {
- diskstat->has_read_ios = true;
- diskstat->read_ios = rd_ios;
- diskstat->has_read_sectors = true;
- diskstat->read_sectors = rd_merges_or_rd_sec;
- diskstat->has_write_ios = true;
- diskstat->write_ios = rd_sec_or_wr_ios;
- diskstat->has_write_sectors = true;
- diskstat->write_sectors = rd_ticks_or_wr_sec;
- }
- if (i >= 14) {
- diskstat->has_read_ios = true;
- diskstat->read_ios = rd_ios;
- diskstat->has_read_sectors = true;
- diskstat->read_sectors = rd_sec_or_wr_ios;
- diskstat->has_read_merges = true;
- diskstat->read_merges = rd_merges_or_rd_sec;
- diskstat->has_read_ticks = true;
- diskstat->read_ticks = rd_ticks_or_wr_sec;
- diskstat->has_write_ios = true;
- diskstat->write_ios = wr_ios;
- diskstat->has_write_sectors = true;
- diskstat->write_sectors = wr_sec;
- diskstat->has_write_merges = true;
- diskstat->write_merges = wr_merges;
- diskstat->has_write_ticks = true;
- diskstat->write_ticks = wr_ticks;
- diskstat->has_ios_pgr = true;
- diskstat->ios_pgr = ios_pgr;
- diskstat->has_total_ticks = true;
- diskstat->total_ticks = tot_ticks;
- diskstat->has_weight_ticks = true;
- diskstat->weight_ticks = rq_ticks;
- }
- if (i >= 18) {
- diskstat->has_discard_ios = true;
- diskstat->discard_ios = dc_ios;
- diskstat->has_discard_merges = true;
- diskstat->discard_merges = dc_merges;
- diskstat->has_discard_sectors = true;
- diskstat->discard_sectors = dc_sec;
- diskstat->has_discard_ticks = true;
- diskstat->discard_ticks = dc_ticks;
- }
- if (i >= 20) {
- diskstat->has_flush_ios = true;
- diskstat->flush_ios = fl_ios;
- diskstat->has_flush_ticks = true;
- diskstat->flush_ticks = fl_ticks;
- }
-
- diskstatinfo->stats = g_steal_pointer(&diskstat);
- QAPI_LIST_APPEND(tail, diskstatinfo);
- diskstatinfo = NULL;
- }
- free(line);
- fclose(fp);
- return head;
-#else
- g_debug("disk stats reporting available only for Linux");
- return NULL;
-#endif
-}
-
-GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
-{
- return guest_get_diskstats(errp);
-}
-
-GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
-{
- GuestCpuStatsList *head = NULL, **tail = &head;
- const char *cpustats = "/proc/stat";
- int clk_tck = sysconf(_SC_CLK_TCK);
- FILE *fp;
- size_t n;
- char *line = NULL;
-
- fp = fopen(cpustats, "r");
- if (fp == NULL) {
- error_setg_errno(errp, errno, "open(\"%s\")", cpustats);
- return NULL;
- }
-
- while (getline(&line, &n, fp) != -1) {
- GuestCpuStats *cpustat = NULL;
- GuestLinuxCpuStats *linuxcpustat;
- int i;
- unsigned long user, system, idle, iowait, irq, softirq, steal, guest;
- unsigned long nice, guest_nice;
- char name[64];
-
- i = sscanf(line, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
- name, &user, &nice, &system, &idle, &iowait, &irq, &softirq,
- &steal, &guest, &guest_nice);
-
- /* drop "cpu 1 2 3 ...", get "cpuX 1 2 3 ..." only */
- if ((i == EOF) || strncmp(name, "cpu", 3) || (name[3] == '\0')) {
- continue;
- }
-
- if (i < 5) {
- slog("Parsing cpu stat from %s failed, see \"man proc\"", cpustats);
- break;
- }
-
- cpustat = g_new0(GuestCpuStats, 1);
- cpustat->type = GUEST_CPU_STATS_TYPE_LINUX;
-
- linuxcpustat = &cpustat->u.q_linux;
- linuxcpustat->cpu = atoi(&name[3]);
- linuxcpustat->user = user * 1000 / clk_tck;
- linuxcpustat->nice = nice * 1000 / clk_tck;
- linuxcpustat->system = system * 1000 / clk_tck;
- linuxcpustat->idle = idle * 1000 / clk_tck;
-
- if (i > 5) {
- linuxcpustat->has_iowait = true;
- linuxcpustat->iowait = iowait * 1000 / clk_tck;
- }
-
- if (i > 6) {
- linuxcpustat->has_irq = true;
- linuxcpustat->irq = irq * 1000 / clk_tck;
- linuxcpustat->has_softirq = true;
- linuxcpustat->softirq = softirq * 1000 / clk_tck;
- }
-
- if (i > 8) {
- linuxcpustat->has_steal = true;
- linuxcpustat->steal = steal * 1000 / clk_tck;
- }
-
- if (i > 9) {
- linuxcpustat->has_guest = true;
- linuxcpustat->guest = guest * 1000 / clk_tck;
- }
-
- if (i > 10) {
- linuxcpustat->has_guest = true;
- linuxcpustat->guest = guest * 1000 / clk_tck;
- linuxcpustat->has_guestnice = true;
- linuxcpustat->guestnice = guest_nice * 1000 / clk_tck;
- }
-
- QAPI_LIST_APPEND(tail, cpustat);
- }
-
- free(line);
- fclose(fp);
- return head;
-}
#else /* defined(__linux__) */
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 06/25] qga: move linux memory block command impls to commands-linux.c
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (4 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 05/25] qga: move linux disk/cpu stats " Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 07/25] qga: move CONFIG_FSFREEZE/TRIM to be meson defined options Konstantin Kostiuk
` (19 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
The qmp_guest_{set,get}_{memory_blocks,block_info} command impls in
commands-posix.c are surrounded by '#ifdef __linux__' so should
instead live in commands-linux.c
This also removes a "#ifdef CONFIG_LINUX" that was nested inside
a "#ifdef __linux__".
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Message-ID: <20240712132459.3974109-7-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-linux.c | 308 ++++++++++++++++++++++++++++++++++++++++++
qga/commands-posix.c | 311 +------------------------------------------
2 files changed, 309 insertions(+), 310 deletions(-)
diff --git a/qga/commands-linux.c b/qga/commands-linux.c
index c0e8bd4062..73b13fbaf6 100644
--- a/qga/commands-linux.c
+++ b/qga/commands-linux.c
@@ -1595,6 +1595,314 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
return processed;
}
+
+static void ga_read_sysfs_file(int dirfd, const char *pathname, char *buf,
+ int size, Error **errp)
+{
+ int fd;
+ int res;
+
+ errno = 0;
+ fd = openat(dirfd, pathname, O_RDONLY);
+ if (fd == -1) {
+ error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
+ return;
+ }
+
+ res = pread(fd, buf, size, 0);
+ if (res == -1) {
+ error_setg_errno(errp, errno, "pread sysfs file \"%s\"", pathname);
+ } else if (res == 0) {
+ error_setg(errp, "pread sysfs file \"%s\": unexpected EOF", pathname);
+ }
+ close(fd);
+}
+
+static void ga_write_sysfs_file(int dirfd, const char *pathname,
+ const char *buf, int size, Error **errp)
+{
+ int fd;
+
+ errno = 0;
+ fd = openat(dirfd, pathname, O_WRONLY);
+ if (fd == -1) {
+ error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
+ return;
+ }
+
+ if (pwrite(fd, buf, size, 0) == -1) {
+ error_setg_errno(errp, errno, "pwrite sysfs file \"%s\"", pathname);
+ }
+
+ close(fd);
+}
+
+/* Transfer online/offline status between @mem_blk and the guest system.
+ *
+ * On input either @errp or *@errp must be NULL.
+ *
+ * In system-to-@mem_blk direction, the following @mem_blk fields are accessed:
+ * - R: mem_blk->phys_index
+ * - W: mem_blk->online
+ * - W: mem_blk->can_offline
+ *
+ * In @mem_blk-to-system direction, the following @mem_blk fields are accessed:
+ * - R: mem_blk->phys_index
+ * - R: mem_blk->online
+ *- R: mem_blk->can_offline
+ * Written members remain unmodified on error.
+ */
+static void transfer_memory_block(GuestMemoryBlock *mem_blk, bool sys2memblk,
+ GuestMemoryBlockResponse *result,
+ Error **errp)
+{
+ char *dirpath;
+ int dirfd;
+ char *status;
+ Error *local_err = NULL;
+
+ if (!sys2memblk) {
+ DIR *dp;
+
+ if (!result) {
+ error_setg(errp, "Internal error, 'result' should not be NULL");
+ return;
+ }
+ errno = 0;
+ dp = opendir("/sys/devices/system/memory/");
+ /* if there is no 'memory' directory in sysfs,
+ * we think this VM does not support online/offline memory block,
+ * any other solution?
+ */
+ if (!dp) {
+ if (errno == ENOENT) {
+ result->response =
+ GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
+ }
+ goto out1;
+ }
+ closedir(dp);
+ }
+
+ dirpath = g_strdup_printf("/sys/devices/system/memory/memory%" PRId64 "/",
+ mem_blk->phys_index);
+ dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
+ if (dirfd == -1) {
+ if (sys2memblk) {
+ error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
+ } else {
+ if (errno == ENOENT) {
+ result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_NOT_FOUND;
+ } else {
+ result->response =
+ GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
+ }
+ }
+ g_free(dirpath);
+ goto out1;
+ }
+ g_free(dirpath);
+
+ status = g_malloc0(10);
+ ga_read_sysfs_file(dirfd, "state", status, 10, &local_err);
+ if (local_err) {
+ /* treat with sysfs file that not exist in old kernel */
+ if (errno == ENOENT) {
+ error_free(local_err);
+ if (sys2memblk) {
+ mem_blk->online = true;
+ mem_blk->can_offline = false;
+ } else if (!mem_blk->online) {
+ result->response =
+ GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
+ }
+ } else {
+ if (sys2memblk) {
+ error_propagate(errp, local_err);
+ } else {
+ error_free(local_err);
+ result->response =
+ GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
+ }
+ }
+ goto out2;
+ }
+
+ if (sys2memblk) {
+ char removable = '0';
+
+ mem_blk->online = (strncmp(status, "online", 6) == 0);
+
+ ga_read_sysfs_file(dirfd, "removable", &removable, 1, &local_err);
+ if (local_err) {
+ /* if no 'removable' file, it doesn't support offline mem blk */
+ if (errno == ENOENT) {
+ error_free(local_err);
+ mem_blk->can_offline = false;
+ } else {
+ error_propagate(errp, local_err);
+ }
+ } else {
+ mem_blk->can_offline = (removable != '0');
+ }
+ } else {
+ if (mem_blk->online != (strncmp(status, "online", 6) == 0)) {
+ const char *new_state = mem_blk->online ? "online" : "offline";
+
+ ga_write_sysfs_file(dirfd, "state", new_state, strlen(new_state),
+ &local_err);
+ if (local_err) {
+ error_free(local_err);
+ result->response =
+ GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
+ goto out2;
+ }
+
+ result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_SUCCESS;
+ result->has_error_code = false;
+ } /* otherwise pretend successful re-(on|off)-lining */
+ }
+ g_free(status);
+ close(dirfd);
+ return;
+
+out2:
+ g_free(status);
+ close(dirfd);
+out1:
+ if (!sys2memblk) {
+ result->has_error_code = true;
+ result->error_code = errno;
+ }
+}
+
+GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
+{
+ GuestMemoryBlockList *head, **tail;
+ Error *local_err = NULL;
+ struct dirent *de;
+ DIR *dp;
+
+ head = NULL;
+ tail = &head;
+
+ dp = opendir("/sys/devices/system/memory/");
+ if (!dp) {
+ /* it's ok if this happens to be a system that doesn't expose
+ * memory blocks via sysfs, but otherwise we should report
+ * an error
+ */
+ if (errno != ENOENT) {
+ error_setg_errno(errp, errno, "Can't open directory"
+ "\"/sys/devices/system/memory/\"");
+ }
+ return NULL;
+ }
+
+ /* Note: the phys_index of memory block may be discontinuous,
+ * this is because a memblk is the unit of the Sparse Memory design, which
+ * allows discontinuous memory ranges (ex. NUMA), so here we should
+ * traverse the memory block directory.
+ */
+ while ((de = readdir(dp)) != NULL) {
+ GuestMemoryBlock *mem_blk;
+
+ if ((strncmp(de->d_name, "memory", 6) != 0) ||
+ !(de->d_type & DT_DIR)) {
+ continue;
+ }
+
+ mem_blk = g_malloc0(sizeof *mem_blk);
+ /* The d_name is "memoryXXX", phys_index is block id, same as XXX */
+ mem_blk->phys_index = strtoul(&de->d_name[6], NULL, 10);
+ mem_blk->has_can_offline = true; /* lolspeak ftw */
+ transfer_memory_block(mem_blk, true, NULL, &local_err);
+ if (local_err) {
+ break;
+ }
+
+ QAPI_LIST_APPEND(tail, mem_blk);
+ }
+
+ closedir(dp);
+ if (local_err == NULL) {
+ /* there's no guest with zero memory blocks */
+ if (head == NULL) {
+ error_setg(errp, "guest reported zero memory blocks!");
+ }
+ return head;
+ }
+
+ qapi_free_GuestMemoryBlockList(head);
+ error_propagate(errp, local_err);
+ return NULL;
+}
+
+GuestMemoryBlockResponseList *
+qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
+{
+ GuestMemoryBlockResponseList *head, **tail;
+ Error *local_err = NULL;
+
+ head = NULL;
+ tail = &head;
+
+ while (mem_blks != NULL) {
+ GuestMemoryBlockResponse *result;
+ GuestMemoryBlock *current_mem_blk = mem_blks->value;
+
+ result = g_malloc0(sizeof(*result));
+ result->phys_index = current_mem_blk->phys_index;
+ transfer_memory_block(current_mem_blk, false, result, &local_err);
+ if (local_err) { /* should never happen */
+ goto err;
+ }
+
+ QAPI_LIST_APPEND(tail, result);
+ mem_blks = mem_blks->next;
+ }
+
+ return head;
+err:
+ qapi_free_GuestMemoryBlockResponseList(head);
+ error_propagate(errp, local_err);
+ return NULL;
+}
+
+GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
+{
+ Error *local_err = NULL;
+ char *dirpath;
+ int dirfd;
+ char *buf;
+ GuestMemoryBlockInfo *info;
+
+ dirpath = g_strdup_printf("/sys/devices/system/memory/");
+ dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
+ if (dirfd == -1) {
+ error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
+ g_free(dirpath);
+ return NULL;
+ }
+ g_free(dirpath);
+
+ buf = g_malloc0(20);
+ ga_read_sysfs_file(dirfd, "block_size_bytes", buf, 20, &local_err);
+ close(dirfd);
+ if (local_err) {
+ g_free(buf);
+ error_propagate(errp, local_err);
+ return NULL;
+ }
+
+ info = g_new0(GuestMemoryBlockInfo, 1);
+ info->size = strtol(buf, NULL, 16); /* the unit is bytes */
+
+ g_free(buf);
+
+ return info;
+}
+
#define MAX_NAME_LEN 128
static GuestDiskStatsInfoList *guest_get_diskstats(Error **errp)
{
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 5da60e65ab..2a3bef7445 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -887,316 +887,7 @@ void qmp_guest_set_user_password(const char *username,
}
#endif /* __linux__ || __FreeBSD__ */
-#ifdef __linux__
-static void ga_read_sysfs_file(int dirfd, const char *pathname, char *buf,
- int size, Error **errp)
-{
- int fd;
- int res;
-
- errno = 0;
- fd = openat(dirfd, pathname, O_RDONLY);
- if (fd == -1) {
- error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
- return;
- }
-
- res = pread(fd, buf, size, 0);
- if (res == -1) {
- error_setg_errno(errp, errno, "pread sysfs file \"%s\"", pathname);
- } else if (res == 0) {
- error_setg(errp, "pread sysfs file \"%s\": unexpected EOF", pathname);
- }
- close(fd);
-}
-
-static void ga_write_sysfs_file(int dirfd, const char *pathname,
- const char *buf, int size, Error **errp)
-{
- int fd;
-
- errno = 0;
- fd = openat(dirfd, pathname, O_WRONLY);
- if (fd == -1) {
- error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
- return;
- }
-
- if (pwrite(fd, buf, size, 0) == -1) {
- error_setg_errno(errp, errno, "pwrite sysfs file \"%s\"", pathname);
- }
-
- close(fd);
-}
-
-/* Transfer online/offline status between @mem_blk and the guest system.
- *
- * On input either @errp or *@errp must be NULL.
- *
- * In system-to-@mem_blk direction, the following @mem_blk fields are accessed:
- * - R: mem_blk->phys_index
- * - W: mem_blk->online
- * - W: mem_blk->can_offline
- *
- * In @mem_blk-to-system direction, the following @mem_blk fields are accessed:
- * - R: mem_blk->phys_index
- * - R: mem_blk->online
- *- R: mem_blk->can_offline
- * Written members remain unmodified on error.
- */
-static void transfer_memory_block(GuestMemoryBlock *mem_blk, bool sys2memblk,
- GuestMemoryBlockResponse *result,
- Error **errp)
-{
- char *dirpath;
- int dirfd;
- char *status;
- Error *local_err = NULL;
-
- if (!sys2memblk) {
- DIR *dp;
-
- if (!result) {
- error_setg(errp, "Internal error, 'result' should not be NULL");
- return;
- }
- errno = 0;
- dp = opendir("/sys/devices/system/memory/");
- /* if there is no 'memory' directory in sysfs,
- * we think this VM does not support online/offline memory block,
- * any other solution?
- */
- if (!dp) {
- if (errno == ENOENT) {
- result->response =
- GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
- }
- goto out1;
- }
- closedir(dp);
- }
-
- dirpath = g_strdup_printf("/sys/devices/system/memory/memory%" PRId64 "/",
- mem_blk->phys_index);
- dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
- if (dirfd == -1) {
- if (sys2memblk) {
- error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
- } else {
- if (errno == ENOENT) {
- result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_NOT_FOUND;
- } else {
- result->response =
- GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
- }
- }
- g_free(dirpath);
- goto out1;
- }
- g_free(dirpath);
-
- status = g_malloc0(10);
- ga_read_sysfs_file(dirfd, "state", status, 10, &local_err);
- if (local_err) {
- /* treat with sysfs file that not exist in old kernel */
- if (errno == ENOENT) {
- error_free(local_err);
- if (sys2memblk) {
- mem_blk->online = true;
- mem_blk->can_offline = false;
- } else if (!mem_blk->online) {
- result->response =
- GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
- }
- } else {
- if (sys2memblk) {
- error_propagate(errp, local_err);
- } else {
- error_free(local_err);
- result->response =
- GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
- }
- }
- goto out2;
- }
-
- if (sys2memblk) {
- char removable = '0';
-
- mem_blk->online = (strncmp(status, "online", 6) == 0);
-
- ga_read_sysfs_file(dirfd, "removable", &removable, 1, &local_err);
- if (local_err) {
- /* if no 'removable' file, it doesn't support offline mem blk */
- if (errno == ENOENT) {
- error_free(local_err);
- mem_blk->can_offline = false;
- } else {
- error_propagate(errp, local_err);
- }
- } else {
- mem_blk->can_offline = (removable != '0');
- }
- } else {
- if (mem_blk->online != (strncmp(status, "online", 6) == 0)) {
- const char *new_state = mem_blk->online ? "online" : "offline";
-
- ga_write_sysfs_file(dirfd, "state", new_state, strlen(new_state),
- &local_err);
- if (local_err) {
- error_free(local_err);
- result->response =
- GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
- goto out2;
- }
-
- result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_SUCCESS;
- result->has_error_code = false;
- } /* otherwise pretend successful re-(on|off)-lining */
- }
- g_free(status);
- close(dirfd);
- return;
-
-out2:
- g_free(status);
- close(dirfd);
-out1:
- if (!sys2memblk) {
- result->has_error_code = true;
- result->error_code = errno;
- }
-}
-
-GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
-{
- GuestMemoryBlockList *head, **tail;
- Error *local_err = NULL;
- struct dirent *de;
- DIR *dp;
-
- head = NULL;
- tail = &head;
-
- dp = opendir("/sys/devices/system/memory/");
- if (!dp) {
- /* it's ok if this happens to be a system that doesn't expose
- * memory blocks via sysfs, but otherwise we should report
- * an error
- */
- if (errno != ENOENT) {
- error_setg_errno(errp, errno, "Can't open directory"
- "\"/sys/devices/system/memory/\"");
- }
- return NULL;
- }
-
- /* Note: the phys_index of memory block may be discontinuous,
- * this is because a memblk is the unit of the Sparse Memory design, which
- * allows discontinuous memory ranges (ex. NUMA), so here we should
- * traverse the memory block directory.
- */
- while ((de = readdir(dp)) != NULL) {
- GuestMemoryBlock *mem_blk;
-
- if ((strncmp(de->d_name, "memory", 6) != 0) ||
- !(de->d_type & DT_DIR)) {
- continue;
- }
-
- mem_blk = g_malloc0(sizeof *mem_blk);
- /* The d_name is "memoryXXX", phys_index is block id, same as XXX */
- mem_blk->phys_index = strtoul(&de->d_name[6], NULL, 10);
- mem_blk->has_can_offline = true; /* lolspeak ftw */
- transfer_memory_block(mem_blk, true, NULL, &local_err);
- if (local_err) {
- break;
- }
-
- QAPI_LIST_APPEND(tail, mem_blk);
- }
-
- closedir(dp);
- if (local_err == NULL) {
- /* there's no guest with zero memory blocks */
- if (head == NULL) {
- error_setg(errp, "guest reported zero memory blocks!");
- }
- return head;
- }
-
- qapi_free_GuestMemoryBlockList(head);
- error_propagate(errp, local_err);
- return NULL;
-}
-
-GuestMemoryBlockResponseList *
-qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
-{
- GuestMemoryBlockResponseList *head, **tail;
- Error *local_err = NULL;
-
- head = NULL;
- tail = &head;
-
- while (mem_blks != NULL) {
- GuestMemoryBlockResponse *result;
- GuestMemoryBlock *current_mem_blk = mem_blks->value;
-
- result = g_malloc0(sizeof(*result));
- result->phys_index = current_mem_blk->phys_index;
- transfer_memory_block(current_mem_blk, false, result, &local_err);
- if (local_err) { /* should never happen */
- goto err;
- }
-
- QAPI_LIST_APPEND(tail, result);
- mem_blks = mem_blks->next;
- }
-
- return head;
-err:
- qapi_free_GuestMemoryBlockResponseList(head);
- error_propagate(errp, local_err);
- return NULL;
-}
-
-GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
-{
- Error *local_err = NULL;
- char *dirpath;
- int dirfd;
- char *buf;
- GuestMemoryBlockInfo *info;
-
- dirpath = g_strdup_printf("/sys/devices/system/memory/");
- dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
- if (dirfd == -1) {
- error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
- g_free(dirpath);
- return NULL;
- }
- g_free(dirpath);
-
- buf = g_malloc0(20);
- ga_read_sysfs_file(dirfd, "block_size_bytes", buf, 20, &local_err);
- close(dirfd);
- if (local_err) {
- g_free(buf);
- error_propagate(errp, local_err);
- return NULL;
- }
-
- info = g_new0(GuestMemoryBlockInfo, 1);
- info->size = strtol(buf, NULL, 16); /* the unit is bytes */
-
- g_free(buf);
-
- return info;
-}
-
-
-#else /* defined(__linux__) */
+#ifndef __linux__
void qmp_guest_suspend_disk(Error **errp)
{
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 07/25] qga: move CONFIG_FSFREEZE/TRIM to be meson defined options
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (5 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 06/25] qga: move linux memory block " Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 08/25] qga: conditionalize schema for commands unsupported on Windows Konstantin Kostiuk
` (18 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
Defining these at the meson level allows them to be used a conditional
tests in the QAPI schemas.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20240712132459.3974109-8-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
meson.build | 15 +++++++++++++++
qga/commands-common.h | 9 ---------
2 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/meson.build b/meson.build
index a1e51277b0..83f9728524 100644
--- a/meson.build
+++ b/meson.build
@@ -2187,6 +2187,19 @@ have_virtfs_proxy_helper = get_option('virtfs_proxy_helper') \
.require(libcap_ng.found(), error_message: 'the virtfs proxy helper requires libcap-ng') \
.allowed()
+qga_fsfreeze = false
+qga_fstrim = false
+if host_os == 'linux'
+ if cc.has_header_symbol('linux/fs.h', 'FIFREEZE')
+ qga_fsfreeze = true
+ endif
+ if cc.has_header_symbol('linux/fs.h', 'FITRIM')
+ qga_fstrim = true
+ endif
+elif host_os == 'freebsd' and cc.has_header_symbol('ufs/ffs/fs.h', 'UFSSUSPEND')
+ qga_fsfreeze = true
+endif
+
if get_option('block_drv_ro_whitelist') == ''
config_host_data.set('CONFIG_BDRV_RO_WHITELIST', '')
else
@@ -2423,6 +2436,8 @@ config_host_data.set('CONFIG_DEBUG_TCG', get_option('debug_tcg'))
config_host_data.set('CONFIG_DEBUG_REMAP', get_option('debug_remap'))
config_host_data.set('CONFIG_QOM_CAST_DEBUG', get_option('qom_cast_debug'))
config_host_data.set('CONFIG_REPLICATION', get_option('replication').allowed())
+config_host_data.set('CONFIG_FSFREEZE', qga_fsfreeze)
+config_host_data.set('CONFIG_FSTRIM', qga_fstrim)
# has_header
config_host_data.set('CONFIG_EPOLL', cc.has_header('sys/epoll.h'))
diff --git a/qga/commands-common.h b/qga/commands-common.h
index 8c1c56aac9..263e7c0525 100644
--- a/qga/commands-common.h
+++ b/qga/commands-common.h
@@ -15,19 +15,10 @@
#if defined(__linux__)
#include <linux/fs.h>
-#ifdef FIFREEZE
-#define CONFIG_FSFREEZE
-#endif
-#ifdef FITRIM
-#define CONFIG_FSTRIM
-#endif
#endif /* __linux__ */
#ifdef __FreeBSD__
#include <ufs/ffs/fs.h>
-#ifdef UFSSUSPEND
-#define CONFIG_FSFREEZE
-#endif
#endif /* __FreeBSD__ */
#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 08/25] qga: conditionalize schema for commands unsupported on Windows
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (6 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 07/25] qga: move CONFIG_FSFREEZE/TRIM to be meson defined options Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 09/25] qga: conditionalize schema for commands unsupported on non-Linux POSIX Konstantin Kostiuk
` (17 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
Rather than creating stubs for every command that just return
QERR_UNSUPPORTED, use 'if' conditions in the QAPI schema to
fully exclude generation of the commands on Windows.
The command will be rejected at QMP dispatch time instead,
avoiding reimplementing rejection by blocking the stub commands.
This changes the error message for affected commands from
{"class": "CommandNotFound", "desc": "Command FOO has been disabled"}
to
{"class": "CommandNotFound", "desc": "The command FOO has not been found"}
This also fixes an accidental inconsistency where some commands
(guest-get-diskstats & guest-get-cpustats) are implemented as
stubs, yet not added to the blockedrpc list. Those change their
error message from
{"class": "GenericError, "desc": "this feature or command is not currently supported"}
to
{"class": "CommandNotFound", "desc": "The command FOO has not been found"}
The final additional benefit is that the QGA protocol reference
now documents what conditions enable use of the command.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-ID: <20240712132459.3974109-9-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-posix.c | 2 +-
qga/commands-win32.c | 56 +-------------------------------------------
qga/qapi-schema.json | 45 +++++++++++++++++++++++------------
3 files changed, 32 insertions(+), 71 deletions(-)
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 2a3bef7445..0dd8555867 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1280,7 +1280,7 @@ GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
"guest-get-memory-blocks", "guest-set-memory-blocks",
"guest-get-memory-block-info",
NULL};
- char **p = (char **)list;
+ const char **p = list;
while (*p) {
blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++));
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 9fe670d5b4..2533e4c748 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -1494,11 +1494,6 @@ out:
}
}
-void qmp_guest_suspend_hybrid(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-}
-
static IP_ADAPTER_ADDRESSES *guest_get_adapters_addresses(Error **errp)
{
IP_ADAPTER_ADDRESSES *adptr_addrs = NULL;
@@ -1862,12 +1857,6 @@ GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
return NULL;
}
-int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return -1;
-}
-
static gchar *
get_net_error_message(gint error)
{
@@ -1969,46 +1958,15 @@ done:
g_free(rawpasswddata);
}
-GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestMemoryBlockResponseList *
-qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
/* add unsupported commands to the list of blocked RPCs */
GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
{
- const char *list_unsupported[] = {
- "guest-suspend-hybrid",
- "guest-set-vcpus",
- "guest-get-memory-blocks", "guest-set-memory-blocks",
- "guest-get-memory-block-info",
- NULL};
- char **p = (char **)list_unsupported;
-
- while (*p) {
- blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++));
- }
-
if (!vss_init(true)) {
g_debug("vss_init failed, vss commands are going to be disabled");
const char *list[] = {
"guest-get-fsinfo", "guest-fsfreeze-status",
"guest-fsfreeze-freeze", "guest-fsfreeze-thaw", NULL};
- p = (char **)list;
+ char **p = (char **)list;
while (*p) {
blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++));
@@ -2505,15 +2463,3 @@ char *qga_get_host_name(Error **errp)
return g_utf16_to_utf8(tmp, size, NULL, NULL, NULL);
}
-
-GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 1273d85bb5..2f0215afc7 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -637,7 +637,8 @@
#
# Since: 1.1
##
-{ 'command': 'guest-suspend-hybrid', 'success-response': false }
+{ 'command': 'guest-suspend-hybrid', 'success-response': false,
+ 'if': 'CONFIG_POSIX' }
##
# @GuestIpAddressType:
@@ -807,7 +808,8 @@
##
{ 'command': 'guest-set-vcpus',
'data': {'vcpus': ['GuestLogicalProcessor'] },
- 'returns': 'int' }
+ 'returns': 'int',
+ 'if': 'CONFIG_POSIX' }
##
# @GuestDiskBusType:
@@ -1100,7 +1102,8 @@
{ 'struct': 'GuestMemoryBlock',
'data': {'phys-index': 'uint64',
'online': 'bool',
- '*can-offline': 'bool'} }
+ '*can-offline': 'bool'},
+ 'if': 'CONFIG_POSIX' }
##
# @guest-get-memory-blocks:
@@ -1116,7 +1119,8 @@
# Since: 2.3
##
{ 'command': 'guest-get-memory-blocks',
- 'returns': ['GuestMemoryBlock'] }
+ 'returns': ['GuestMemoryBlock'],
+ 'if': 'CONFIG_POSIX' }
##
# @GuestMemoryBlockResponseType:
@@ -1139,7 +1143,8 @@
##
{ 'enum': 'GuestMemoryBlockResponseType',
'data': ['success', 'not-found', 'operation-not-supported',
- 'operation-failed'] }
+ 'operation-failed'],
+ 'if': 'CONFIG_POSIX' }
##
# @GuestMemoryBlockResponse:
@@ -1157,7 +1162,8 @@
{ 'struct': 'GuestMemoryBlockResponse',
'data': { 'phys-index': 'uint64',
'response': 'GuestMemoryBlockResponseType',
- '*error-code': 'int' }}
+ '*error-code': 'int' },
+ 'if': 'CONFIG_POSIX'}
##
# @guest-set-memory-blocks:
@@ -1188,7 +1194,8 @@
##
{ 'command': 'guest-set-memory-blocks',
'data': {'mem-blks': ['GuestMemoryBlock'] },
- 'returns': ['GuestMemoryBlockResponse'] }
+ 'returns': ['GuestMemoryBlockResponse'],
+ 'if': 'CONFIG_POSIX' }
##
# @GuestMemoryBlockInfo:
@@ -1200,7 +1207,8 @@
# Since: 2.3
##
{ 'struct': 'GuestMemoryBlockInfo',
- 'data': {'size': 'uint64'} }
+ 'data': {'size': 'uint64'},
+ 'if': 'CONFIG_POSIX' }
##
# @guest-get-memory-block-info:
@@ -1212,7 +1220,8 @@
# Since: 2.3
##
{ 'command': 'guest-get-memory-block-info',
- 'returns': 'GuestMemoryBlockInfo' }
+ 'returns': 'GuestMemoryBlockInfo',
+ 'if': 'CONFIG_POSIX' }
##
# @GuestExecStatus:
@@ -1702,7 +1711,8 @@
'data': {'name': 'str',
'major': 'uint64',
'minor': 'uint64',
- 'stats': 'GuestDiskStats' } }
+ 'stats': 'GuestDiskStats' },
+ 'if': 'CONFIG_POSIX' }
##
# @guest-get-diskstats:
@@ -1714,7 +1724,8 @@
# Since: 7.1
##
{ 'command': 'guest-get-diskstats',
- 'returns': ['GuestDiskStatsInfo']
+ 'returns': ['GuestDiskStatsInfo'],
+ 'if': 'CONFIG_POSIX'
}
##
@@ -1727,7 +1738,8 @@
# Since: 7.1
##
{ 'enum': 'GuestCpuStatsType',
- 'data': [ 'linux' ] }
+ 'data': [ 'linux' ],
+ 'if': 'CONFIG_POSIX' }
##
@@ -1772,7 +1784,8 @@
'*steal': 'uint64',
'*guest': 'uint64',
'*guestnice': 'uint64'
- } }
+ },
+ 'if': 'CONFIG_POSIX' }
##
# @GuestCpuStats:
@@ -1786,7 +1799,8 @@
{ 'union': 'GuestCpuStats',
'base': { 'type': 'GuestCpuStatsType' },
'discriminator': 'type',
- 'data': { 'linux': 'GuestLinuxCpuStats' } }
+ 'data': { 'linux': 'GuestLinuxCpuStats' },
+ 'if': 'CONFIG_POSIX' }
##
# @guest-get-cpustats:
@@ -1798,5 +1812,6 @@
# Since: 7.1
##
{ 'command': 'guest-get-cpustats',
- 'returns': ['GuestCpuStats']
+ 'returns': ['GuestCpuStats'],
+ 'if': 'CONFIG_POSIX'
}
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 09/25] qga: conditionalize schema for commands unsupported on non-Linux POSIX
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (7 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 08/25] qga: conditionalize schema for commands unsupported on Windows Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 10/25] qga: conditionalize schema for commands requiring getifaddrs Konstantin Kostiuk
` (16 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
Rather than creating stubs for every command that just return
QERR_UNSUPPORTED, use 'if' conditions in the QAPI schema to
fully exclude generation of the commands on non-Linux POSIX
platforms
The command will be rejected at QMP dispatch time instead,
avoiding reimplementing rejection by blocking the stub commands.
This changes the error message for affected commands from
{"class": "CommandNotFound", "desc": "Command FOO has been disabled"}
to
{"class": "CommandNotFound", "desc": "The command FOO has not been found"}
This has the additional benefit that the QGA protocol reference
now documents what conditions enable use of the command.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-ID: <20240712132459.3974109-10-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-posix.c | 66 --------------------------------------------
qga/qapi-schema.json | 30 +++++++++++---------
2 files changed, 17 insertions(+), 79 deletions(-)
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 0dd8555867..559d71ffae 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -887,56 +887,6 @@ void qmp_guest_set_user_password(const char *username,
}
#endif /* __linux__ || __FreeBSD__ */
-#ifndef __linux__
-
-void qmp_guest_suspend_disk(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-}
-
-void qmp_guest_suspend_ram(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-}
-
-void qmp_guest_suspend_hybrid(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-}
-
-GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return -1;
-}
-
-GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestMemoryBlockResponseList *
-qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-#endif
-
#ifdef HAVE_GETIFADDRS
static GuestNetworkInterface *
guest_find_interface(GuestNetworkInterfaceList *head,
@@ -1272,22 +1222,6 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
/* add unsupported commands to the list of blocked RPCs */
GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
{
-#if !defined(__linux__)
- {
- const char *list[] = {
- "guest-suspend-disk", "guest-suspend-ram",
- "guest-suspend-hybrid", "guest-get-vcpus", "guest-set-vcpus",
- "guest-get-memory-blocks", "guest-set-memory-blocks",
- "guest-get-memory-block-info",
- NULL};
- const char **p = list;
-
- while (*p) {
- blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++));
- }
- }
-#endif
-
#if !defined(HAVE_GETIFADDRS)
blockedrpcs = g_list_append(blockedrpcs,
g_strdup("guest-network-get-interfaces"));
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 2f0215afc7..38483652ac 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -566,7 +566,8 @@
#
# Since: 1.1
##
-{ 'command': 'guest-suspend-disk', 'success-response': false }
+{ 'command': 'guest-suspend-disk', 'success-response': false,
+ 'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] } }
##
# @guest-suspend-ram:
@@ -602,7 +603,8 @@
#
# Since: 1.1
##
-{ 'command': 'guest-suspend-ram', 'success-response': false }
+{ 'command': 'guest-suspend-ram', 'success-response': false,
+ 'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] } }
##
# @guest-suspend-hybrid:
@@ -638,7 +640,7 @@
# Since: 1.1
##
{ 'command': 'guest-suspend-hybrid', 'success-response': false,
- 'if': 'CONFIG_POSIX' }
+ 'if': 'CONFIG_LINUX' }
##
# @GuestIpAddressType:
@@ -751,7 +753,8 @@
{ 'struct': 'GuestLogicalProcessor',
'data': {'logical-id': 'int',
'online': 'bool',
- '*can-offline': 'bool'} }
+ '*can-offline': 'bool'},
+ 'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] } }
##
# @guest-get-vcpus:
@@ -766,7 +769,8 @@
# Since: 1.5
##
{ 'command': 'guest-get-vcpus',
- 'returns': ['GuestLogicalProcessor'] }
+ 'returns': ['GuestLogicalProcessor'],
+ 'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] } }
##
# @guest-set-vcpus:
@@ -809,7 +813,7 @@
{ 'command': 'guest-set-vcpus',
'data': {'vcpus': ['GuestLogicalProcessor'] },
'returns': 'int',
- 'if': 'CONFIG_POSIX' }
+ 'if': 'CONFIG_LINUX' }
##
# @GuestDiskBusType:
@@ -1103,7 +1107,7 @@
'data': {'phys-index': 'uint64',
'online': 'bool',
'*can-offline': 'bool'},
- 'if': 'CONFIG_POSIX' }
+ 'if': 'CONFIG_LINUX' }
##
# @guest-get-memory-blocks:
@@ -1120,7 +1124,7 @@
##
{ 'command': 'guest-get-memory-blocks',
'returns': ['GuestMemoryBlock'],
- 'if': 'CONFIG_POSIX' }
+ 'if': 'CONFIG_LINUX' }
##
# @GuestMemoryBlockResponseType:
@@ -1144,7 +1148,7 @@
{ 'enum': 'GuestMemoryBlockResponseType',
'data': ['success', 'not-found', 'operation-not-supported',
'operation-failed'],
- 'if': 'CONFIG_POSIX' }
+ 'if': 'CONFIG_LINUX' }
##
# @GuestMemoryBlockResponse:
@@ -1163,7 +1167,7 @@
'data': { 'phys-index': 'uint64',
'response': 'GuestMemoryBlockResponseType',
'*error-code': 'int' },
- 'if': 'CONFIG_POSIX'}
+ 'if': 'CONFIG_LINUX'}
##
# @guest-set-memory-blocks:
@@ -1195,7 +1199,7 @@
{ 'command': 'guest-set-memory-blocks',
'data': {'mem-blks': ['GuestMemoryBlock'] },
'returns': ['GuestMemoryBlockResponse'],
- 'if': 'CONFIG_POSIX' }
+ 'if': 'CONFIG_LINUX' }
##
# @GuestMemoryBlockInfo:
@@ -1208,7 +1212,7 @@
##
{ 'struct': 'GuestMemoryBlockInfo',
'data': {'size': 'uint64'},
- 'if': 'CONFIG_POSIX' }
+ 'if': 'CONFIG_LINUX' }
##
# @guest-get-memory-block-info:
@@ -1221,7 +1225,7 @@
##
{ 'command': 'guest-get-memory-block-info',
'returns': 'GuestMemoryBlockInfo',
- 'if': 'CONFIG_POSIX' }
+ 'if': 'CONFIG_LINUX' }
##
# @GuestExecStatus:
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 10/25] qga: conditionalize schema for commands requiring getifaddrs
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (8 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 09/25] qga: conditionalize schema for commands unsupported on non-Linux POSIX Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 11/25] qga: conditionalize schema for commands requiring linux/win32 Konstantin Kostiuk
` (15 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
Rather than creating stubs for every comamnd that just return
QERR_UNSUPPORTED, use 'if' conditions in the QAPI schema to
fully exclude generation of the network interface command on
POSIX platforms lacking getifaddrs().
The command will be rejected at QMP dispatch time instead,
avoiding reimplementing rejection by blocking the stub commands.
This changes the error message for affected commands from
{"class": "CommandNotFound", "desc": "Command FOO has been disabled"}
to
{"class": "CommandNotFound", "desc": "The command FOO has not been found"}
This has the additional benefit that the QGA protocol reference
now documents what conditions enable use of the command.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Message-ID: <20240712132459.3974109-11-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-posix.c | 13 -------------
qga/qapi-schema.json | 15 ++++++++++-----
2 files changed, 10 insertions(+), 18 deletions(-)
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 559d71ffae..09d08ee2ca 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1142,14 +1142,6 @@ error:
return NULL;
}
-#else
-
-GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
#endif /* HAVE_GETIFADDRS */
#if !defined(CONFIG_FSFREEZE)
@@ -1222,11 +1214,6 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
/* add unsupported commands to the list of blocked RPCs */
GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
{
-#if !defined(HAVE_GETIFADDRS)
- blockedrpcs = g_list_append(blockedrpcs,
- g_strdup("guest-network-get-interfaces"));
-#endif
-
#if !defined(CONFIG_FSFREEZE)
{
const char *list[] = {
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 38483652ac..79ed4f0e21 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -654,7 +654,8 @@
# Since: 1.1
##
{ 'enum': 'GuestIpAddressType',
- 'data': [ 'ipv4', 'ipv6' ] }
+ 'data': [ 'ipv4', 'ipv6' ],
+ 'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @GuestIpAddress:
@@ -670,7 +671,8 @@
{ 'struct': 'GuestIpAddress',
'data': {'ip-address': 'str',
'ip-address-type': 'GuestIpAddressType',
- 'prefix': 'int'} }
+ 'prefix': 'int'},
+ 'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @GuestNetworkInterfaceStat:
@@ -702,7 +704,8 @@
'tx-packets': 'uint64',
'tx-errs': 'uint64',
'tx-dropped': 'uint64'
- } }
+ },
+ 'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @GuestNetworkInterface:
@@ -722,7 +725,8 @@
'data': {'name': 'str',
'*hardware-address': 'str',
'*ip-addresses': ['GuestIpAddress'],
- '*statistics': 'GuestNetworkInterfaceStat' } }
+ '*statistics': 'GuestNetworkInterfaceStat' },
+ 'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @guest-network-get-interfaces:
@@ -734,7 +738,8 @@
# Since: 1.1
##
{ 'command': 'guest-network-get-interfaces',
- 'returns': ['GuestNetworkInterface'] }
+ 'returns': ['GuestNetworkInterface'],
+ 'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @GuestLogicalProcessor:
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 11/25] qga: conditionalize schema for commands requiring linux/win32
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (9 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 10/25] qga: conditionalize schema for commands requiring getifaddrs Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 12/25] qga: conditionalize schema for commands only supported on Windows Konstantin Kostiuk
` (14 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
Some commands were blocked based on CONFIG_FSFREEZE, but their
impl had nothing todo with CONFIG_FSFREEZE, and were instead
either Linux-only, or Win+Linux-only.
Rather than creating stubs for every command that just return
QERR_UNSUPPORTED, use 'if' conditions in the QAPI schema to
fully exclude generation of the stats and fsinfo commands on
platforms that can't support them.
The command will be rejected at QMP dispatch time instead,
avoiding reimplementing rejection by blocking the stub commands.
This changes the error message for affected commands from
{"class": "CommandNotFound", "desc": "Command FOO has been disabled"}
to
{"class": "CommandNotFound", "desc": "The command FOO has not been found"}
This has the additional benefit that the QGA protocol reference
now documents what conditions enable use of the command.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Message-ID: <20240712132459.3974109-12-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-bsd.c | 24 -----------------------
qga/commands-posix.c | 30 ++---------------------------
qga/qapi-schema.json | 45 +++++++++++++++++++++++++++-----------------
3 files changed, 30 insertions(+), 69 deletions(-)
diff --git a/qga/commands-bsd.c b/qga/commands-bsd.c
index 17bddda1cf..9ce48af311 100644
--- a/qga/commands-bsd.c
+++ b/qga/commands-bsd.c
@@ -149,30 +149,6 @@ int qmp_guest_fsfreeze_do_thaw(Error **errp)
}
return ret;
}
-
-GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
#endif /* CONFIG_FSFREEZE */
#ifdef HAVE_GETIFADDRS
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 09d08ee2ca..838dc3cf98 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1146,12 +1146,6 @@ error:
#if !defined(CONFIG_FSFREEZE)
-GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
{
error_setg(errp, QERR_UNSUPPORTED);
@@ -1181,25 +1175,6 @@ int64_t qmp_guest_fsfreeze_thaw(Error **errp)
return 0;
}
-
-GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
#endif /* CONFIG_FSFREEZE */
#if !defined(CONFIG_FSTRIM)
@@ -1217,10 +1192,9 @@ GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
#if !defined(CONFIG_FSFREEZE)
{
const char *list[] = {
- "guest-get-fsinfo", "guest-fsfreeze-status",
+ "guest-fsfreeze-status",
"guest-fsfreeze-freeze", "guest-fsfreeze-freeze-list",
- "guest-fsfreeze-thaw", "guest-get-fsinfo",
- "guest-get-disks", NULL};
+ "guest-fsfreeze-thaw", NULL};
char **p = (char **)list;
while (*p) {
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 79ed4f0e21..9bd5aa53bc 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -870,7 +870,8 @@
{ 'enum': 'GuestDiskBusType',
'data': [ 'ide', 'fdc', 'scsi', 'virtio', 'xen', 'usb', 'uml', 'sata',
'sd', 'unknown', 'ieee1394', 'ssa', 'fibre', 'raid', 'iscsi',
- 'sas', 'mmc', 'virtual', 'file-backed-virtual', 'nvme' ] }
+ 'sas', 'mmc', 'virtual', 'file-backed-virtual', 'nvme' ],
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
@@ -888,7 +889,8 @@
##
{ 'struct': 'GuestPCIAddress',
'data': {'domain': 'int', 'bus': 'int',
- 'slot': 'int', 'function': 'int'} }
+ 'slot': 'int', 'function': 'int'},
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @GuestCCWAddress:
@@ -907,7 +909,8 @@
'data': {'cssid': 'int',
'ssid': 'int',
'subchno': 'int',
- 'devno': 'int'} }
+ 'devno': 'int'},
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @GuestDiskAddress:
@@ -936,7 +939,8 @@
'bus-type': 'GuestDiskBusType',
'bus': 'int', 'target': 'int', 'unit': 'int',
'*serial': 'str', '*dev': 'str',
- '*ccw-address': 'GuestCCWAddress'} }
+ '*ccw-address': 'GuestCCWAddress'},
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @GuestNVMeSmart:
@@ -973,7 +977,8 @@
'media-errors-lo': 'uint64',
'media-errors-hi': 'uint64',
'number-of-error-log-entries-lo': 'uint64',
- 'number-of-error-log-entries-hi': 'uint64' } }
+ 'number-of-error-log-entries-hi': 'uint64' },
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @GuestDiskSmart:
@@ -987,7 +992,8 @@
{ 'union': 'GuestDiskSmart',
'base': { 'type': 'GuestDiskBusType' },
'discriminator': 'type',
- 'data': { 'nvme': 'GuestNVMeSmart' } }
+ 'data': { 'nvme': 'GuestNVMeSmart' },
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @GuestDiskInfo:
@@ -1012,7 +1018,8 @@
{ 'struct': 'GuestDiskInfo',
'data': {'name': 'str', 'partition': 'bool', '*dependencies': ['str'],
'*address': 'GuestDiskAddress', '*alias': 'str',
- '*smart': 'GuestDiskSmart'} }
+ '*smart': 'GuestDiskSmart'},
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @guest-get-disks:
@@ -1025,7 +1032,8 @@
# Since: 5.2
##
{ 'command': 'guest-get-disks',
- 'returns': ['GuestDiskInfo'] }
+ 'returns': ['GuestDiskInfo'],
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @GuestFilesystemInfo:
@@ -1051,7 +1059,8 @@
{ 'struct': 'GuestFilesystemInfo',
'data': {'name': 'str', 'mountpoint': 'str', 'type': 'str',
'*used-bytes': 'uint64', '*total-bytes': 'uint64',
- '*total-bytes-privileged': 'uint64', 'disk': ['GuestDiskAddress']} }
+ '*total-bytes-privileged': 'uint64', 'disk': ['GuestDiskAddress']},
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @guest-get-fsinfo:
@@ -1064,7 +1073,8 @@
# Since: 2.2
##
{ 'command': 'guest-get-fsinfo',
- 'returns': ['GuestFilesystemInfo'] }
+ 'returns': ['GuestFilesystemInfo'],
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @guest-set-user-password:
@@ -1703,7 +1713,8 @@
'*ios-pgr': 'uint64',
'*total-ticks': 'uint64',
'*weight-ticks': 'uint64'
- } }
+ },
+ 'if': 'CONFIG_LINUX' }
##
# @GuestDiskStatsInfo:
@@ -1721,7 +1732,7 @@
'major': 'uint64',
'minor': 'uint64',
'stats': 'GuestDiskStats' },
- 'if': 'CONFIG_POSIX' }
+ 'if': 'CONFIG_LINUX' }
##
# @guest-get-diskstats:
@@ -1734,7 +1745,7 @@
##
{ 'command': 'guest-get-diskstats',
'returns': ['GuestDiskStatsInfo'],
- 'if': 'CONFIG_POSIX'
+ 'if': 'CONFIG_LINUX'
}
##
@@ -1748,7 +1759,7 @@
##
{ 'enum': 'GuestCpuStatsType',
'data': [ 'linux' ],
- 'if': 'CONFIG_POSIX' }
+ 'if': 'CONFIG_LINUX' }
##
@@ -1794,7 +1805,7 @@
'*guest': 'uint64',
'*guestnice': 'uint64'
},
- 'if': 'CONFIG_POSIX' }
+ 'if': 'CONFIG_LINUX' }
##
# @GuestCpuStats:
@@ -1809,7 +1820,7 @@
'base': { 'type': 'GuestCpuStatsType' },
'discriminator': 'type',
'data': { 'linux': 'GuestLinuxCpuStats' },
- 'if': 'CONFIG_POSIX' }
+ 'if': 'CONFIG_LINUX' }
##
# @guest-get-cpustats:
@@ -1822,5 +1833,5 @@
##
{ 'command': 'guest-get-cpustats',
'returns': ['GuestCpuStats'],
- 'if': 'CONFIG_POSIX'
+ 'if': 'CONFIG_LINUX'
}
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 12/25] qga: conditionalize schema for commands only supported on Windows
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (10 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 11/25] qga: conditionalize schema for commands requiring linux/win32 Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 13/25] qga: conditionalize schema for commands requiring fsfreeze Konstantin Kostiuk
` (13 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
Rather than creating stubs for every command that just return
QERR_UNSUPPORTED, use 'if' conditions in the QAPI schema to
fully exclude generation of the commands on non-Windows.
The command will be rejected at QMP dispatch time instead,
avoiding reimplementing rejection by blocking the stub commands.
This changes the error message for affected commands from
{"class": "CommandNotFound", "desc": "Command FOO has been disabled"}
to
{"class": "CommandNotFound", "desc": "The command FOO has not been found"}
This has the additional benefit that the QGA protocol reference
now documents what conditions enable use of the command.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Message-ID: <20240712132459.3974109-13-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-posix.c | 9 ---------
qga/qapi-schema.json | 15 ++++++++++-----
2 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 838dc3cf98..b7f96aa005 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1207,8 +1207,6 @@ GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
blockedrpcs = g_list_append(blockedrpcs, g_strdup("guest-fstrim"));
#endif
- blockedrpcs = g_list_append(blockedrpcs, g_strdup("guest-get-devices"));
-
return blockedrpcs;
}
@@ -1419,13 +1417,6 @@ GuestOSInfo *qmp_guest_get_osinfo(Error **errp)
return info;
}
-GuestDeviceInfoList *qmp_guest_get_devices(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-
- return NULL;
-}
-
#ifndef HOST_NAME_MAX
# ifdef _POSIX_HOST_NAME_MAX
# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 9bd5aa53bc..de3fc46d2e 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -1527,7 +1527,8 @@
# @pci: PCI device
##
{ 'enum': 'GuestDeviceType',
- 'data': [ 'pci' ] }
+ 'data': [ 'pci' ],
+ 'if': 'CONFIG_WIN32' }
##
# @GuestDeviceIdPCI:
@@ -1539,7 +1540,8 @@
# Since: 5.2
##
{ 'struct': 'GuestDeviceIdPCI',
- 'data': { 'vendor-id': 'uint16', 'device-id': 'uint16' } }
+ 'data': { 'vendor-id': 'uint16', 'device-id': 'uint16' },
+ 'if': 'CONFIG_WIN32' }
##
# @GuestDeviceId:
@@ -1553,7 +1555,8 @@
{ 'union': 'GuestDeviceId',
'base': { 'type': 'GuestDeviceType' },
'discriminator': 'type',
- 'data': { 'pci': 'GuestDeviceIdPCI' } }
+ 'data': { 'pci': 'GuestDeviceIdPCI' },
+ 'if': 'CONFIG_WIN32' }
##
# @GuestDeviceInfo:
@@ -1574,7 +1577,8 @@
'*driver-date': 'int',
'*driver-version': 'str',
'*id': 'GuestDeviceId'
- } }
+ },
+ 'if': 'CONFIG_WIN32' }
##
# @guest-get-devices:
@@ -1586,7 +1590,8 @@
# Since: 5.2
##
{ 'command': 'guest-get-devices',
- 'returns': ['GuestDeviceInfo'] }
+ 'returns': ['GuestDeviceInfo'],
+ 'if': 'CONFIG_WIN32' }
##
# @GuestAuthorizedKeys:
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 13/25] qga: conditionalize schema for commands requiring fsfreeze
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (11 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 12/25] qga: conditionalize schema for commands only supported on Windows Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 14/25] qga: conditionalize schema for commands requiring fstrim Konstantin Kostiuk
` (12 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
Rather than creating stubs for every command that just return
QERR_UNSUPPORTED, use 'if' conditions in the schema to fully
exclude generation of the filesystem freezing commands on POSIX
platforms lacking the required APIs.
The command will be rejected at QMP dispatch time instead,
avoiding reimplementing rejection by blocking the stub commands.
This changes the error message for affected commands from
{"class": "CommandNotFound", "desc": "Command FOO has been disabled"}
to
{"class": "CommandNotFound", "desc": "The command FOO has not been found"}
This has the additional benefit that the QGA protocol reference
now documents what conditions enable use of the command.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Message-ID: <20240712132459.3974109-14-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-posix.c | 47 --------------------------------------------
qga/qapi-schema.json | 15 +++++++++-----
2 files changed, 10 insertions(+), 52 deletions(-)
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index b7f96aa005..9207cb7a8f 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1144,39 +1144,6 @@ error:
#endif /* HAVE_GETIFADDRS */
-#if !defined(CONFIG_FSFREEZE)
-
-GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-
- return 0;
-}
-
-int64_t qmp_guest_fsfreeze_freeze(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-
- return 0;
-}
-
-int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
- strList *mountpoints,
- Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-
- return 0;
-}
-
-int64_t qmp_guest_fsfreeze_thaw(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-
- return 0;
-}
-#endif /* CONFIG_FSFREEZE */
-
#if !defined(CONFIG_FSTRIM)
GuestFilesystemTrimResponse *
qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
@@ -1189,20 +1156,6 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
/* add unsupported commands to the list of blocked RPCs */
GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
{
-#if !defined(CONFIG_FSFREEZE)
- {
- const char *list[] = {
- "guest-fsfreeze-status",
- "guest-fsfreeze-freeze", "guest-fsfreeze-freeze-list",
- "guest-fsfreeze-thaw", NULL};
- char **p = (char **)list;
-
- while (*p) {
- blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++));
- }
- }
-#endif
-
#if !defined(CONFIG_FSTRIM)
blockedrpcs = g_list_append(blockedrpcs, g_strdup("guest-fstrim"));
#endif
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index de3fc46d2e..62462f092c 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -412,7 +412,8 @@
# Since: 0.15.0
##
{ 'enum': 'GuestFsfreezeStatus',
- 'data': [ 'thawed', 'frozen' ] }
+ 'data': [ 'thawed', 'frozen' ],
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @guest-fsfreeze-status:
@@ -429,7 +430,8 @@
# Since: 0.15.0
##
{ 'command': 'guest-fsfreeze-status',
- 'returns': 'GuestFsfreezeStatus' }
+ 'returns': 'GuestFsfreezeStatus',
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @guest-fsfreeze-freeze:
@@ -451,7 +453,8 @@
# Since: 0.15.0
##
{ 'command': 'guest-fsfreeze-freeze',
- 'returns': 'int' }
+ 'returns': 'int',
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @guest-fsfreeze-freeze-list:
@@ -471,7 +474,8 @@
##
{ 'command': 'guest-fsfreeze-freeze-list',
'data': { '*mountpoints': ['str'] },
- 'returns': 'int' }
+ 'returns': 'int',
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @guest-fsfreeze-thaw:
@@ -488,7 +492,8 @@
# Since: 0.15.0
##
{ 'command': 'guest-fsfreeze-thaw',
- 'returns': 'int' }
+ 'returns': 'int',
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @GuestFilesystemTrimResult:
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 14/25] qga: conditionalize schema for commands requiring fstrim
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (12 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 13/25] qga: conditionalize schema for commands requiring fsfreeze Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 15/25] qga: conditionalize schema for commands requiring libudev Konstantin Kostiuk
` (11 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
Rather than creating stubs for every command that just return
QERR_UNSUPPORTED, use 'if' conditions in the QAPI schema to
fully exclude generation of the filesystem trimming commands
on POSIX platforms lacking required APIs.
The command will be rejected at QMP dispatch time instead,
avoiding reimplementing rejection by blocking the stub commands.
This changes the error message for affected commands from
{"class": "CommandNotFound", "desc": "Command FOO has been disabled"}
to
{"class": "CommandNotFound", "desc": "The command FOO has not been found"}
This has the additional benefit that the QGA protocol reference
now documents what conditions enable use of the command.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Message-ID: <20240712132459.3974109-15-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-posix.c | 13 -------------
qga/qapi-schema.json | 9 ++++++---
2 files changed, 6 insertions(+), 16 deletions(-)
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 9207cb7a8f..d92fa0ec87 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1144,22 +1144,9 @@ error:
#endif /* HAVE_GETIFADDRS */
-#if !defined(CONFIG_FSTRIM)
-GuestFilesystemTrimResponse *
-qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-#endif
-
/* add unsupported commands to the list of blocked RPCs */
GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
{
-#if !defined(CONFIG_FSTRIM)
- blockedrpcs = g_list_append(blockedrpcs, g_strdup("guest-fstrim"));
-#endif
-
return blockedrpcs;
}
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 62462f092c..21c65d1806 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -510,7 +510,8 @@
##
{ 'struct': 'GuestFilesystemTrimResult',
'data': {'path': 'str',
- '*trimmed': 'int', '*minimum': 'int', '*error': 'str'} }
+ '*trimmed': 'int', '*minimum': 'int', '*error': 'str'},
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSTRIM'] } }
##
# @GuestFilesystemTrimResponse:
@@ -520,7 +521,8 @@
# Since: 2.4
##
{ 'struct': 'GuestFilesystemTrimResponse',
- 'data': {'paths': ['GuestFilesystemTrimResult']} }
+ 'data': {'paths': ['GuestFilesystemTrimResult']},
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSTRIM'] } }
##
# @guest-fstrim:
@@ -542,7 +544,8 @@
##
{ 'command': 'guest-fstrim',
'data': { '*minimum': 'int' },
- 'returns': 'GuestFilesystemTrimResponse' }
+ 'returns': 'GuestFilesystemTrimResponse',
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSTRIM'] } }
##
# @guest-suspend-disk:
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 15/25] qga: conditionalize schema for commands requiring libudev
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (13 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 14/25] qga: conditionalize schema for commands requiring fstrim Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 16/25] qga: conditionalize schema for commands requiring utmpx Konstantin Kostiuk
` (10 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
Rather than creating stubs for every command that just return
QERR_UNSUPPORTED, use 'if' conditions in the schema to fully
exclude generation of the filesystem trimming commands on POSIX
platforms lacking required APIs.
The command will be rejected at QMP dispatch time instead,
avoiding reimplementing rejection by blocking the stub commands.
This changes the error message for affected commands from
{"class": "CommandNotFound", "desc": "Command FOO has been disabled"}
to
{"class": "CommandNotFound", "desc": "The command FOO has not been found"}
This has the additional benefit that the QGA protocol reference
now documents what conditions enable use of the command.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Message-ID: <20240712132459.3974109-16-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-linux.c | 8 --------
qga/qapi-schema.json | 8 ++++----
2 files changed, 4 insertions(+), 12 deletions(-)
diff --git a/qga/commands-linux.c b/qga/commands-linux.c
index 73b13fbaf6..89bdcded01 100644
--- a/qga/commands-linux.c
+++ b/qga/commands-linux.c
@@ -1049,14 +1049,6 @@ GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
return ret;
}
-#else
-
-GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
#endif
/* Return a list of the disk device(s)' info which @mount lies on */
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 21c65d1806..cf1ad42519 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -986,7 +986,7 @@
'media-errors-hi': 'uint64',
'number-of-error-log-entries-lo': 'uint64',
'number-of-error-log-entries-hi': 'uint64' },
- 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LIBUDEV' ] } }
##
# @GuestDiskSmart:
@@ -1001,7 +1001,7 @@
'base': { 'type': 'GuestDiskBusType' },
'discriminator': 'type',
'data': { 'nvme': 'GuestNVMeSmart' },
- 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LIBUDEV' ] } }
##
# @GuestDiskInfo:
@@ -1027,7 +1027,7 @@
'data': {'name': 'str', 'partition': 'bool', '*dependencies': ['str'],
'*address': 'GuestDiskAddress', '*alias': 'str',
'*smart': 'GuestDiskSmart'},
- 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LIBUDEV' ] } }
##
# @guest-get-disks:
@@ -1041,7 +1041,7 @@
##
{ 'command': 'guest-get-disks',
'returns': ['GuestDiskInfo'],
- 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LIBUDEV' ] } }
##
# @GuestFilesystemInfo:
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 16/25] qga: conditionalize schema for commands requiring utmpx
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (14 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 15/25] qga: conditionalize schema for commands requiring libudev Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 17/25] qga: conditionalize schema for commands not supported on other UNIX Konstantin Kostiuk
` (9 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
Rather than creating stubs for every command that just return
QERR_UNSUPPORTED, use 'if' conditions in the QAPI schema to
fully exclude generation of the get-users command on POSIX
platforms lacking required APIs.
The command will be rejected at QMP dispatch time instead,
avoiding reimplementing rejection by blocking the stub commands.
This changes the error message for affected commands from
{"class": "CommandNotFound", "desc": "Command FOO has been disabled"}
to
{"class": "CommandNotFound", "desc": "The command FOO has not been found"}
This has the additional benefit that the QGA protocol reference
now documents what conditions enable use of the command.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Message-ID: <20240712132459.3974109-17-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-posix.c | 10 +---------
qga/qapi-schema.json | 6 ++++--
2 files changed, 5 insertions(+), 11 deletions(-)
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index d92fa0ec87..a353f64ae6 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1212,15 +1212,7 @@ GuestUserList *qmp_guest_get_users(Error **errp)
return head;
}
-#else
-
-GuestUserList *qmp_guest_get_users(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-#endif
+#endif /* HAVE_UTMPX */
/* Replace escaped special characters with their real values. The replacement
* is done in place -- returned value is in the original string.
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index cf1ad42519..0662a68c43 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -1414,7 +1414,8 @@
# Since: 2.10
##
{ 'struct': 'GuestUser',
- 'data': { 'user': 'str', 'login-time': 'number', '*domain': 'str' } }
+ 'data': { 'user': 'str', 'login-time': 'number', '*domain': 'str' },
+ 'if': { 'any': ['CONFIG_WIN32', 'HAVE_UTMPX' ] } }
##
# @guest-get-users:
@@ -1426,7 +1427,8 @@
# Since: 2.10
##
{ 'command': 'guest-get-users',
- 'returns': ['GuestUser'] }
+ 'returns': ['GuestUser'],
+ 'if': { 'any': ['CONFIG_WIN32', 'HAVE_UTMPX' ] } }
##
# @GuestTimezone:
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 17/25] qga: conditionalize schema for commands not supported on other UNIX
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (15 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 16/25] qga: conditionalize schema for commands requiring utmpx Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 18/25] qga: don't disable fsfreeze commands if vss_init fails Konstantin Kostiuk
` (8 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
Rather than creating stubs for every command that just return
QERR_UNSUPPORTED, use 'if' conditions in the QAPI schema to
fully exclude generation of the commands on other UNIX.
The command will be rejected at QMP dispatch time instead,
avoiding reimplementing rejection by blocking the stub commands.
This changes the error message for affected commands from
{"class": "CommandNotFound", "desc": "Command FOO has been disabled"}
to
{"class": "CommandNotFound", "desc": "The command FOO has not been found"}
This has the additional benefit that the QGA protocol reference
now documents what conditions enable use of the command.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Message-ID: <20240712132459.3974109-18-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
meson.build | 1 +
qga/commands-posix.c | 8 --------
qga/qapi-schema.json | 3 ++-
3 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/meson.build b/meson.build
index 83f9728524..23f35193ee 100644
--- a/meson.build
+++ b/meson.build
@@ -2276,6 +2276,7 @@ config_host_data.set('CONFIG_ATTR', libattr.found())
config_host_data.set('CONFIG_BDRV_WHITELIST_TOOLS', get_option('block_drv_whitelist_in_tools'))
config_host_data.set('CONFIG_BRLAPI', brlapi.found())
config_host_data.set('CONFIG_BSD', host_os in bsd_oses)
+config_host_data.set('CONFIG_FREEBSD', host_os == 'freebsd')
config_host_data.set('CONFIG_CAPSTONE', capstone.found())
config_host_data.set('CONFIG_COCOA', cocoa.found())
config_host_data.set('CONFIG_DARWIN', host_os == 'darwin')
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index a353f64ae6..f4104f2760 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -877,14 +877,6 @@ void qmp_guest_set_user_password(const char *username,
return;
}
}
-#else /* __linux__ || __FreeBSD__ */
-void qmp_guest_set_user_password(const char *username,
- const char *password,
- bool crypted,
- Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-}
#endif /* __linux__ || __FreeBSD__ */
#ifdef HAVE_GETIFADDRS
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 0662a68c43..c763163fcd 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -1109,7 +1109,8 @@
# Since: 2.3
##
{ 'command': 'guest-set-user-password',
- 'data': { 'username': 'str', 'password': 'str', 'crypted': 'bool' } }
+ 'data': { 'username': 'str', 'password': 'str', 'crypted': 'bool' },
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX', 'CONFIG_FREEBSD'] } }
##
# @GuestMemoryBlock:
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 18/25] qga: don't disable fsfreeze commands if vss_init fails
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (16 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 17/25] qga: conditionalize schema for commands not supported on other UNIX Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 19/25] qga: move declare of QGAConfig struct to top of file Konstantin Kostiuk
` (7 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
The fsfreeze commands are already written to report an error if
vss_init() fails. Reporting a more specific error message is more
helpful than a generic "command is disabled" message, which cannot
between an admin config decision and lack of platform support.
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20240712132459.3974109-19-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-win32.c | 18 +++---------------
qga/main.c | 4 ++++
2 files changed, 7 insertions(+), 15 deletions(-)
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 2533e4c748..5866cc2e3c 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -1203,7 +1203,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
{
if (!vss_initialized()) {
- error_setg(errp, QERR_UNSUPPORTED);
+ error_setg(errp, "fsfreeze not possible as VSS failed to initialize");
return 0;
}
@@ -1231,7 +1231,7 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
Error *local_err = NULL;
if (!vss_initialized()) {
- error_setg(errp, QERR_UNSUPPORTED);
+ error_setg(errp, "fsfreeze not possible as VSS failed to initialize");
return 0;
}
@@ -1266,7 +1266,7 @@ int64_t qmp_guest_fsfreeze_thaw(Error **errp)
int i;
if (!vss_initialized()) {
- error_setg(errp, QERR_UNSUPPORTED);
+ error_setg(errp, "fsfreeze not possible as VSS failed to initialize");
return 0;
}
@@ -1961,18 +1961,6 @@ done:
/* add unsupported commands to the list of blocked RPCs */
GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
{
- if (!vss_init(true)) {
- g_debug("vss_init failed, vss commands are going to be disabled");
- const char *list[] = {
- "guest-get-fsinfo", "guest-fsfreeze-status",
- "guest-fsfreeze-freeze", "guest-fsfreeze-thaw", NULL};
- char **p = (char **)list;
-
- while (*p) {
- blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++));
- }
- }
-
return blockedrpcs;
}
diff --git a/qga/main.c b/qga/main.c
index f4d5f15bb3..17b6ce18ac 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -1395,6 +1395,10 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
" '%s': %s", config->state_dir, strerror(errno));
return NULL;
}
+
+ if (!vss_init(true)) {
+ g_debug("vss_init failed, vss commands will not function");
+ }
#endif
if (ga_is_frozen(s)) {
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 19/25] qga: move declare of QGAConfig struct to top of file
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (17 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 18/25] qga: don't disable fsfreeze commands if vss_init fails Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 20/25] qga: remove pointless 'blockrpcs_key' variable Konstantin Kostiuk
` (6 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
It is referenced by QGAState already, and it is clearer to declare all
data types at the top of the file, rather than have them mixed with
code later.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Message-ID: <20240712132459.3974109-20-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/main.c | 44 ++++++++++++++++++++++----------------------
1 file changed, 22 insertions(+), 22 deletions(-)
diff --git a/qga/main.c b/qga/main.c
index 17b6ce18ac..647d27037c 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -70,6 +70,28 @@ typedef struct GAPersistentState {
typedef struct GAConfig GAConfig;
+struct GAConfig {
+ char *channel_path;
+ char *method;
+ char *log_filepath;
+ char *pid_filepath;
+#ifdef CONFIG_FSFREEZE
+ char *fsfreeze_hook;
+#endif
+ char *state_dir;
+#ifdef _WIN32
+ const char *service;
+#endif
+ gchar *bliststr; /* blockedrpcs may point to this string */
+ gchar *aliststr; /* allowedrpcs may point to this string */
+ GList *blockedrpcs;
+ GList *allowedrpcs;
+ int daemonize;
+ GLogLevelFlags log_level;
+ int dumpconf;
+ bool retry_path;
+};
+
struct GAState {
JSONMessageParser parser;
GMainLoop *main_loop;
@@ -996,28 +1018,6 @@ static GList *split_list(const gchar *str, const gchar *delim)
return list;
}
-struct GAConfig {
- char *channel_path;
- char *method;
- char *log_filepath;
- char *pid_filepath;
-#ifdef CONFIG_FSFREEZE
- char *fsfreeze_hook;
-#endif
- char *state_dir;
-#ifdef _WIN32
- const char *service;
-#endif
- gchar *bliststr; /* blockedrpcs may point to this string */
- gchar *aliststr; /* allowedrpcs may point to this string */
- GList *blockedrpcs;
- GList *allowedrpcs;
- int daemonize;
- GLogLevelFlags log_level;
- int dumpconf;
- bool retry_path;
-};
-
static void config_load(GAConfig *config)
{
GError *gerr = NULL;
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 20/25] qga: remove pointless 'blockrpcs_key' variable
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (18 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 19/25] qga: move declare of QGAConfig struct to top of file Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 21/25] qga: allow configuration file path via the cli Konstantin Kostiuk
` (5 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
This variable was used to support back compat for the old config
file key name, and became redundant after the following change:
commit a7a2d636ae4549ef0551134d4bf8e084a14431c4
Author: Philippe Mathieu-Daudé <philmd@linaro.org>
Date: Thu May 30 08:36:43 2024 +0200
qga: Remove deprecated 'blacklist' argument / config key
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-ID: <20240712132459.3974109-21-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/main.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/qga/main.c b/qga/main.c
index 647d27037c..6ff022a85d 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -1023,7 +1023,6 @@ static void config_load(GAConfig *config)
GError *gerr = NULL;
GKeyFile *keyfile;
g_autofree char *conf = g_strdup(g_getenv("QGA_CONF")) ?: get_relocated_path(QGA_CONF_DEFAULT);
- const gchar *blockrpcs_key = "block-rpcs";
/* read system config */
keyfile = g_key_file_new();
@@ -1071,9 +1070,9 @@ static void config_load(GAConfig *config)
g_key_file_get_boolean(keyfile, "general", "retry-path", &gerr);
}
- if (g_key_file_has_key(keyfile, "general", blockrpcs_key, NULL)) {
+ if (g_key_file_has_key(keyfile, "general", "block-rpcs", NULL)) {
config->bliststr =
- g_key_file_get_string(keyfile, "general", blockrpcs_key, &gerr);
+ g_key_file_get_string(keyfile, "general", "block-rpcs", &gerr);
config->blockedrpcs = g_list_concat(config->blockedrpcs,
split_list(config->bliststr, ","));
}
@@ -1084,7 +1083,7 @@ static void config_load(GAConfig *config)
split_list(config->aliststr, ","));
}
- if (g_key_file_has_key(keyfile, "general", blockrpcs_key, NULL) &&
+ if (g_key_file_has_key(keyfile, "general", "block-rpcs", NULL) &&
g_key_file_has_key(keyfile, "general", "allow-rpcs", NULL)) {
g_critical("wrong config, using 'block-rpcs' and 'allow-rpcs' keys at"
" the same time is not allowed");
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 21/25] qga: allow configuration file path via the cli
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (19 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 20/25] qga: remove pointless 'blockrpcs_key' variable Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 22/25] qga: centralize logic for disabling/enabling commands Konstantin Kostiuk
` (4 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
Allowing the user to set the QGA_CONF environment variable to change
the default configuration file path is very unusual practice, made
more obscure since this ability is not documented.
This introduces the more normal '-c PATH' / '--config=PATH' command
line argument approach. This requires that we parse the comamnd line
twice, since we want the command line arguments to take priority over
the configuration file settings in general.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Message-ID: <20240712132459.3974109-22-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
docs/interop/qemu-ga.rst | 5 +++++
qga/main.c | 43 ++++++++++++++++++++++++++++++----------
2 files changed, 38 insertions(+), 10 deletions(-)
diff --git a/docs/interop/qemu-ga.rst b/docs/interop/qemu-ga.rst
index 72fb75a6f5..e42b370319 100644
--- a/docs/interop/qemu-ga.rst
+++ b/docs/interop/qemu-ga.rst
@@ -33,6 +33,11 @@ Options
.. program:: qemu-ga
+.. option:: -c, --config=PATH
+
+ Configuration file path (the default is |CONFDIR|\ ``/qemu-ga.conf``,
+ unless overriden by the QGA_CONF environment variable)
+
.. option:: -m, --method=METHOD
Transport method: one of ``unix-listen``, ``virtio-serial``, or
diff --git a/qga/main.c b/qga/main.c
index 6ff022a85d..6ae911eb15 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -248,12 +248,16 @@ static void usage(const char *cmd)
#ifdef CONFIG_FSFREEZE
g_autofree char *fsfreeze_hook = get_relocated_path(QGA_FSFREEZE_HOOK_DEFAULT);
#endif
+ g_autofree char *conf_path = get_relocated_path(QGA_CONF_DEFAULT);
printf(
"Usage: %s [-m <method> -p <path>] [<options>]\n"
"QEMU Guest Agent " QEMU_FULL_VERSION "\n"
QEMU_COPYRIGHT "\n"
"\n"
+" -c, --config=PATH configuration file path (default is\n"
+" %s/qemu-ga.conf\n"
+" unless overriden by the QGA_CONF environment variable)\n"
" -m, --method transport method: one of unix-listen, virtio-serial,\n"
" isa-serial, or vsock-listen (virtio-serial is the default)\n"
" -p, --path device/socket path (the default for virtio-serial is:\n"
@@ -294,8 +298,8 @@ QEMU_COPYRIGHT "\n"
" plug/unplug, etc.)\n"
" -h, --help display this help and exit\n"
"\n"
-QEMU_HELP_BOTTOM "\n"
- , cmd, QGA_VIRTIO_PATH_DEFAULT, QGA_SERIAL_PATH_DEFAULT,
+QEMU_HELP_BOTTOM "\n",
+ cmd, conf_path, QGA_VIRTIO_PATH_DEFAULT, QGA_SERIAL_PATH_DEFAULT,
dfl_pathnames.pidfile,
#ifdef CONFIG_FSFREEZE
fsfreeze_hook,
@@ -1018,15 +1022,14 @@ static GList *split_list(const gchar *str, const gchar *delim)
return list;
}
-static void config_load(GAConfig *config)
+static void config_load(GAConfig *config, const char *confpath, bool required)
{
GError *gerr = NULL;
GKeyFile *keyfile;
- g_autofree char *conf = g_strdup(g_getenv("QGA_CONF")) ?: get_relocated_path(QGA_CONF_DEFAULT);
/* read system config */
keyfile = g_key_file_new();
- if (!g_key_file_load_from_file(keyfile, conf, 0, &gerr)) {
+ if (!g_key_file_load_from_file(keyfile, confpath, 0, &gerr)) {
goto end;
}
if (g_key_file_has_key(keyfile, "general", "daemon", NULL)) {
@@ -1092,10 +1095,10 @@ static void config_load(GAConfig *config)
end:
g_key_file_free(keyfile);
- if (gerr &&
- !(gerr->domain == G_FILE_ERROR && gerr->code == G_FILE_ERROR_NOENT)) {
+ if (gerr && (required ||
+ !(gerr->domain == G_FILE_ERROR && gerr->code == G_FILE_ERROR_NOENT))) {
g_critical("error loading configuration from path: %s, %s",
- conf, gerr->message);
+ confpath, gerr->message);
exit(EXIT_FAILURE);
}
g_clear_error(&gerr);
@@ -1167,12 +1170,13 @@ static void config_dump(GAConfig *config)
static void config_parse(GAConfig *config, int argc, char **argv)
{
- const char *sopt = "hVvdm:p:l:f:F::b:a:s:t:Dr";
+ const char *sopt = "hVvdc:m:p:l:f:F::b:a:s:t:Dr";
int opt_ind = 0, ch;
bool block_rpcs = false, allow_rpcs = false;
const struct option lopt[] = {
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'V' },
+ { "config", 1, NULL, 'c' },
{ "dump-conf", 0, NULL, 'D' },
{ "logfile", 1, NULL, 'l' },
{ "pidfile", 1, NULL, 'f' },
@@ -1192,6 +1196,26 @@ static void config_parse(GAConfig *config, int argc, char **argv)
{ "retry-path", 0, NULL, 'r' },
{ NULL, 0, NULL, 0 }
};
+ g_autofree char *confpath = g_strdup(g_getenv("QGA_CONF")) ?:
+ get_relocated_path(QGA_CONF_DEFAULT);
+ bool confrequired = false;
+
+ while ((ch = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
+ switch (ch) {
+ case 'c':
+ g_free(confpath);
+ confpath = g_strdup(optarg);
+ confrequired = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ config_load(config, confpath, confrequired);
+
+ /* Reset for second pass */
+ optind = 1;
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
switch (ch) {
@@ -1582,7 +1606,6 @@ int main(int argc, char **argv)
qga_qmp_init_marshal(&ga_commands);
init_dfl_pathnames();
- config_load(config);
config_parse(config, argc, argv);
if (config->pid_filepath == NULL) {
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 22/25] qga: centralize logic for disabling/enabling commands
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (20 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 21/25] qga: allow configuration file path via the cli Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 23/25] qga/commands-posix: Make ga_wait_child() return boolean Konstantin Kostiuk
` (3 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Daniel P. Berrangé <berrange@redhat.com>
It is confusing having many different pieces of code enabling and
disabling commands, and it is not clear that they all have the same
semantics, especially wrt prioritization of the block/allow lists.
The code attempted to prevent the user from setting both the block
and allow lists concurrently, however, the logic was flawed as it
checked settings in the configuration file separately from the
command line arguments. Thus it was possible to set a block list
in the config file and an allow list via a command line argument.
The --dump-conf option also creates a configuration file with both
keys present, even if unset, which means it is creating a config
that cannot actually be loaded again.
Centralizing the code in a single method "ga_apply_command_filters"
will provide a strong guarantee of consistency and clarify the
intended behaviour. With this there is no compelling technical
reason to prevent concurrent setting of both the allow and block
lists, so this flawed restriction is removed.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Message-ID: <20240712132459.3974109-23-berrange@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
docs/interop/qemu-ga.rst | 14 +++++
qga/commands-posix.c | 6 --
qga/commands-win32.c | 6 --
qga/main.c | 128 +++++++++++++++++----------------------
4 files changed, 70 insertions(+), 84 deletions(-)
diff --git a/docs/interop/qemu-ga.rst b/docs/interop/qemu-ga.rst
index e42b370319..fb75cfd8d4 100644
--- a/docs/interop/qemu-ga.rst
+++ b/docs/interop/qemu-ga.rst
@@ -28,6 +28,20 @@ configuration options on the command line. For the same key, the last
option wins, but the lists accumulate (see below for configuration
file format).
+If an allowed RPCs list is defined in the configuration, then all
+RPCs will be blocked by default, except for the allowed list.
+
+If a blocked RPCs list is defined in the configuration, then all
+RPCs will be allowed by default, except for the blocked list.
+
+If both allowed and blocked RPCs lists are defined in the configuration,
+then all RPCs will be blocked by default, then the allowed list will
+be applied, followed by the blocked list.
+
+While filesystems are frozen, all except for a designated safe set
+of RPCs will blocked, regardless of what the general configuration
+declares.
+
Options
-------
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index f4104f2760..578d29f228 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1136,12 +1136,6 @@ error:
#endif /* HAVE_GETIFADDRS */
-/* add unsupported commands to the list of blocked RPCs */
-GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
-{
- return blockedrpcs;
-}
-
/* register init/cleanup routines for stateful command groups */
void ga_command_state_init(GAState *s, GACommandState *cs)
{
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 5866cc2e3c..61b36da469 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -1958,12 +1958,6 @@ done:
g_free(rawpasswddata);
}
-/* add unsupported commands to the list of blocked RPCs */
-GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
-{
- return blockedrpcs;
-}
-
/* register init/cleanup routines for stateful command groups */
void ga_command_state_init(GAState *s, GACommandState *cs)
{
diff --git a/qga/main.c b/qga/main.c
index 6ae911eb15..b8f7b1e4a3 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -423,60 +423,79 @@ static gint ga_strcmp(gconstpointer str1, gconstpointer str2)
return strcmp(str1, str2);
}
-/* disable commands that aren't safe for fsfreeze */
-static void ga_disable_not_allowed_freeze(const QmpCommand *cmd, void *opaque)
+static bool ga_command_is_allowed(const QmpCommand *cmd, GAState *state)
{
- bool allowed = false;
int i = 0;
+ GAConfig *config = state->config;
const char *name = qmp_command_name(cmd);
+ /* Fallback policy is allow everything */
+ bool allowed = true;
- while (ga_freeze_allowlist[i] != NULL) {
- if (strcmp(name, ga_freeze_allowlist[i]) == 0) {
+ if (config->allowedrpcs) {
+ /*
+ * If an allow-list is given, this changes the fallback
+ * policy to deny everything
+ */
+ allowed = false;
+
+ if (g_list_find_custom(config->allowedrpcs, name, ga_strcmp) != NULL) {
allowed = true;
}
- i++;
}
- if (!allowed) {
- g_debug("disabling command: %s", name);
- qmp_disable_command(&ga_commands, name, "the agent is in frozen state");
- }
-}
-/* [re-]enable all commands, except those explicitly blocked by user */
-static void ga_enable_non_blocked(const QmpCommand *cmd, void *opaque)
-{
- GAState *s = opaque;
- GList *blockedrpcs = s->blockedrpcs;
- GList *allowedrpcs = s->allowedrpcs;
- const char *name = qmp_command_name(cmd);
-
- if (g_list_find_custom(blockedrpcs, name, ga_strcmp) == NULL) {
- if (qmp_command_is_enabled(cmd)) {
- return;
+ /*
+ * If both allowedrpcs and blockedrpcs are set, the blocked
+ * list will take priority
+ */
+ if (config->blockedrpcs) {
+ if (g_list_find_custom(config->blockedrpcs, name, ga_strcmp) != NULL) {
+ allowed = false;
}
+ }
- if (allowedrpcs &&
- g_list_find_custom(allowedrpcs, name, ga_strcmp) == NULL) {
- return;
- }
+ /*
+ * If frozen, this filtering must take priority over
+ * absolutely everything
+ */
+ if (state->frozen) {
+ allowed = false;
- g_debug("enabling command: %s", name);
- qmp_enable_command(&ga_commands, name);
+ while (ga_freeze_allowlist[i] != NULL) {
+ if (strcmp(name, ga_freeze_allowlist[i]) == 0) {
+ allowed = true;
+ }
+ i++;
+ }
}
+
+ return allowed;
}
-/* disable commands that aren't allowed */
-static void ga_disable_not_allowed(const QmpCommand *cmd, void *opaque)
+static void ga_apply_command_filters_iter(const QmpCommand *cmd, void *opaque)
{
- GList *allowedrpcs = opaque;
+ GAState *state = opaque;
+ bool want = ga_command_is_allowed(cmd, state);
+ bool have = qmp_command_is_enabled(cmd);
const char *name = qmp_command_name(cmd);
- if (g_list_find_custom(allowedrpcs, name, ga_strcmp) == NULL) {
+ if (want == have) {
+ return;
+ }
+
+ if (have) {
g_debug("disabling command: %s", name);
qmp_disable_command(&ga_commands, name, "the command is not allowed");
+ } else {
+ g_debug("enabling command: %s", name);
+ qmp_enable_command(&ga_commands, name);
}
}
+static void ga_apply_command_filters(GAState *state)
+{
+ qmp_for_each_command(&ga_commands, ga_apply_command_filters_iter, state);
+}
+
static bool ga_create_file(const char *path)
{
int fd = open(path, O_CREAT | O_WRONLY, S_IWUSR | S_IRUSR);
@@ -509,15 +528,14 @@ void ga_set_frozen(GAState *s)
if (ga_is_frozen(s)) {
return;
}
- /* disable all forbidden (for frozen state) commands */
- qmp_for_each_command(&ga_commands, ga_disable_not_allowed_freeze, NULL);
g_warning("disabling logging due to filesystem freeze");
- ga_disable_logging(s);
s->frozen = true;
if (!ga_create_file(s->state_filepath_isfrozen)) {
g_warning("unable to create %s, fsfreeze may not function properly",
s->state_filepath_isfrozen);
}
+ ga_apply_command_filters(s);
+ ga_disable_logging(s);
}
void ga_unset_frozen(GAState *s)
@@ -549,12 +567,12 @@ void ga_unset_frozen(GAState *s)
}
/* enable all disabled, non-blocked and allowed commands */
- qmp_for_each_command(&ga_commands, ga_enable_non_blocked, s);
s->frozen = false;
if (!ga_delete_file(s->state_filepath_isfrozen)) {
g_warning("unable to delete %s, fsfreeze may not function properly",
s->state_filepath_isfrozen);
}
+ ga_apply_command_filters(s);
}
#ifdef CONFIG_FSFREEZE
@@ -1086,13 +1104,6 @@ static void config_load(GAConfig *config, const char *confpath, bool required)
split_list(config->aliststr, ","));
}
- if (g_key_file_has_key(keyfile, "general", "block-rpcs", NULL) &&
- g_key_file_has_key(keyfile, "general", "allow-rpcs", NULL)) {
- g_critical("wrong config, using 'block-rpcs' and 'allow-rpcs' keys at"
- " the same time is not allowed");
- exit(EXIT_FAILURE);
- }
-
end:
g_key_file_free(keyfile);
if (gerr && (required ||
@@ -1172,7 +1183,6 @@ static void config_parse(GAConfig *config, int argc, char **argv)
{
const char *sopt = "hVvdc:m:p:l:f:F::b:a:s:t:Dr";
int opt_ind = 0, ch;
- bool block_rpcs = false, allow_rpcs = false;
const struct option lopt[] = {
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'V' },
@@ -1268,7 +1278,6 @@ static void config_parse(GAConfig *config, int argc, char **argv)
}
config->blockedrpcs = g_list_concat(config->blockedrpcs,
split_list(optarg, ","));
- block_rpcs = true;
break;
}
case 'a': {
@@ -1278,7 +1287,6 @@ static void config_parse(GAConfig *config, int argc, char **argv)
}
config->allowedrpcs = g_list_concat(config->allowedrpcs,
split_list(optarg, ","));
- allow_rpcs = true;
break;
}
#ifdef _WIN32
@@ -1319,12 +1327,6 @@ static void config_parse(GAConfig *config, int argc, char **argv)
exit(EXIT_FAILURE);
}
}
-
- if (block_rpcs && allow_rpcs) {
- g_critical("wrong commandline, using --block-rpcs and --allow-rpcs at the"
- " same time is not allowed");
- exit(EXIT_FAILURE);
- }
}
static void config_free(GAConfig *config)
@@ -1435,7 +1437,6 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
s->deferred_options.log_filepath = config->log_filepath;
}
ga_disable_logging(s);
- qmp_for_each_command(&ga_commands, ga_disable_not_allowed_freeze, NULL);
} else {
if (config->daemonize) {
become_daemon(config->pid_filepath);
@@ -1459,25 +1460,6 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
return NULL;
}
- if (config->allowedrpcs) {
- qmp_for_each_command(&ga_commands, ga_disable_not_allowed, config->allowedrpcs);
- s->allowedrpcs = config->allowedrpcs;
- }
-
- /*
- * Some commands can be blocked due to system limitation.
- * Initialize blockedrpcs list even if allowedrpcs specified.
- */
- config->blockedrpcs = ga_command_init_blockedrpcs(config->blockedrpcs);
- if (config->blockedrpcs) {
- GList *l = config->blockedrpcs;
- s->blockedrpcs = config->blockedrpcs;
- do {
- g_debug("disabling command: %s", (char *)l->data);
- qmp_disable_command(&ga_commands, l->data, NULL);
- l = g_list_next(l);
- } while (l);
- }
s->command_state = ga_command_state_new();
ga_command_state_init(s, s->command_state);
ga_command_state_init_all(s->command_state);
@@ -1503,6 +1485,8 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
}
#endif
+ ga_apply_command_filters(s);
+
ga_state = s;
return s;
}
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 23/25] qga/commands-posix: Make ga_wait_child() return boolean
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (21 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 22/25] qga: centralize logic for disabling/enabling commands Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 24/25] guest-agent: document allow-rpcs in config file section Konstantin Kostiuk
` (2 subsequent siblings)
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Zhao Liu <zhao1.liu@intel.com>
Make ga_wait_child() return boolean and check the returned boolean
in ga_run_command() instead of dereferencing @errp.
Cc: Michael Roth <michael.roth@amd.com>
Cc: Konstantin Kostiuk <kkostiuk@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Message-ID: <20240716162351.270095-1-zhao1.liu@intel.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-posix.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 578d29f228..c2bd0b4316 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -48,7 +48,7 @@
#endif
#endif
-static void ga_wait_child(pid_t pid, int *status, Error **errp)
+static bool ga_wait_child(pid_t pid, int *status, Error **errp)
{
pid_t rpid;
@@ -59,10 +59,11 @@ static void ga_wait_child(pid_t pid, int *status, Error **errp)
if (rpid == -1) {
error_setg_errno(errp, errno, "failed to wait for child (pid: %d)",
pid);
- return;
+ return false;
}
g_assert(rpid == pid);
+ return true;
}
static ssize_t ga_pipe_read_str(int fd[2], char **str)
@@ -167,8 +168,7 @@ static int ga_run_command(const char *argv[], const char *in_str,
goto out;
}
- ga_wait_child(pid, &status, errp);
- if (*errp) {
+ if (!ga_wait_child(pid, &status, errp)) {
goto out;
}
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 24/25] guest-agent: document allow-rpcs in config file section
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (22 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 23/25] qga/commands-posix: Make ga_wait_child() return boolean Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 25/25] qga/linux: Add new api 'guest-network-get-route' Konstantin Kostiuk
2024-07-23 23:17 ` [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Richard Henderson
25 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Thomas Lamprecht <t.lamprecht@proxmox.com>
While the `allow-rpcs` option is documented in the CLI options
section, it was missing in the section about the configuration file
syntax.
And while it's mentioned that "the list of keys follows the command line
options", having `block-rpcs` there but not `allow-rpcs` seems like
being a potential source of confusion; and as it's cheap to add let's
just do so.
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Message-ID: <20240718140407.444160-1-t.lamprecht@proxmox.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
docs/interop/qemu-ga.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/docs/interop/qemu-ga.rst b/docs/interop/qemu-ga.rst
index fb75cfd8d4..9c7380896a 100644
--- a/docs/interop/qemu-ga.rst
+++ b/docs/interop/qemu-ga.rst
@@ -150,6 +150,7 @@ fsfreeze-hook string
statedir string
verbose boolean
block-rpcs string list
+allow-rpcs string list
============= ===========
See also
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PULL v2 25/25] qga/linux: Add new api 'guest-network-get-route'
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (23 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 24/25] guest-agent: document allow-rpcs in config file section Konstantin Kostiuk
@ 2024-07-23 7:02 ` Konstantin Kostiuk
2024-07-25 10:12 ` Peter Maydell
2024-07-23 23:17 ` [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Richard Henderson
25 siblings, 1 reply; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-23 7:02 UTC (permalink / raw)
To: qemu-devel, Peter Maydell, Stefan Hajnoczi
From: Dehan Meng <demeng@redhat.com>
The Route information of the Linux VM needs to be used
by administrators and users when debugging network problems
and troubleshooting.
Signed-off-by: Dehan Meng <demeng@redhat.com>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Message-ID: <20240613092802.346246-2-demeng@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
---
qga/commands-linux.c | 133 +++++++++++++++++++++++++++++++++++++++++++
qga/qapi-schema.json | 73 ++++++++++++++++++++++++
2 files changed, 206 insertions(+)
diff --git a/qga/commands-linux.c b/qga/commands-linux.c
index 89bdcded01..51d5e3d927 100644
--- a/qga/commands-linux.c
+++ b/qga/commands-linux.c
@@ -28,6 +28,10 @@
#include <libudev.h>
#endif
+#ifdef HAVE_GETIFADDRS
+#include <net/if.h>
+#endif
+
#include <sys/statvfs.h>
#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
@@ -2089,3 +2093,132 @@ GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
fclose(fp);
return head;
}
+
+static char *hexToIPAddress(const void *hexValue, int is_ipv6)
+{
+ if (is_ipv6) {
+ char addr[INET6_ADDRSTRLEN];
+ struct in6_addr in6;
+ const char *hexStr = (const char *)hexValue;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ sscanf(&hexStr[i * 2], "%02hhx", &in6.s6_addr[i]);
+ }
+ inet_ntop(AF_INET6, &in6, addr, INET6_ADDRSTRLEN);
+
+ return g_strdup(addr);
+ } else {
+ unsigned int hexInt = *(unsigned int *)hexValue;
+ unsigned int byte1 = (hexInt >> 24) & 0xFF;
+ unsigned int byte2 = (hexInt >> 16) & 0xFF;
+ unsigned int byte3 = (hexInt >> 8) & 0xFF;
+ unsigned int byte4 = hexInt & 0xFF;
+
+ return g_strdup_printf("%u.%u.%u.%u", byte4, byte3, byte2, byte1);
+ }
+}
+
+GuestNetworkRouteList *qmp_guest_network_get_route(Error **errp)
+{
+ GuestNetworkRouteList *head = NULL, **tail = &head;
+ const char *routeFiles[] = {"/proc/net/route", "/proc/net/ipv6_route"};
+ FILE *fp;
+ size_t n;
+ char *line = NULL;
+ int firstLine;
+ int is_ipv6;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ firstLine = 1;
+ is_ipv6 = (i == 1);
+ fp = fopen(routeFiles[i], "r");
+ if (fp == NULL) {
+ error_setg_errno(errp, errno, "open(\"%s\")", routeFiles[i]);
+ free(line);
+ continue;
+ }
+
+ while (getline(&line, &n, fp) != -1) {
+ if (firstLine && !is_ipv6) {
+ firstLine = 0;
+ continue;
+ }
+ GuestNetworkRoute *route = NULL;
+ GuestNetworkRoute *networkroute;
+ char Iface[IFNAMSIZ];
+ if (is_ipv6) {
+ char Destination[33], Source[33], NextHop[33];
+ int DesPrefixlen, SrcPrefixlen, Metric, RefCnt, Use, Flags;
+
+ /* Parse the line and extract the values */
+ if (sscanf(line, "%32s %x %32s %x %32s %x %x %x %x %s",
+ Destination, &DesPrefixlen, Source,
+ &SrcPrefixlen, NextHop, &Metric, &RefCnt,
+ &Use, &Flags, Iface) != 10) {
+ continue;
+ }
+
+ route = g_new0(GuestNetworkRoute, 1);
+ networkroute = route;
+ networkroute->iface = g_strdup(Iface);
+ networkroute->destination = hexToIPAddress(Destination, 1);
+ networkroute->metric = Metric;
+ networkroute->source = hexToIPAddress(Source, 1);
+ networkroute->desprefixlen = g_strdup_printf(
+ "%d", DesPrefixlen
+ );
+ networkroute->srcprefixlen = g_strdup_printf(
+ "%d", SrcPrefixlen
+ );
+ networkroute->nexthop = hexToIPAddress(NextHop, 1);
+ networkroute->has_flags = true;
+ networkroute->flags = Flags;
+ networkroute->has_refcnt = true;
+ networkroute->refcnt = RefCnt;
+ networkroute->has_use = true;
+ networkroute->use = Use;
+ networkroute->version = 6;
+ } else {
+ unsigned int Destination, Gateway, Mask, Flags;
+ int RefCnt, Use, Metric, MTU, Window, IRTT;
+
+ /* Parse the line and extract the values */
+ if (sscanf(line, "%s %X %X %x %d %d %d %X %d %d %d",
+ Iface, &Destination, &Gateway, &Flags, &RefCnt,
+ &Use, &Metric, &Mask, &MTU, &Window, &IRTT) != 11) {
+ continue;
+ }
+
+ route = g_new0(GuestNetworkRoute, 1);
+ networkroute = route;
+ networkroute->iface = g_strdup(Iface);
+ networkroute->destination = hexToIPAddress(&Destination, 0);
+ networkroute->gateway = hexToIPAddress(&Gateway, 0);
+ networkroute->mask = hexToIPAddress(&Mask, 0);
+ networkroute->metric = Metric;
+ networkroute->has_flags = true;
+ networkroute->flags = Flags;
+ networkroute->has_refcnt = true;
+ networkroute->refcnt = RefCnt;
+ networkroute->has_use = true;
+ networkroute->use = Use;
+ networkroute->has_mtu = true;
+ networkroute->mtu = MTU;
+ networkroute->has_window = true;
+ networkroute->window = Window;
+ networkroute->has_irtt = true;
+ networkroute->irtt = IRTT;
+ networkroute->version = 4;
+ }
+
+ QAPI_LIST_APPEND(tail, route);
+ }
+
+ free(line);
+ fclose(fp);
+ }
+
+ return head;
+}
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index c763163fcd..495706cf73 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -1851,3 +1851,76 @@
'returns': ['GuestCpuStats'],
'if': 'CONFIG_LINUX'
}
+
+##
+# @GuestNetworkRoute:
+#
+# Route information, currently, only linux supported.
+#
+# @iface: The destination network or host's egress network interface in the routing table
+#
+# @destination: The IP address of the target network or host, The final destination of the packet
+#
+# @metric: Route metric
+#
+# @gateway: The IP address of the next hop router
+#
+# @mask: Subnet Mask (IPv4 only)
+#
+# @irtt: Initial round-trip delay (not for windows, IPv4 only)
+#
+# @flags: Route flags (not for windows)
+#
+# @refcnt: The route's reference count (not for windows)
+#
+# @use: Route usage count (not for windows)
+#
+# @window: TCP window size, used for flow control (not for windows, IPv4 only)
+#
+# @mtu: Data link layer maximum packet size (not for windows)
+#
+# @desprefixlen: Destination prefix length (for IPv6)
+#
+# @source: Source IP address (for IPv6)
+#
+# @srcprefixlen: Source prefix length (for IPv6)
+#
+# @nexthop: Next hop IP address (for IPv6)
+#
+# @version: IP version (4 or 6)
+#
+# Since: 9.1
+
+##
+{ 'struct': 'GuestNetworkRoute',
+ 'data': {'iface': 'str',
+ 'destination': 'str',
+ 'metric': 'int',
+ '*gateway': 'str',
+ '*mask': 'str',
+ '*irtt': 'int',
+ '*flags': 'uint64',
+ '*refcnt': 'int',
+ '*use': 'int',
+ '*window': 'int',
+ '*mtu': 'int',
+ '*desprefixlen': 'str',
+ '*source': 'str',
+ '*srcprefixlen': 'str',
+ '*nexthop': 'str',
+ 'version': 'int'
+ },
+ 'if': 'CONFIG_LINUX' }
+
+##
+# @guest-network-get-route:
+#
+# Retrieve information about route of network.
+# Returns: List of route info of guest.
+#
+# Since: 9.1
+##
+{ 'command': 'guest-network-get-route',
+ 'returns': ['GuestNetworkRoute'],
+ 'if': 'CONFIG_LINUX'
+}
--
2.45.2
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
` (24 preceding siblings ...)
2024-07-23 7:02 ` [PULL v2 25/25] qga/linux: Add new api 'guest-network-get-route' Konstantin Kostiuk
@ 2024-07-23 23:17 ` Richard Henderson
25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2024-07-23 23:17 UTC (permalink / raw)
To: Konstantin Kostiuk, qemu-devel, Peter Maydell, Stefan Hajnoczi
On 7/23/24 17:02, Konstantin Kostiuk wrote:
> The following changes since commit 23fa74974d8c96bc95cbecc0d4e2d90f984939f6:
>
> Merge tag 'pull-target-arm-20240718' ofhttps://git.linaro.org/people/pmaydell/qemu-arm into staging (2024-07-19 07:02:17 +1000)
>
> are available in the Git repository at:
>
> https://github.com/kostyanf14/qemu.git tags/qga-pull-2024-07-23
>
> for you to fetch changes up to 8e326d36dd16b91d9abc4963b5f75b8f637c2312:
>
> qga/linux: Add new api 'guest-network-get-route' (2024-07-23 09:49:07 +0300)
>
> ----------------------------------------------------------------
> qga-pull-2024-07-23
>
> v1->v2:
> Fix clang build failure of qga/linux: Add new api 'guest-network-get-route'
Applied, thanks. Please update https://wiki.qemu.org/ChangeLog/9.1 as appropriate.
r~
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PULL v2 25/25] qga/linux: Add new api 'guest-network-get-route'
2024-07-23 7:02 ` [PULL v2 25/25] qga/linux: Add new api 'guest-network-get-route' Konstantin Kostiuk
@ 2024-07-25 10:12 ` Peter Maydell
2024-07-29 7:40 ` Konstantin Kostiuk
0 siblings, 1 reply; 32+ messages in thread
From: Peter Maydell @ 2024-07-25 10:12 UTC (permalink / raw)
To: Konstantin Kostiuk; +Cc: qemu-devel, Stefan Hajnoczi
On Tue, 23 Jul 2024 at 08:03, Konstantin Kostiuk <kkostiuk@redhat.com> wrote:
>
> From: Dehan Meng <demeng@redhat.com>
>
> The Route information of the Linux VM needs to be used
> by administrators and users when debugging network problems
> and troubleshooting.
>
> Signed-off-by: Dehan Meng <demeng@redhat.com>
> Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
> Message-ID: <20240613092802.346246-2-demeng@redhat.com>
> Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Hi; Coverity points out some potential issues with this commit:
> +static char *hexToIPAddress(const void *hexValue, int is_ipv6)
> +{
> + if (is_ipv6) {
> + char addr[INET6_ADDRSTRLEN];
> + struct in6_addr in6;
> + const char *hexStr = (const char *)hexValue;
> + int i;
> +
> + for (i = 0; i < 16; i++) {
> + sscanf(&hexStr[i * 2], "%02hhx", &in6.s6_addr[i]);
We don't check the sscanf() return value here. (CID 1558558)
> + }
> + inet_ntop(AF_INET6, &in6, addr, INET6_ADDRSTRLEN);
> +
> + return g_strdup(addr);
> + } else {
> + unsigned int hexInt = *(unsigned int *)hexValue;
> + unsigned int byte1 = (hexInt >> 24) & 0xFF;
> + unsigned int byte2 = (hexInt >> 16) & 0xFF;
> + unsigned int byte3 = (hexInt >> 8) & 0xFF;
> + unsigned int byte4 = hexInt & 0xFF;
> +
> + return g_strdup_printf("%u.%u.%u.%u", byte4, byte3, byte2, byte1);
> + }
> +}
> +
> +GuestNetworkRouteList *qmp_guest_network_get_route(Error **errp)
> +{
> + GuestNetworkRouteList *head = NULL, **tail = &head;
> + const char *routeFiles[] = {"/proc/net/route", "/proc/net/ipv6_route"};
> + FILE *fp;
> + size_t n;
> + char *line = NULL;
> + int firstLine;
> + int is_ipv6;
> + int i;
The handling of the getline() buffer in this function doesn't
seem to be correct (CID 1558559).
Firstly, the manpage says that to get the initial "allocate me
a buffer", line must be NULL and also n must be 0, but we don't
initialize n here.
> + for (i = 0; i < 2; i++) {
> + firstLine = 1;
> + is_ipv6 = (i == 1);
> + fp = fopen(routeFiles[i], "r");
> + if (fp == NULL) {
> + error_setg_errno(errp, errno, "open(\"%s\")", routeFiles[i]);
> + free(line);
Here we free() line, but we continue the for() loop. So next
time around the loop (assuming the second fopen succeeds)
we'll pass line to getline() and it will be a non-NULL
pointer to freed memory.
Is this error case supposed to exit the for() loop entirely
instead of continuing?
Either way, it shouldn't free(line) here I think.
> + continue;
> + }
> +
> + while (getline(&line, &n, fp) != -1) {
> + if (firstLine && !is_ipv6) {
> + firstLine = 0;
> + continue;
> + }
> + GuestNetworkRoute *route = NULL;
> + GuestNetworkRoute *networkroute;
> + char Iface[IFNAMSIZ];
Our coding style says you shouldn't declare variables in the
middle of a block. Coding style also says variable names are
lowercase with underscores, not CamelCase. (CamelCase is for
typenames.)
> + if (is_ipv6) {
> + char Destination[33], Source[33], NextHop[33];
> + int DesPrefixlen, SrcPrefixlen, Metric, RefCnt, Use, Flags;
> +
> + /* Parse the line and extract the values */
> + if (sscanf(line, "%32s %x %32s %x %32s %x %x %x %x %s",
> + Destination, &DesPrefixlen, Source,
> + &SrcPrefixlen, NextHop, &Metric, &RefCnt,
> + &Use, &Flags, Iface) != 10) {
> + continue;
> + }
> +
> + route = g_new0(GuestNetworkRoute, 1);
> + networkroute = route;
Why do we have separate "route" and "networkroute" variables
here? As far as I can see they are identical and can be merged.
> + networkroute->iface = g_strdup(Iface);
> + networkroute->destination = hexToIPAddress(Destination, 1);
> + networkroute->metric = Metric;
> + networkroute->source = hexToIPAddress(Source, 1);
> + networkroute->desprefixlen = g_strdup_printf(
> + "%d", DesPrefixlen
> + );
> + networkroute->srcprefixlen = g_strdup_printf(
> + "%d", SrcPrefixlen
> + );
> + networkroute->nexthop = hexToIPAddress(NextHop, 1);
> + networkroute->has_flags = true;
> + networkroute->flags = Flags;
> + networkroute->has_refcnt = true;
> + networkroute->refcnt = RefCnt;
> + networkroute->has_use = true;
> + networkroute->use = Use;
> + networkroute->version = 6;
> + } else {
> + unsigned int Destination, Gateway, Mask, Flags;
> + int RefCnt, Use, Metric, MTU, Window, IRTT;
> +
> + /* Parse the line and extract the values */
> + if (sscanf(line, "%s %X %X %x %d %d %d %X %d %d %d",
> + Iface, &Destination, &Gateway, &Flags, &RefCnt,
> + &Use, &Metric, &Mask, &MTU, &Window, &IRTT) != 11) {
> + continue;
> + }
> +
> + route = g_new0(GuestNetworkRoute, 1);
> + networkroute = route;
> + networkroute->iface = g_strdup(Iface);
> + networkroute->destination = hexToIPAddress(&Destination, 0);
> + networkroute->gateway = hexToIPAddress(&Gateway, 0);
> + networkroute->mask = hexToIPAddress(&Mask, 0);
> + networkroute->metric = Metric;
> + networkroute->has_flags = true;
> + networkroute->flags = Flags;
> + networkroute->has_refcnt = true;
> + networkroute->refcnt = RefCnt;
> + networkroute->has_use = true;
> + networkroute->use = Use;
> + networkroute->has_mtu = true;
> + networkroute->mtu = MTU;
> + networkroute->has_window = true;
> + networkroute->window = Window;
> + networkroute->has_irtt = true;
> + networkroute->irtt = IRTT;
> + networkroute->version = 4;
> + }
> +
> + QAPI_LIST_APPEND(tail, route);
> + }
> +
> + free(line);
Similarly here we free(line) but next time around the for()
loop we'll pass it to getline anyway.
> + fclose(fp);
> + }
Since getline() will reallocate the buffer as needed, we don't
need to free it anywhere except right before we exit the
function, here.
> +
> + return head;
> +}
thanks
-- PMM
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PULL v2 25/25] qga/linux: Add new api 'guest-network-get-route'
2024-07-25 10:12 ` Peter Maydell
@ 2024-07-29 7:40 ` Konstantin Kostiuk
2024-07-29 9:35 ` Peter Maydell
0 siblings, 1 reply; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-07-29 7:40 UTC (permalink / raw)
To: Peter Maydell; +Cc: qemu-devel, Stefan Hajnoczi
[-- Attachment #1: Type: text/plain, Size: 7771 bytes --]
Hi Peter,
How to see the full coverity report? In
https://gitlab.com/qemu-project/qemu/-/artifacts, I see only job.log
Do you expect to fix these errors for the 9.1 release?
Best Regards,
Konstantin Kostiuk.
On Thu, Jul 25, 2024 at 1:12 PM Peter Maydell <peter.maydell@linaro.org>
wrote:
> On Tue, 23 Jul 2024 at 08:03, Konstantin Kostiuk <kkostiuk@redhat.com>
> wrote:
> >
> > From: Dehan Meng <demeng@redhat.com>
> >
> > The Route information of the Linux VM needs to be used
> > by administrators and users when debugging network problems
> > and troubleshooting.
> >
> > Signed-off-by: Dehan Meng <demeng@redhat.com>
> > Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
> > Message-ID: <20240613092802.346246-2-demeng@redhat.com>
> > Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
>
> Hi; Coverity points out some potential issues with this commit:
>
> > +static char *hexToIPAddress(const void *hexValue, int is_ipv6)
> > +{
> > + if (is_ipv6) {
> > + char addr[INET6_ADDRSTRLEN];
> > + struct in6_addr in6;
> > + const char *hexStr = (const char *)hexValue;
> > + int i;
> > +
> > + for (i = 0; i < 16; i++) {
> > + sscanf(&hexStr[i * 2], "%02hhx", &in6.s6_addr[i]);
>
> We don't check the sscanf() return value here. (CID 1558558)
>
> > + }
> > + inet_ntop(AF_INET6, &in6, addr, INET6_ADDRSTRLEN);
> > +
> > + return g_strdup(addr);
> > + } else {
> > + unsigned int hexInt = *(unsigned int *)hexValue;
> > + unsigned int byte1 = (hexInt >> 24) & 0xFF;
> > + unsigned int byte2 = (hexInt >> 16) & 0xFF;
> > + unsigned int byte3 = (hexInt >> 8) & 0xFF;
> > + unsigned int byte4 = hexInt & 0xFF;
> > +
> > + return g_strdup_printf("%u.%u.%u.%u", byte4, byte3, byte2,
> byte1);
> > + }
> > +}
> > +
> > +GuestNetworkRouteList *qmp_guest_network_get_route(Error **errp)
> > +{
> > + GuestNetworkRouteList *head = NULL, **tail = &head;
> > + const char *routeFiles[] = {"/proc/net/route",
> "/proc/net/ipv6_route"};
> > + FILE *fp;
> > + size_t n;
> > + char *line = NULL;
> > + int firstLine;
> > + int is_ipv6;
> > + int i;
>
> The handling of the getline() buffer in this function doesn't
> seem to be correct (CID 1558559).
>
> Firstly, the manpage says that to get the initial "allocate me
> a buffer", line must be NULL and also n must be 0, but we don't
> initialize n here.
>
> > + for (i = 0; i < 2; i++) {
> > + firstLine = 1;
> > + is_ipv6 = (i == 1);
> > + fp = fopen(routeFiles[i], "r");
> > + if (fp == NULL) {
> > + error_setg_errno(errp, errno, "open(\"%s\")",
> routeFiles[i]);
> > + free(line);
>
> Here we free() line, but we continue the for() loop. So next
> time around the loop (assuming the second fopen succeeds)
> we'll pass line to getline() and it will be a non-NULL
> pointer to freed memory.
>
> Is this error case supposed to exit the for() loop entirely
> instead of continuing?
>
> Either way, it shouldn't free(line) here I think.
>
> > + continue;
> > + }
> > +
> > + while (getline(&line, &n, fp) != -1) {
> > + if (firstLine && !is_ipv6) {
> > + firstLine = 0;
> > + continue;
> > + }
> > + GuestNetworkRoute *route = NULL;
> > + GuestNetworkRoute *networkroute;
> > + char Iface[IFNAMSIZ];
>
> Our coding style says you shouldn't declare variables in the
> middle of a block. Coding style also says variable names are
> lowercase with underscores, not CamelCase. (CamelCase is for
> typenames.)
>
> > + if (is_ipv6) {
> > + char Destination[33], Source[33], NextHop[33];
> > + int DesPrefixlen, SrcPrefixlen, Metric, RefCnt, Use,
> Flags;
> > +
> > + /* Parse the line and extract the values */
> > + if (sscanf(line, "%32s %x %32s %x %32s %x %x %x %x %s",
> > + Destination, &DesPrefixlen, Source,
> > + &SrcPrefixlen, NextHop, &Metric, &RefCnt,
> > + &Use, &Flags, Iface) != 10) {
> > + continue;
> > + }
> > +
> > + route = g_new0(GuestNetworkRoute, 1);
> > + networkroute = route;
>
> Why do we have separate "route" and "networkroute" variables
> here? As far as I can see they are identical and can be merged.
>
> > + networkroute->iface = g_strdup(Iface);
> > + networkroute->destination = hexToIPAddress(Destination,
> 1);
> > + networkroute->metric = Metric;
> > + networkroute->source = hexToIPAddress(Source, 1);
> > + networkroute->desprefixlen = g_strdup_printf(
> > + "%d", DesPrefixlen
> > + );
> > + networkroute->srcprefixlen = g_strdup_printf(
> > + "%d", SrcPrefixlen
> > + );
> > + networkroute->nexthop = hexToIPAddress(NextHop, 1);
> > + networkroute->has_flags = true;
> > + networkroute->flags = Flags;
> > + networkroute->has_refcnt = true;
> > + networkroute->refcnt = RefCnt;
> > + networkroute->has_use = true;
> > + networkroute->use = Use;
> > + networkroute->version = 6;
> > + } else {
> > + unsigned int Destination, Gateway, Mask, Flags;
> > + int RefCnt, Use, Metric, MTU, Window, IRTT;
> > +
> > + /* Parse the line and extract the values */
> > + if (sscanf(line, "%s %X %X %x %d %d %d %X %d %d %d",
> > + Iface, &Destination, &Gateway, &Flags,
> &RefCnt,
> > + &Use, &Metric, &Mask, &MTU, &Window, &IRTT)
> != 11) {
> > + continue;
> > + }
> > +
> > + route = g_new0(GuestNetworkRoute, 1);
> > + networkroute = route;
> > + networkroute->iface = g_strdup(Iface);
> > + networkroute->destination =
> hexToIPAddress(&Destination, 0);
> > + networkroute->gateway = hexToIPAddress(&Gateway, 0);
> > + networkroute->mask = hexToIPAddress(&Mask, 0);
> > + networkroute->metric = Metric;
> > + networkroute->has_flags = true;
> > + networkroute->flags = Flags;
> > + networkroute->has_refcnt = true;
> > + networkroute->refcnt = RefCnt;
> > + networkroute->has_use = true;
> > + networkroute->use = Use;
> > + networkroute->has_mtu = true;
> > + networkroute->mtu = MTU;
> > + networkroute->has_window = true;
> > + networkroute->window = Window;
> > + networkroute->has_irtt = true;
> > + networkroute->irtt = IRTT;
> > + networkroute->version = 4;
> > + }
> > +
> > + QAPI_LIST_APPEND(tail, route);
> > + }
> > +
> > + free(line);
>
> Similarly here we free(line) but next time around the for()
> loop we'll pass it to getline anyway.
>
> > + fclose(fp);
> > + }
>
> Since getline() will reallocate the buffer as needed, we don't
> need to free it anywhere except right before we exit the
> function, here.
>
> > +
> > + return head;
> > +}
>
> thanks
> -- PMM
>
>
[-- Attachment #2: Type: text/html, Size: 10612 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PULL v2 25/25] qga/linux: Add new api 'guest-network-get-route'
2024-07-29 7:40 ` Konstantin Kostiuk
@ 2024-07-29 9:35 ` Peter Maydell
2024-08-15 14:17 ` Peter Maydell
0 siblings, 1 reply; 32+ messages in thread
From: Peter Maydell @ 2024-07-29 9:35 UTC (permalink / raw)
To: Konstantin Kostiuk; +Cc: qemu-devel, Stefan Hajnoczi
On Mon, 29 Jul 2024 at 08:40, Konstantin Kostiuk <kkostiuk@redhat.com> wrote:
>
> Hi Peter,
>
> How to see the full coverity report? In https://gitlab.com/qemu-project/qemu/-/artifacts, I see only job.log
> Do you expect to fix these errors for the 9.1 release?
Coverity errors are in https://scan.coverity.com/projects/qemu
-- you can ask for an account with the project if you want
to see them directly. But I think you have the information
you need in this email: the actual coverity issue isn't
much more informative.
> Do you expect to fix these errors for the 9.1 release?
No, I post these emails to inform the people responsible
for the original commits about the problem so that they
can provide fixes -- after all, it's the original author
that knows most about the code and how to test it.
thanks
-- PMM
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PULL v2 25/25] qga/linux: Add new api 'guest-network-get-route'
2024-07-29 9:35 ` Peter Maydell
@ 2024-08-15 14:17 ` Peter Maydell
2024-08-19 7:07 ` Konstantin Kostiuk
0 siblings, 1 reply; 32+ messages in thread
From: Peter Maydell @ 2024-08-15 14:17 UTC (permalink / raw)
To: Konstantin Kostiuk; +Cc: qemu-devel, Stefan Hajnoczi
On Mon, 29 Jul 2024 at 10:35, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Mon, 29 Jul 2024 at 08:40, Konstantin Kostiuk <kkostiuk@redhat.com> wrote:
> >
> > Hi Peter,
> >
> > How to see the full coverity report? In https://gitlab.com/qemu-project/qemu/-/artifacts, I see only job.log
> > Do you expect to fix these errors for the 9.1 release?
>
> Coverity errors are in https://scan.coverity.com/projects/qemu
> -- you can ask for an account with the project if you want
> to see them directly. But I think you have the information
> you need in this email: the actual coverity issue isn't
> much more informative.
>
> > Do you expect to fix these errors for the 9.1 release?
>
> No, I post these emails to inform the people responsible
> for the original commits about the problem so that they
> can provide fixes -- after all, it's the original author
> that knows most about the code and how to test it.
Konstantin, are you or Dehan planning to write fixes
for these bugs?
thanks
-- PMM
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PULL v2 25/25] qga/linux: Add new api 'guest-network-get-route'
2024-08-15 14:17 ` Peter Maydell
@ 2024-08-19 7:07 ` Konstantin Kostiuk
0 siblings, 0 replies; 32+ messages in thread
From: Konstantin Kostiuk @ 2024-08-19 7:07 UTC (permalink / raw)
To: Peter Maydell; +Cc: qemu-devel, Stefan Hajnoczi, Dehan Meng, Yan Vugenfirer
[-- Attachment #1: Type: text/plain, Size: 1297 bytes --]
On Thu, Aug 15, 2024 at 5:18 PM Peter Maydell <peter.maydell@linaro.org>
wrote:
> On Mon, 29 Jul 2024 at 10:35, Peter Maydell <peter.maydell@linaro.org>
> wrote:
> >
> > On Mon, 29 Jul 2024 at 08:40, Konstantin Kostiuk <kkostiuk@redhat.com>
> wrote:
> > >
> > > Hi Peter,
> > >
> > > How to see the full coverity report? In
> https://gitlab.com/qemu-project/qemu/-/artifacts, I see only job.log
> > > Do you expect to fix these errors for the 9.1 release?
> >
> > Coverity errors are in https://scan.coverity.com/projects/qemu
> > -- you can ask for an account with the project if you want
> > to see them directly. But I think you have the information
> > you need in this email: the actual coverity issue isn't
> > much more informative.
> >
> > > Do you expect to fix these errors for the 9.1 release?
> >
> > No, I post these emails to inform the people responsible
> > for the original commits about the problem so that they
> > can provide fixes -- after all, it's the original author
> > that knows most about the code and how to test it.
>
> Konstantin, are you or Dehan planning to write fixes
> for these bugs?
>
Hi Peter,
Yes, we plan to fix these bugs for the 9.2 release.
Best Regards,
Konstantin Kostiuk.
>
> thanks
> -- PMM
>
>
[-- Attachment #2: Type: text/html, Size: 2361 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
end of thread, other threads:[~2024-08-19 7:08 UTC | newest]
Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-23 7:02 [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 01/25] qga: drop blocking of guest-get-memory-block-size command Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 02/25] qga: move linux vcpu command impls to commands-linux.c Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 03/25] qga: move linux suspend " Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 04/25] qga: move linux fs/disk " Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 05/25] qga: move linux disk/cpu stats " Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 06/25] qga: move linux memory block " Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 07/25] qga: move CONFIG_FSFREEZE/TRIM to be meson defined options Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 08/25] qga: conditionalize schema for commands unsupported on Windows Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 09/25] qga: conditionalize schema for commands unsupported on non-Linux POSIX Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 10/25] qga: conditionalize schema for commands requiring getifaddrs Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 11/25] qga: conditionalize schema for commands requiring linux/win32 Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 12/25] qga: conditionalize schema for commands only supported on Windows Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 13/25] qga: conditionalize schema for commands requiring fsfreeze Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 14/25] qga: conditionalize schema for commands requiring fstrim Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 15/25] qga: conditionalize schema for commands requiring libudev Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 16/25] qga: conditionalize schema for commands requiring utmpx Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 17/25] qga: conditionalize schema for commands not supported on other UNIX Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 18/25] qga: don't disable fsfreeze commands if vss_init fails Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 19/25] qga: move declare of QGAConfig struct to top of file Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 20/25] qga: remove pointless 'blockrpcs_key' variable Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 21/25] qga: allow configuration file path via the cli Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 22/25] qga: centralize logic for disabling/enabling commands Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 23/25] qga/commands-posix: Make ga_wait_child() return boolean Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 24/25] guest-agent: document allow-rpcs in config file section Konstantin Kostiuk
2024-07-23 7:02 ` [PULL v2 25/25] qga/linux: Add new api 'guest-network-get-route' Konstantin Kostiuk
2024-07-25 10:12 ` Peter Maydell
2024-07-29 7:40 ` Konstantin Kostiuk
2024-07-29 9:35 ` Peter Maydell
2024-08-15 14:17 ` Peter Maydell
2024-08-19 7:07 ` Konstantin Kostiuk
2024-07-23 23:17 ` [PULL v2 00/25] Misc QEMU-GA patches 2024-07-22 Richard Henderson
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).