[Qemu-devel] Re: [PATCH 1/2] Add virtagent file system freeze/thaw
On Tue, 2011-02-01 at 11:58 +0100, jes.soren...@redhat.com wrote: > +/* > + * 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 (fsfreeze_status == FREEZE_FROZEN) { > +ret = 0; > +goto out; > +} > + > +ret = build_mount_list(); > +if (ret < 0) { > +goto out; > +} > + > +fsfreeze_status = FREEZE_INPROGRESS; > + > +entry = mount_list; > +while(entry) { > +fd = qemu_open(entry->dirname, O_RDONLY); > +if (fd == -1) { > +ret = errno; > +goto error; > +} > +ret = ioctl(fd, FIFREEZE); > +if (ret < 0 && ret != EOPNOTSUPP) { > +goto error; > +} Here we silently ignore filesystems that do not support the FIFREEZE ioctl. Do we need to have a more complex return value so that we can communicate which mount points could not be frozen? Otherwise, an unsuspecting host could retrieve a corrupted snapshot of that filesystem, right? > + > +close(fd); > +entry = entry->next; > +i++; > +} > + > +fsfreeze_status = FREEZE_FROZEN; > +ret = i; > +out: > +result = xmlrpc_build_value(env, "i", ret); > +return result; > +error: > +if (i > 0) { > +fsfreeze_status = FREEZE_ERROR; > +} > +goto out; > +} -- Thanks, Adam
[Qemu-devel] Re: [PATCH 1/2] Add virtagent file system freeze/thaw
On 02/01/11 15:48, Adam Litke wrote: > On Tue, 2011-02-01 at 11:58 +0100, jes.soren...@redhat.com wrote: >> +/* >> + * 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 (fsfreeze_status == FREEZE_FROZEN) { >> +ret = 0; >> +goto out; >> +} >> + >> +ret = build_mount_list(); >> +if (ret < 0) { >> +goto out; >> +} >> + >> +fsfreeze_status = FREEZE_INPROGRESS; >> + >> +entry = mount_list; >> +while(entry) { >> +fd = qemu_open(entry->dirname, O_RDONLY); >> +if (fd == -1) { >> +ret = errno; >> +goto error; >> +} >> +ret = ioctl(fd, FIFREEZE); >> +if (ret < 0 && ret != EOPNOTSUPP) { >> +goto error; >> +} > > Here we silently ignore filesystems that do not support the FIFREEZE > ioctl. Do we need to have a more complex return value so that we can > communicate which mount points could not be frozen? Otherwise, an > unsuspecting host could retrieve a corrupted snapshot of that > filesystem, right? That is correct, however most Linux file systems do support it, and for the ones that don't, there really isn't anything we can do. Cheers, Jes
[Qemu-devel] Re: [PATCH 1/2] Add virtagent file system freeze/thaw
On 02/01/2011 04:58 AM, jes.soren...@redhat.com wrote: From: Jes Sorensen 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 --- virtagent-common.h |8 ++ virtagent-server.c | 196 2 files changed, 204 insertions(+), 0 deletions(-) diff --git a/virtagent-common.h b/virtagent-common.h index 5d8f5c1..220a4b6 100644 --- a/virtagent-common.h +++ b/virtagent-common.h @@ -61,6 +61,14 @@ typedef struct VAContext { const char *channel_path; } VAContext; +enum vs_fsfreeze_status { +FREEZE_ERROR = -1, +FREEZE_THAWED = 0, +FREEZE_INPROGRESS = 1, +FREEZE_FROZEN = 2, +FREEZE_THAWINPROGRESS = 3, +}; Any reason for vs_* vs. va_*? + 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..cf2a3f0 100644 --- a/virtagent-server.c +++ b/virtagent-server.c @@ -14,6 +14,13 @@ #include #include "qemu_socket.h" #include "virtagent-common.h" +#include +#include +#include +#include +#include +#include +#include Can probably clean these up a bit, I believe fcntl.h/errno.h/stat.h are already available at least. static VAServerData *va_server_data; static bool va_enable_syslog = false; /* enable syslog'ing of RPCs */ @@ -217,6 +224,189 @@ 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; +}; + +static struct direntry *mount_list; +static int fsfreeze_status; + +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)); + if (!entry) { + goto fail; + } + entry->dirname = qemu_strdup(mnt->mnt_dir); + entry->devtype = qemu_strdup(mnt->mnt_type); + entry->next = mount_list; + + mount_list = entry; +} + +endmntent(fp); + +return 0; + +fail: +while(mount_list) { + next = mount_list->next; + qemu_free(mount_list->dirname); + qemu_free(mount_list->devtype); + qemu_free(mount_list); + mount_list = next; +} should be spaces instead of tabs + +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 (fsfreeze_status == FREEZE_FROZEN) { +ret = 0; +goto out; +} + +ret = build_mount_list(); +if (ret< 0) { +goto out; +} + +fsfreeze_status = FREEZE_INPROGRESS; + +entry = mount_list; I think as we start adding more and more stateful RPCs, free-floating state variables can start getting a bit hairy to keep track of. Eventually I'd like to have state information that only applies to a subset of RPCs consolidated into a single object. I wouldn't focus on this too much because I'd like to have an interface to do this in the future (mainly so they can state objects can register themselves and provide a reset() function that can be called when, for instance, an agent disconnects/reconnects), but in the meantime I think it would be more readable to have a global va_fsfreeze_state object to track freeze status and mount points. +while(entry) { +fd = qemu_open(entry->dirname, O_RDONL
[Qemu-devel] Re: [PATCH 1/2] Add virtagent file system freeze/thaw
On 02/01/11 17:50, Michael Roth wrote: > On 02/01/2011 04:58 AM, jes.soren...@redhat.com wrote: >> +enum vs_fsfreeze_status { >> +FREEZE_ERROR = -1, >> +FREEZE_THAWED = 0, >> +FREEZE_INPROGRESS = 1, >> +FREEZE_FROZEN = 2, >> +FREEZE_THAWINPROGRESS = 3, >> +}; > > Any reason for vs_* vs. va_*? H let me see if I can find a good excuse for that typo :) >> diff --git a/virtagent-server.c b/virtagent-server.c >> index 7bb35b2..cf2a3f0 100644 >> --- a/virtagent-server.c >> +++ b/virtagent-server.c >> @@ -14,6 +14,13 @@ >> #include >> #include "qemu_socket.h" >> #include "virtagent-common.h" >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include > > Can probably clean these up a bit, I believe fcntl.h/errno.h/stat.h are > already available at least. Carry-over from writing the code outside of qemu. Would be much cleaner than relying on the include everything and the kitchen sink in a global header file, but thats how it is :( >> + >> +fsfreeze_status = FREEZE_INPROGRESS; >> + >> +entry = mount_list; > > I think as we start adding more and more stateful RPCs, free-floating > state variables can start getting a bit hairy to keep track of. > Eventually I'd like to have state information that only applies to a > subset of RPCs consolidated into a single object. I wouldn't focus on > this too much because I'd like to have an interface to do this in the > future (mainly so they can state objects can register themselves and > provide a reset() function that can be called when, for instance, an > agent disconnects/reconnects), but in the meantime I think it would be > more readable to have a global va_fsfreeze_state object to track freeze > status and mount points. Urgh, what do you mean by object here? I have to admit the word object always makes me cringe I changed the variables to have the va_ prefix. >> +static xmlrpc_value *va_fsstatus(xmlrpc_env *env, >> + xmlrpc_value *params, >> + void *user_data) >> +{ >> +xmlrpc_value *result = xmlrpc_build_value(env, "i", >> fsfreeze_status); >> +SLOG("va_fsstatus()"); >> +return result; >> +} > > Hmm, you mentioned before that these freezes may be long-running > jobs...do the ioctl()'s not return until completion? There is global > timeout in virtagent, currently under a minute, to prevent a virtagent > monitor command from hanging the monitor session, so if it's unlikely > you'll fit in this window we'll need to work on something to better > support these this kinds of situations. I think 1 minute is fine, but we should probably look at something a little more flexible for handling commands over the longer term. Maybe have virtagent spawn threads for executing some commands? > The 3 main approaches would be: > > 1) allow command-specific timeouts with values that are sane for the > command in question, and potentially allow timeouts to be disabled > 2) fork() long running jobs and provide a mechanism for them to provide > asynchronous updates to us to we can query status > 3) fork() long running jobs, have them provide status information > elsewhere, and provide a polling function to check that status > > 3) would likely require something like writing status to a file and then > provide a polling function to check it, which doesn't work here so > that's probably out. > > I'd initially planned on doing 2) at some point, but I'm beginning to > think 1) is the better approach, since qemu "opts in" on how long it's > willing to hang for a particular command, so there's not really any > surprises. At least not to qemu...users might get worried after a while, > so there is a bit of a trade-off. But it's also more user-friendlyno > need for polling or dealing with asynchronous updates to figure out when > an RPC has actually finished. Seem reasonable? I am not sure which is really the best solution. Basically we will need to classify commands into two categories, so if you issue a certain type of command, like agent_fsfreeze() (basically when the agent is in FREEZE_FROZEN state) only status commands are allowed to execute in parallel. Anything that tries to issue a write to the file system will hang until agent_fsthaw is called. However it would be useful to be able to call in for non-blocking status commands etc. I'll post a v2 in a minute that addresses the issues pointed out by Stefan and you. I think the threading/timeout aspect is something we need to look at for the longer term. Cheers, Jes
[Qemu-devel] Re: [PATCH 1/2] Add virtagent file system freeze/thaw
On 02/02/2011 02:42 AM, jes.soren...@redhat.com wrote: From: Jes Sorensen 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 --- virtagent-common.h |8 ++ virtagent-server.c | 190 2 files changed, 198 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..ffbe163 100644 --- a/virtagent-server.c +++ b/virtagent-server.c @@ -14,6 +14,10 @@ #include #include "qemu_socket.h" #include "virtagent-common.h" +#include +#include +#include +#include static VAServerData *va_server_data; static bool va_enable_syslog = false; /* enable syslog'ing of RPCs */ @@ -217,6 +221,186 @@ 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; +}; + +static struct direntry *va_mount_list; +static int va_fsfreeze_status; And what I meant in the last RFC about using "objects" was to encapsulate global state information for a particular group of commands in single data type/variable. We're gonna end up with a similar set of variables for stateful RPCs like copyfile and potentially a few for things like spice. So to avoid having things get too cluttered up I'd prefer something like, in this particular case: typedef struct VAFSFreezeState { struct direntry *mount_list; int status; } VAFSFeezeState; static VAFSFreezeState va_fsfreeze_state; + +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; +} You have tabs instead of spaces here + +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 = va_mount_list; + + va_mount_list = entry; Here too +} + +endmntent(fp); + +return 0; + +fail: +while(va_mount_list) { + next = va_mount_list->next; Here too. Might be some other spots but you get the point :) +qemu_free(va_mount_list->dirname); +qemu_free(va_mount_list->devtype); +qemu_free(va_mount_list); +va_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 (va_fsfreeze_status != FREEZE_THAWED) { +ret = 0; +goto out; +} + +ret = build_mount_list(); +if (ret< 0) { +goto out; +} + +va_fsfreeze_status = FREEZE_INPROGRESS; + +entry = va_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; +
[Qemu-devel] Re: [PATCH 1/2] Add virtagent file system freeze/thaw
On 02/03/11 19:11, Michael Roth wrote: >> @@ -217,6 +221,186 @@ 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; >> +}; >> + >> +static struct direntry *va_mount_list; >> +static int va_fsfreeze_status; > > And what I meant in the last RFC about using "objects" was to > encapsulate global state information for a particular group of commands > in single data type/variable. We're gonna end up with a similar set of > variables for stateful RPCs like copyfile and potentially a few for > things like spice. So to avoid having things get too cluttered up I'd > prefer something like, in this particular case: > > typedef struct VAFSFreezeState { > struct direntry *mount_list; > int status; > } VAFSFeezeState; > > static VAFSFreezeState va_fsfreeze_state; Ok, I got rid of the tabs (damn I thought I had caught them all), and added a struct to keep the freeze state. I didn't add any typedef grossness though. v3 coming up. Cheers, Jes