All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 0/2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
@ 2014-05-22 13:56 Tomoki Sekiyama
  2014-05-22 13:56 ` [Qemu-devel] [PATCH v3 1/2] " Tomoki Sekiyama
  2014-05-22 13:56 ` [Qemu-devel] [PATCH v3 2/2] qga: Add guest-get-fs-info command Tomoki Sekiyama
  0 siblings, 2 replies; 10+ messages in thread
From: Tomoki Sekiyama @ 2014-05-22 13:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: mitsuhiro.tanino, mdroth

Hi,

This is v3 patch for qemu-ga to add argument to specify which filesystems
to be frozen by guest-fsfreeze-freeze command.

Changes since v2:
 - new PATCH 2/2 to add a command 'guest-get-fs-info' get mounted
   filesysmtes information
 - rebased to latest master
 (v2: http://lists.gnu.org/archive/html/qemu-devel/2014-04/msg04433.html)

---
Tomoki Sekiyama (2):
      qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
      qga: Add guest-get-fs-info command


 qga/commands-posix.c |  437 ++++++++++++++++++++++++++++++++++++++++++++++++++
 qga/commands-win32.c |    3 
 qga/qapi-schema.json |   82 +++++++++
 3 files changed, 519 insertions(+), 3 deletions(-)

-- 
Regards,
Tomoki Sekiyama

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 1/2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
  2014-05-22 13:56 [Qemu-devel] [PATCH v3 0/2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command Tomoki Sekiyama
@ 2014-05-22 13:56 ` Tomoki Sekiyama
  2014-06-03 21:21   ` Michael Roth
  2014-05-22 13:56 ` [Qemu-devel] [PATCH v3 2/2] qga: Add guest-get-fs-info command Tomoki Sekiyama
  1 sibling, 1 reply; 10+ messages in thread
From: Tomoki Sekiyama @ 2014-05-22 13:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: mitsuhiro.tanino, mdroth

When an array of mount point paths is specified as 'mountpoints' argument
of guest-fsfreeze-freeze, qemu-ga with this patch will only freeze the file
systems mounted on specified paths in Linux.
This would be useful when the host wants to create partial disk snapshots.

Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama@hds.com>
---
 qga/commands-posix.c |   17 ++++++++++++++++-
 qga/commands-win32.c |    3 ++-
 qga/qapi-schema.json |    4 ++++
 3 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 34ddba0..771f00c 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -714,9 +714,11 @@ GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
  * Walk list of mounted file systems in the guest, and freeze the ones which
  * are real local file systems.
  */
-int64_t qmp_guest_fsfreeze_freeze(Error **errp)
+int64_t qmp_guest_fsfreeze_freeze(bool has_mountpoints, strList *mountpoints,
+                                  Error **errp)
 {
     int ret = 0, i = 0;
+    strList *list;
     FsMountList mounts;
     struct FsMount *mount;
     Error *local_err = NULL;
@@ -741,6 +743,19 @@ int64_t qmp_guest_fsfreeze_freeze(Error **errp)
     ga_set_frozen(ga_state);
 
     QTAILQ_FOREACH_REVERSE(mount, &mounts, FsMountList, next) {
+        /* To issue fsfreeze in the reverse order of mounts, check if the
+         * mount is listed in the list here */
+        if (has_mountpoints) {
+            for (list = mountpoints; list; list = list->next) {
+                if (strcmp(list->value, mount->dirname) == 0) {
+                    break;
+                }
+            }
+            if (!list) {
+                continue;
+            }
+        }
+
         fd = qemu_open(mount->dirname, O_RDONLY);
         if (fd == -1) {
             error_setg_errno(errp, errno, "failed to open %s", mount->dirname);
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index d793dd0..0c6296d 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -171,7 +171,8 @@ GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
  * Freeze local file systems using Volume Shadow-copy Service.
  * The frozen state is limited for up to 10 seconds by VSS.
  */
-int64_t qmp_guest_fsfreeze_freeze(Error **errp)
+int64_t qmp_guest_fsfreeze_freeze(bool has_mountpoints, strList *mountpoints,
+                                  Error **errp)
 {
     int i;
     Error *local_err = NULL;
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index a8cdcb3..31c0dc8 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -378,12 +378,16 @@
 #
 # Sync and freeze all freezable, local guest filesystems
 #
+# @mountpoints: #optional an array of mountpoints of filesystems to be frozen.
+#               If omitted, every mounted filesystem is frozen. (Since: 2.1)
+#
 # Returns: Number of file systems currently frozen. On error, all filesystems
 # will be thawed.
 #
 # Since: 0.15.0
 ##
 { 'command': 'guest-fsfreeze-freeze',
+  'data':    { '*mountpoints': ['str'] },
   'returns': 'int' }
 
 ##

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 2/2] qga: Add guest-get-fs-info command
  2014-05-22 13:56 [Qemu-devel] [PATCH v3 0/2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command Tomoki Sekiyama
  2014-05-22 13:56 ` [Qemu-devel] [PATCH v3 1/2] " Tomoki Sekiyama
@ 2014-05-22 13:56 ` Tomoki Sekiyama
  1 sibling, 0 replies; 10+ messages in thread
From: Tomoki Sekiyama @ 2014-05-22 13:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: mitsuhiro.tanino, mdroth

Add command to get mounted filesystems information in the guest.
The returned value contains a list of mountpoint paths and
corresponding disks info such as disk bus type, drive address,
and the disk controllers' PCI addresses, so that management layer
such as libvirt can resolve the disk backends.

For example, when `lsblk' result is:

    NAME           MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
    sdb              8:16   0    1G  0 disk
    `-sdb1           8:17   0 1024M  0 part
      `-vg0-lv0    253:1    0  1.4G  0 lvm  /mnt/test
    sdc              8:32   0    1G  0 disk
    `-sdc1           8:33   0  512M  0 part
      `-vg0-lv0    253:1    0  1.4G  0 lvm  /mnt/test
    vda            252:0    0   25G  0 disk
    `-vda1         252:1    0   25G  0 part /

where sdb is a SCSI disk with PCI controller 0000:00:0a.0 and ID=1,
      sdc is an IDE disk with PCI controller 0000:00:01.1, and
      vda is a virtio-blk disk with PCI device 0000:00:06.0,

guest-get-fs-info command will return the following result:

    {"return":
     [{"name":"dm-1",
       "mountpoint":"/mnt/test",
       "disk":[
        {"bus-type":"scsi","bus":0,"unit":1,"target":0,
         "pci-controller":{"bus":0,"slot":10,"domain":0,"function":0}},
        {"bus-type":"ide","bus":0,"unit":0,"target":0,
         "pci-controller":{"bus":0,"slot":1,"domain":0,"function":1}}],
       "type":"xfs"},
      {"name":"vda1", "mountpoint":"/",
       "disk":[
        {"bus-type":"virtio","bus":0,"unit":0,"target":0,
         "pci-controller":{"bus":0,"slot":6,"domain":0,"function":0}}],
       "type":"ext4"}]}

In Linux guest, the disk information is resolved from sysfs. So far,
it only supports virtio-blk, virtio-scsi, IDE, SATA, SCSI disks on x86
hosts, and "disk" parameter may be empty for unsupported disk types.

Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama@hds.com>
---
 qga/commands-posix.c |  420 ++++++++++++++++++++++++++++++++++++++++++++++++++
 qga/qapi-schema.json |   78 +++++++++
 2 files changed, 497 insertions(+), 1 deletion(-)

diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 771f00c..c7a2c09 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -18,6 +18,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <dirent.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/stat.h>
@@ -575,6 +576,7 @@ static void guest_file_init(void)
 typedef struct FsMount {
     char *dirname;
     char *devtype;
+    unsigned int devmajor, devminor;
     QTAILQ_ENTRY(FsMount) next;
 } FsMount;
 
@@ -596,15 +598,40 @@ static void free_fs_mount_list(FsMountList *mounts)
      }
 }
 
+static int dev_major_minor(const char *devpath,
+                           unsigned int *devmajor, unsigned int *devminor)
+{
+    struct stat st;
+
+    *devmajor = 0;
+    *devminor = 0;
+
+    if (stat(devpath, &st) < 0) {
+        slog("failed to stat device file '%s': %s", devpath, strerror(errno));
+        return -1;
+    }
+    if (S_ISDIR(st.st_mode)) {
+        /* It is bind mount */
+        return -2;
+    }
+    if (S_ISBLK(st.st_mode)) {
+        *devmajor = major(st.st_rdev);
+        *devminor = minor(st.st_rdev);
+        return 0;
+    }
+    return -1;
+}
+
 /*
  * Walk the mount table and build a list of local file systems
  */
-static void build_fs_mount_list(FsMountList *mounts, Error **errp)
+static void build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp)
 {
     struct mntent *ment;
     FsMount *mount;
     char const *mtab = "/proc/self/mounts";
     FILE *fp;
+    unsigned int devmajor, devminor;
 
     fp = setmntent(mtab, "r");
     if (!fp) {
@@ -624,20 +651,368 @@ static void build_fs_mount_list(FsMountList *mounts, Error **errp)
             (strcmp(ment->mnt_type, "cifs") == 0)) {
             continue;
         }
+        if (dev_major_minor(ment->mnt_fsname, &devmajor, &devminor) == -2) {
+            /* Skip bind mounts */
+            continue;
+        }
 
         mount = g_malloc0(sizeof(FsMount));
         mount->dirname = g_strdup(ment->mnt_dir);
         mount->devtype = g_strdup(ment->mnt_type);
+        mount->devmajor = devmajor;
+        mount->devminor = devminor;
 
         QTAILQ_INSERT_TAIL(mounts, mount, next);
     }
 
     endmntent(fp);
 }
+
+static void decode_mntname(char *name, int len)
+{
+    int i, j = 0;
+    for (i = 0; i <= len; i++) {
+        if (name[i] != '\\') {
+            name[j++] = name[i];
+        } else if (name[i+1] == '\\') {
+            name[j++] = '\\';
+            i++;
+        } else if (name[i+1] == '0' && name[i+2] == '4' && name[i+3] == '0') {
+            name[j++] = ' ';
+            i += 3;
+        } else if (name[i+1] == '0' && name[i+2] == '1' && name[i+3] == '1') {
+            name[j++] = '\t';
+            i += 3;
+        } else if (name[i+1] == '0' && name[i+2] == '1' && name[i+3] == '2') {
+            name[j++] = '\n';
+            i += 3;
+        } else if (name[i+1] == '1' && name[i+2] == '3' && name[i+3] == '4') {
+            name[j++] = '\\';
+            i += 3;
+        } else {
+            name[j++] = name[i];
+        }
+    }
+}
+
+static void build_fs_mount_list(FsMountList *mounts, Error **errp)
+{
+    FsMount *mount;
+    char const *mountinfo = "/proc/self/mountinfo";
+    FILE *fp;
+    char *line = NULL;
+    size_t n;
+    char check;
+    unsigned int devmajor, devminor;
+    int ret, dir_s, dir_e, type_s, type_e, dev_s, dev_e;
+
+    fp = fopen(mountinfo, "r");
+    if (!fp) {
+        build_fs_mount_list_from_mtab(mounts, errp);
+        return;
+    }
+
+    while (getline(&line, &n, fp) != -1) {
+        ret = sscanf(line,
+                     "%*u %*u %u:%u %*s %n%*s%n %*s %*s %*s %n%*s%n %n%*s%n%c",
+                     &devmajor, &devminor, &dir_s, &dir_e, &type_s, &type_e,
+                     &dev_s, &dev_e, &check);
+        if (ret < 3) {
+            continue;
+        }
+        line[dir_e] = 0;
+        line[type_e] = 0;
+        line[dev_e] = 0;
+        decode_mntname(line+dir_s, dir_e-dir_s);
+        decode_mntname(line+dev_s, dev_e-dev_s);
+        if (devmajor == 0) {
+            /* btrfs reports major number = 0 */
+            if (strcmp("btrfs", line+type_s) != 0 ||
+                dev_major_minor(line+dev_s, &devmajor, &devminor) < 0) {
+                continue;
+            }
+        }
+
+        mount = g_malloc0(sizeof(FsMount));
+        mount->dirname = g_strdup(line+dir_s);
+        mount->devtype = g_strdup(line+type_s);
+        mount->devmajor = devmajor;
+        mount->devminor = devminor;
+
+        QTAILQ_INSERT_TAIL(mounts, mount, next);
+    }
+    free(line);
+
+    fclose(fp);
+}
 #endif
 
 #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_strdup(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 path and build a sorted list of ata port numbers */
+static int build_ata_ports(char const *syspath, char const *ata,
+                           unsigned int *ports, int ports_max, Error **errp)
+{
+    char *path;
+    DIR *dir;
+    struct dirent *entry;
+    int i = 0;
+
+    path = g_strndup(syspath, ata - syspath);
+    dir = opendir(path);
+    if (!dir) {
+        error_setg_errno(errp, errno, "opendir(\"%s\")", path);
+        g_free(path);
+        return -1;
+    }
+
+    while (i < ports_max) {
+        entry = readdir(dir);
+        if (!entry) {
+            break;
+        }
+        if (sscanf(entry->d_name, "ata%d", ports+i) == 1) {
+            ++i;
+        }
+    }
+
+    qsort(ports, i, sizeof(ports[0]), compare_uint);
+
+    g_free(path);
+    closedir(dir);
+    return i;
+}
+
+static bool __build_mounted_fs_info(char const *syspath,
+                                    GuestFilesystemInfo *fs, Error **errp)
+{
+    unsigned int pci[4], ata, tgt[3], ports[8];
+    int i, nports = 0, pcilen;
+    GuestDiskAddress *disk;
+    GuestPCIAddress *pciaddr;
+    GuestDiskAddressList *list = NULL;
+    bool has_ata = false, has_tgt = false;
+    char *p, *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) {
+        slog("only pci device is supported: sysfs path \"%s\"", syspath);
+        return false;
+    }
+
+    driver = get_pci_driver(syspath, (p+12+pcilen)-syspath, errp);
+    if (!driver) {
+        goto cleanup;
+    }
+
+    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 && sscanf(p+4, "%u", &ata) == 1) {
+        has_ata = true;
+        nports = build_ata_ports(syspath, p, ports,
+                                 sizeof(ports)/sizeof(ports[0]), errp);
+    }
+
+    pciaddr = g_malloc0(sizeof(*pciaddr));
+    pciaddr->domain = pci[0];
+    pciaddr->bus = pci[1];
+    pciaddr->slot = pci[2];
+    pciaddr->function = pci[3];
+
+    disk = g_malloc0(sizeof(*disk));
+    disk->pci_controller = pciaddr;
+
+    list = g_malloc0(sizeof(*list));
+    list->value = disk;
+
+    if (strcmp(driver, "ata_piix") == 0) {
+        /* an ata port per ide bus, target*:0:<unit>:0 */
+        if (!has_ata || !has_tgt) {
+            goto cleanup;
+        }
+        for (i = 0; i < nports; i++) {
+            if (ata == ports[i]) {
+                disk->bus_type = GUEST_DISK_BUS_TYPE_IDE;
+                disk->bus = i;
+                disk->unit = tgt[1];
+                goto ok;
+            }
+        }
+        goto cleanup;
+    } else if (strcmp(driver, "sym53c8xx") == 0) {
+        /* scsi(LSI Logic): target*:0:<unit>:0 */
+        if (!has_tgt) {
+            goto cleanup;
+        }
+        disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
+        disk->unit = tgt[1];
+        goto ok;
+    } 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;
+        }
+        goto ok;
+    } else if (strcmp(driver, "ahci") == 0) {
+        /* ahci: an ata port per unit */
+        if (!has_ata || !has_tgt) {
+            goto cleanup;
+        }
+        for (i = 0; i < nports; i++) {
+            if (ata == ports[i]) {
+                disk->unit = i;
+                disk->bus_type = GUEST_DISK_BUS_TYPE_SATA;
+                goto ok;
+            }
+        }
+    } else {
+        g_debug("unknown driver '%s' (sysfs path '%s')", driver, syspath);
+        goto cleanup;
+    }
+
+ok:
+    ret = true;
+    list->next = fs->disk;
+    fs->disk = list;
+
+cleanup:
+    g_free(driver);
+    if (!ret && list) {
+        qapi_free_GuestDiskAddressList(list);
+    }
+    return ret;
+}
+
+static bool _build_mounted_fs_info(char const *dirpath,
+                                   GuestFilesystemInfo *fs, Error **errp);
+
+/* Return true if some of slave devices of virtual volume specified by @syspath
+ * are listed in @disks */
+static bool __build_mounted_fs_info_virtual(char const *syspath,
+                                            GuestFilesystemInfo *fs,
+                                            Error **errp)
+{
+    bool ret = false;
+    DIR *dir;
+    char *dirpath;
+    struct dirent entry, *result;
+
+    dirpath = g_strdup_printf("%s/slaves", syspath);
+    dir = opendir(dirpath);
+    if (!dir) {
+        error_setg_errno(errp, errno, "opendir(\"%s\")", dirpath);
+        g_free(dirpath);
+        return false;
+    }
+    g_free(dirpath);
+
+    for (;;) {
+        if (readdir_r(dir, &entry, &result) != 0) {
+            error_setg_errno(errp, errno, "readdir_r(\"%s\")", dirpath);
+            break;
+        }
+        if (!result) {
+            break;
+        }
+
+        if (entry.d_type == DT_LNK) {
+            g_debug(" slave device '%s'", entry.d_name);
+            dirpath = g_strdup_printf("%s/slaves/%s", syspath, entry.d_name);
+            ret = _build_mounted_fs_info(dirpath, fs, errp) || ret;
+            g_free(dirpath);
+
+            if (error_is_set(errp)) {
+                break;
+            }
+        }
+    }
+
+    closedir(dir);
+    return ret;
+}
+
+static bool _build_mounted_fs_info(char const *dirpath,
+                                   GuestFilesystemInfo *fs, Error **errp)
+{
+    char *syspath = realpath(dirpath, NULL);
+    bool ret;
+
+    if (!syspath) {
+        error_setg_errno(errp, errno, "realpath(\"%s\")", dirpath);
+        return false;
+    }
+
+    if (!fs->name) {
+        fs->name = g_strdup(basename(syspath));
+    }
+
+    g_debug("  parse sysfs path '%s'", syspath);
+
+    if (strstr(syspath, "/devices/virtual/block/")) {
+        ret = __build_mounted_fs_info_virtual(syspath, fs, errp);
+    } else {
+        ret = __build_mounted_fs_info(syspath, fs, errp);
+    }
+
+    free(syspath);
+    return ret;
+}
+
+/* Return true if @mount is on the disk device(s) listed in @disks. */
+static GuestFilesystemInfo *build_mounted_fs_info(struct FsMount *mount,
+                                                  Error **errp)
+{
+    GuestFilesystemInfo *fs = g_malloc0(sizeof(*fs));
+    char *dirpath = 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_mounted_fs_info(dirpath, fs, errp);
+
+    g_free(dirpath);
+    return fs;
+}
+
+
 typedef enum {
     FSFREEZE_HOOK_THAW = 0,
     FSFREEZE_HOOK_FREEZE,
@@ -1436,6 +1811,44 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
     return processed;
 }
 
+GuestFilesystemInfoList *qmp_guest_get_fs_info(Error **errp)
+{
+    FsMountList mounts;
+    struct FsMount *mount;
+    GuestFilesystemInfoList *new, *ret = NULL;
+    GuestFilesystemInfo *fs;
+    Error *local_err = NULL;
+
+    QTAILQ_INIT(&mounts);
+    build_fs_mount_list(&mounts, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return NULL;
+    }
+
+    QTAILQ_FOREACH(mount, &mounts, next) {
+        g_debug("Building mounted fs info for '%s'", mount->dirname);
+
+        fs = build_mounted_fs_info(mount, &local_err);
+        if (!fs) {
+            continue;
+        }
+        new = g_malloc0(sizeof(*ret));
+        new->value = fs;
+        new->next = ret;
+        ret = new;
+        if (local_err) {
+            error_propagate(errp, local_err);
+            qapi_free_GuestFilesystemInfoList(ret);
+            ret = NULL;
+            break;
+        }
+    }
+
+    free_fs_mount_list(&mounts);
+    return ret;
+}
+
 #else /* defined(__linux__) */
 
 void qmp_guest_suspend_disk(Error **errp)
@@ -1471,6 +1884,11 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
     return -1;
 }
 
+GuestFilesystemInfoList *qmp_guest_get_mounted_filesystems(Error **errp)
+{
+    error_set(errp, QERR_UNSUPPORTED);
+    return NULL;
+}
 #endif
 
 #if !defined(CONFIG_FSFREEZE)
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 31c0dc8..ef6c4a6 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -646,3 +646,81 @@
 { 'command': 'guest-set-vcpus',
   'data':    {'vcpus': ['GuestLogicalProcessor'] },
   'returns': 'int' }
+
+##
+# @GuestDiskBusType
+#
+# An enumeration of bus type of disks
+#
+# @ide: IDE disks
+# @fdc: floppy disks
+# @scsi: SCSI disks
+# @virtio: virtio disks
+# @xen: Xen disks
+# @usb: USB disks
+# @uml: UML disks
+# @sata: SATA disks
+# @sd: SD cards
+#
+# Since: 2.1
+##
+{ 'enum': 'GuestDiskBusType',
+  'data': [ 'ide', 'fdc', 'scsi', 'virtio', 'xen', 'usb', 'uml', 'sata',
+            'sd' ] }
+
+##
+# @GuestPCIAddress:
+#
+# @domain: domain id
+# @bus: bus id
+# @slot: slot id
+# @function: function id
+#
+# Since: 2.1
+##
+{ 'type': 'GuestPCIAddress',
+  'data': {'domain': 'int', 'bus': 'int',
+           'slot': 'int', 'function': 'int'} }
+
+##
+# @GuestDiskAddress:
+#
+# @pci-controller: controller's PCI address
+# @type: bus type
+# @bus: bus id
+# @target: target id
+# @unit: unit id
+#
+# Since: 2.1
+##
+{ 'type': 'GuestDiskAddress',
+  'data': {'pci-controller': 'GuestPCIAddress',
+           'bus-type': 'GuestDiskBusType',
+           'bus': 'int', 'target': 'int', 'unit': 'int'} }
+
+##
+# @GuestFilesystemInfo
+#
+# @name: disk name
+# @mountpoint: mount point path
+# @type: file system type string
+# @disk: an array of disk hardware information that the volume lies on,
+#        which may be empty if the disk type is not supported
+#
+# Since: 2.1
+##
+{ 'type': 'GuestFilesystemInfo',
+  'data': {'name': 'str', 'mountpoint': 'str', 'type': 'str',
+           'disk': ['GuestDiskAddress']} }
+
+##
+# @guest-get-fs-info:
+#
+# Returns: The list of filesystems information mounted in the guest.
+#          The returned mountpoints may be specified to @guest-fsfreeze-freeze.
+#          Network filesystems (such as CIFS and NFS) are not listed.
+#
+# Since: 2.1
+##
+{ 'command': 'guest-get-fs-info',
+  'returns': ['GuestFilesystemInfo'] }

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v3 1/2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
  2014-05-22 13:56 ` [Qemu-devel] [PATCH v3 1/2] " Tomoki Sekiyama
@ 2014-06-03 21:21   ` Michael Roth
  2014-06-03 21:38     ` Eric Blake
  0 siblings, 1 reply; 10+ messages in thread
From: Michael Roth @ 2014-06-03 21:21 UTC (permalink / raw)
  To: Tomoki Sekiyama, qemu-devel; +Cc: mitsuhiro.tanino

Quoting Tomoki Sekiyama (2014-05-22 08:56:53)
> When an array of mount point paths is specified as 'mountpoints' argument
> of guest-fsfreeze-freeze, qemu-ga with this patch will only freeze the file
> systems mounted on specified paths in Linux.
> This would be useful when the host wants to create partial disk snapshots.

Since this isn't really applicable for win32, and it's hard to discover
optional params via guest-info without some extensive changes to how we handle
capabilities negotiation, I think it makes more sense to introduce a new
command for this, something like guest-fsfreeze-freeze-filesystems, which we
can easily discover and properly mark as unsupported on win32.

Other than that looks good.

> 
> Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama@hds.com>
> ---
>  qga/commands-posix.c |   17 ++++++++++++++++-
>  qga/commands-win32.c |    3 ++-
>  qga/qapi-schema.json |    4 ++++
>  3 files changed, 22 insertions(+), 2 deletions(-)
> 
> diff --git a/qga/commands-posix.c b/qga/commands-posix.c
> index 34ddba0..771f00c 100644
> --- a/qga/commands-posix.c
> +++ b/qga/commands-posix.c
> @@ -714,9 +714,11 @@ GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
>   * Walk list of mounted file systems in the guest, and freeze the ones which
>   * are real local file systems.
>   */
> -int64_t qmp_guest_fsfreeze_freeze(Error **errp)
> +int64_t qmp_guest_fsfreeze_freeze(bool has_mountpoints, strList *mountpoints,
> +                                  Error **errp)
>  {
>      int ret = 0, i = 0;
> +    strList *list;
>      FsMountList mounts;
>      struct FsMount *mount;
>      Error *local_err = NULL;
> @@ -741,6 +743,19 @@ int64_t qmp_guest_fsfreeze_freeze(Error **errp)
>      ga_set_frozen(ga_state);
> 
>      QTAILQ_FOREACH_REVERSE(mount, &mounts, FsMountList, next) {
> +        /* To issue fsfreeze in the reverse order of mounts, check if the
> +         * mount is listed in the list here */
> +        if (has_mountpoints) {
> +            for (list = mountpoints; list; list = list->next) {
> +                if (strcmp(list->value, mount->dirname) == 0) {
> +                    break;
> +                }
> +            }
> +            if (!list) {
> +                continue;
> +            }
> +        }
> +
>          fd = qemu_open(mount->dirname, O_RDONLY);
>          if (fd == -1) {
>              error_setg_errno(errp, errno, "failed to open %s", mount->dirname);
> diff --git a/qga/commands-win32.c b/qga/commands-win32.c
> index d793dd0..0c6296d 100644
> --- a/qga/commands-win32.c
> +++ b/qga/commands-win32.c
> @@ -171,7 +171,8 @@ GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
>   * Freeze local file systems using Volume Shadow-copy Service.
>   * The frozen state is limited for up to 10 seconds by VSS.
>   */
> -int64_t qmp_guest_fsfreeze_freeze(Error **errp)
> +int64_t qmp_guest_fsfreeze_freeze(bool has_mountpoints, strList *mountpoints,
> +                                  Error **errp)
>  {
>      int i;
>      Error *local_err = NULL;
> diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
> index a8cdcb3..31c0dc8 100644
> --- a/qga/qapi-schema.json
> +++ b/qga/qapi-schema.json
> @@ -378,12 +378,16 @@
>  #
>  # Sync and freeze all freezable, local guest filesystems
>  #
> +# @mountpoints: #optional an array of mountpoints of filesystems to be frozen.
> +#               If omitted, every mounted filesystem is frozen. (Since: 2.1)
> +#
>  # Returns: Number of file systems currently frozen. On error, all filesystems
>  # will be thawed.
>  #
>  # Since: 0.15.0
>  ##
>  { 'command': 'guest-fsfreeze-freeze',
> +  'data':    { '*mountpoints': ['str'] },
>    'returns': 'int' }
> 
>  ##

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v3 1/2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
  2014-06-03 21:21   ` Michael Roth
@ 2014-06-03 21:38     ` Eric Blake
  2014-06-03 21:58       ` Michael Roth
  0 siblings, 1 reply; 10+ messages in thread
From: Eric Blake @ 2014-06-03 21:38 UTC (permalink / raw)
  To: Michael Roth, Tomoki Sekiyama, qemu-devel; +Cc: mitsuhiro.tanino

[-- Attachment #1: Type: text/plain, Size: 1177 bytes --]

On 06/03/2014 03:21 PM, Michael Roth wrote:
> Quoting Tomoki Sekiyama (2014-05-22 08:56:53)
>> When an array of mount point paths is specified as 'mountpoints' argument
>> of guest-fsfreeze-freeze, qemu-ga with this patch will only freeze the file
>> systems mounted on specified paths in Linux.
>> This would be useful when the host wants to create partial disk snapshots.
> 
> Since this isn't really applicable for win32, and it's hard to discover
> optional params via guest-info without some extensive changes to how we handle
> capabilities negotiation, I think it makes more sense to introduce a new
> command for this, something like guest-fsfreeze-freeze-filesystems, which we
> can easily discover and properly mark as unsupported on win32.

Bikeshedding on the proposed name: given that 'fs' is an abbreviation of
'filesystem', "fsfreeze-freeze-filesystems" sounds rather redundant.  I
would suggest guest-fsfreeze-list as a shorter name that conveys the
intent, without quite as much repetition.

> 
> Other than that looks good.
> 

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v3 1/2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
  2014-06-03 21:38     ` Eric Blake
@ 2014-06-03 21:58       ` Michael Roth
  2014-06-03 22:06         ` Eric Blake
  0 siblings, 1 reply; 10+ messages in thread
From: Michael Roth @ 2014-06-03 21:58 UTC (permalink / raw)
  To: Eric Blake, Tomoki Sekiyama, qemu-devel; +Cc: mitsuhiro.tanino

Quoting Eric Blake (2014-06-03 16:38:35)
> On 06/03/2014 03:21 PM, Michael Roth wrote:
> > Quoting Tomoki Sekiyama (2014-05-22 08:56:53)
> >> When an array of mount point paths is specified as 'mountpoints' argument
> >> of guest-fsfreeze-freeze, qemu-ga with this patch will only freeze the file
> >> systems mounted on specified paths in Linux.
> >> This would be useful when the host wants to create partial disk snapshots.
> > 
> > Since this isn't really applicable for win32, and it's hard to discover
> > optional params via guest-info without some extensive changes to how we handle
> > capabilities negotiation, I think it makes more sense to introduce a new
> > command for this, something like guest-fsfreeze-freeze-filesystems, which we
> > can easily discover and properly mark as unsupported on win32.
> 
> Bikeshedding on the proposed name: given that 'fs' is an abbreviation of
> 'filesystem', "fsfreeze-freeze-filesystems" sounds rather redundant.  I
> would suggest guest-fsfreeze-list as a shorter name that conveys the
> intent, without quite as much repetition.

Somewhat agree, though I think we should retain the guest-<command_group>-<verb>
structure and at least go with guest-fsfreeze-freeze-list.

I do think that is easy to confuse with 'get me a list of frozen mounts', but
probably nothing a little documentation shouldn't clarify. I'll throw
guest-fsfreeze-freeze-mountpoints out there, but don't have a strong preference
either way.

> 
> > 
> > Other than that looks good.
> > 
> 
> -- 
> Eric Blake   eblake redhat com    +1-919-301-3266
> Libvirt virtualization library http://libvirt.org

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v3 1/2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
  2014-06-03 21:58       ` Michael Roth
@ 2014-06-03 22:06         ` Eric Blake
  2014-06-03 22:10           ` Eric Blake
  2014-06-04  0:39           ` Michael Roth
  0 siblings, 2 replies; 10+ messages in thread
From: Eric Blake @ 2014-06-03 22:06 UTC (permalink / raw)
  To: Michael Roth, Tomoki Sekiyama, qemu-devel; +Cc: mitsuhiro.tanino

[-- Attachment #1: Type: text/plain, Size: 1044 bytes --]

On 06/03/2014 03:58 PM, Michael Roth wrote:

>> Bikeshedding on the proposed name: given that 'fs' is an abbreviation of
>> 'filesystem', "fsfreeze-freeze-filesystems" sounds rather redundant.  I
>> would suggest guest-fsfreeze-list as a shorter name that conveys the
>> intent, without quite as much repetition.
> 
> Somewhat agree, though I think we should retain the guest-<command_group>-<verb>
> structure and at least go with guest-fsfreeze-freeze-list.

guest- prefix is uncontroversial
command_group is 'fsfreeze'.
Currently in that group are the verbs 'status', 'freeze', and 'thaw';
and my proposal is to add 'list' (not 'freeze-list') as the new verb
(just as we don't have 'freeze-status' as a verb).

Oh, and adding this command to freeze by list may require a change to
the existing guest-fsfreeze-status command to report a third enum value
of 'partial' (neither fully 'thawed' nor fully 'frozen').

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v3 1/2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
  2014-06-03 22:06         ` Eric Blake
@ 2014-06-03 22:10           ` Eric Blake
  2014-06-03 23:02             ` Tomoki Sekiyama
  2014-06-04  0:39           ` Michael Roth
  1 sibling, 1 reply; 10+ messages in thread
From: Eric Blake @ 2014-06-03 22:10 UTC (permalink / raw)
  To: Michael Roth, Tomoki Sekiyama, qemu-devel; +Cc: mitsuhiro.tanino

[-- Attachment #1: Type: text/plain, Size: 1420 bytes --]

On 06/03/2014 04:06 PM, Eric Blake wrote:
> On 06/03/2014 03:58 PM, Michael Roth wrote:
> 
>>> Bikeshedding on the proposed name: given that 'fs' is an abbreviation of
>>> 'filesystem', "fsfreeze-freeze-filesystems" sounds rather redundant.  I
>>> would suggest guest-fsfreeze-list as a shorter name that conveys the
>>> intent, without quite as much repetition.
>>
>> Somewhat agree, though I think we should retain the guest-<command_group>-<verb>
>> structure and at least go with guest-fsfreeze-freeze-list.
> 
> guest- prefix is uncontroversial
> command_group is 'fsfreeze'.
> Currently in that group are the verbs 'status', 'freeze', and 'thaw';
> and my proposal is to add 'list' (not 'freeze-list') as the new verb
> (just as we don't have 'freeze-status' as a verb).

Uggh, now that I reread the thread...

'freeze-list' is indeed a better verb than 'list' - we aren't listing
the mountpoints (that is patch 2/2 with guest-fs-get-info), but freezing
a list of mountpoints (the existing 'freeze' action is taken, so we are
doing a new action based on freeze but with a longer name).

Okay, I can live with 'guest-fsfreeze-freeze-list'.

Do we need a guest-fsfreeze-thaw-list counterpart, or is it sufficient
to always thaw all systems without worrying about listing them?

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v3 1/2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
  2014-06-03 22:10           ` Eric Blake
@ 2014-06-03 23:02             ` Tomoki Sekiyama
  0 siblings, 0 replies; 10+ messages in thread
From: Tomoki Sekiyama @ 2014-06-03 23:02 UTC (permalink / raw)
  To: Eric Blake, Michael Roth, qemu-devel; +Cc: Mitsuhiro Tanino

On 6/3/14 18:10 , "Eric Blake" <eblake@redhat.com> wrote:

>On 06/03/2014 04:06 PM, Eric Blake wrote:
>> On 06/03/2014 03:58 PM, Michael Roth wrote:
>> 
>>>> Bikeshedding on the proposed name: given that 'fs' is an abbreviation
>>>>of
>>>> 'filesystem', "fsfreeze-freeze-filesystems" sounds rather redundant.
>>>>I
>>>> would suggest guest-fsfreeze-list as a shorter name that conveys the
>>>> intent, without quite as much repetition.
>>>
>>> Somewhat agree, though I think we should retain the
>>>guest-<command_group>-<verb>
>>> structure and at least go with guest-fsfreeze-freeze-list.
>> 
>> guest- prefix is uncontroversial
>> command_group is 'fsfreeze'.
>> Currently in that group are the verbs 'status', 'freeze', and 'thaw';
>> and my proposal is to add 'list' (not 'freeze-list') as the new verb
>> (just as we don't have 'freeze-status' as a verb).
>
>Uggh, now that I reread the thread...
>
>'freeze-list' is indeed a better verb than 'list' - we aren't listing
>the mountpoints (that is patch 2/2 with guest-fs-get-info), but freezing
>a list of mountpoints (the existing 'freeze' action is taken, so we are
>doing a new action based on freeze but with a longer name).
>
>Okay, I can live with 'guest-fsfreeze-freeze-list'.

I'm okay with 'guest-fsfreeze-freeze-list' too.

>Do we need a guest-fsfreeze-thaw-list counterpart, or is it sufficient
>to always thaw all systems without worrying about listing them?

I think current guest-fsfreeze-thaw is sufficient; don't want to risk
leaving some filesystems unfrozen that may cause deadlocks..

Thanks,
Tomoki Sekiyama

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v3 1/2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
  2014-06-03 22:06         ` Eric Blake
  2014-06-03 22:10           ` Eric Blake
@ 2014-06-04  0:39           ` Michael Roth
  1 sibling, 0 replies; 10+ messages in thread
From: Michael Roth @ 2014-06-04  0:39 UTC (permalink / raw)
  To: Eric Blake, Tomoki Sekiyama, qemu-devel; +Cc: mitsuhiro.tanino

Quoting Eric Blake (2014-06-03 17:06:22)
> On 06/03/2014 03:58 PM, Michael Roth wrote:
> 
> >> Bikeshedding on the proposed name: given that 'fs' is an abbreviation of
> >> 'filesystem', "fsfreeze-freeze-filesystems" sounds rather redundant.  I
> >> would suggest guest-fsfreeze-list as a shorter name that conveys the
> >> intent, without quite as much repetition.
> > 
> > Somewhat agree, though I think we should retain the guest-<command_group>-<verb>
> > structure and at least go with guest-fsfreeze-freeze-list.
> 
> guest- prefix is uncontroversial
> command_group is 'fsfreeze'.
> Currently in that group are the verbs 'status', 'freeze', and 'thaw';
> and my proposal is to add 'list' (not 'freeze-list') as the new verb
> (just as we don't have 'freeze-status' as a verb).
> 
> Oh, and adding this command to freeze by list may require a change to
> the existing guest-fsfreeze-status command to report a third enum value
> of 'partial' (neither fully 'thawed' nor fully 'frozen').

Since multiple disk snapshots can be done concurrently, and it's possible
management might initiate snapshotting for another disk while a prior
snapshot is still being done, being able to freeze a separate subset
of filesystems while others are still in a frozen state (and, unfreeze
a subset of filesystem while leaving others are left frozen)
does seem desirable.

OTOH (and I know this may be relying too much on implementation details),
technically you only need to flush/freeze the filesystems long enough
for QEMU to pivot over to another overlay image (correct me if I'm wrong
on how libvirt actually handles this), at which point you should have an
immutable, data-consistent backing chain that can be backed up in the
background. So, at least for the common use-case, the extra book-keeping
doesn't seem very beneficial.

In any case, since the current implementation doesn't allow for freezing
additional filesystems when others are still frozen, I think that sort of
handling could be done as a follow-up. And until that sort of behavior is
supported I don't think a 'partial' state really has a useful meaning for
users.

> 
> -- 
> Eric Blake   eblake redhat com    +1-919-301-3266
> Libvirt virtualization library http://libvirt.org

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2014-06-04  0:39 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-22 13:56 [Qemu-devel] [PATCH v3 0/2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command Tomoki Sekiyama
2014-05-22 13:56 ` [Qemu-devel] [PATCH v3 1/2] " Tomoki Sekiyama
2014-06-03 21:21   ` Michael Roth
2014-06-03 21:38     ` Eric Blake
2014-06-03 21:58       ` Michael Roth
2014-06-03 22:06         ` Eric Blake
2014-06-03 22:10           ` Eric Blake
2014-06-03 23:02             ` Tomoki Sekiyama
2014-06-04  0:39           ` Michael Roth
2014-05-22 13:56 ` [Qemu-devel] [PATCH v3 2/2] qga: Add guest-get-fs-info command Tomoki Sekiyama

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.