[Libguestfs] [PATCH] p2v: Inhibit power saving during the conversion.

Richard W.M. Jones rjones at redhat.com
Mon Oct 24 17:23:26 UTC 2016


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




More information about the Libguestfs mailing list