diff options
author | Tomoki Sekiyama <tomoki.sekiyama.qu@hitachi.com> | 2012-12-12 12:55:55 +0900 |
---|---|---|
committer | Michael Roth <mdroth@linux.vnet.ibm.com> | 2013-01-08 16:38:12 -0600 |
commit | ec0f694c11e8e0958d727e40e0759ab99e5908d6 (patch) | |
tree | 6167bf79990fcde0edf3c0fe862fd7c62619b764 /qga/commands-posix.c | |
parent | 7b3760879bf323a0d9654a5158d5b3ed51882505 (diff) |
qemu-ga: execute hook to quiesce the guest on fsfreeze-freeze/thaw
To use the online disk snapshot for online-backup, application-level
consistency of the snapshot image is required. However, currently the
guest agent can provide only filesystem-level consistency, and the
snapshot may contain dirty data, for example, incomplete transactions.
This patch provides the opportunity to quiesce applications before
snapshot is taken.
If --fsfreeze-hook option is specified, the hook is executed with
"freeze" argument before the filesystem is frozen by fsfreeze-freeze
command. As for fsfreeze-thaw command, the hook is executed with "thaw"
argument after the filesystem is thawed.
This patch depends on patchset to improve error reporting by Luiz Capitulino:
http://lists.gnu.org/archive/html/qemu-devel/2012-11/msg03016.html
Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama.qu@hitachi.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
*clarified usage in help output
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Diffstat (limited to 'qga/commands-posix.c')
-rw-r--r-- | qga/commands-posix.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 614a421ffd..77f6ee7d5f 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -410,6 +410,66 @@ static void build_fs_mount_list(FsMountList *mounts, Error **err) #if defined(CONFIG_FSFREEZE) +typedef enum { + FSFREEZE_HOOK_THAW = 0, + FSFREEZE_HOOK_FREEZE, +} FsfreezeHookArg; + +const char *fsfreeze_hook_arg_string[] = { + "thaw", + "freeze", +}; + +static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **err) +{ + int status; + pid_t pid; + const char *hook; + const char *arg_str = fsfreeze_hook_arg_string[arg]; + Error *local_err = NULL; + + hook = ga_fsfreeze_hook(ga_state); + if (!hook) { + return; + } + if (access(hook, X_OK) != 0) { + error_setg_errno(err, errno, "can't access fsfreeze hook '%s'", hook); + return; + } + + slog("executing fsfreeze hook with arg '%s'", arg_str); + pid = fork(); + if (pid == 0) { + setsid(); + reopen_fd_to_null(0); + reopen_fd_to_null(1); + reopen_fd_to_null(2); + + execle(hook, hook, arg_str, NULL, environ); + _exit(EXIT_FAILURE); + } else if (pid < 0) { + error_setg_errno(err, errno, "failed to create child process"); + return; + } + + ga_wait_child(pid, &status, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); + return; + } + + if (!WIFEXITED(status)) { + error_setg(err, "fsfreeze hook has terminated abnormally"); + return; + } + + status = WEXITSTATUS(status); + if (status) { + error_setg(err, "fsfreeze hook has failed with status %d", status); + return; + } +} + /* * Return status of freeze/thaw */ @@ -436,6 +496,12 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err) slog("guest-fsfreeze called"); + execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); + return -1; + } + QTAILQ_INIT(&mounts); build_fs_mount_list(&mounts, &local_err); if (error_is_set(&local_err)) { @@ -537,6 +603,9 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) ga_unset_frozen(ga_state); free_fs_mount_list(&mounts); + + execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, err); + return i; } |