qga-win: add support for qmp_guest_fsfreeze_freeze_list
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 <mdroth@linux.vnet.ibm.com> Signed-off-by: Chen Hanxiao <chenhanxiao@gmail.com> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
This commit is contained in:
parent
bad0227d3a
commit
0692b03ee1
@ -790,6 +790,13 @@ GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
|
|||||||
* The frozen state is limited for up to 10 seconds by VSS.
|
* 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(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;
|
int i;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
@ -804,7 +811,7 @@ int64_t qmp_guest_fsfreeze_freeze(Error **errp)
|
|||||||
/* cannot risk guest agent blocking itself on a write in this state */
|
/* cannot risk guest agent blocking itself on a write in this state */
|
||||||
ga_set_frozen(ga_state);
|
ga_set_frozen(ga_state);
|
||||||
|
|
||||||
qga_vss_fsfreeze(&i, true, &local_err);
|
qga_vss_fsfreeze(&i, true, mountpoints, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto error;
|
goto error;
|
||||||
@ -822,15 +829,6 @@ error:
|
|||||||
return 0;
|
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.
|
* Thaw local file systems using Volume Shadow-copy Service.
|
||||||
*/
|
*/
|
||||||
@ -843,7 +841,7 @@ int64_t qmp_guest_fsfreeze_thaw(Error **errp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
qga_vss_fsfreeze(&i, false, errp);
|
qga_vss_fsfreeze(&i, false, NULL, errp);
|
||||||
|
|
||||||
ga_unset_frozen(ga_state);
|
ga_unset_frozen(ga_state);
|
||||||
return i;
|
return i;
|
||||||
@ -1660,7 +1658,6 @@ GList *ga_command_blacklist_init(GList *blacklist)
|
|||||||
"guest-set-vcpus",
|
"guest-set-vcpus",
|
||||||
"guest-get-memory-blocks", "guest-set-memory-blocks",
|
"guest-get-memory-blocks", "guest-set-memory-blocks",
|
||||||
"guest-get-memory-block-size",
|
"guest-get-memory-block-size",
|
||||||
"guest-fsfreeze-freeze-list",
|
|
||||||
NULL};
|
NULL};
|
||||||
char **p = (char **)list_unsupported;
|
char **p = (char **)list_unsupported;
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ static void quit_handler(int sig)
|
|||||||
WaitForSingleObject(hEventTimeout, 0);
|
WaitForSingleObject(hEventTimeout, 0);
|
||||||
CloseHandle(hEventTimeout);
|
CloseHandle(hEventTimeout);
|
||||||
}
|
}
|
||||||
qga_vss_fsfreeze(&i, false, &err);
|
qga_vss_fsfreeze(&i, false, NULL, &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
g_debug("Error unfreezing filesystems prior to exiting: %s",
|
g_debug("Error unfreezing filesystems prior to exiting: %s",
|
||||||
error_get_pretty(err));
|
error_get_pretty(err));
|
||||||
|
@ -147,7 +147,8 @@ void ga_uninstall_vss_provider(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Call VSS requester and freeze/thaw filesystems and applications */
|
/* 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";
|
const char *func_name = freeze ? "requester_freeze" : "requester_thaw";
|
||||||
QGAVSSRequesterFunc func;
|
QGAVSSRequesterFunc func;
|
||||||
@ -164,5 +165,5 @@ void qga_vss_fsfreeze(int *nr_volume, bool freeze, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
func(nr_volume, &errset);
|
func(nr_volume, mountpoints, &errset);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ bool vss_initialized(void);
|
|||||||
int ga_install_vss_provider(void);
|
int ga_install_vss_provider(void);
|
||||||
void ga_uninstall_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
|
#endif
|
||||||
|
@ -234,7 +234,7 @@ out:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void requester_freeze(int *num_vols, ErrorSet *errset)
|
void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset)
|
||||||
{
|
{
|
||||||
COMPointer<IVssAsync> pAsync;
|
COMPointer<IVssAsync> pAsync;
|
||||||
HANDLE volume;
|
HANDLE volume;
|
||||||
@ -246,6 +246,7 @@ void requester_freeze(int *num_vols, ErrorSet *errset)
|
|||||||
WCHAR short_volume_name[64], *display_name = short_volume_name;
|
WCHAR short_volume_name[64], *display_name = short_volume_name;
|
||||||
DWORD wait_status;
|
DWORD wait_status;
|
||||||
int num_fixed_drives = 0, i;
|
int num_fixed_drives = 0, i;
|
||||||
|
int num_mount_points = 0;
|
||||||
|
|
||||||
if (vss_ctx.pVssbc) { /* already frozen */
|
if (vss_ctx.pVssbc) { /* already frozen */
|
||||||
*num_vols = 0;
|
*num_vols = 0;
|
||||||
@ -337,39 +338,73 @@ void requester_freeze(int *num_vols, ErrorSet *errset)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name));
|
if (mountpoints) {
|
||||||
if (volume == INVALID_HANDLE_VALUE) {
|
PWCHAR volume_name_wchar;
|
||||||
err_set(errset, hr, "failed to find first volume");
|
for (volList *list = (volList *)mountpoints; list; list = list->next) {
|
||||||
goto out;
|
size_t len = strlen(list->value) + 1;
|
||||||
}
|
size_t converted = 0;
|
||||||
for (;;) {
|
|
||||||
if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) {
|
|
||||||
VSS_ID pid;
|
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);
|
g_gProviderId, &pid);
|
||||||
if (FAILED(hr)) {
|
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",
|
err_set(errset, hr, "failed to add %S to snapshot set",
|
||||||
display_name);
|
volume_name_wchar);
|
||||||
FindVolumeClose(volume);
|
delete volume_name_wchar;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
num_fixed_drives++;
|
num_mount_points++;
|
||||||
|
|
||||||
|
delete volume_name_wchar;
|
||||||
}
|
}
|
||||||
if (!FindNextVolumeW(volume, short_volume_name,
|
|
||||||
sizeof(short_volume_name))) {
|
if (num_mount_points == 0) {
|
||||||
FindVolumeClose(volume);
|
/* If there is no valid mount points, just exit. */
|
||||||
break;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_fixed_drives == 0) {
|
if (!mountpoints) {
|
||||||
goto out; /* If there is no fixed drive, just exit. */
|
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());
|
hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace());
|
||||||
@ -435,7 +470,12 @@ void requester_freeze(int *num_vols, ErrorSet *errset)
|
|||||||
goto out;
|
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;
|
return;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -449,7 +489,7 @@ out1:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void requester_thaw(int *num_vols, ErrorSet *errset)
|
void requester_thaw(int *num_vols, void *mountpints, ErrorSet *errset)
|
||||||
{
|
{
|
||||||
COMPointer<IVssAsync> pAsync;
|
COMPointer<IVssAsync> pAsync;
|
||||||
|
|
||||||
|
@ -34,9 +34,16 @@ typedef struct ErrorSet {
|
|||||||
STDAPI requester_init(void);
|
STDAPI requester_init(void);
|
||||||
STDAPI requester_deinit(void);
|
STDAPI requester_deinit(void);
|
||||||
|
|
||||||
typedef void (*QGAVSSRequesterFunc)(int *, ErrorSet *);
|
typedef struct volList volList;
|
||||||
void requester_freeze(int *num_vols, ErrorSet *errset);
|
|
||||||
void requester_thaw(int *num_vols, ErrorSet *errset);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user