Skip to content

Commit

Permalink
qga-win: add support for qmp_guest_fsfreeze_freeze_list
Browse files Browse the repository at this point in the history
This patch add support for freeze specified fs.

The valid mountpoints list member are [1]:

  The path of a mounted folder, for example, Y:\MountX\
  A drive letter, for example, D:\
  A volume GUID path of the form \\?\Volume{GUID}\,
      where GUID identifies the volume
  A UNC path that specifies a remote file share,
      for example, \\Clusterx\Share1\

[1] https://docs.microsoft.com/en-us/windows/desktop/api/vsbackup/nf-vsbackup-ivssbackupcomponents-addtosnapshotset

Cc: Michael Roth <[email protected]>
Signed-off-by: Chen Hanxiao <[email protected]>
Signed-off-by: Michael Roth <[email protected]>
  • Loading branch information
chenhanxiao authored and mdroth committed Oct 30, 2018
1 parent bad0227 commit 0692b03
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 45 deletions.
21 changes: 9 additions & 12 deletions qga/commands-win32.c
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,13 @@ GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
* The frozen state is limited for up to 10 seconds by VSS.
*/
int64_t qmp_guest_fsfreeze_freeze(Error **errp)
{
return qmp_guest_fsfreeze_freeze_list(false, NULL, errp);
}

int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
strList *mountpoints,
Error **errp)
{
int i;
Error *local_err = NULL;
Expand All @@ -804,7 +811,7 @@ int64_t qmp_guest_fsfreeze_freeze(Error **errp)
/* cannot risk guest agent blocking itself on a write in this state */
ga_set_frozen(ga_state);

qga_vss_fsfreeze(&i, true, &local_err);
qga_vss_fsfreeze(&i, true, mountpoints, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto error;
Expand All @@ -822,15 +829,6 @@ 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_setg(errp, QERR_UNSUPPORTED);

return 0;
}

/*
* Thaw local file systems using Volume Shadow-copy Service.
*/
Expand All @@ -843,7 +841,7 @@ int64_t qmp_guest_fsfreeze_thaw(Error **errp)
return 0;
}

qga_vss_fsfreeze(&i, false, errp);
qga_vss_fsfreeze(&i, false, NULL, errp);

ga_unset_frozen(ga_state);
return i;
Expand Down Expand Up @@ -1660,7 +1658,6 @@ GList *ga_command_blacklist_init(GList *blacklist)
"guest-set-vcpus",
"guest-get-memory-blocks", "guest-set-memory-blocks",
"guest-get-memory-block-size",
"guest-fsfreeze-freeze-list",
NULL};
char **p = (char **)list_unsupported;

Expand Down
2 changes: 1 addition & 1 deletion qga/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ static void quit_handler(int sig)
WaitForSingleObject(hEventTimeout, 0);
CloseHandle(hEventTimeout);
}
qga_vss_fsfreeze(&i, false, &err);
qga_vss_fsfreeze(&i, false, NULL, &err);
if (err) {
g_debug("Error unfreezing filesystems prior to exiting: %s",
error_get_pretty(err));
Expand Down
5 changes: 3 additions & 2 deletions qga/vss-win32.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ void ga_uninstall_vss_provider(void)
}

/* Call VSS requester and freeze/thaw filesystems and applications */
void qga_vss_fsfreeze(int *nr_volume, bool freeze, Error **errp)
void qga_vss_fsfreeze(int *nr_volume, bool freeze,
strList *mountpoints, Error **errp)
{
const char *func_name = freeze ? "requester_freeze" : "requester_thaw";
QGAVSSRequesterFunc func;
Expand All @@ -164,5 +165,5 @@ void qga_vss_fsfreeze(int *nr_volume, bool freeze, Error **errp)
return;
}

func(nr_volume, &errset);
func(nr_volume, mountpoints, &errset);
}
3 changes: 2 additions & 1 deletion qga/vss-win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ bool vss_initialized(void);
int ga_install_vss_provider(void);
void ga_uninstall_vss_provider(void);

void qga_vss_fsfreeze(int *nr_volume, bool freeze, Error **errp);
void qga_vss_fsfreeze(int *nr_volume, bool freeze,
strList *mountpints, Error **errp);

#endif
92 changes: 66 additions & 26 deletions qga/vss-win32/requester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ static void AddComponents(ErrorSet *errset)
}
}

void requester_freeze(int *num_vols, ErrorSet *errset)
void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset)
{
COMPointer<IVssAsync> pAsync;
HANDLE volume;
Expand All @@ -246,6 +246,7 @@ void requester_freeze(int *num_vols, ErrorSet *errset)
WCHAR short_volume_name[64], *display_name = short_volume_name;
DWORD wait_status;
int num_fixed_drives = 0, i;
int num_mount_points = 0;

if (vss_ctx.pVssbc) { /* already frozen */
*num_vols = 0;
Expand Down Expand Up @@ -337,39 +338,73 @@ void requester_freeze(int *num_vols, ErrorSet *errset)
goto out;
}

volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name));
if (volume == INVALID_HANDLE_VALUE) {
err_set(errset, hr, "failed to find first volume");
goto out;
}
for (;;) {
if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) {
if (mountpoints) {
PWCHAR volume_name_wchar;
for (volList *list = (volList *)mountpoints; list; list = list->next) {
size_t len = strlen(list->value) + 1;
size_t converted = 0;
VSS_ID pid;
hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name,

volume_name_wchar = new wchar_t[len];
mbstowcs_s(&converted, volume_name_wchar, len,
list->value, _TRUNCATE);

hr = vss_ctx.pVssbc->AddToSnapshotSet(volume_name_wchar,
g_gProviderId, &pid);
if (FAILED(hr)) {
WCHAR volume_path_name[PATH_MAX];
if (GetVolumePathNamesForVolumeNameW(
short_volume_name, volume_path_name,
sizeof(volume_path_name), NULL) && *volume_path_name) {
display_name = volume_path_name;
}
err_set(errset, hr, "failed to add %S to snapshot set",
display_name);
FindVolumeClose(volume);
volume_name_wchar);
delete volume_name_wchar;
goto out;
}
num_fixed_drives++;
num_mount_points++;

delete volume_name_wchar;
}
if (!FindNextVolumeW(volume, short_volume_name,
sizeof(short_volume_name))) {
FindVolumeClose(volume);
break;

if (num_mount_points == 0) {
/* If there is no valid mount points, just exit. */
goto out;
}
}

if (num_fixed_drives == 0) {
goto out; /* If there is no fixed drive, just exit. */
if (!mountpoints) {
volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name));
if (volume == INVALID_HANDLE_VALUE) {
err_set(errset, hr, "failed to find first volume");
goto out;
}

for (;;) {
if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) {
VSS_ID pid;
hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name,
g_gProviderId, &pid);
if (FAILED(hr)) {
WCHAR volume_path_name[PATH_MAX];
if (GetVolumePathNamesForVolumeNameW(
short_volume_name, volume_path_name,
sizeof(volume_path_name), NULL) &&
*volume_path_name) {
display_name = volume_path_name;
}
err_set(errset, hr, "failed to add %S to snapshot set",
display_name);
FindVolumeClose(volume);
goto out;
}
num_fixed_drives++;
}
if (!FindNextVolumeW(volume, short_volume_name,
sizeof(short_volume_name))) {
FindVolumeClose(volume);
break;
}
}

if (num_fixed_drives == 0) {
goto out; /* If there is no fixed drive, just exit. */
}
}

hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace());
Expand Down Expand Up @@ -435,7 +470,12 @@ void requester_freeze(int *num_vols, ErrorSet *errset)
goto out;
}

*num_vols = vss_ctx.cFrozenVols = num_fixed_drives;
if (mountpoints) {
*num_vols = vss_ctx.cFrozenVols = num_mount_points;
} else {
*num_vols = vss_ctx.cFrozenVols = num_fixed_drives;
}

return;

out:
Expand All @@ -449,7 +489,7 @@ void requester_freeze(int *num_vols, ErrorSet *errset)
}


void requester_thaw(int *num_vols, ErrorSet *errset)
void requester_thaw(int *num_vols, void *mountpints, ErrorSet *errset)
{
COMPointer<IVssAsync> pAsync;

Expand Down
13 changes: 10 additions & 3 deletions qga/vss-win32/requester.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,16 @@ typedef struct ErrorSet {
STDAPI requester_init(void);
STDAPI requester_deinit(void);

typedef void (*QGAVSSRequesterFunc)(int *, ErrorSet *);
void requester_freeze(int *num_vols, ErrorSet *errset);
void requester_thaw(int *num_vols, ErrorSet *errset);
typedef struct volList volList;

struct volList {
volList *next;
char *value;
};

typedef void (*QGAVSSRequesterFunc)(int *, void *, ErrorSet *);
void requester_freeze(int *num_vols, void *volList, ErrorSet *errset);
void requester_thaw(int *num_vols, void *volList, ErrorSet *errset);

#ifdef __cplusplus
}
Expand Down

0 comments on commit 0692b03

Please sign in to comment.