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(a)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