[libvirt] [PATCH 25/27] fdstream: Suppress use of IO helper for sparse streams

Michal Privoznik mprivozn at redhat.com
Thu Apr 28 10:05:12 UTC 2016


This is kind of a hacky approach to the following problem, but so
far I am unable to come up with anything better. On some
occasions (esp. when dealing with regular files) libvirt_iohelper
is spawned to prefetch data for us. We will then have a pipe then
for reading the data from it. This does not fit in our sparse
stream implementation as one simply doesn't lseek() over a pipe.
Until this is resolved, let's suppress use of the IO helper and
read data from FD directly.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 src/fdstream.c                | 58 +++++++++++++++++++++++++++----------------
 src/fdstream.h                |  3 ++-
 src/storage/storage_backend.c |  6 +++--
 3 files changed, 43 insertions(+), 24 deletions(-)

diff --git a/src/fdstream.c b/src/fdstream.c
index 38342a7..41e9e06 100644
--- a/src/fdstream.c
+++ b/src/fdstream.c
@@ -78,6 +78,11 @@ struct virFDStreamData {
     virMutex lock;
 };
 
+enum {
+    VIR_FDSTREAM_OPEN_FORCE_IOHELPER    = 1 << 0,
+    VIR_FDSTREAM_OPEN_SPARSE            = 1 << 1,
+};
+
 
 static int virFDStreamRemoveCallback(virStreamPtr stream)
 {
@@ -574,7 +579,8 @@ static int virFDStreamOpenInternal(virStreamPtr st,
                                    int fd,
                                    virCommandPtr cmd,
                                    int errfd,
-                                   unsigned long long length)
+                                   unsigned long long length,
+                                   unsigned int flags)
 {
     struct virFDStreamData *fdst;
 
@@ -603,8 +609,10 @@ static int virFDStreamOpenInternal(virStreamPtr st,
 
     st->driver = &virFDStreamDrv;
     st->privateData = fdst;
-    st->skipCb = virFDStreamSkip;
-    st->inDataCb = virFDStreamInData;
+    if (flags & VIR_FDSTREAM_OPEN_SPARSE) {
+        st->skipCb = virFDStreamSkip;
+        st->inDataCb = virFDStreamInData;
+    }
 
     return 0;
 }
@@ -613,7 +621,7 @@ static int virFDStreamOpenInternal(virStreamPtr st,
 int virFDStreamOpen(virStreamPtr st,
                     int fd)
 {
-    return virFDStreamOpenInternal(st, fd, NULL, -1, 0);
+    return virFDStreamOpenInternal(st, fd, NULL, -1, 0, 0);
 }
 
 
@@ -659,7 +667,7 @@ int virFDStreamConnectUNIX(virStreamPtr st,
         goto error;
     }
 
-    if (virFDStreamOpenInternal(st, fd, NULL, -1, 0) < 0)
+    if (virFDStreamOpenInternal(st, fd, NULL, -1, 0, 0) < 0)
         goto error;
     return 0;
 
@@ -685,7 +693,7 @@ virFDStreamOpenFileInternal(virStreamPtr st,
                             unsigned long long length,
                             int oflags,
                             int mode,
-                            bool forceIOHelper)
+                            unsigned int flags)
 {
     int fd = -1;
     int childfd = -1;
@@ -694,8 +702,8 @@ virFDStreamOpenFileInternal(virStreamPtr st,
     int errfd = -1;
     char *iohelper_path = NULL;
 
-    VIR_DEBUG("st=%p path=%s oflags=%x offset=%llu length=%llu mode=%o",
-              st, path, oflags, offset, length, mode);
+    VIR_DEBUG("st=%p path=%s oflags=%x offset=%llu length=%llu mode=%o flags=%x",
+              st, path, oflags, offset, length, mode, flags);
 
     oflags |= O_NOCTTY | O_BINARY;
 
@@ -729,10 +737,15 @@ virFDStreamOpenFileInternal(virStreamPtr st,
      * non-blocking I/O on block devs/regular files. To
      * support those we need to fork a helper process to do
      * the I/O so we just have a fifo. Or use AIO :-(
+     * Moreover, when opening a file for a sparse stream, make
+     * sure we end up with something seekable which a FIFO is
+     * not.
      */
-    if ((st->flags & VIR_STREAM_NONBLOCK) &&
-        ((!S_ISCHR(sb.st_mode) &&
-          !S_ISFIFO(sb.st_mode)) || forceIOHelper)) {
+    if (!(flags & VIR_FDSTREAM_OPEN_SPARSE) &&
+        ((st->flags & VIR_STREAM_NONBLOCK) &&
+         ((!S_ISCHR(sb.st_mode) &&
+           !S_ISFIFO(sb.st_mode)) ||
+          flags & VIR_FDSTREAM_OPEN_FORCE_IOHELPER))) {
         int fds[2] = { -1, -1 };
 
         if ((oflags & O_ACCMODE) == O_RDWR) {
@@ -781,7 +794,7 @@ virFDStreamOpenFileInternal(virStreamPtr st,
         VIR_FORCE_CLOSE(childfd);
     }
 
-    if (virFDStreamOpenInternal(st, fd, cmd, errfd, length) < 0)
+    if (virFDStreamOpenInternal(st, fd, cmd, errfd, length, flags) < 0)
         goto error;
 
     return 0;
@@ -811,7 +824,7 @@ int virFDStreamOpenFile(virStreamPtr st,
     }
     return virFDStreamOpenFileInternal(st, path,
                                        offset, length,
-                                       oflags, 0, false);
+                                       oflags, 0, 0);
 }
 
 int virFDStreamCreateFile(virStreamPtr st,
@@ -823,8 +836,7 @@ int virFDStreamCreateFile(virStreamPtr st,
 {
     return virFDStreamOpenFileInternal(st, path,
                                        offset, length,
-                                       oflags | O_CREAT, mode,
-                                       false);
+                                       oflags | O_CREAT, mode, 0);
 }
 
 #ifdef HAVE_CFMAKERAW
@@ -839,8 +851,7 @@ int virFDStreamOpenPTY(virStreamPtr st,
 
     if (virFDStreamOpenFileInternal(st, path,
                                     offset, length,
-                                    oflags | O_CREAT, 0,
-                                    false) < 0)
+                                    oflags | O_CREAT, 0, 0) < 0)
         return -1;
 
     fdst = st->privateData;
@@ -876,8 +887,7 @@ int virFDStreamOpenPTY(virStreamPtr st,
 {
     return virFDStreamOpenFileInternal(st, path,
                                        offset, length,
-                                       oflags | O_CREAT, 0,
-                                       false);
+                                       oflags | O_CREAT, 0, 0);
 }
 #endif /* !HAVE_CFMAKERAW */
 
@@ -885,11 +895,17 @@ int virFDStreamOpenBlockDevice(virStreamPtr st,
                                const char *path,
                                unsigned long long offset,
                                unsigned long long length,
-                               int oflags)
+                               int oflags,
+                               bool sparse)
 {
+    unsigned int flags = VIR_FDSTREAM_OPEN_FORCE_IOHELPER;
+
+    if (sparse)
+        flags |= VIR_FDSTREAM_OPEN_SPARSE;
+
     return virFDStreamOpenFileInternal(st, path,
                                        offset, length,
-                                       oflags, 0, true);
+                                       oflags, 0, flags);
 }
 
 int virFDStreamSetInternalCloseCb(virStreamPtr st,
diff --git a/src/fdstream.h b/src/fdstream.h
index 2c913ea..bfdebc2 100644
--- a/src/fdstream.h
+++ b/src/fdstream.h
@@ -60,7 +60,8 @@ int virFDStreamOpenBlockDevice(virStreamPtr st,
                                const char *path,
                                unsigned long long offset,
                                unsigned long long length,
-                               int oflags);
+                               int oflags,
+                               bool sparse);
 
 int virFDStreamSetInternalCloseCb(virStreamPtr st,
                                   virFDStreamInternalCloseCb cb,
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index 3a23cd7..f92d074 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -2030,7 +2030,8 @@ virStorageBackendVolUploadLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
     /* Not using O_CREAT because the file is required to already exist at
      * this point */
     ret = virFDStreamOpenBlockDevice(stream, target_path,
-                                     offset, len, O_WRONLY);
+                                     offset, len, O_WRONLY,
+                                     flags & VIR_STORAGE_VOL_UPLOAD_SPARSE_STREAM);
 
  cleanup:
     VIR_FREE(path);
@@ -2068,7 +2069,8 @@ virStorageBackendVolDownloadLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
     }
 
     ret = virFDStreamOpenBlockDevice(stream, target_path,
-                                     offset, len, O_RDONLY);
+                                     offset, len, O_RDONLY,
+                                     flags & VIR_STORAGE_VOL_DOWNLOAD_SPARSE_STREAM);
 
  cleanup:
     VIR_FREE(path);
-- 
2.8.1




More information about the libvir-list mailing list