From patchwork Wed Dec 14 18:17:51 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Capitulino X-Patchwork-Id: 131453 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 8A5CC1007D7 for ; Thu, 15 Dec 2011 05:18:20 +1100 (EST) Received: from localhost ([::1]:53773 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RatPE-0002Pk-AC for incoming@patchwork.ozlabs.org; Wed, 14 Dec 2011 13:18:16 -0500 Received: from eggs.gnu.org ([140.186.70.92]:33822) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RatP3-0002PU-El for qemu-devel@nongnu.org; Wed, 14 Dec 2011 13:18:11 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RatOx-0008EW-9V for qemu-devel@nongnu.org; Wed, 14 Dec 2011 13:18:05 -0500 Received: from mx1.redhat.com ([209.132.183.28]:15687) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RatOw-0008EQ-Rq for qemu-devel@nongnu.org; Wed, 14 Dec 2011 13:17:59 -0500 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id pBEIHssC005360 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 14 Dec 2011 13:17:54 -0500 Received: from doriath (ovpn-113-145.phx2.redhat.com [10.3.113.145]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id pBEIHqli028515; Wed, 14 Dec 2011 13:17:53 -0500 Date: Wed, 14 Dec 2011 16:17:51 -0200 From: Luiz Capitulino To: Michael Roth Message-ID: <20111214161751.543e0b02@doriath> In-Reply-To: <20111214143855.5652b0cb@doriath> References: <20111213162850.4cd135a3@doriath> <4EE7AF7C.2060302@linux.vnet.ibm.com> <20111214110029.4549bf90@doriath> <4EE8C6B5.1010406@linux.vnet.ibm.com> <20111214143855.5652b0cb@doriath> Organization: Red Hat Mime-Version: 1.0 X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 209.132.183.28 Cc: Amit Shah , aliguori@us.ibm.com, qemu-devel Subject: Re: [Qemu-devel] [PATCH v2] 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 On Wed, 14 Dec 2011 14:38:55 -0200 Luiz Capitulino wrote: > > > I'm also wondering if we could use g_child_watch_add(), but it's not clear > > > to me if it works with processes not created with g_spawn_*() functions. > > > > GPid's map to something other than PIDs on Windows, so I think we'd have > > issues there. But our fork() approach probably wouldn't work at all on > > Windows except maybe under cygwin, so at some point we'd probably want > > to switch over to g_spawn for this kind of stuff anyway... > > > > So this might be a good point to switch over to using the glib functions. > > > > Would you mind trying to do the hibernate/zombie reaping stuff using > > g_spawn+g_child_watch_add()? It might end up being the easiest route. > > Otherwise I can take a look at it later today. > > Well, there are two problems with g_spawn wrt to the manual method of > writing to the sysfs file. The first one is that I'm not sure if g_spawn() > reports the file not found error synchronously. The other problem is that, > I'd have to fork() anyway to write to the sysfs file (unless we decide that > it's ok to do this synchronously, which seems ok to me). The version below uses g_spawn_async(). The code is a bit simpler than previous versions, but there are two important details about it: 1. I'm letting g_spawn_async() reap the child automatically. I don't know how it does it though. I'd guess it uses g_child_watch_add(), worst case it ignores SIGCHLD (although I think this would be awful) 2. The manual method of writing to the sysfs is done synchronously. This means that the command response will only be sent when the guest resumes If you think this approach is acceptable, I'll test it more, update its doc, etc and post it again. diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json index 5f8a18d..63f65a6 100644 --- a/qapi-schema-guest.json +++ b/qapi-schema-guest.json @@ -219,3 +219,20 @@ ## { 'command': 'guest-fsfreeze-thaw', 'returns': 'int' } + +## +# @guest-suspend +# +# Suspend guest execution by entering ACPI power state S3 or S4. +# +# @mode: 'hibernate' RAM content is saved in the disk and the guest is +# powered down (this corresponds to ACPI S4) +# 'sleep' execution is suspended but the RAM retains its contents +# (this corresponds to ACPI S3) +# +# Notes: This is an asynchronous request. There's no guarantee it will +# succeed. Errors will be logged to guest's syslog. +# +# Since: 1.1 +## +{ 'command': 'guest-suspend', 'data': { 'mode': 'str' } } diff --git a/qga/guest-agent-commands.c b/qga/guest-agent-commands.c index a09c8ca..0c6b78e 100644 --- a/qga/guest-agent-commands.c +++ b/qga/guest-agent-commands.c @@ -574,6 +574,56 @@ 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) +{ + GError *error = NULL; + gchar *argv[2]; + + if (strcmp(mode, "hibernate") == 0) { + argv[0] = (gchar *) "pm-hibernate"; + } else if (strcmp(mode, "sleep") == 0) { + argv[0] = (gchar *) "pm-suspend"; + } else if (strcmp(mode, "hybrid") == 0) { + argv[0] = (gchar *) "pm-hybrid"; + } else { + error_set(err, QERR_INVALID_PARAMETER, "mode"); + return; + } + + argv[1] = NULL; + if (g_spawn_async(NULL, argv, NULL,G_SPAWN_SEARCH_PATH | + G_SPAWN_FILE_AND_ARGV_ZERO, + NULL, NULL, NULL, &error) < 0) { + int fd; + const char *cmd; + + slog("%s\n", error->message); + g_error_free(error); + + if (strcmp(mode, "hybrid") == 0) { + error_set(err, QERR_UNDEFINED_ERROR); + return; + } + + slog("trying to suspend using the manual method...\n"); + + fd = open(LINUX_SYS_STATE_FILE, O_WRONLY); + if (fd < 0) { + error_set(err, QERR_OPEN_FILE_FAILED, LINUX_SYS_STATE_FILE); + return; + } + + cmd = strcmp(mode, "sleep") == 0 ? "mem" : "disk"; + if (write(fd, cmd, strlen(cmd)) < 0) { + error_set(err, QERR_IO_ERROR); + } + + close(fd); + } +} + /* register init/cleanup routines for stateful command groups */ void ga_command_state_init(GAState *s, GACommandState *cs) {