qga: Add guest-fsfreeze-freeze-list command
v5 cover qga: Add guest-fsfreeze-freeze-list command
Hi,
As patch 3/3 was missing in the last post, I'm resending this patchset.
===
This is v5 patch for qemu-ga to add functions to freeze specific file systems mounted in a guest.
Changes since v4:
- PATCH 2: fix coding styles (spaces around operators)
make decode_mntname() more generic
rename functions to avoid leading '__'
improve compatibility with older Linux
- PATCH 3 (new in v5): disable unsupported commands by default (v4: http://lists.gnu.org/archive/html/qemu-devel/2014-06/msg01357.html)
---
Tomoki Sekiyama (3):
qga: Add guest-fsfreeze-freeze-list command
qga: Add guest-get-fsinfo command
qga: Disable unsupported commands by default
qga/commands-posix.c | 508 ++++++++++++++++++++++++++++++++++++++++++++++++ qga/commands-win32.c | 47 ++++ qga/guest-agent-core.h | 1 qga/main.c | 1 qga/qapi-schema.json | 96 +++++++++ 5 files changed, 650 insertions(+), 3 deletions(-)
Signature · 2 lines
Regards, Tomoki Sekiyama
PATCH RESEND v5 1/3 qga: Add guest-fsfreeze-freeze-list command
If an array of mount point paths is specified as 'mountpoints' argument of guest-fsfreeze-freeze-list, qemu-ga will only freeze the file systems mounted on specified paths in Linux guests. Otherwise, it works as the same way as guest-fsfreeze-freeze.
This would be useful when the host wants to create partial disk snapshots.
--- qga/commands-posix.c | 32 +++++++++++++++++++++++++++++++- qga/commands-win32.c | 9 +++++++++ qga/qapi-schema.json | 17 +++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-)
qga/commands-posix.c +31 -1
@@ -710,13 +710,21 @@ GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)return GUEST_FSFREEZE_STATUS_THAWED ; } +int64_t qmp_guest_fsfreeze_freeze (Error **errp) +{ +return qmp_guest_fsfreeze_freeze_list (false,NULL , 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_list (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 +749,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);
@@ -1474,6 +1495,15 @@ int64_t qmp_guest_fsfreeze_freeze(Error **errp)return 0 ; } +int64_t qmp_guest_fsfreeze_freeze_list (bool has_mountpoints, +strList *mountpoints, +Error **errp) +{ +error_set (errp,QERR_UNSUPPORTED ); + +return 0 ; +} +int64_t qmp_guest_fsfreeze_thaw (Error **errp) {error_set (errp,QERR_UNSUPPORTED );
qga/commands-win32.c +9 -0
@@ -206,6 +206,15 @@ error:return 0 ; } +int64_t qmp_guest_fsfreeze_freeze_list (bool has_mountpoints, +strList *mountpoints, +Error **errp) +{ +error_set (errp,QERR_UNSUPPORTED ); + +return 0 ; +} +/* * Thaw local file systems using Volume Shadow-copy Service. */
qga/qapi-schema.json +17 -0
@@ -387,6 +387,23 @@ 'returns': 'int' } ## +# @guest-fsfreeze-freeze-list: +# +# Sync and freeze specified guest filesystems +# +# @mountpoints: #optional an array of mountpoints of filesystems to be frozen. +# If omitted, every mounted filesystem is frozen. +# +# Returns: Number of file systems currently frozen. On error, all filesystems +# will be thawed. +# +# Since: 2.1 +## +{ 'command': 'guest-fsfreeze-freeze-list', + 'data': { '*mountpoints': ['str'] }, + 'returns': 'int' } + +## # @guest-fsfreeze-thaw: # # Unfreeze all frozen guest filesystems
Quoted 21 lines · Tomoki Sekiyama
If an array of mount point paths is specified as 'mountpoints' argument of guest-fsfreeze-freeze-list, qemu-ga will only freeze the file systems mounted on specified paths in Linux guests. Otherwise, it works as the same way as guest-fsfreeze-freeze.
This would be useful when the host wants to create partial disk snapshots.Signed-off-by Tomoki Sekiyama <[email protected]>Reviewed-by Eric Blake <[email protected]>--- qga/commands-posix.c | 32 +++++++++++++++++++++++++++++++- qga/commands-win32.c | 9 +++++++++ qga/qapi-schema.json | 17 +++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-)+++
b/qga/qapi-schema.jsonqga/qapi-schema.json +1
-0@@ -387,6 +387,23 @@ 'returns': 'int' } ## +# @guest-fsfreeze-freeze-list:
qga/qapi-schema.json line 400
Quoted 10 lines
qga/qapi-schema.json +10
-0+# +# Sync and freeze specified guest filesystems +# +# @mountpoints: #optional an array of mountpoints of filesystems to be frozen. +# If omitted, every mounted filesystem is frozen. +# +# Returns: Number of file systems currently frozen. On error, all filesystems +# will be thawed. +# +# Since: 2.1
This missed 2.1. We'll need a followup patch (or rebase mdroth's staging tree) to bump this to 2.2.
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Quoting Eric Blake (2014-08-07 17:03:57)
Quoted 20 lines · Tomoki Sekiyama
Quoted 19 lines
If an array of mount point paths is specified as 'mountpoints' argument of guest-fsfreeze-freeze-list, qemu-ga will only freeze the file systems mounted on specified paths in Linux guests. Otherwise, it works as the same way as guest-fsfreeze-freeze.
This would be useful when the host wants to create partial disk snapshots.Signed-off-by Tomoki Sekiyama <[email protected]>Reviewed-by Eric Blake <[email protected]>--- qga/commands-posix.c | 32 +++++++++++++++++++++++++++++++- qga/commands-win32.c | 9 +++++++++ qga/qapi-schema.json | 17 +++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-)+++
b/qga/qapi-schema.jsonqga/qapi-schema.json +0
-0@@ -387,6 +387,23 @@ 'returns': 'int' }
Quoted 15 lines
qga/qapi-schema.json line 400
Quoted 12 lines
qga/qapi-schema.json +11
-0## +# @guest-fsfreeze-freeze-list: +# +# Sync and freeze specified guest filesystems +# +# @mountpoints: #optional an array of mountpoints of filesystems to be frozen. +# If omitted, every mounted filesystem is frozen. +# +# Returns: Number of file systems currently frozen. On error, all filesystems +# will be thawed. +# +# Since: 2.1This missed 2.1. We'll need a followup patch (or rebase mdroth's staging tree) to bump this to 2.2.
Yikes, thanks for the quick catch. Updated the versions in qga branch and in the pull branch that was just sent.
Quoted 4 lines
Signature · 3 lines
-- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH RESEND v5 2/3 qga: Add guest-get-fsinfo command
In reply to Tomoki SekiyamaAdd 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-fsinfo 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.
--- qga/commands-posix.c | 438 ++++++++++++++++++++++++++++++++++++++++++++++++++ qga/commands-win32.c | 6 + qga/qapi-schema.json | 79 +++++++++ 3 files changed, 522 insertions(+), 1 deletion(-)
qga/commands-posix.c +437 -1
@@ -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,423 @@ 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 +1 ] <='3' && + name[i +2 ] >='0' && name[i +2 ] <='7' && + name[i +3 ] >='0' && name[i +3 ] <='7' ) { + name[j++] = (name[i +1 ] -'0' ) *64 + + (name[i +2 ] -'0' ) *8 + + (name[i +3 ] -'0' ); + 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 , *dash; +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%c" , + &devmajor, &devminor, &dir_s, &dir_e, &check); +if (ret <3 ) { +continue ; + } + dash =strstr (line + dir_e," - " ); +if (!dash) { +continue ; + } + ret =sscanf (dash," - %n%*s%n %n%*s%n%c" , + &type_s, &type_e, &dev_s, &dev_e, &check); +if (ret <1 ) { +continue ; + } + line[dir_e] =0 ; + dash[type_e] =0 ; + dash[dev_e] =0 ; +decode_mntname (line + dir_s, dir_e - dir_s); +decode_mntname (dash + dev_s, dev_e - dev_s); +if (devmajor ==0 ) { +/* btrfs reports major number = 0 */ +if (strcmp ("btrfs" , dash + type_s) !=0 || +dev_major_minor (dash + dev_s, &devmajor, &devminor) <0 ) { +continue ; + } + } + + mount =g_malloc0 (sizeof (FsMount)); + mount->dirname =g_strdup (line + dir_s); + mount->devtype =g_strdup (dash + 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 and build a sorted list of host or ata numbers */ +static int build_hosts(char const *syspath, char const *host, bool ata, + unsigned int *hosts, int hosts_max, Error **errp) +{ + char *path; + DIR *dir; + struct dirent *entry; + int i = 0; + + path = g_strndup(syspath, host - syspath); + dir = opendir(path); + if (!dir) { + error_setg_errno(errp, errno, "opendir(\"%s\")", path); + g_free(path); + return -1; + } + + while (i < hosts_max) { + entry = readdir(dir); + if (!entry) { + break; + } + if (ata && sscanf(entry->d_name, "ata%d", hosts + i) == 1) { + ++i; + } else if (!ata && sscanf(entry->d_name, "host%d", hosts + i) == 1) { + ++i; + } + } + + qsort(hosts, i, sizeof(hosts[0]), compare_uint); + + g_free(path); + closedir(dir); + return i; +} + +/* Store disk device info specified by @sysfs into @fs */ +static void build_guest_fsinfo_for_real_device(char const *syspath, + GuestFilesystemInfo *fs, + Error **errp) +{ + unsigned int pci[4], host, hosts[8], tgt[3]; + int i, nhosts = 0, pcilen; + GuestDiskAddress *disk; + GuestPCIAddress *pciaddr; + GuestDiskAddressList *list = NULL; + bool has_ata = false, has_host = false, has_tgt = false; + char *p, *q, *driver = NULL; + + p = strstr(syspath, "/devices/pci"); + if (!p || sscanf(p + 12, "%*x:%*x/%x:%x:%x.%x%n", + pci, pci + 1, pci + 2, pci + 3, &pcilen) < 4) { + g_debug("only pci device is supported: sysfs path \"%s\"", syspath); + return; + } + + 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) { + q = p + 4; + has_ata = true; + } else { + p = strstr(syspath, "/host"); + q = p + 5; + } + if (p && sscanf(q, "%u", &host) == 1) { + has_host = true; + nhosts = build_hosts(syspath, p, has_ata, hosts, + sizeof(hosts) / sizeof(hosts[0]), errp); + if (nhosts < 0) { + goto cleanup; + } + } + + 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) { + /* a host per ide bus, target*:0:<unit>:0 */ + if (!has_host || !has_tgt) { + g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver); + goto cleanup; + } + for (i = 0; i < nhosts; i++) { + if (host == hosts[i]) { + disk->bus_type = GUEST_DISK_BUS_TYPE_IDE; + disk->bus = i; + disk->unit = tgt[1]; + break; + } + } + if (i >= nhosts) { + g_debug("no host for '%s' (driver '%s')", syspath, driver); + goto cleanup; + } + } else if (strcmp(driver, "sym53c8xx") == 0) { + /* scsi(LSI Logic): target*:0:<unit>:0 */ + if (!has_tgt) { + g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver); + goto cleanup; + } + disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI; + disk->unit = tgt[1]; + } else if (strcmp(driver, "virtio-pci") == 0) { + if (has_tgt) { + /* virtio-scsi: target*:0:0:<unit> */ + disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI; + disk->unit = tgt[2]; + } else { + /* virtio-blk: 1 disk per 1 device */ + disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO; + } + } else if (strcmp(driver, "ahci") == 0) { + /* ahci: 1 host per 1 unit */ + if (!has_host || !has_tgt) { + g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver); + goto cleanup; + } + for (i = 0; i < nhosts; i++) { + if (host == hosts[i]) { + disk->unit = i; + disk->bus_type = GUEST_DISK_BUS_TYPE_SATA; + break; + } + } + if (i >= nhosts) { + g_debug("no host for '%s' (driver '%s')", syspath, driver); + goto cleanup; + } + } else { + g_debug("unknown driver '%s' (sysfs path '%s')", driver, syspath); + goto cleanup; + } + + list->next = fs->disk; + fs->disk = list; + g_free(driver); + return; + +cleanup: + if (list) { + qapi_free_GuestDiskAddressList(list); + } + g_free(driver); +} + +static void build_guest_fsinfo_for_device(char const *devpath, + GuestFilesystemInfo *fs, + Error **errp); + +/* Store a list of slave devices of virtual volume specified by @syspath into + * @fs */ +static void build_guest_fsinfo_for_virtual_device(char const *syspath, + GuestFilesystemInfo *fs, + Error **errp) +{ + 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; + } + 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); + build_guest_fsinfo_for_device(dirpath, fs, errp); + g_free(dirpath); + + if (*errp) { + break; + } + } + } + + closedir(dir); +} + +/* Dispatch to functions for virtual/real device */ +static void build_guest_fsinfo_for_device(char const *devpath, + GuestFilesystemInfo *fs, + Error **errp) +{ + char *syspath = realpath(devpath, NULL); + + if (!syspath) { + error_setg_errno(errp, errno, "realpath(\"%s\")", devpath); + return; + } + + if (!fs->name) { + fs->name = g_strdup(basename(syspath)); + } + + g_debug(" parse sysfs path '%s'", syspath); + + if (strstr(syspath, "/devices/virtual/block/")) { + build_guest_fsinfo_for_virtual_device(syspath, fs, errp); + } else { + build_guest_fsinfo_for_real_device(syspath, fs, errp); + } + + free(syspath); +} + +/* Return a list of the disk device(s)' info which @mount lies on */ +static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount, + Error **errp) +{ + GuestFilesystemInfo *fs = g_malloc0(sizeof(*fs)); + char *devpath = g_strdup_printf("/sys/dev/block/%u:%u", + mount->devmajor, mount->devminor); + + fs->mountpoint = g_strdup(mount->dirname); + fs->type = g_strdup(mount->devtype); + build_guest_fsinfo_for_device(devpath, fs, errp); + + g_free(devpath); + return fs; +} + +GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp) +{ + FsMountList mounts; + struct FsMount *mount; + GuestFilesystemInfoList *new, *ret = NULL; + 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 guest fsinfo for '%s'", mount->dirname); + + new = g_malloc0(sizeof(*ret)); + new->value = build_guest_fsinfo(mount, &local_err); + 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; +} + + typedef enum { FSFREEZE_HOOK_THAW = 0, FSFREEZE_HOOK_FREEZE,
@@ -1481,6 +1911,12 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)#if !defined(CONFIG_FSFREEZE ) +GuestFilesystemInfoList *qmp_guest_get_fsinfo (Error **errp) +{ +error_set (errp,QERR_UNSUPPORTED ); +return NULL ; +} +GuestFsfreezeStatus qmp_guest_fsfreeze_status (Error **errp) {error_set (errp,QERR_UNSUPPORTED );
qga/commands-win32.c +6 -0
@@ -152,6 +152,12 @@ void qmp_guest_file_flush(int64_t handle, Error **errp)error_set (errp,QERR_UNSUPPORTED ); } +GuestFilesystemInfoList *qmp_guest_get_fsinfo (Error **errp) +{ +error_set (errp,QERR_UNSUPPORTED ); +return NULL ; +} +/* * Return status of freeze/thaw */
qga/qapi-schema.json +79 -0
82 lines not on this page · raw message
Re: [Qemu-devel] [RESEND PATCH v5 2/3] qga: Add guest-get-fsinfo command
Quoted 25 lines · Tomoki Sekiyama
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. 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 <[email protected]>--- qga/commands-posix.c | 438 ++++++++++++++++++++++++++++++++++++++++++++++++++ qga/commands-win32.c | 6 + qga/qapi-schema.json | 79 +++++++++ 3 files changed, 522 insertions(+), 1 deletion(-)qga/qapi-schema.json +6
-0+## +# @GuestDiskBusType +# +# An enumeration of bus type of disks +# +# @ide: IDE disks
qga/qapi-schema.json line 678
Quoted 10 lines
qga/qapi-schema.json +10
-0+# @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
Another change to 2.2.
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH RESEND v5 3/3 qga: Disable unsupported commands by default
In reply to Tomoki SekiyamaCurrently management softwares cannot know whether a qemu-ga command is supported or not on the running platform until they actually execute it. This patch disables unsupported commands at launch time of qemu-ga, so that management softwares can check whether they are supported from 'enabled' property of the result from 'guest-info' command.
--- qga/commands-posix.c | 38 ++++++++++++++++++++++++++++++++++++++ qga/commands-win32.c | 32 +++++++++++++++++++++++++++++++- qga/guest-agent-core.h | 1 + qga/main.c | 1 + 4 files changed, 71 insertions(+), 1 deletion(-)
qga/commands-posix.c +38 -0
@@ -1955,6 +1955,44 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) }#endif +/* add unsupported commands to the blacklist */ +GList *ga_command_blacklist_init (GList *blacklist) +{ +#if !defined(__linux__) + { +const char *list[] = { +"guest-suspend-disk" ,"guest-suspend-ram" , +"guest-suspend-hybrid" ,"guest-network-get-interfaces" , +"guest-get-vcpus" ,"guest-set-vcpus" ,NULL }; +char **p = (char **)list; + +while (*p) { + blacklist =g_list_append (blacklist, *p++); + } + } +#endif + +#if !defined(CONFIG_FSFREEZE ) + { +const char *list[] = { +"guest-get-fsinfo" ,"guest-fsfreeze-status" , +"guest-fsfreeze-freeze" ,"guest-fsfreeze-freeze-list" , +"guest-fsfreeze-thaw" ,"guest-get-fsinfo" ,NULL }; +char **p = (char **)list; + +while (*p) { + blacklist =g_list_append (blacklist, *p++); + } + } +#endif + +#if !defined(CONFIG_FSTRIM ) + blacklist =g_list_append (blacklist, (char *)"guest-fstrim" ); +#endif + +return blacklist; +} +/* register init/cleanup routines for stateful command groups */ void ga_command_state_init (GAState *s,GACommandState *cs) {
qga/commands-win32.c +31 -1
@@ -446,10 +446,40 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)return -1 ; } +/* add unsupported commands to the blacklist */ +GList *ga_command_blacklist_init (GList *blacklist) +{ +const char *list_unsupported[] = { +"guest-file-open" ,"guest-file-close" ,"guest-file-read" , +"guest-file-write" ,"guest-file-seek" ,"guest-file-flush" , +"guest-suspend-hybrid" ,"guest-network-get-interfaces" , +"guest-get-vcpus" ,"guest-set-vcpus" , +"guest-fsfreeze-freeze-list" ,"guest-get-fsinfo" , +"guest-fstrim" ,NULL }; +char **p = (char **)list_unsupported; + +while (*p) { + blacklist =g_list_append (blacklist, *p++); + } + +if (!vss_init (true)) { +const char *list[] = { +"guest-get-fsinfo" ,"guest-fsfreeze-status" , +"guest-fsfreeze-freeze" ,"guest-fsfreeze-thaw" ,NULL }; + p = (char **)list; + +while (*p) { + blacklist =g_list_append (blacklist, *p++); + } + } + +return blacklist; +} +/* register init/cleanup routines for stateful command groups */ void ga_command_state_init (GAState *s,GACommandState *cs) { -if (vss_init (true)) { +if (!vss_initialized ()) {ga_command_state_add (cs,NULL , guest_fsfreeze_cleanup); } }
qga/guest-agent-core.h +1 -0
@@ -19,6 +19,7 @@ typedef struct GAState GAState;typedef struct GACommandState GACommandState ;extern GAState *ga_state; +GList *ga_command_blacklist_init (GList *blacklist);void ga_command_state_init (GAState *s,GACommandState *cs); void ga_command_state_add(GACommandState *cs, void (*init)(void),
qga/main.c +1 -0
@@ -1144,6 +1144,7 @@ int main(int argc, char **argv) goto out_bad; } + blacklist =ga_command_blacklist_init (blacklist);if (blacklist) { s->blacklist = blacklist; do {
Any comments for this patch?
Quoted 35 lines · Tomoki Sekiyama
Hi,
As patch 3/3 was missing in the last post, I'm resending this patchset.
===
This is v5 patch for qemu-ga to add functions to freeze specific file systems
mounted in a guest.Changes since v4:
- PATCH 2: fix coding styles (spaces around operators)
makedecode_mntname()more generic
rename functions to avoid leading '__'
improve compatibility with older Linux
- PATCH 3 (new in v5): disable unsupported commands by default (v4: http://lists.gnu.org/archive/html/qemu-devel/2014-06/msg01357.html)---
Tomoki Sekiyama (3):
qga: Add guest-fsfreeze-freeze-list command
qga: Add guest-get-fsinfo command
qga: Disable unsupported commands by default
qga/commands-posix.c| 508
++++++++++++++++++++++++++++++++++++++++++++++++qga/commands-win32.c | 47 ++++ qga/guest-agent-core.h | 1 qga/main.c | 1 qga/qapi-schema.json | 96 +++++++++ 5 files changed, 650 insertions(+), 3 deletions(-)Signature · 2 lines
Regards, Tomoki Sekiyama
Michael Roth
AppliedQuoting Tomoki Sekiyama (2014-06-30 16:51:21)
Quoted 8 lines
Hi,
As patch 3/3 was missing in the last post, I'm resending this patchset.
===
This is v5 patch for qemu-ga to add functions to freeze specific file systems mounted in a guest.
Quoted 7 lines
Changes since v4:
- PATCH 2: fix coding styles (spaces around operators)
makedecode_mntname()more generic
rename functions to avoid leading '__'
improve compatibility with older Linux
- PATCH 3 (new in v5): disable unsupported commands by default (v4: http://lists.gnu.org/archive/html/qemu-devel/2014-06/msg01357.html)
Thanks! Applied to qga tree:
https://github.com/mdroth/qemu/commits/qga
Quoted 18 lines
---
Tomoki Sekiyama (3):
qga: Add guest-fsfreeze-freeze-list command
qga: Add guest-get-fsinfo command
qga: Disable unsupported commands by defaultqga/commands-posix.c | 508 ++++++++++++++++++++++++++++++++++++++++++++++++ qga/commands-win32.c | 47 ++++ qga/guest-agent-core.h | 1 qga/main.c | 1 qga/qapi-schema.json | 96 +++++++++ 5 files changed, 650 insertions(+), 3 deletions(-)Signature · 2 lines
Regards, Tomoki Sekiyama