]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: Report errors from iohelper
authorMichal Privoznik <mprivozn@redhat.com>
Mon, 22 Oct 2012 15:07:49 +0000 (17:07 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Mon, 29 Oct 2012 16:04:26 +0000 (17:04 +0100)
Currently, we use iohelper when saving/restoring a domain.
However, if there's some kind of error (like I/O) it is not
propagated to libvirt. Since it is not qemu who is doing
the actual write() it will not get error. The iohelper does.
Therefore we should check for iohelper errors as it makes
libvirt more user friendly.

src/libvirt_private.syms
src/qemu/qemu_driver.c
src/util/virfile.c
src/util/virfile.h

index 02ca2c7af877695bf81b22977f04ebebfa198cbb..59d6de089271bb9c5801ff63536856c4df7f5a01 100644 (file)
@@ -1335,6 +1335,7 @@ virDomainListSnapshots;
 virFileLoopDeviceAssociate;
 virFileClose;
 virFileDirectFdFlag;
+virFileWrapperFdCatchError;
 virFileWrapperFdClose;
 virFileWrapperFdFree;
 virFileWrapperFdNew;
index 7dccf86f0ac645186cb9ee093bd1a7ca1ba47988..3980c10debea4e9b8dbf68cc30e3e9fbc0693ebd 100644 (file)
@@ -2950,6 +2950,7 @@ endjob:
                 if (rc < 0)
                     VIR_WARN("Unable to resume guest CPUs after save failure");
             }
+            virFileWrapperFdCatchError(wrapperFd);
         }
         if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
             vm = NULL;
@@ -3287,9 +3288,11 @@ doCoreDump(struct qemud_driver *driver,
 
 cleanup:
     VIR_FORCE_CLOSE(fd);
-    virFileWrapperFdFree(wrapperFd);
-    if (ret != 0)
+    if (ret != 0) {
+        virFileWrapperFdCatchError(wrapperFd);
         unlink(path);
+    }
+    virFileWrapperFdFree(wrapperFd);
     return ret;
 }
 
index 5b00ead2a3d3c6ad8c92735fb0eb6cbcc2ef0707..95931517473b0c8e7179223b88adf625d8868a21 100644 (file)
@@ -135,9 +135,57 @@ virFileDirectFdFlag(void)
  * read-write is not supported, just a single direction.  */
 struct _virFileWrapperFd {
     virCommandPtr cmd; /* Child iohelper process to do the I/O.  */
+    int err_fd; /* FD to read stderr of @cmd */
+    char *err_msg; /* stderr of @cmd */
+    size_t err_msg_len; /* strlen of err_msg so we don't
+                           have to compute it every time */
+    int err_watch; /* ID of watch in the event loop */
 };
 
 #ifndef WIN32
+/**
+ * virFileWrapperFdReadStdErr:
+ * @watch: watch ID
+ * @fd: the read end of pipe to iohelper's stderr
+ * @events: an OR-ed set of events which occurred on @fd
+ * @opaque: virFileWrapperFdPtr
+ *
+ * This is a callback to our eventloop which will read iohelper's
+ * stderr, reallocate @opaque->err_msg and copy data.
+ */
+static void
+virFileWrapperFdReadStdErr(int watch ATTRIBUTE_UNUSED,
+                           int fd, int events, void *opaque)
+{
+    virFileWrapperFdPtr wfd = (virFileWrapperFdPtr) opaque;
+    char ebuf[1024];
+    ssize_t nread;
+
+    if (events & VIR_EVENT_HANDLE_READABLE) {
+        while ((nread = saferead(fd, ebuf, sizeof(ebuf)))) {
+            if (nread < 0) {
+                if (errno != EAGAIN)
+                    virReportSystemError(errno, "%s",
+                                         _("unable to read iohelper's stderr"));
+                break;
+            }
+
+            if (VIR_REALLOC_N(wfd->err_msg, wfd->err_msg_len + nread + 1) < 0) {
+                virReportOOMError();
+                return;
+            }
+            memcpy(wfd->err_msg + wfd->err_msg_len, ebuf, nread);
+            wfd->err_msg_len += nread;
+            wfd->err_msg[wfd->err_msg_len] = '\0';
+        }
+    }
+
+    if (events & VIR_EVENT_HANDLE_HANGUP) {
+        virEventRemoveHandle(watch);
+        wfd->err_watch = -1;
+    }
+}
+
 /**
  * virFileWrapperFdNew:
  * @fd: pointer to fd to wrap
@@ -197,6 +245,8 @@ virFileWrapperFdNew(int *fd, const char *name, unsigned int flags)
         return NULL;
     }
 
+    ret->err_watch = -1;
+
     mode = fcntl(*fd, F_GETFL);
 
     if (mode < 0) {
@@ -229,9 +279,38 @@ virFileWrapperFdNew(int *fd, const char *name, unsigned int flags)
         virCommandAddArg(ret->cmd, "0");
     }
 
+    /* In order to catch iohelper stderr, we must:
+     * - pass a FD to virCommand (-1 to auto-allocate one)
+     * - change iohelper's env so virLog functions print to stderr
+     */
+    ret->err_fd = -1;
+    virCommandSetErrorFD(ret->cmd, &ret->err_fd);
+    virCommandAddEnvPair(ret->cmd, "LIBVIRT_LOG_OUTPUTS", "1:stderr");
+
     if (virCommandRunAsync(ret->cmd, NULL) < 0)
         goto error;
 
+    /* deliberately don't use virCommandNonblockingFDs here as it is all or
+     * nothing. And we want iohelper's stdin and stdout to block (default).
+     * However, stderr is read within event loop and therefore it must be
+     * nonblocking.*/
+    if (virSetNonBlock(ret->err_fd) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Failed to set non-blocking "
+                               "file descriptor flag"));
+        goto error;
+    }
+
+    if ((ret->err_watch = virEventAddHandle(ret->err_fd,
+                                            VIR_EVENT_HANDLE_READABLE,
+                                            virFileWrapperFdReadStdErr,
+                                            ret, NULL)) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("unable to register iohelper's "
+                         "stderr FD in the eventloop"));
+        goto error;
+    }
+
     if (VIR_CLOSE(pipefd[!output]) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("unable to close pipe"));
         goto error;
@@ -280,6 +359,21 @@ virFileWrapperFdClose(virFileWrapperFdPtr wfd)
     return virCommandWait(wfd->cmd, NULL);
 }
 
+
+/**
+ * virFileWrapperFdCatchError:
+ * @wfd: fd wrapper, or NULL
+ *
+ * If iohelper reported any error VIR_WARN() about it.
+ */
+void
+virFileWrapperFdCatchError(virFileWrapperFdPtr wfd)
+{
+    if (wfd->err_msg)
+        VIR_WARN("iohelper reports: %s", wfd->err_msg);
+}
+
+
 /**
  * virFileWrapperFdFree:
  * @wfd: fd wrapper, or NULL
@@ -295,6 +389,11 @@ virFileWrapperFdFree(virFileWrapperFdPtr wfd)
     if (!wfd)
         return;
 
+    VIR_FORCE_CLOSE(wfd->err_fd);
+    if (wfd->err_watch != -1)
+        virEventRemoveHandle(wfd->err_watch);
+    VIR_FREE(wfd->err_msg);
+
     virCommandFree(wfd->cmd);
     VIR_FREE(wfd);
 }
index c885b73c365fab39aa39aa7c6882e4306cd0764e..80daf867a5cf2d0ac9b39d408431009baeffa0a9 100644 (file)
@@ -90,6 +90,8 @@ int virFileWrapperFdClose(virFileWrapperFdPtr dfd);
 
 void virFileWrapperFdFree(virFileWrapperFdPtr dfd);
 
+void virFileWrapperFdCatchError(virFileWrapperFdPtr dfd);
+
 int virFileLock(int fd, bool shared, off_t start, off_t len);
 int virFileUnlock(int fd, off_t start, off_t len);