qemu-ga: execute script to quiesce the guest on fsfreeze-freeze/thaw
PATCH 1/2 qemu-ga: execute script 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.
When the qemu-ga receives fsfreeze-freeze command, the script specified in --fsfreeze-script option is executed with "freeze" argument before the filesystem is frozen. For fsfreeze-thaw command, the script is executed with "thaw" argument after the filesystem is thawed.
--- qemu-ga.c | 42 +++++++++++++++++++++++++++++++++++++++++- qga/commands-posix.c | 34 ++++++++++++++++++++++++++++++++++ qga/guest-agent-core.h | 2 ++ 3 files changed, 77 insertions(+), 1 deletion(-)
qemu-ga.c +41 -1
@@ -34,6 +34,12 @@#include "qga/service-win32.h" #include <windows.h> #endif +#ifdef __linux__ +#include <linux/fs.h> +#ifdef FIFREEZE +#define CONFIG_FSFREEZE +#endif +#endif #ifndef _WIN32#define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0"
@@ -42,6 +48,9 @@#endif #define QGA_STATEDIR_DEFAULT CONFIG_QEMU_LOCALSTATEDIR "/run"#define QGA_PIDFILE_DEFAULT QGA_STATEDIR_DEFAULT "/qemu-ga.pid" +#ifdef CONFIG_FSFREEZE +#define QGA_FSFREEZE_SCRIPT_DEFAULT CONFIG_QEMU_CONFDIR "/fsfreeze.sh" +#endif #define QGA_SENTINEL_BYTE 0xFFstruct GAState {
@@ -64,6 +73,9 @@ struct GAState {const char *log_filepath;const char *pid_filepath; } deferred_options; +#ifdef CONFIG_FSFREEZE +const char *fsfreeze_script; +#endif };struct GAState *ga_state;
@@ -153,6 +165,10 @@ static void usage(const char *cmd) " %s)\n" " -l, --logfile set logfile path, logs to stderr by default\n" " -f, --pidfile specify pidfile (default is %s)\n" +#ifdef CONFIG_FSFREEZE +" -F, --fsfreeze_script\n" +" specify fsfreeze script (default is %s)\n" +#endif" -t, --statedir specify dir to store state information (absolute paths\n" " only, default is %s)\n" " -v, --verbose log extra debugging information\n"
@@ -167,6 +183,9 @@ static void usage(const char *cmd)"\n" "Report bugs to <[email protected]>\n" , cmd,QEMU_VERSION ,QGA_VIRTIO_PATH_DEFAULT ,QGA_PIDFILE_DEFAULT , +#ifdef CONFIG_FSFREEZE +QGA_FSFREEZE_SCRIPT_DEFAULT , +#endif QGA_STATEDIR_DEFAULT); }
@@ -401,6 +420,13 @@ void ga_unset_frozen(GAState *s) } } +#ifdef CONFIG_FSFREEZE +const char *ga_fsfreeze_script (GAState *s) +{ +return s->fsfreeze_script; +} +#endif +static void become_daemon (const char *pidfile) {#ifndef _WIN32
@@ -678,10 +704,13 @@ VOID WINAPI service_main(DWORD argc, TCHAR *argv[])int main (int argc,char **argv) { -const char *sopt ="hVvdm:p:l:f:b:s:t:" ; +const char *sopt ="hVvdm:p:l:f:F:b:s:t:" ;const char *method =NULL , *path =NULL ;const char *log_filepath =NULL ;const char *pid_filepath =QGA_PIDFILE_DEFAULT ; +#ifdef CONFIG_FSFREEZE +const char *fsfreeze_script =QGA_FSFREEZE_SCRIPT_DEFAULT ; +#endif const char *state_dir =QGA_STATEDIR_DEFAULT ;#ifdef _WIN32const char *service =NULL ;
@@ -691,6 +720,9 @@ int main(int argc, char **argv) { "version", 0, NULL, 'V' }, { "logfile", 1, NULL, 'l' }, { "pidfile", 1, NULL, 'f' }, +#ifdef CONFIG_FSFREEZE + { "fsfreeze-script", 1, NULL, 'F' }, +#endif { "verbose", 0, NULL, 'v' }, { "method", 1, NULL, 'm' }, { "path", 1, NULL, 'p' },
@@ -723,6 +755,11 @@ int main(int argc, char **argv)case 'f' : pid_filepath = optarg;break ; +#ifdef CONFIG_FSFREEZE +case 'F' : + fsfreeze_script = optarg; +break ; +#endif case 't' : state_dir = optarg;break ;
@@ -786,6 +823,9 @@ int main(int argc, char **argv) s =g_malloc0 (sizeof (GAState)); s->log_level = log_level; s->log_file = stderr; +#ifdef CONFIG_FSFREEZE + s->fsfreeze_script = fsfreeze_script; +#endif g_log_set_default_handler (ga_log, s);g_log_set_fatal_mask (NULL ,G_LOG_LEVEL_ERROR );ga_enable_logging (s);
qga/commands-posix.c +34 -0
@@ -13,6 +13,7 @@#include <glib.h> #include <sys/types.h> +#include <sys/stat.h> #include <sys/ioctl.h> #include <sys/wait.h> #include "qga/guest-agent-core.h"
@@ -396,6 +397,34 @@ GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)return GUEST_FSFREEZE_STATUS_THAWED ; } +int execute_fsfreeze_script (const char *arg) +{ +int ret =-1 ; +const char *fsfreeze_script; +char *cmdline; +struct stat st; + + fsfreeze_script =ga_fsfreeze_script (ga_state); +if (fsfreeze_script &&stat (fsfreeze_script, &st) ==0 ) { +if (S_ISREG (st.st_mode) && (st.st_mode &S_IXUSR )) { +slog ("executing fsfreeze script with arg `%s'" , arg); + cmdline =malloc (strlen (fsfreeze_script) +strlen (arg) +2 ); +if (cmdline) { +sprintf (cmdline,"%s %s" , fsfreeze_script, arg); + ret =system (cmdline); +free (cmdline); + } +if (ret >0 ) { +g_warning ("fsfreeze script failed with status=%d" , ret); + }else if (ret ==-1 ) { +g_warning ("execution of fsfreeze script failed: %s" , +strerror (errno)); + } + } + } +return ret; +} +/* * Walk list of mounted file systems in the guest, and freeze the ones which * are real local file systems.
@@ -410,6 +439,8 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err)slog ("guest-fsfreeze called" ); +execute_fsfreeze_script ("freeze" ); +QTAILQ_INIT (&mounts); ret =build_fs_mount_list (&mounts);if (ret <0 ) {
@@ -513,6 +544,9 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err)ga_unset_frozen (ga_state);free_fs_mount_list (&mounts); + +execute_fsfreeze_script ("thaw" ); +return i; }
qga/guest-agent-core.h +2 -0
@@ -34,6 +34,8 @@ void ga_set_response_delimited(GAState *s);bool ga_is_frozen (GAState *s);void ga_set_frozen (GAState *s);void ga_unset_frozen (GAState *s); +const char *ga_fsfreeze_script (GAState *s); +int execute_fsfreeze_script (const char *arg);#ifndef _WIN32void reopen_fd_to_null (int fd);
Signature · 1 line
1.7.11.7
Hi Tomoki,
You should use the plain text format to send your patch. Otherwise people will not be able to apply the patch. :)
Quoted 217 lines · Tomoki Sekiyama
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.
When the qemu-ga receives fsfreeze-freeze command, the script specified in --fsfreeze-script option is executed with "freeze" argument before the filesystem is frozen. For fsfreeze-thaw command, the script is executed with "thaw" argument after the filesystem is thawed.
Signed-off-by Tomoki Sekiyama <[email protected]>--- qemu-ga.c | 42 +++++++++++++++++++++++++++++++++++++++++- qga/commands-posix.c | 34 ++++++++++++++++++++++++++++++++++ qga/guest-agent-core.h | 2 ++ 3 files changed, 77 insertions(+), 1 deletion(-)qemu-ga.c +41
-1@@ -34,6 +34,12 @@#include "qga/service-win32.h" #include <windows.h> #endif +#ifdef __linux__ +#include <linux/fs.h> +#ifdef FIFREEZE +#define CONFIG_FSFREEZE +#endif +#endif #ifndef _WIN32#define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0"@@ -42,6 +48,9 @@#endif #define QGA_STATEDIR_DEFAULT CONFIG_QEMU_LOCALSTATEDIR "/run"#define QGA_PIDFILE_DEFAULT QGA_STATEDIR_DEFAULT "/qemu-ga.pid" +#ifdef CONFIG_FSFREEZE +#define QGA_FSFREEZE_SCRIPT_DEFAULT CONFIG_QEMU_CONFDIR "/fsfreeze.sh" +#endif #define QGA_SENTINEL_BYTE 0xFFstruct GAState {@@ -64,6 +73,9 @@ struct GAState {const char *log_filepath;const char *pid_filepath; } deferred_options; +#ifdef CONFIG_FSFREEZE +const char *fsfreeze_script; +#endif };struct GAState *ga_state;@@ -153,6 +165,10 @@ static void usage(const char *cmd) " %s)\n" " -l, --logfile set logfile path, logs to stderr by default\n" " -f, --pidfile specify pidfile (default is %s)\n" +#ifdef CONFIG_FSFREEZE +" -F, --fsfreeze_script\n" +" specify fsfreeze script (default is %s)\n" +#endif" -t, --statedir specify dir to store state information (absolute paths\n" " only, default is %s)\n" " -v, --verbose log extra debugging information\n" @@ -167,6 +183,9 @@ static void usage(const char *cmd)"\n" "Report bugs to <[email protected]>\n" , cmd,QEMU_VERSION ,QGA_VIRTIO_PATH_DEFAULT ,QGA_PIDFILE_DEFAULT , +#ifdef CONFIG_FSFREEZE +QGA_FSFREEZE_SCRIPT_DEFAULT , +#endif QGA_STATEDIR_DEFAULT); }@@ -401,6 +420,13 @@ void ga_unset_frozen(GAState *s) } } +#ifdef CONFIG_FSFREEZE +const char *ga_fsfreeze_script (GAState *s) +{ +return s->fsfreeze_script; +} +#endif +static void become_daemon (const char *pidfile) {#ifndef _WIN32@@ -678,10 +704,13 @@ VOID WINAPI service_main(DWORD argc, TCHAR *argv[])int main (int argc,char **argv) { -const char *sopt ="hVvdm:p:l:f:b:s:t:" ; +const char *sopt ="hVvdm:p:l:f:F:b:s:t:" ;const char *method =NULL , *path =NULL ;const char *log_filepath =NULL ;const char *pid_filepath =QGA_PIDFILE_DEFAULT ; +#ifdef CONFIG_FSFREEZE +const char *fsfreeze_script =QGA_FSFREEZE_SCRIPT_DEFAULT ; +#endif const char *state_dir =QGA_STATEDIR_DEFAULT ;#ifdef _WIN32const char *service =NULL ;@@ -691,6 +720,9 @@ int main(int argc, char **argv) { "version", 0, NULL, 'V' }, { "logfile", 1, NULL, 'l' }, { "pidfile", 1, NULL, 'f' }, +#ifdef CONFIG_FSFREEZE + { "fsfreeze-script", 1, NULL, 'F' }, +#endif { "verbose", 0, NULL, 'v' }, { "method", 1, NULL, 'm' }, { "path", 1, NULL, 'p' },@@ -723,6 +755,11 @@ int main(int argc, char **argv)case 'f' : pid_filepath = optarg;break ; +#ifdef CONFIG_FSFREEZE +case 'F' : + fsfreeze_script = optarg; +break ; +#endif case 't' : state_dir = optarg;break ;@@ -786,6 +823,9 @@ int main(int argc, char **argv) s =g_malloc0 (sizeof (GAState)); s->log_level = log_level; s->log_file = stderr; +#ifdef CONFIG_FSFREEZE + s->fsfreeze_script = fsfreeze_script; +#endif g_log_set_default_handler (ga_log, s);g_log_set_fatal_mask (NULL ,G_LOG_LEVEL_ERROR );ga_enable_logging (s);qga/commands-posix.c +34
-0@@ -13,6 +13,7 @@#include <glib.h> #include <sys/types.h> +#include <sys/stat.h> #include <sys/ioctl.h> #include <sys/wait.h> #include "qga/guest-agent-core.h" @@ -396,6 +397,34 @@ GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)return GUEST_FSFREEZE_STATUS_THAWED ; } +int execute_fsfreeze_script (const char *arg) +{ +int ret =-1 ; +const char *fsfreeze_script; +char *cmdline; +struct stat st; + + fsfreeze_script =ga_fsfreeze_script (ga_state); +if (fsfreeze_script &&stat (fsfreeze_script, &st) ==0 ) { +if (S_ISREG (st.st_mode) && (st.st_mode &S_IXUSR )) { +slog ("executing fsfreeze script with arg `%s'" , arg); + cmdline =malloc (strlen (fsfreeze_script) +strlen (arg) +2 ); +if (cmdline) { +sprintf (cmdline,"%s %s" , fsfreeze_script, arg); + ret =system (cmdline); +free (cmdline); + } +if (ret >0 ) { +g_warning ("fsfreeze script failed with status=%d" , ret); + }else if (ret ==-1 ) { +g_warning ("execution of fsfreeze script failed: %s" , +strerror (errno)); + } + } + } +return ret; +} +/* * Walk list of mounted file systems in the guest, and freeze the ones which * are real local file systems. @@ -410,6 +439,8 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err)slog ("guest-fsfreeze called" ); +execute_fsfreeze_script ("freeze" ); +QTAILQ_INIT (&mounts); ret =build_fs_mount_list (&mounts);if (ret <0 ) {@@ -513,6 +544,9 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err)ga_unset_frozen (ga_state);free_fs_mount_list (&mounts); + +execute_fsfreeze_script ("thaw" ); +return i; }qga/guest-agent-core.h +2
-0@@ -34,6 +34,8 @@ void ga_set_response_delimited(GAState *s);bool ga_is_frozen (GAState *s);void ga_set_frozen (GAState *s);void ga_unset_frozen (GAState *s); +const char *ga_fsfreeze_script (GAState *s); +int execute_fsfreeze_script (const char *arg);#ifndef _WIN32void reopen_fd_to_null (int fd);
Signature · 1 line
Lei