* [Qemu-devel] [PATCH 1/2] Add virtagent file system freeze/thaw
2011-02-04 10:57 [Qemu-devel] [PATCH v3 0/2] virtagent - fsfreeze support Jes.Sorensen
@ 2011-02-04 10:57 ` Jes.Sorensen
2011-02-04 10:57 ` [Qemu-devel] [PATCH 2/2] Add monitor commands for fsfreeze support Jes.Sorensen
1 sibling, 0 replies; 3+ messages in thread
From: Jes.Sorensen @ 2011-02-04 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: lcapitulino, badari, mdroth, stefanha, agl
From: Jes Sorensen <Jes.Sorensen@redhat.com>
Implement freeze/thaw support in the guest, allowing the host to
request the guest freezes all it's file systems before a live snapshot
is performed.
- fsfreeze(): Walk the list of mounted local real file systems,
and freeze them.
- fsthaw(): Walk the list of previously frozen file systems and
thaw them.
- fsstatus(): Return the current status of freeze/thaw. The host must
poll this function, in case fsfreeze() returned with a
timeout, to wait for the operation to finish.
Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
---
virtagent-common.h | 8 ++
virtagent-server.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 203 insertions(+), 0 deletions(-)
diff --git a/virtagent-common.h b/virtagent-common.h
index 5d8f5c1..7c6d9ef 100644
--- a/virtagent-common.h
+++ b/virtagent-common.h
@@ -61,6 +61,14 @@ typedef struct VAContext {
const char *channel_path;
} VAContext;
+enum va_fsfreeze_status {
+ FREEZE_ERROR = -1,
+ FREEZE_THAWED = 0,
+ FREEZE_INPROGRESS = 1,
+ FREEZE_FROZEN = 2,
+ FREEZE_THAWINPROGRESS = 3,
+};
+
enum va_job_status {
VA_JOB_STATUS_PENDING = 0,
VA_JOB_STATUS_OK,
diff --git a/virtagent-server.c b/virtagent-server.c
index 7bb35b2..5140918 100644
--- a/virtagent-server.c
+++ b/virtagent-server.c
@@ -14,6 +14,10 @@
#include <syslog.h>
#include "qemu_socket.h"
#include "virtagent-common.h"
+#include <mntent.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
static VAServerData *va_server_data;
static bool va_enable_syslog = false; /* enable syslog'ing of RPCs */
@@ -217,6 +221,191 @@ static xmlrpc_value *va_hello(xmlrpc_env *env,
return result;
}
+
+/*
+ * Walk the mount table and build a list of local file systems
+ */
+
+struct direntry {
+ char *dirname;
+ char *devtype;
+ struct direntry *next;
+};
+
+struct va_freezestate {
+ struct direntry *mount_list;
+ int status;
+};
+
+static struct va_freezestate freezestate;
+
+static int build_mount_list(void)
+{
+ struct mntent *mnt;
+ struct direntry *entry;
+ struct direntry *next;
+ char const *mtab = MOUNTED;
+ FILE *fp;
+
+ fp = setmntent(mtab, "r");
+ if (!fp) {
+ fprintf(stderr, "unable to read mtab\n");
+ goto fail;
+ }
+
+ while ((mnt = getmntent(fp))) {
+ /*
+ * An entry which device name doesn't start with a '/' is
+ * either a dummy file system or a network file system.
+ * Add special handling for smbfs and cifs as is done by
+ * coreutils as well.
+ */
+ if ((mnt->mnt_fsname[0] != '/') ||
+ (strcmp(mnt->mnt_type, "smbfs") == 0) ||
+ (strcmp(mnt->mnt_type, "cifs") == 0)) {
+ continue;
+ }
+
+ entry = qemu_malloc(sizeof(struct direntry));
+ entry->dirname = qemu_strdup(mnt->mnt_dir);
+ entry->devtype = qemu_strdup(mnt->mnt_type);
+ entry->next = freezestate.mount_list;
+
+ freezestate.mount_list = entry;
+ }
+
+ endmntent(fp);
+
+ return 0;
+
+fail:
+ while(freezestate.mount_list) {
+ next = freezestate.mount_list->next;
+ qemu_free(freezestate.mount_list->dirname);
+ qemu_free(freezestate.mount_list->devtype);
+ qemu_free(freezestate.mount_list);
+ freezestate.mount_list = next;
+ }
+
+ return -1;
+}
+
+/*
+ * va_fsfreeze(): Walk list of mounted file systems in the guest, and
+ * freeze the ones which are real local file systems.
+ * rpc return values: Number of file systems frozen, -1 on error.
+ */
+static xmlrpc_value *va_fsfreeze(xmlrpc_env *env,
+ xmlrpc_value *params,
+ void *user_data)
+{
+ xmlrpc_int32 ret = 0, i = 0;
+ xmlrpc_value *result;
+ struct direntry *entry;
+ int fd;
+ SLOG("va_fsfreeze()");
+
+ if (freezestate.status != FREEZE_THAWED) {
+ ret = 0;
+ goto out;
+ }
+
+ ret = build_mount_list();
+ if (ret < 0) {
+ goto out;
+ }
+
+ freezestate.status = FREEZE_INPROGRESS;
+
+ entry = freezestate.mount_list;
+ while(entry) {
+ fd = qemu_open(entry->dirname, O_RDONLY);
+ if (fd == -1) {
+ ret = errno;
+ goto error;
+ }
+ ret = ioctl(fd, FIFREEZE);
+ close(fd);
+ if (ret < 0 && ret != EOPNOTSUPP) {
+ goto error;
+ }
+
+ entry = entry->next;
+ i++;
+ }
+
+ freezestate.status = FREEZE_FROZEN;
+ ret = i;
+out:
+ result = xmlrpc_build_value(env, "i", ret);
+ return result;
+error:
+ if (i > 0) {
+ freezestate.status = FREEZE_ERROR;
+ }
+ goto out;
+}
+
+/*
+ * va_fsthaw(): Walk list of frozen file systems in the guest, and
+ * thaw them.
+ * rpc return values: Number of file systems thawed on success, -1 on error.
+ */
+static xmlrpc_value *va_fsthaw(xmlrpc_env *env,
+ xmlrpc_value *params,
+ void *user_data)
+{
+ xmlrpc_int32 ret;
+ xmlrpc_value *result;
+ struct direntry *entry;
+ int fd, i = 0;
+ SLOG("va_fsthaw()");
+
+ if (freezestate.status != FREEZE_FROZEN) {
+ ret = 0;
+ goto out;
+ }
+
+ while((entry = freezestate.mount_list)) {
+ fd = qemu_open(entry->dirname, O_RDONLY);
+ if (fd == -1) {
+ ret = -1;
+ goto out;
+ }
+ ret = ioctl(fd, FITHAW);
+ close(fd);
+ if (ret < 0 && ret != EOPNOTSUPP) {
+ ret = -1;
+ goto out;
+ }
+
+ freezestate.mount_list = entry->next;
+ qemu_free(entry->dirname);
+ qemu_free(entry->devtype);
+ qemu_free(entry);
+ i++;
+ }
+
+ freezestate.status = FREEZE_THAWED;
+ ret = i;
+out:
+ result = xmlrpc_build_value(env, "i", ret);
+ return result;
+}
+
+/*
+ * va_fsstatus(): Return status of freeze/thaw
+ * rpc return values: fsfreeze_status
+ */
+static xmlrpc_value *va_fsstatus(xmlrpc_env *env,
+ xmlrpc_value *params,
+ void *user_data)
+{
+ xmlrpc_value *result = xmlrpc_build_value(env, "i", freezestate.status);
+ SLOG("va_fsstatus()");
+ return result;
+}
+
typedef struct RPCFunction {
xmlrpc_value *(*func)(xmlrpc_env *env, xmlrpc_value *param, void *unused);
const char *func_name;
@@ -237,6 +426,12 @@ static RPCFunction guest_functions[] = {
.func_name = "va.ping" },
{ .func = va_capabilities,
.func_name = "va.capabilities" },
+ { .func = va_fsfreeze,
+ .func_name = "va.fsfreeze" },
+ { .func = va_fsthaw,
+ .func_name = "va.fsthaw" },
+ { .func = va_fsstatus,
+ .func_name = "va.fsstatus" },
{ NULL, NULL }
};
static RPCFunction host_functions[] = {
--
1.7.3.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [Qemu-devel] [PATCH 2/2] Add monitor commands for fsfreeze support
2011-02-04 10:57 [Qemu-devel] [PATCH v3 0/2] virtagent - fsfreeze support Jes.Sorensen
2011-02-04 10:57 ` [Qemu-devel] [PATCH 1/2] Add virtagent file system freeze/thaw Jes.Sorensen
@ 2011-02-04 10:57 ` Jes.Sorensen
1 sibling, 0 replies; 3+ messages in thread
From: Jes.Sorensen @ 2011-02-04 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: lcapitulino, badari, mdroth, stefanha, agl
From: Jes Sorensen <Jes.Sorensen@redhat.com>
This patch adds the following monitor commands:
agent_fsfreeze:
- Freezes all local file systems in the guest. Command will print
the number of file systems that were frozen.
agent_fsthaw:
- Thaws all local file systems in the guest. Command will print
the number of file systems that were thawed.
agent_fsstatus:
- Prints the current status of file systems in the guest:
Thawed, frozen, thaw in progress, freeze in progress, error.
Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
---
hmp-commands.hx | 48 +++++++++++
virtagent-common.h | 1 +
virtagent.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++++++++
virtagent.h | 9 ++
4 files changed, 293 insertions(+), 0 deletions(-)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 9c7ac0b..f4150da 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1310,6 +1310,54 @@ STEXI
Fetch and re-negotiate guest agent capabilties
ETEXI
+ {
+ .name = "agent_fsfreeze",
+ .args_type = "",
+ .params = "",
+ .help = "Freeze all local file systems mounted in the guest",
+ .user_print = do_agent_fsfreeze_print,
+ .mhandler.cmd_async = do_agent_fsfreeze,
+ .flags = MONITOR_CMD_ASYNC,
+ },
+
+STEXI
+@item agent_fsfreeze
+@findex agent_fsfreeze
+Freeze all local mounted file systems in guest
+ETEXI
+
+ {
+ .name = "agent_fsthaw",
+ .args_type = "",
+ .params = "",
+ .help = "Thaw all local file systems mounted in the guest",
+ .user_print = do_agent_fsthaw_print,
+ .mhandler.cmd_async = do_agent_fsthaw,
+ .flags = MONITOR_CMD_ASYNC,
+ },
+
+STEXI
+@item agent_fsthaw
+@findex agent_fsthaw
+Thaw all local mounted file systems in guest
+ETEXI
+
+ {
+ .name = "agent_fsstatus",
+ .args_type = "",
+ .params = "",
+ .help = "Display status of file system freeze progress in guest",
+ .user_print = do_agent_fsstatus_print,
+ .mhandler.cmd_async = do_agent_fsstatus,
+ .flags = MONITOR_CMD_ASYNC,
+ },
+
+STEXI
+@item agent_fsstatus
+@findex agent_fsstatus
+Get status of file system freeze in guest
+ETEXI
+
STEXI
@end table
ETEXI
diff --git a/virtagent-common.h b/virtagent-common.h
index 7c6d9ef..ff7bf23 100644
--- a/virtagent-common.h
+++ b/virtagent-common.h
@@ -24,6 +24,7 @@
#include "monitor.h"
#include "virtagent-server.h"
#include "virtagent.h"
+#include "qint.h"
#define DEBUG_VA
diff --git a/virtagent.c b/virtagent.c
index b5e7944..4277802 100644
--- a/virtagent.c
+++ b/virtagent.c
@@ -640,3 +640,238 @@ int va_send_hello(void)
xmlrpc_DECREF(params);
return ret;
}
+
+void do_agent_fsfreeze_print(Monitor *mon, const QObject *data)
+{
+ TRACE("called");
+
+ monitor_printf(mon, "File systems frozen: %" PRId64 "\n",
+ qint_get_int((qobject_to_qint(data))));
+}
+
+static void do_agent_fsfreeze_cb(const char *resp_data,
+ size_t resp_data_len,
+ MonitorCompletion *mon_cb,
+ void *mon_data)
+{
+ xmlrpc_value *resp = NULL;
+ xmlrpc_env env;
+ xmlrpc_int32 retval = 0;
+ QInt *qint;
+
+ TRACE("called");
+
+ if (resp_data == NULL) {
+ LOG("error handling RPC request");
+ return;
+ }
+
+ xmlrpc_env_init(&env);
+ resp = xmlrpc_parse_response(&env, resp_data, resp_data_len);
+ if (va_rpc_has_error(&env)) {
+ LOG("error parsing RPC response");
+ return;
+ }
+
+ xmlrpc_parse_value(&env, resp, "i", &retval);
+ if (va_rpc_has_error(&env)) {
+ retval = -1;
+ goto out;
+ }
+
+out:
+ qint = qint_from_int(retval);
+ xmlrpc_DECREF(resp);
+ if (mon_cb) {
+ mon_cb(mon_data, QOBJECT(qint));
+ }
+ qobject_decref(QOBJECT(qint));
+}
+
+int do_agent_fsfreeze(Monitor *mon, const QDict *mon_params,
+ MonitorCompletion cb, void *opaque)
+{
+ xmlrpc_env env;
+ xmlrpc_value *params;
+ int ret;
+
+ TRACE("called");
+
+ xmlrpc_env_init(&env);
+ params = xmlrpc_build_value(&env, "()");
+ if (va_rpc_has_error(&env)) {
+ return -1;
+ }
+
+ ret = va_do_rpc(&env, "va.fsfreeze", params, do_agent_fsfreeze_cb,
+ cb, opaque);
+ if (ret) {
+ qerror_report(QERR_VA_FAILED, ret, strerror(ret));
+ }
+ xmlrpc_DECREF(params);
+ return ret;
+}
+
+void do_agent_fsthaw_print(Monitor *mon, const QObject *data)
+{
+ TRACE("called");
+
+ monitor_printf(mon, "File systems thawed: %" PRId64 "\n",
+ qint_get_int((qobject_to_qint(data))));
+}
+
+static void do_agent_fsthaw_cb(const char *resp_data,
+ size_t resp_data_len,
+ MonitorCompletion *mon_cb,
+ void *mon_data)
+{
+ xmlrpc_value *resp = NULL;
+ xmlrpc_env env;
+ xmlrpc_int32 retval = 0;
+ QInt *qint;
+
+ TRACE("called");
+
+ if (resp_data == NULL) {
+ LOG("error handling RPC request");
+ return;
+ }
+
+ xmlrpc_env_init(&env);
+ resp = xmlrpc_parse_response(&env, resp_data, resp_data_len);
+ if (va_rpc_has_error(&env)) {
+ LOG("error parsing RPC response");
+ return;
+ }
+
+ xmlrpc_parse_value(&env, resp, "i", &retval);
+ if (va_rpc_has_error(&env)) {
+ retval = -1;
+ goto out;
+ }
+
+out:
+ qint = qint_from_int(retval);
+ xmlrpc_DECREF(resp);
+ if (mon_cb) {
+ mon_cb(mon_data, QOBJECT(qint));
+ }
+ qobject_decref(QOBJECT(qint));
+}
+
+int do_agent_fsthaw(Monitor *mon, const QDict *mon_params,
+ MonitorCompletion cb, void *opaque)
+{
+ xmlrpc_env env;
+ xmlrpc_value *params;
+ int ret;
+
+ TRACE("called");
+
+ xmlrpc_env_init(&env);
+ params = xmlrpc_build_value(&env, "()");
+ if (va_rpc_has_error(&env)) {
+ return -1;
+ }
+
+ ret = va_do_rpc(&env, "va.fsthaw", params, do_agent_fsthaw_cb, cb, opaque);
+ if (ret) {
+ qerror_report(QERR_VA_FAILED, ret, strerror(ret));
+ }
+ xmlrpc_DECREF(params);
+ return ret;
+}
+
+void do_agent_fsstatus_print(Monitor *mon, const QObject *data)
+{
+ int64_t fsstatus;
+ TRACE("called");
+
+ fsstatus = qint_get_int((qobject_to_qint(data)));
+
+ monitor_printf(mon, "File systems freeze status: ");
+ switch(fsstatus) {
+ case FREEZE_THAWED:
+ monitor_printf(mon, "Thawed");
+ break;
+ case FREEZE_INPROGRESS:
+ monitor_printf(mon, "Freeze in progress");
+ break;
+ case FREEZE_THAWINPROGRESS:
+ monitor_printf(mon, "Thaw in progress");
+ break;
+ case FREEZE_FROZEN:
+ monitor_printf(mon, "Frozen");
+ break;
+ case FREEZE_ERROR:
+ monitor_printf(mon, "Error");
+ break;
+ default:
+ monitor_printf(mon, "unknown");
+ }
+
+ monitor_printf(mon, "\n");
+}
+
+static void do_agent_fsstatus_cb(const char *resp_data,
+ size_t resp_data_len,
+ MonitorCompletion *mon_cb,
+ void *mon_data)
+{
+ xmlrpc_value *resp = NULL;
+ xmlrpc_env env;
+ xmlrpc_int32 retval = 0;
+ QInt *qint;
+
+ TRACE("called");
+
+ if (resp_data == NULL) {
+ LOG("error handling RPC request");
+ return;
+ }
+
+ xmlrpc_env_init(&env);
+ resp = xmlrpc_parse_response(&env, resp_data, resp_data_len);
+ if (va_rpc_has_error(&env)) {
+ LOG("error parsing RPC response");
+ return;
+ }
+
+ xmlrpc_parse_value(&env, resp, "i", &retval);
+ if (va_rpc_has_error(&env)) {
+ retval = -1;
+ goto out;
+ }
+
+out:
+ qint = qint_from_int(retval);
+ xmlrpc_DECREF(resp);
+ if (mon_cb) {
+ mon_cb(mon_data, QOBJECT(qint));
+ }
+ qobject_decref(QOBJECT(qint));
+}
+
+int do_agent_fsstatus(Monitor *mon, const QDict *mon_params,
+ MonitorCompletion cb, void *opaque)
+{
+ xmlrpc_env env;
+ xmlrpc_value *params;
+ int ret;
+
+ TRACE("called");
+
+ xmlrpc_env_init(&env);
+ params = xmlrpc_build_value(&env, "()");
+ if (va_rpc_has_error(&env)) {
+ return -1;
+ }
+
+ ret = va_do_rpc(&env, "va.fsstatus", params, do_agent_fsstatus_cb,
+ cb, opaque);
+ if (ret) {
+ qerror_report(QERR_VA_FAILED, ret, strerror(ret));
+ }
+ xmlrpc_DECREF(params);
+ return ret;
+}
diff --git a/virtagent.h b/virtagent.h
index dba90d0..0d7575d 100644
--- a/virtagent.h
+++ b/virtagent.h
@@ -46,5 +46,14 @@ int do_agent_capabilities(Monitor *mon, const QDict *mon_params,
MonitorCompletion cb, void *opaque);
int va_client_init_capabilities(void);
int va_send_hello(void);
+void do_agent_fsfreeze_print(Monitor *mon, const QObject *qobject);
+int do_agent_fsfreeze(Monitor *mon, const QDict *mon_params,
+ MonitorCompletion cb, void *opaque);
+void do_agent_fsthaw_print(Monitor *mon, const QObject *qobject);
+int do_agent_fsthaw(Monitor *mon, const QDict *mon_params,
+ MonitorCompletion cb, void *opaque);
+void do_agent_fsstatus_print(Monitor *mon, const QObject *qobject);
+int do_agent_fsstatus(Monitor *mon, const QDict *mon_params,
+ MonitorCompletion cb, void *opaque);
#endif /* VIRTAGENT_H */
--
1.7.3.5
^ permalink raw reply related [flat|nested] 3+ messages in thread