From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:35821) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RiX0W-0001rw-TV for qemu-devel@nongnu.org; Wed, 04 Jan 2012 15:00:22 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RiX0V-00006F-FU for qemu-devel@nongnu.org; Wed, 04 Jan 2012 15:00:20 -0500 Received: from e5.ny.us.ibm.com ([32.97.182.145]:51742) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RiX0V-000068-5j for qemu-devel@nongnu.org; Wed, 04 Jan 2012 15:00:19 -0500 Received: from /spool/local by e5.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 4 Jan 2012 15:00:18 -0500 Received: from d03av03.boulder.ibm.com (d03av03.boulder.ibm.com [9.17.195.169]) by d01relay04.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q04K0E8O292692 for ; Wed, 4 Jan 2012 15:00:15 -0500 Received: from d03av03.boulder.ibm.com (loopback [127.0.0.1]) by d03av03.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q04K0EtE016853 for ; Wed, 4 Jan 2012 13:00:14 -0700 Message-ID: <4F04AFCB.4060800@linux.vnet.ibm.com> Date: Wed, 04 Jan 2012 14:00:11 -0600 From: Michael Roth MIME-Version: 1.0 References: <1325706313-21936-1-git-send-email-lcapitulino@redhat.com> <1325706313-21936-3-git-send-email-lcapitulino@redhat.com> In-Reply-To: <1325706313-21936-3-git-send-email-lcapitulino@redhat.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH 2/2] qemu-ga: Add the guest-suspend command List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Luiz Capitulino Cc: amit.shah@redhat.com, jcody@redhat.com, qemu-devel@nongnu.org On 01/04/2012 01:45 PM, Luiz Capitulino wrote: > For now it only supports the "hibernate" mode, which suspends the > guest to disk. > > This command will try to execute the scripts provided by the pm-utils > package. If that fails, it will try to suspend manually by writing > to the "/sys/power/state" file. > > To reap terminated children, a new signal handler is installed to > catch SIGCHLD signals and a non-blocking call to waitpid() is done to > collect their exit statuses. > > Signed-off-by: Luiz Capitulino Looks good. Reviewed-by: Michael Roth > --- > qapi-schema-guest.json | 23 ++++++++++++++++++ > qemu-ga.c | 17 ++++++++++++- > qga/guest-agent-commands.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 94 insertions(+), 1 deletions(-) > > diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json > index 5f8a18d..b151670 100644 > --- a/qapi-schema-guest.json > +++ b/qapi-schema-guest.json > @@ -219,3 +219,26 @@ > ## > { 'command': 'guest-fsfreeze-thaw', > 'returns': 'int' } > + > +## > +# @guest-suspend > +# > +# Suspend guest execution by changing the guest's ACPI power state. > +# > +# This command tries to execute the scripts provided by the pm-utils > +# package. If they are not available, it will perform the suspend > +# operation by manually writing to a sysfs file. > +# > +# For the best results it's strongly recommended to have the pm-utils > +# package installed in the guest. > +# > +# @mode: 'hibernate' RAM content is saved to the disk and the guest is > +# powered off (this corresponds to ACPI S4) > +# > +# Notes: This is an asynchronous request. There's no guarantee a response > +# will be sent. Errors will be logged to guest's syslog. More modes are > +# expected in the future. > +# > +# Since: 1.1 > +## > +{ 'command': 'guest-suspend', 'data': { 'mode': 'str' } } > diff --git a/qemu-ga.c b/qemu-ga.c > index 98e4dfe..5b7a7a5 100644 > --- a/qemu-ga.c > +++ b/qemu-ga.c > @@ -17,6 +17,7 @@ > #include > #include > #include > +#include > #include "qemu_socket.h" > #include "json-streamer.h" > #include "json-parser.h" > @@ -59,9 +60,15 @@ static void quit_handler(int sig) > } > } > > +static void child_handler(int sig) > +{ > + int status; > + waitpid(-1,&status, WNOHANG); > +} > + > static void register_signal_handlers(void) > { > - struct sigaction sigact; > + struct sigaction sigact, sigact_chld; > int ret; > > memset(&sigact, 0, sizeof(struct sigaction)); > @@ -76,6 +83,14 @@ static void register_signal_handlers(void) > if (ret == -1) { > g_error("error configuring signal handler: %s", strerror(errno)); > } > + > + memset(&sigact_chld, 0, sizeof(struct sigaction)); > + sigact_chld.sa_handler = child_handler; > + sigact_chld.sa_flags = SA_NOCLDSTOP; > + ret = sigaction(SIGCHLD,&sigact_chld, NULL); > + if (ret == -1) { > + g_error("error configuring signal handler: %s", strerror(errno)); > + } > } > > static void usage(const char *cmd) > diff --git a/qga/guest-agent-commands.c b/qga/guest-agent-commands.c > index a09c8ca..19f29c6 100644 > --- a/qga/guest-agent-commands.c > +++ b/qga/guest-agent-commands.c > @@ -574,6 +574,61 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) > } > #endif > > +#define LINUX_SYS_STATE_FILE "/sys/power/state" > + > +void qmp_guest_suspend(const char *mode, Error **err) > +{ > + pid_t pid; > + const char *pmutils_bin; > + > + /* TODO implement 'sleep' and 'hybrid' modes once qemu is fixed to > + support them */ > + if (strcmp(mode, "hibernate") == 0) { > + pmutils_bin = "pm-hibernate"; > + } else { > + error_set(err, QERR_INVALID_PARAMETER, "mode"); > + return; > + } > + > + pid = fork(); > + if (pid == 0) { > + /* child */ > + int fd; > + > + setsid(); > + fclose(stdin); > + fclose(stdout); > + fclose(stderr); > + > + execlp(pmutils_bin, pmutils_bin, NULL); > + > + /* > + * The exec call should not return, if it does something went wrong. > + * In this case we try to suspend manually if 'mode' is 'hibernate' > + */ > + slog("could not execute %s: %s\n", pmutils_bin, strerror(errno)); > + slog("trying to suspend using the manual method...\n"); > + > + fd = open(LINUX_SYS_STATE_FILE, O_WRONLY); > + if (fd< 0) { > + slog("can't open file %s: %s\n", LINUX_SYS_STATE_FILE, > + strerror(errno)); > + exit(1); > + } > + > + if (write(fd, "disk", 4)< 0) { > + slog("can't write to %s: %s\n", LINUX_SYS_STATE_FILE, > + strerror(errno)); > + exit(1); > + } > + > + exit(0); > + } else if (pid< 0) { > + error_set(err, QERR_UNDEFINED_ERROR); > + return; > + } > +} > + > /* register init/cleanup routines for stateful command groups */ > void ga_command_state_init(GAState *s, GACommandState *cs) > {