From patchwork Wed Jan 4 19:45:13 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Capitulino X-Patchwork-Id: 134335 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 636F01007D7 for ; Thu, 5 Jan 2012 06:45:55 +1100 (EST) Received: from localhost ([::1]:39614 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RiWmP-0002nh-I0 for incoming@patchwork.ozlabs.org; Wed, 04 Jan 2012 14:45:45 -0500 Received: from eggs.gnu.org ([140.186.70.92]:59031) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RiWm8-0002aE-Dn for qemu-devel@nongnu.org; Wed, 04 Jan 2012 14:45:30 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RiWm6-0005qJ-1c for qemu-devel@nongnu.org; Wed, 04 Jan 2012 14:45:28 -0500 Received: from mx1.redhat.com ([209.132.183.28]:34976) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RiWm5-0005pt-Jc for qemu-devel@nongnu.org; Wed, 04 Jan 2012 14:45:25 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q04JjM4X009575 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 4 Jan 2012 14:45:22 -0500 Received: from localhost (ovpn-113-123.phx2.redhat.com [10.3.113.123]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q04JjLEr013571; Wed, 4 Jan 2012 14:45:22 -0500 From: Luiz Capitulino To: qemu-devel@nongnu.org Date: Wed, 4 Jan 2012 17:45:13 -0200 Message-Id: <1325706313-21936-3-git-send-email-lcapitulino@redhat.com> In-Reply-To: <1325706313-21936-1-git-send-email-lcapitulino@redhat.com> References: <1325706313-21936-1-git-send-email-lcapitulino@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 209.132.183.28 Cc: amit.shah@redhat.com, jcody@redhat.com, mdroth@linux.vnet.ibm.com Subject: [Qemu-devel] [PATCH 2/2] qemu-ga: Add the guest-suspend command X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 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) {