[Libguestfs] [PATCH libguestfs v3] lib: Handle slow USB devices more gracefully.

Richard W.M. Jones rjones at redhat.com
Tue Jan 19 16:18:46 UTC 2016


Libvirt has a fixed 15 second timeout for qemu to exit.  If qemu is
writing to a slow USB key, it can hang (in D state) for much longer
than this - many minutes usually.

The solution is to check specifically for the libvirt EBUSY error when
this happens, and retry the virDomainDestroyFlags operation
(indefinitely).

See also the description here:
https://www.redhat.com/archives/libvir-list/2016-January/msg00767.html

Similar to the following OpenStack Nova commit:
http://git.openstack.org/cgit/openstack/nova/commit/?id=3907867

Thanks: Kashyap Chamarthy and Daniel Berrange.
---
 src/launch-libvirt.c | 45 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 35 insertions(+), 10 deletions(-)

diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c
index 8215e02..90b6c49 100644
--- a/src/launch-libvirt.c
+++ b/src/launch-libvirt.c
@@ -25,6 +25,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <grp.h>
+#include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <assert.h>
@@ -2015,6 +2016,8 @@ ignore_errors (void *ignore, virErrorPtr ignore2)
   /* empty */
 }
 
+static int destroy_domain (guestfs_h *g, virDomainPtr dom, int check_for_errors);
+
 static int
 shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors)
 {
@@ -2023,23 +2026,14 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors)
   virDomainPtr dom = data->dom;
   size_t i;
   int ret = 0;
-  int flags;
 
   /* Note that we can be called back very early in launch (specifically
    * from launch_libvirt itself), when conn and dom might be NULL.
    */
-
   if (dom != NULL) {
-    flags = check_for_errors ? VIR_DOMAIN_DESTROY_GRACEFUL : 0;
-    debug (g, "calling virDomainDestroy \"%s\" flags=%s",
-           data->name, check_for_errors ? "VIR_DOMAIN_DESTROY_GRACEFUL" : "0");
-    if (virDomainDestroyFlags (dom, flags) == -1) {
-      libvirt_error (g, _("could not destroy libvirt domain"));
-      ret = -1;
-    }
+    ret = destroy_domain (g, dom, check_for_errors);
     virDomainFree (dom);
   }
-
   if (conn != NULL)
     virConnectClose (conn);
 
@@ -2068,6 +2062,37 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors)
   return ret;
 }
 
+/* Wrapper around virDomainDestroy which handles errors and retries.. */
+static int
+destroy_domain (guestfs_h *g, virDomainPtr dom, int check_for_errors)
+{
+  const int flags = check_for_errors ? VIR_DOMAIN_DESTROY_GRACEFUL : 0;
+  virErrorPtr err;
+
+ again:
+  debug (g, "calling virDomainDestroy flags=%s",
+         check_for_errors ? "VIR_DOMAIN_DESTROY_GRACEFUL" : "0");
+  if (virDomainDestroyFlags (dom, flags) == -1) {
+    err = virGetLastError ();
+
+    /* Second chance if we're just waiting for qemu to shut down.  See:
+     * https://www.redhat.com/archives/libvir-list/2016-January/msg00767.html
+     */
+    if ((flags & VIR_DOMAIN_DESTROY_GRACEFUL) &&
+        err && err->code == VIR_ERR_SYSTEM_ERROR && err->int1 == EBUSY)
+      goto again;
+
+    /* "Domain not found" is not treated as an error. */
+    if (err && err->code == VIR_ERR_NO_DOMAIN)
+      return 0;
+
+    libvirt_error (g, _("could not destroy libvirt domain"));
+    return -1;
+  }
+
+  return 0;
+}
+
 /* Wrapper around error() which produces better errors for
  * libvirt functions.
  */
-- 
2.5.0




More information about the Libguestfs mailing list