* Re: [Qemu-devel] [PATCH v2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
[not found] <20140428152505.10474.3587.stgit@dhcp-17-12.bos.redhat.com>
@ 2014-05-20 15:04 ` Tomoki Sekiyama
[not found] ` <20140428152514.10474.67500.stgit@dhcp-17-12.bos.redhat.com>
1 sibling, 0 replies; 6+ messages in thread
From: Tomoki Sekiyama @ 2014-05-20 15:04 UTC (permalink / raw)
To: qemu-devel@nongnu.org; +Cc: Mitsuhiro Tanino, mdroth@linux.vnet.ibm.com
Any comments for this patch?
Thanks,
Tomoki Sekiyama
On 4/28/14 11:25 , "Tomoki Sekiyama" <tomoki.sekiyama@hds.com> wrote:
>Hi,
>
>This is v2 patch for qemu-ga to add argument to specify which filesystems
>to be frozen by guest-fsfreeze-freeze command.
>
>Changes to v1:
> added documentation of the new field
> (v1: http://lists.gnu.org/archive/html/qemu-devel/2014-04/msg04085.html)
>
>---
>Tomoki Sekiyama (1):
> qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
>
>
> qga/commands-posix.c | 17 ++++++++++++++++-
> qga/commands-win32.c | 3 ++-
> qga/qapi-schema.json | 4 ++++
> 3 files changed, 22 insertions(+), 2 deletions(-)
>
>--
>Regards,
>Tomoki Sekiyama
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH v2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
[not found] ` <20140428152514.10474.67500.stgit@dhcp-17-12.bos.redhat.com>
@ 2014-05-20 15:45 ` Eric Blake
2014-05-20 22:01 ` Tomoki Sekiyama
2014-05-20 22:01 ` Tomoki Sekiyama
0 siblings, 2 replies; 6+ messages in thread
From: Eric Blake @ 2014-05-20 15:45 UTC (permalink / raw)
To: Tomoki Sekiyama, qemu-devel; +Cc: mitsuhiro.tanino, mdroth
[-- Attachment #1: Type: text/plain, Size: 1305 bytes --]
On 04/28/2014 09:25 AM, Tomoki Sekiyama wrote:
> 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.
How does the management application learn the set of valid mountpoints
arguments it can pass to this command? Shouldn't there be a query
counterpart that asks the guest to return the full list of mountpoints
that it can support freezing? In the case of guests that are
all-or-none, like Windows, the query command would return an empty list
to make it obvious there is no ability to freeze just a subset.
In returning a list of mountpoint names, it might also be nice to
correlate which names map to which devices (it can be a many:many
mapping, thanks to things like RAID setups in the guest).
> 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(-)
>
--
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] 6+ messages in thread
* Re: [Qemu-devel] [PATCH v2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
2014-05-20 15:45 ` Eric Blake
@ 2014-05-20 22:01 ` Tomoki Sekiyama
2014-05-20 22:46 ` Eric Blake
2014-05-20 22:01 ` Tomoki Sekiyama
1 sibling, 1 reply; 6+ messages in thread
From: Tomoki Sekiyama @ 2014-05-20 22:01 UTC (permalink / raw)
To: eblake, qemu-devel; +Cc: mitsuhiro.tanino, mdroth
> On 04/28/2014 09:25 AM, Tomoki Sekiyama wrote:
>> 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.
>
> How does the management application learn the set of valid mountpoints
> arguments it can pass to this command? Shouldn't there be a query
> counterpart that asks the guest to return the full list of mountpoints
> that it can support freezing? In the case of guests that are
> all-or-none, like Windows, the query command would return an empty list
> to make it obvious there is no ability to freeze just a subset.
>
> In returning a list of mountpoint names, it might also be nice to
> correlate which names map to which devices (it can be a many:many
> mapping, thanks to things like RAID setups in the guest).
I agree.
The patch below is for the command to get filesystems list.
===
From: Tomoki Sekiyama <tomoki.sekiyama@hds.com>
qga: Add guest-get-fs-info command
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.
In Linux guest, the disk information is resolved from sysfs.
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 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"}]}
Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama@hds.com>
---
qga/commands-posix.c | 420 ++++++++++++++++++++++++++++++++++++++++++++++++++-
qga/qapi-schema.json | 77 ++++++++++
2 files changed, 496 insertions(+), 1 deletion(-)
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 771f00c..212913a 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);
+ fs->has_disk = _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..eb0c133 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -646,3 +646,80 @@
{ '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 informations that the volume lies on
+#
+# 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'] }
--
1.9.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH v2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
2014-05-20 15:45 ` Eric Blake
2014-05-20 22:01 ` Tomoki Sekiyama
@ 2014-05-20 22:01 ` Tomoki Sekiyama
1 sibling, 0 replies; 6+ messages in thread
From: Tomoki Sekiyama @ 2014-05-20 22:01 UTC (permalink / raw)
To: eblake, qemu-devel; +Cc: mitsuhiro.tanino, mdroth
> On 04/28/2014 09:25 AM, Tomoki Sekiyama wrote:
>> 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.
>
> How does the management application learn the set of valid mountpoints
> arguments it can pass to this command? Shouldn't there be a query
> counterpart that asks the guest to return the full list of mountpoints
> that it can support freezing? In the case of guests that are
> all-or-none, like Windows, the query command would return an empty list
> to make it obvious there is no ability to freeze just a subset.
>
> In returning a list of mountpoint names, it might also be nice to
> correlate which names map to which devices (it can be a many:many
> mapping, thanks to things like RAID setups in the guest).
I agree.
The patch below is for the command to get filesystems list.
===
From: Tomoki Sekiyama <tomoki.sekiyama@hds.com>
qga: Add guest-get-fs-info command
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.
In Linux guest, the disk information is resolved from sysfs.
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 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"}]}
Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama@hds.com>
---
qga/commands-posix.c | 420 ++++++++++++++++++++++++++++++++++++++++++++++++++-
qga/qapi-schema.json | 77 ++++++++++
2 files changed, 496 insertions(+), 1 deletion(-)
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 771f00c..212913a 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);
+ fs->has_disk = _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..eb0c133 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -646,3 +646,80 @@
{ '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 informations that the volume lies on
+#
+# 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'] }
--
1.9.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH v2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
2014-05-20 22:01 ` Tomoki Sekiyama
@ 2014-05-20 22:46 ` Eric Blake
2014-05-21 19:28 ` Tomoki Sekiyama
0 siblings, 1 reply; 6+ messages in thread
From: Eric Blake @ 2014-05-20 22:46 UTC (permalink / raw)
To: Tomoki Sekiyama, qemu-devel; +Cc: mitsuhiro.tanino, mdroth
[-- Attachment #1: Type: text/plain, Size: 2928 bytes --]
On 05/20/2014 04:01 PM, Tomoki Sekiyama wrote:
> The patch below is for the command to get filesystems list.
>
> ===
> From: Tomoki Sekiyama <tomoki.sekiyama@hds.com>
You'll want to resend it as a series of patches as a top-level thread;
not everyone notices a patch buried as a reply.
>
> qga: Add guest-get-fs-info command
>
> 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.
> In Linux guest, the disk information is resolved from sysfs.
>
> 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"},
Definitely looks like a useful set of information. I have not reviewed
the patch closely, but it looks like you have a good API for Linux. I'm
a bit worried that it might be hard to translate this API into non-Linux
guests, but it still seems generic enough; and the argument also holds
that if this command is not implemented, the guest does not support
partial freezing.
> +++ b/qga/qapi-schema.json
> @@ -646,3 +646,80 @@
> { 'command': 'guest-set-vcpus',
> 'data': {'vcpus': ['GuestLogicalProcessor'] },
> +
> +##
> +# @GuestFilesystemInfo
> +#
> +# @name: disk name
> +# @mountpoint: mount point path
> +# @type: file system type string
> +# @disk: an array of disk hardware informations that the volume lies on
s/informations/information/
> +#
> +# Since: 2.1
> +##
> +{ 'type': 'GuestFilesystemInfo',
> + 'data': {'name': 'str', 'mountpoint': 'str', 'type': 'str',
> + '*disk': ['GuestDiskAddress']} }
Why is the array optional? Is it something where an empty array has
different meaning than omitting the array altogether?
> +
> +##
> +# @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'] }
Should this command support an optional input argument '*name':'str'
that filters the results to a one-element array about that one named
mountpoint?
--
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] 6+ messages in thread
* Re: [Qemu-devel] [PATCH v2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
2014-05-20 22:46 ` Eric Blake
@ 2014-05-21 19:28 ` Tomoki Sekiyama
0 siblings, 0 replies; 6+ messages in thread
From: Tomoki Sekiyama @ 2014-05-21 19:28 UTC (permalink / raw)
To: Eric Blake, qemu-devel@nongnu.org
Cc: Mitsuhiro Tanino, mdroth@linux.vnet.ibm.com
Hi Eric, thank you for the comments.
On 5/20/14 18:46 , "Eric Blake" <eblake@redhat.com> wrote:
>On 05/20/2014 04:01 PM, Tomoki Sekiyama wrote:
>> The patch below is for the command to get filesystems list.
>>
>> ===
>> From: Tomoki Sekiyama <tomoki.sekiyama@hds.com>
>
>You'll want to resend it as a series of patches as a top-level thread;
>not everyone notices a patch buried as a reply.
OK. I will resend as a series (with a fix below).
>>
>> qga: Add guest-get-fs-info command
>>
>> 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.
>> In Linux guest, the disk information is resolved from sysfs.
>>
>> 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"},
>
>Definitely looks like a useful set of information. I have not reviewed
>the patch closely, but it looks like you have a good API for Linux. I'm
>a bit worried that it might be hard to translate this API into non-Linux
>guests, but it still seems generic enough; and the argument also holds
>that if this command is not implemented, the guest does not support
>partial freezing.
>>+++ b/qga/qapi-schema.json
>> @@ -646,3 +646,80 @@
>> { 'command': 'guest-set-vcpus',
>> 'data': {'vcpus': ['GuestLogicalProcessor'] },
>
>> +
>> +##
>> +# @GuestFilesystemInfo
>> +#
>> +# @name: disk name
>> +# @mountpoint: mount point path
>> +# @type: file system type string
>> +# @disk: an array of disk hardware informations that the volume lies on
>
>s/informations/information/
Will fix it.
>> +#
>> +# Since: 2.1
>> +##
>> +{ 'type': 'GuestFilesystemInfo',
>> + 'data': {'name': 'str', 'mountpoint': 'str', 'type': 'str',
>> + '*disk': ['GuestDiskAddress']} }
>
>Why is the array optional? Is it something where an empty array has
>different meaning than omitting the array altogether?
Not actually. Currently it omits the array when the disk type is not
supported (non-PCI device like floppy disks or SD cards). But it can
be replaced with an empty array if preferable.
>>+
>> +##
>> +# @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'] }
>
>Should this command support an optional input argument '*name':'str'
>that filters the results to a one-element array about that one named
>mountpoint?
Hmm, I don't have specific use-cases for the name argument.
As other commands like 'guest-network-get-interfaces' don't have a such
filter, I don't have a reason to give a filter for this command.
Anyway, the caller can easily filter the result by him/herself.
Regards,
Tomoki Sekiyama
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2014-05-21 19:28 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20140428152505.10474.3587.stgit@dhcp-17-12.bos.redhat.com>
2014-05-20 15:04 ` [Qemu-devel] [PATCH v2] qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command Tomoki Sekiyama
[not found] ` <20140428152514.10474.67500.stgit@dhcp-17-12.bos.redhat.com>
2014-05-20 15:45 ` Eric Blake
2014-05-20 22:01 ` Tomoki Sekiyama
2014-05-20 22:46 ` Eric Blake
2014-05-21 19:28 ` Tomoki Sekiyama
2014-05-20 22:01 ` Tomoki Sekiyama
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).