]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
utils: Extend virCommandProcessIO to include the send buffers
authorStefan Berger <stefanb@linux.vnet.ibm.com>
Thu, 25 Jul 2019 18:22:09 +0000 (14:22 -0400)
committerDaniel P. Berrangé <berrange@redhat.com>
Fri, 26 Jul 2019 09:30:56 +0000 (10:30 +0100)
Extend virCommandProcessIO to include the send buffers in the poll
loop.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
src/util/vircommand.c

index a3a5780d2911d362fa39243da57a11b50e96fd8c..774038e536a2d7af8c9e4814bd25a0b60273b237 100644 (file)
@@ -1820,6 +1820,61 @@ virCommandSetSendBuffer(virCommandPtr cmd,
 
 #endif
 
+static int
+virCommandSendBuffersFillPollfd(virCommandPtr cmd,
+                                struct pollfd *fds,
+                                int startidx)
+{
+    size_t i, j;
+
+    for (i = 0, j = 0; i < virCommandGetNumSendBuffers(cmd); i++) {
+        if (cmd->sendBuffers[i].fd >= 0) {
+            fds[startidx + j].fd = cmd->sendBuffers[i].fd;
+            fds[startidx + j].events = POLLOUT;
+            fds[startidx + j].revents = 0;
+            j++;
+        }
+    }
+
+    return j;
+}
+
+
+static int
+virCommandSendBuffersHandlePoll(virCommandPtr cmd,
+                                struct pollfd *fds)
+{
+    size_t i;
+    ssize_t done;
+
+    for (i = 0; i < virCommandGetNumSendBuffers(cmd); i++) {
+        if (fds->fd == cmd->sendBuffers[i].fd)
+            break;
+    }
+    if (i == virCommandGetNumSendBuffers(cmd))
+        return 0;
+
+    done = write(fds->fd,
+                 cmd->sendBuffers[i].buffer + cmd->sendBuffers[i].offset,
+                 cmd->sendBuffers[i].buflen - cmd->sendBuffers[i].offset);
+    if (done < 0) {
+        if (errno == EPIPE) {
+            VIR_DEBUG("child closed PIPE early, ignoring EPIPE "
+                      "on fd %d", cmd->sendBuffers[i].fd);
+            VIR_FORCE_CLOSE(cmd->sendBuffers[i].fd);
+        } else if (errno != EINTR && errno != EAGAIN) {
+            virReportSystemError(errno, "%s",
+                                 _("unable to write to child input"));
+            return -1;
+        }
+    } else {
+        cmd->sendBuffers[i].offset += done;
+        if (cmd->sendBuffers[i].offset == cmd->sendBuffers[i].buflen)
+            VIR_FORCE_CLOSE(cmd->sendBuffers[i].fd);
+    }
+    return 0;
+}
+
 /**
  * virCommandSetInputBuffer:
  * @cmd: the command to modify
@@ -2174,7 +2229,7 @@ virCommandProcessIO(virCommandPtr cmd)
         goto cleanup;
     ret = -1;
 
-    if (VIR_ALLOC_N(fds, 3) < 0)
+    if (VIR_ALLOC_N(fds, 3 + virCommandGetNumSendBuffers(cmd)) < 0)
         goto cleanup;
 
     for (;;) {
@@ -2200,6 +2255,8 @@ virCommandProcessIO(virCommandPtr cmd)
             nfds++;
         }
 
+        nfds += virCommandSendBuffersFillPollfd(cmd, fds, nfds);
+
         if (nfds == 0)
             break;
 
@@ -2272,6 +2329,9 @@ virCommandProcessIO(virCommandPtr cmd)
                     if (inoff == inlen)
                         VIR_FORCE_CLOSE(cmd->inpipe);
                 }
+            } else if (fds[i].revents & (POLLOUT | POLLHUP | POLLERR)) {
+                if (virCommandSendBuffersHandlePoll(cmd, &fds[i]) < 0)
+                    goto cleanup;
             }
         }
     }