qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
v3 cover qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
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(-)
Signature · 2 lines
Regards, Tomoki Sekiyama
PATCH v3 1/2 qga: Add 'mountpoints' argument to guest-fsfreeze-freeze command
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.
--- qga/commands-posix.c | 17 ++++++++++++++++- qga/commands-win32.c | 3 ++- qga/qapi-schema.json | 4 ++++ 3 files changed, 22 insertions(+), 2 deletions(-)
qga/commands-posix.c +16 -1
@@ -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);
qga/commands-win32.c +2 -1
@@ -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 ;
qga/qapi-schema.json +4 -0
@@ -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' } ##
Quoting Tomoki Sekiyama (2014-05-22 08:56:53)
Quoted 4 lines
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.
Quoted 80 lines
Signed-off-by Tomoki Sekiyama <[email protected]>--- qga/commands-posix.c | 17 ++++++++++++++++- qga/commands-win32.c | 3 ++- qga/qapi-schema.json | 4 ++++ 3 files changed, 22 insertions(+), 2 deletions(-)qga/commands-posix.c +16
-1@@ -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);qga/commands-win32.c +2
-1@@ -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 ;qga/qapi-schema.json +4
-0@@ -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' } ##
Quoted 11 lines · Michael Roth
Quoting Tomoki Sekiyama (2014-05-22 08:56:53)
Quoted 4 lines
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.
Quoted 3 lines
Other than that looks good.
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Quoting Eric Blake (2014-06-03 16:38:35)
Quoted 13 lines · Michael Roth
Quoted 11 lines
Quoting Tomoki Sekiyama (2014-05-22 08:56:53)
Quoted 4 lines
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.
Quoted 4 lines
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.
Quoted 8 lines
Quoted 4 lines
Other than that looks good.
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Quoted 7 lines · Michael Roth
Quoted 4 lines
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 uncontroversialcommand_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').
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Quoted 7 lines · Eric Blake
Quoted 5 lines · Michael Roth
Quoted 4 lines
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.
Quoted 8 lines
Quoted 2 lines
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_groupis '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?
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Quoted 20 lines · Eric Blake
Quoted 13 lines · Eric Blake
Quoted 10 lines · Michael Roth
Quoted 6 lines
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.Quoted 5 lines
guest- prefix is uncontroversial
command_groupis '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).
Quoted 8 lines
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.
Quoted 2 lines
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
Quoting Eric Blake (2014-06-03 17:06:22)
Quoted 16 lines · Michael Roth
Quoted 8 lines
Quoted 5 lines
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_groupis '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).
Quoted 3 lines
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.
Quoted 4 lines
Signature · 3 lines
-- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH v3 2/2 qga: Add guest-get-fs-info 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-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.
--- qga/commands-posix.c | 420 ++++++++++++++++++++++++++++++++++++++++++++++++++ qga/qapi-schema.json | 78 +++++++++ 2 files changed, 497 insertions(+), 1 deletion(-)
qga/commands-posix.c +419 -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,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 )
qga/qapi-schema.json +78 -0
81 lines not on this page · raw message