Richard W.M. Jones
2016-Oct-24 17:23 UTC
[Libguestfs] [PATCH] p2v: Inhibit power saving during the conversion.
We do this by sending an Inhibit() message to logind and receiving a file descriptor back, which we hold open until the conversion completes (or fails). This is described here: https://www.freedesktop.org/wiki/Software/systemd/inhibit/ This adds an additional optional dependency on DBus since we use DBus to call the Inhibit() method. Reported-by: Chris Cowley. --- docs/guestfs-building.pod | 8 +++ m4/guestfs_misc_libraries.m4 | 9 +++ p2v/Makefile.am | 5 +- p2v/conversion.c | 10 +++ p2v/inhibit.c | 153 +++++++++++++++++++++++++++++++++++++++++++ p2v/p2v.h | 3 + 6 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 p2v/inhibit.c diff --git a/docs/guestfs-building.pod b/docs/guestfs-building.pod index 5c1806d..1e4a574 100644 --- a/docs/guestfs-building.pod +++ b/docs/guestfs-building.pod @@ -282,6 +282,14 @@ Either Gtk 2 or Gtk 3 can be used. If you want to select a specific version of Gtk, use S<C<./configure --with-gtk=2>> or S<C<./configure --with-gtk=3>>. +=item DBus + +Optional. + +If the DBus C API is available, virt-p2v can send a DBus message to +logind to inhibit power saving (sleep, suspend, etc) during P2V +conversions. + =item zip =item unzip diff --git a/m4/guestfs_misc_libraries.m4 b/m4/guestfs_misc_libraries.m4 index fee265b..82864f9 100644 --- a/m4/guestfs_misc_libraries.m4 +++ b/m4/guestfs_misc_libraries.m4 @@ -103,6 +103,15 @@ elif test "x$with_gtk" = "xcheck"; then ]) fi +dnl DBus is an optional dependency of virt-p2v. +PKG_CHECK_MODULES([DBUS], [dbus-1], [ + AC_SUBST([DBUS_CFLAGS]) + AC_SUBST([DBUS_LIBS]) + AC_DEFINE([HAVE_DBUS],[1],[DBus found at compile time.]) +],[ + AC_MSG_WARN([DBus not found, virt-p2v will not be able to inhibit power saving during P2V conversions]) +]) + dnl Can we build virt-p2v? AC_MSG_CHECKING([if we can build virt-p2v]) if test "x$GTK_LIBS" != "x"; then diff --git a/p2v/Makefile.am b/p2v/Makefile.am index 1f6e601..216ab30 100644 --- a/p2v/Makefile.am +++ b/p2v/Makefile.am @@ -77,6 +77,7 @@ virt_p2v_SOURCES = \ config.c \ conversion.c \ gui.c \ + inhibit.c \ kernel.c \ kernel-cmdline.c \ main.c \ @@ -97,13 +98,15 @@ virt_p2v_CFLAGS = \ $(WARN_CFLAGS) $(WERROR_CFLAGS) \ $(PCRE_CFLAGS) \ $(LIBXML2_CFLAGS) \ - $(GTK_CFLAGS) + $(GTK_CFLAGS) \ + $(DBUS_CFLAGS) virt_p2v_LDADD = \ $(top_builddir)/src/libutils.la \ $(PCRE_LIBS) \ $(LIBXML2_LIBS) \ $(GTK_LIBS) \ + $(DBUS_LIBS) \ ../gnulib/lib/libgnu.la # Scripts to build the disk image, USB key, or kickstart. diff --git a/p2v/conversion.c b/p2v/conversion.c index 3be9a45..a5b6769 100644 --- a/p2v/conversion.c +++ b/p2v/conversion.c @@ -208,6 +208,7 @@ start_conversion (struct config *config, char libvirt_xml_file[] = "/tmp/p2v.XXXXXX/physical.xml"; char wrapper_script[] = "/tmp/p2v.XXXXXX/virt-v2v-wrapper.sh"; char dmesg_file[] = "/tmp/p2v.XXXXXX/dmesg"; + int inhibit_fd = -1; #if DEBUG_STDERR print_config (config, stderr); @@ -218,6 +219,12 @@ start_conversion (struct config *config, set_running (1); set_cancel_requested (0); + inhibit_fd = inhibit_sleep (); +#ifdef DEBUG_STDERR + if (inhibit_fd == -1) + fprintf (stderr, "warning: virt-p2v cannot inhibit power saving during conversion.\n"); +#endif + data_conns = malloc (sizeof (struct data_conn) * nr_disks); if (data_conns == NULL) error (EXIT_FAILURE, errno, "malloc"); @@ -426,6 +433,9 @@ start_conversion (struct config *config, } cleanup_data_conns (data_conns, nr_disks); + if (inhibit_fd >= 0) + close (inhibit_fd); + set_running (0); return ret; diff --git a/p2v/inhibit.c b/p2v/inhibit.c new file mode 100644 index 0000000..b5acfd4 --- /dev/null +++ b/p2v/inhibit.c @@ -0,0 +1,153 @@ +/* virt-p2v + * Copyright (C) 2016 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** + * This file is used to inhibit power saving, sleep, suspend etc during + * the conversion. + * + * The method it uses is to send a dbus message to logind, as + * described here: + * + * https://www.freedesktop.org/wiki/Software/systemd/inhibit/ + * + * If virt-p2v is compiled with DBus support then this does nothing. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef HAVE_DBUS +#include <dbus/dbus.h> +#endif + +#include "p2v.h" + +/** + * Inhibit all forms of power saving. A file descriptor is returned, + * and when the file descriptor is closed the inhibit is stopped. + * + * If the function returns C<-1> then C<Inhibit> operation could not + * be performed (eg. if we are compiled with DBus support, or there is + * some error contacting logind). This is not usually fatal from the + * point of view of the caller, conversion can continue. + */ +int +inhibit_sleep (void) +{ +#ifdef HAVE_DBUS + DBusError err; + DBusConnection *conn = NULL; + DBusMessage *msg = NULL; + DBusMessageIter args; + DBusPendingCall *pending = NULL; + const char *what = "shutdown:sleep:idle"; + const char *who = "virt-p2v"; + const char *why = "virt-p2v conversion is running"; + const char *mode = "block"; + int fd = -1; + + dbus_error_init (&err); + + conn = dbus_bus_get (DBUS_BUS_SYSTEM, &err); + if (dbus_error_is_set (&err)) { + fprintf (stderr, "dbus: cannot connect to system bus: %s\n", err.message); + goto out; + } + if (conn == NULL) + goto out; + + msg = dbus_message_new_method_call ("org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "Inhibit"); + if (msg == NULL) { + fprintf (stderr, "dbus: cannot create message\n"); + goto out; + } + + dbus_message_iter_init_append (msg, &args); + if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &what) || + !dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &who) || + !dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &why) || + !dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &mode)) { + fprintf (stderr, "dbus: cannot add message arguments\n"); + goto out; + } + + if (!dbus_connection_send_with_reply (conn, msg, &pending, -1)) { + fprintf (stderr, "dbus: cannot send Inhibit message to logind\n"); + goto out; + } + if (pending == NULL) + goto out; + dbus_connection_flush (conn); + dbus_message_unref (msg); + msg = NULL; + + dbus_pending_call_block (pending); + msg = dbus_pending_call_steal_reply (pending); + if (msg == NULL) { + fprintf (stderr, "dbus: could not read message reply\n"); + goto out; + } + + dbus_pending_call_unref (pending); + pending = NULL; + + if (!dbus_message_iter_init (msg, &args)) { + fprintf (stderr, "dbus: message reply has no return value\n"); + goto out; + } + + if (dbus_message_iter_get_arg_type (&args) != DBUS_TYPE_UNIX_FD) { + fprintf (stderr, "dbus: message reply is not a file descriptor\n"); + goto out; + } + + dbus_message_iter_get_basic (&args, &fd); + +#ifdef DEBUG_STDERR + fprintf (stderr, "dbus: Inhibit() call returned file descriptor %d\n", fd); +#endif + +out: + if (pending != NULL) + dbus_pending_call_unref (pending); + if (msg != NULL) + dbus_message_unref (msg); + + /* This is the system bus connection, so unref-ing it does not + * actually close it. + */ + if (conn != NULL) + dbus_connection_unref (conn); + + dbus_error_free (&err); + + return fd; + +#else /* !HAVE_DBUS */ +#ifdef DEBUG_STDERR + fprintf (stderr, "warning: virt-p2v compiled without DBus support.\n"); +#endif + return -1; +#endif +} diff --git a/p2v/p2v.h b/p2v/p2v.h index 1282a17..86e2c50 100644 --- a/p2v/p2v.h +++ b/p2v/p2v.h @@ -120,6 +120,9 @@ extern const char *get_conversion_error (void); extern void cancel_conversion (void); extern int conversion_is_running (void); +/* inhibit.c */ +extern int inhibit_sleep (void); + /* ssh.c */ extern int test_connection (struct config *); extern mexp_h *open_data_connection (struct config *, int *local_port, int *remote_port); -- 2.9.3
Pino Toscano
2016-Oct-25 09:01 UTC
Re: [Libguestfs] [PATCH] p2v: Inhibit power saving during the conversion.
On Monday, 24 October 2016 18:23:26 CEST Richard W.M. Jones wrote:> We do this by sending an Inhibit() message to logind and receiving a > file descriptor back, which we hold open until the conversion > completes (or fails). This is described here: > https://www.freedesktop.org/wiki/Software/systemd/inhibit/ > > This adds an additional optional dependency on DBus since we use DBus > to call the Inhibit() method. > > Reported-by: Chris Cowley.Minor nitpick: "D-Bus" is the proper spelling. The rest of the libdbus-1 implementation looks correct, checking with the API docs (and a bit the internals). Maybe could be worth using the glib-based interface for it (dbus glib or GDBus). -- Pino Toscano
Richard W.M. Jones
2016-Oct-25 09:16 UTC
Re: [Libguestfs] [PATCH] p2v: Inhibit power saving during the conversion.
On Tue, Oct 25, 2016 at 11:01:08AM +0200, Pino Toscano wrote:> On Monday, 24 October 2016 18:23:26 CEST Richard W.M. Jones wrote: > > We do this by sending an Inhibit() message to logind and receiving a > > file descriptor back, which we hold open until the conversion > > completes (or fails). This is described here: > > https://www.freedesktop.org/wiki/Software/systemd/inhibit/ > > > > This adds an additional optional dependency on DBus since we use DBus > > to call the Inhibit() method. > > > > Reported-by: Chris Cowley. > > Minor nitpick: "D-Bus" is the proper spelling.OK I will change this.> The rest of the libdbus-1 implementation looks correct, checking with > the API docs (and a bit the internals). Maybe could be worth using > the glib-based interface for it (dbus glib or GDBus).Is there any particular advantage? The low level API is pretty horrible to use, but in the end it wasn't too much code. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 100 libraries supported. http://fedoraproject.org/wiki/MinGW
Possibly Parallel Threads
- [PATCH] p2v: wait for qemu-nbd before starting conversion (RHBZ#1167774)
- [PATCH] p2v: Calculate offset of the Real Time Clock from UTC.
- [PATCH] p2v: show error dialog if virt-v2v fails (RHBZ#1167601)
- [PATCH] Add getCoreInfo function
- [PATCH] build: improve Gtk check