thebeanogamer / rpms / qemu-kvm

Forked from rpms/qemu-kvm 5 months ago
Clone

Blame SOURCES/kvm-qga-add-implementation-of-guest-get-disks-for-Linux.patch

709dde
From 7be40868e976b12107a0111dcd5ee5fe77e9df61 Mon Sep 17 00:00:00 2001
709dde
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
709dde
Date: Fri, 8 Jan 2021 07:40:58 -0500
709dde
Subject: [PATCH 07/10] qga: add implementation of guest-get-disks for Linux
709dde
MIME-Version: 1.0
709dde
Content-Type: text/plain; charset=UTF-8
709dde
Content-Transfer-Encoding: 8bit
709dde
709dde
RH-Author: Marc-André Lureau <marcandre.lureau@redhat.com>
709dde
Message-id: <20210108074101.290008-8-marcandre.lureau@redhat.com>
709dde
Patchwork-id: 100526
709dde
O-Subject: [RHEL-8.3.0.z qemu-kvm PATCH 07/10] qga: add implementation of guest-get-disks for Linux
709dde
Bugzilla: 1913818
709dde
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
709dde
RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
709dde
RH-Acked-by: Stefano Garzarella <sgarzare@redhat.com>
709dde
709dde
From: Marc-André Lureau <marcandre.lureau@redhat.com>
709dde
709dde
From: Tomáš Golembiovský <tgolembi@redhat.com>
709dde
709dde
The command lists all disks (real and virtual) as well as disk
709dde
partitions. For each disk the list of dependent disks is also listed and
709dde
/dev path is used as a handle so it can be matched with "name" field of
709dde
other returned disk entries. For disk partitions the "dependents" list
709dde
is populated with the the parent device for easier tracking of
709dde
hierarchy.
709dde
709dde
Example output:
709dde
{
709dde
  "return": [
709dde
    ...
709dde
    {
709dde
      "name": "/dev/dm-0",
709dde
      "partition": false,
709dde
      "dependents": [
709dde
        "/dev/sda2"
709dde
      ],
709dde
      "alias": "luks-7062202e-5b9b-433e-81e8-6628c40da9f7"
709dde
    },
709dde
    {
709dde
      "name": "/dev/sda2",
709dde
      "partition": true,
709dde
      "dependents": [
709dde
        "/dev/sda"
709dde
      ]
709dde
    },
709dde
    {
709dde
      "name": "/dev/sda",
709dde
      "partition": false,
709dde
      "address": {
709dde
        "serial": "SAMSUNG_MZ7LN512HCHP-000L1_S1ZKNXAG822493",
709dde
        "bus-type": "sata",
709dde
        ...
709dde
        "dev": "/dev/sda",
709dde
        "target": 0
709dde
      },
709dde
      "dependents": []
709dde
    },
709dde
    ...
709dde
  ]
709dde
}
709dde
709dde
Signed-off-by: Tomáš Golembiovský <tgolembi@redhat.com>
709dde
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
709dde
*add missing stub for !defined(CONFIG_FSFREEZE)
709dde
*remove unused deps_dir variable
709dde
Signed-off-by: Michael Roth <michael.roth@amd.com>
709dde
709dde
(cherry picked from commit fed3956429d560a06fc2d2fcf1a01efb58659f87)
709dde
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
709dde
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
709dde
---
709dde
 qga/commands-posix.c | 303 +++++++++++++++++++++++++++++++++++++++++--
709dde
 1 file changed, 292 insertions(+), 11 deletions(-)
709dde
709dde
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
709dde
index 9b690f3cceb..af80bb7ccbb 100644
709dde
--- a/qga/commands-posix.c
709dde
+++ b/qga/commands-posix.c
709dde
@@ -1091,13 +1091,27 @@ static void build_guest_fsinfo_for_virtual_device(char const *syspath,
709dde
     closedir(dir);
709dde
 }
709dde
 
709dde
+static bool is_disk_virtual(const char *devpath, Error **errp)
709dde
+{
709dde
+    g_autofree char *syspath = realpath(devpath, NULL);
709dde
+
709dde
+    if (!syspath) {
709dde
+        error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
709dde
+        return false;
709dde
+    }
709dde
+    return strstr(syspath, "/devices/virtual/block/") != NULL;
709dde
+}
709dde
+
709dde
 /* Dispatch to functions for virtual/real device */
709dde
 static void build_guest_fsinfo_for_device(char const *devpath,
709dde
                                           GuestFilesystemInfo *fs,
709dde
                                           Error **errp)
709dde
 {
709dde
-    char *syspath = realpath(devpath, NULL);
709dde
+    ERRP_GUARD();
709dde
+    g_autofree char *syspath = NULL;
709dde
+    bool is_virtual = false;
709dde
 
709dde
+    syspath = realpath(devpath, NULL);
709dde
     if (!syspath) {
709dde
         error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
709dde
         return;
709dde
@@ -1108,16 +1122,281 @@ static void build_guest_fsinfo_for_device(char const *devpath,
709dde
     }
709dde
 
709dde
     g_debug("  parse sysfs path '%s'", syspath);
709dde
-
709dde
-    if (strstr(syspath, "/devices/virtual/block/")) {
709dde
+    is_virtual = is_disk_virtual(syspath, errp);
709dde
+    if (*errp != NULL) {
709dde
+        return;
709dde
+    }
709dde
+    if (is_virtual) {
709dde
         build_guest_fsinfo_for_virtual_device(syspath, fs, errp);
709dde
     } else {
709dde
         build_guest_fsinfo_for_real_device(syspath, fs, errp);
709dde
     }
709dde
+}
709dde
+
709dde
+#ifdef CONFIG_LIBUDEV
709dde
+
709dde
+/*
709dde
+ * Wrapper around build_guest_fsinfo_for_device() for getting just
709dde
+ * the disk address.
709dde
+ */
709dde
+static GuestDiskAddress *get_disk_address(const char *syspath, Error **errp)
709dde
+{
709dde
+    g_autoptr(GuestFilesystemInfo) fs = NULL;
709dde
 
709dde
-    free(syspath);
709dde
+    fs = g_new0(GuestFilesystemInfo, 1);
709dde
+    build_guest_fsinfo_for_device(syspath, fs, errp);
709dde
+    if (fs->disk != NULL) {
709dde
+        return g_steal_pointer(&fs->disk->value);
709dde
+    }
709dde
+    return NULL;
709dde
 }
709dde
 
709dde
+static char *get_alias_for_syspath(const char *syspath)
709dde
+{
709dde
+    struct udev *udev = NULL;
709dde
+    struct udev_device *udevice = NULL;
709dde
+    char *ret = NULL;
709dde
+
709dde
+    udev = udev_new();
709dde
+    if (udev == NULL) {
709dde
+        g_debug("failed to query udev");
709dde
+        goto out;
709dde
+    }
709dde
+    udevice = udev_device_new_from_syspath(udev, syspath);
709dde
+    if (udevice == NULL) {
709dde
+        g_debug("failed to query udev for path: %s", syspath);
709dde
+        goto out;
709dde
+    } else {
709dde
+        const char *alias = udev_device_get_property_value(
709dde
+            udevice, "DM_NAME");
709dde
+        /*
709dde
+         * NULL means there was an error and empty string means there is no
709dde
+         * alias. In case of no alias we return NULL instead of empty string.
709dde
+         */
709dde
+        if (alias == NULL) {
709dde
+            g_debug("failed to query udev for device alias for: %s",
709dde
+                syspath);
709dde
+        } else if (*alias != 0) {
709dde
+            ret = g_strdup(alias);
709dde
+        }
709dde
+    }
709dde
+
709dde
+out:
709dde
+    udev_unref(udev);
709dde
+    udev_device_unref(udevice);
709dde
+    return ret;
709dde
+}
709dde
+
709dde
+static char *get_device_for_syspath(const char *syspath)
709dde
+{
709dde
+    struct udev *udev = NULL;
709dde
+    struct udev_device *udevice = NULL;
709dde
+    char *ret = NULL;
709dde
+
709dde
+    udev = udev_new();
709dde
+    if (udev == NULL) {
709dde
+        g_debug("failed to query udev");
709dde
+        goto out;
709dde
+    }
709dde
+    udevice = udev_device_new_from_syspath(udev, syspath);
709dde
+    if (udevice == NULL) {
709dde
+        g_debug("failed to query udev for path: %s", syspath);
709dde
+        goto out;
709dde
+    } else {
709dde
+        ret = g_strdup(udev_device_get_devnode(udevice));
709dde
+    }
709dde
+
709dde
+out:
709dde
+    udev_unref(udev);
709dde
+    udev_device_unref(udevice);
709dde
+    return ret;
709dde
+}
709dde
+
709dde
+static void get_disk_deps(const char *disk_dir, GuestDiskInfo *disk)
709dde
+{
709dde
+    g_autofree char *deps_dir = NULL;
709dde
+    const gchar *dep;
709dde
+    GDir *dp_deps = NULL;
709dde
+
709dde
+    /* List dependent disks */
709dde
+    deps_dir = g_strdup_printf("%s/slaves", disk_dir);
709dde
+    g_debug("  listing entries in: %s", deps_dir);
709dde
+    dp_deps = g_dir_open(deps_dir, 0, NULL);
709dde
+    if (dp_deps == NULL) {
709dde
+        g_debug("failed to list entries in %s", deps_dir);
709dde
+        return;
709dde
+    }
709dde
+    while ((dep = g_dir_read_name(dp_deps)) != NULL) {
709dde
+        g_autofree char *dep_dir = NULL;
709dde
+        strList *dep_item = NULL;
709dde
+        char *dev_name;
709dde
+
709dde
+        /* Add dependent disks */
709dde
+        dep_dir = g_strdup_printf("%s/%s", deps_dir, dep);
709dde
+        dev_name = get_device_for_syspath(dep_dir);
709dde
+        if (dev_name != NULL) {
709dde
+            g_debug("  adding dependent device: %s", dev_name);
709dde
+            dep_item = g_new0(strList, 1);
709dde
+            dep_item->value = dev_name;
709dde
+            dep_item->next = disk->dependents;
709dde
+            disk->dependents = dep_item;
709dde
+        }
709dde
+    }
709dde
+    g_dir_close(dp_deps);
709dde
+}
709dde
+
709dde
+/*
709dde
+ * Detect partitions subdirectory, name is "<disk_name><number>" or
709dde
+ * "<disk_name>p<number>"
709dde
+ *
709dde
+ * @disk_name -- last component of /sys path (e.g. sda)
709dde
+ * @disk_dir -- sys path of the disk (e.g. /sys/block/sda)
709dde
+ * @disk_dev -- device node of the disk (e.g. /dev/sda)
709dde
+ */
709dde
+static GuestDiskInfoList *get_disk_partitions(
709dde
+    GuestDiskInfoList *list,
709dde
+    const char *disk_name, const char *disk_dir,
709dde
+    const char *disk_dev)
709dde
+{
709dde
+    GuestDiskInfoList *item, *ret = list;
709dde
+    struct dirent *de_disk;
709dde
+    DIR *dp_disk = NULL;
709dde
+    size_t len = strlen(disk_name);
709dde
+
709dde
+    dp_disk = opendir(disk_dir);
709dde
+    while ((de_disk = readdir(dp_disk)) != NULL) {
709dde
+        g_autofree char *partition_dir = NULL;
709dde
+        char *dev_name;
709dde
+        GuestDiskInfo *partition;
709dde
+
709dde
+        if (!(de_disk->d_type & DT_DIR)) {
709dde
+            continue;
709dde
+        }
709dde
+
709dde
+        if (!(strncmp(disk_name, de_disk->d_name, len) == 0 &&
709dde
+            ((*(de_disk->d_name + len) == 'p' &&
709dde
+            isdigit(*(de_disk->d_name + len + 1))) ||
709dde
+                isdigit(*(de_disk->d_name + len))))) {
709dde
+            continue;
709dde
+        }
709dde
+
709dde
+        partition_dir = g_strdup_printf("%s/%s",
709dde
+            disk_dir, de_disk->d_name);
709dde
+        dev_name = get_device_for_syspath(partition_dir);
709dde
+        if (dev_name == NULL) {
709dde
+            g_debug("Failed to get device name for syspath: %s",
709dde
+                disk_dir);
709dde
+            continue;
709dde
+        }
709dde
+        partition = g_new0(GuestDiskInfo, 1);
709dde
+        partition->name = dev_name;
709dde
+        partition->partition = true;
709dde
+        /* Add parent disk as dependent for easier tracking of hierarchy */
709dde
+        partition->dependents = g_new0(strList, 1);
709dde
+        partition->dependents->value = g_strdup(disk_dev);
709dde
+
709dde
+        item = g_new0(GuestDiskInfoList, 1);
709dde
+        item->value = partition;
709dde
+        item->next = ret;
709dde
+        ret = item;
709dde
+
709dde
+    }
709dde
+    closedir(dp_disk);
709dde
+
709dde
+    return ret;
709dde
+}
709dde
+
709dde
+GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
709dde
+{
709dde
+    GuestDiskInfoList *item, *ret = NULL;
709dde
+    GuestDiskInfo *disk;
709dde
+    DIR *dp = NULL;
709dde
+    struct dirent *de = NULL;
709dde
+
709dde
+    g_debug("listing /sys/block directory");
709dde
+    dp = opendir("/sys/block");
709dde
+    if (dp == NULL) {
709dde
+        error_setg_errno(errp, errno, "Can't open directory \"/sys/block\"");
709dde
+        return NULL;
709dde
+    }
709dde
+    while ((de = readdir(dp)) != NULL) {
709dde
+        g_autofree char *disk_dir = NULL, *line = NULL,
709dde
+            *size_path = NULL;
709dde
+        char *dev_name;
709dde
+        Error *local_err = NULL;
709dde
+        if (de->d_type != DT_LNK) {
709dde
+            g_debug("  skipping entry: %s", de->d_name);
709dde
+            continue;
709dde
+        }
709dde
+
709dde
+        /* Check size and skip zero-sized disks */
709dde
+        g_debug("  checking disk size");
709dde
+        size_path = g_strdup_printf("/sys/block/%s/size", de->d_name);
709dde
+        if (!g_file_get_contents(size_path, &line, NULL, NULL)) {
709dde
+            g_debug("  failed to read disk size");
709dde
+            continue;
709dde
+        }
709dde
+        if (g_strcmp0(line, "0\n") == 0) {
709dde
+            g_debug("  skipping zero-sized disk");
709dde
+            continue;
709dde
+        }
709dde
+
709dde
+        g_debug("  adding %s", de->d_name);
709dde
+        disk_dir = g_strdup_printf("/sys/block/%s", de->d_name);
709dde
+        dev_name = get_device_for_syspath(disk_dir);
709dde
+        if (dev_name == NULL) {
709dde
+            g_debug("Failed to get device name for syspath: %s",
709dde
+                disk_dir);
709dde
+            continue;
709dde
+        }
709dde
+        disk = g_new0(GuestDiskInfo, 1);
709dde
+        disk->name = dev_name;
709dde
+        disk->partition = false;
709dde
+        disk->alias = get_alias_for_syspath(disk_dir);
709dde
+        disk->has_alias = (disk->alias != NULL);
709dde
+        item = g_new0(GuestDiskInfoList, 1);
709dde
+        item->value = disk;
709dde
+        item->next = ret;
709dde
+        ret = item;
709dde
+
709dde
+        /* Get address for non-virtual devices */
709dde
+        bool is_virtual = is_disk_virtual(disk_dir, &local_err);
709dde
+        if (local_err != NULL) {
709dde
+            g_debug("  failed to check disk path, ignoring error: %s",
709dde
+                error_get_pretty(local_err));
709dde
+            error_free(local_err);
709dde
+            local_err = NULL;
709dde
+            /* Don't try to get the address */
709dde
+            is_virtual = true;
709dde
+        }
709dde
+        if (!is_virtual) {
709dde
+            disk->address = get_disk_address(disk_dir, &local_err);
709dde
+            if (local_err != NULL) {
709dde
+                g_debug("  failed to get device info, ignoring error: %s",
709dde
+                    error_get_pretty(local_err));
709dde
+                error_free(local_err);
709dde
+                local_err = NULL;
709dde
+            } else if (disk->address != NULL) {
709dde
+                disk->has_address = true;
709dde
+            }
709dde
+        }
709dde
+
709dde
+        get_disk_deps(disk_dir, disk);
709dde
+        ret = get_disk_partitions(ret, de->d_name, disk_dir, dev_name);
709dde
+    }
709dde
+    return ret;
709dde
+}
709dde
+
709dde
+#else
709dde
+
709dde
+GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
709dde
+{
709dde
+    error_setg(errp, QERR_UNSUPPORTED);
709dde
+    return NULL;
709dde
+}
709dde
+
709dde
+#endif
709dde
+
709dde
 /* Return a list of the disk device(s)' info which @mount lies on */
709dde
 static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount,
709dde
                                                Error **errp)
709dde
@@ -2709,6 +2988,13 @@ int64_t qmp_guest_fsfreeze_thaw(Error **errp)
709dde
 
709dde
     return 0;
709dde
 }
709dde
+
709dde
+GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
709dde
+{
709dde
+    error_setg(errp, QERR_UNSUPPORTED);
709dde
+    return NULL;
709dde
+}
709dde
+
709dde
 #endif /* CONFIG_FSFREEZE */
709dde
 
709dde
 #if !defined(CONFIG_FSTRIM)
709dde
@@ -2745,7 +3031,8 @@ GList *ga_command_blacklist_init(GList *blacklist)
709dde
         const char *list[] = {
709dde
             "guest-get-fsinfo", "guest-fsfreeze-status",
709dde
             "guest-fsfreeze-freeze", "guest-fsfreeze-freeze-list",
709dde
-            "guest-fsfreeze-thaw", "guest-get-fsinfo", NULL};
709dde
+            "guest-fsfreeze-thaw", "guest-get-fsinfo",
709dde
+            "guest-get-disks", NULL};
709dde
         char **p = (char **)list;
709dde
 
709dde
         while (*p) {
709dde
@@ -2978,9 +3265,3 @@ GuestOSInfo *qmp_guest_get_osinfo(Error **errp)
709dde
 
709dde
     return info;
709dde
 }
709dde
-
709dde
-GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
709dde
-{
709dde
-    error_setg(errp, QERR_UNSUPPORTED);
709dde
-    return NULL;
709dde
-}
709dde
-- 
709dde
2.27.0
709dde