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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list