1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2025-03-20 07:59:00 +00:00

virfdstream: Emulate skip for block devices

This is similar to one of previous patches.

When receiving stream (on virStorageVolUpload() and subsequent
virStreamSparseSendAll()) we may receive a hole. If the volume we
are saving the incoming data into is a regular file we just
lseek() and ftruncate() to create the hole. But this won't work
if the file is a block device. If that is the case we must write
zeroes so that any subsequent reader reads nothing just zeroes
(just like they would from a hole in a regular file).

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1852528

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
This commit is contained in:
Michal Privoznik 2020-07-01 21:39:40 +02:00
parent 9e0ba037cd
commit fd6b531cb2

View File

@ -512,6 +512,7 @@ virFDStreamThreadDoRead(virFDStreamDataPtr fdst,
static ssize_t static ssize_t
virFDStreamThreadDoWrite(virFDStreamDataPtr fdst, virFDStreamThreadDoWrite(virFDStreamDataPtr fdst,
bool sparse, bool sparse,
bool isBlock,
const int fdin, const int fdin,
const int fdout, const int fdout,
const char *fdinname, const char *fdinname,
@ -519,7 +520,6 @@ virFDStreamThreadDoWrite(virFDStreamDataPtr fdst,
{ {
ssize_t got = 0; ssize_t got = 0;
virFDStreamMsgPtr msg = fdst->msg; virFDStreamMsgPtr msg = fdst->msg;
off_t off;
bool pop = false; bool pop = false;
switch (msg->type) { switch (msg->type) {
@ -547,19 +547,48 @@ virFDStreamThreadDoWrite(virFDStreamDataPtr fdst,
} }
got = msg->stream.hole.len; got = msg->stream.hole.len;
off = lseek(fdout, got, SEEK_CUR); if (isBlock) {
if (off == (off_t) -1) { g_autofree char * buf = NULL;
virReportSystemError(errno, const size_t buflen = 1 * 1024 * 1024; /* 1MiB */
_("unable to seek in %s"), size_t toWrite = got;
fdoutname);
return -1;
}
if (ftruncate(fdout, off) < 0) { /* While for files it's enough to lseek() and ftruncate() to create
virReportSystemError(errno, * a hole which would emulate zeroes on read(), for block devices
_("unable to truncate %s"), * we have to write zeroes to read() zeroes. And we have to write
fdoutname); * @got bytes of zeroes. Do that in smaller chunks though.*/
return -1;
buf = g_new0(char, buflen);
while (toWrite) {
size_t count = MIN(toWrite, buflen);
ssize_t r;
if ((r = safewrite(fdout, buf, count)) < 0) {
virReportSystemError(errno,
_("Unable to write %s"),
fdoutname);
return -1;
}
toWrite -= r;
}
} else {
off_t off;
off = lseek(fdout, got, SEEK_CUR);
if (off == (off_t) -1) {
virReportSystemError(errno,
_("unable to seek in %s"),
fdoutname);
return -1;
}
if (ftruncate(fdout, off) < 0) {
virReportSystemError(errno,
_("unable to truncate %s"),
fdoutname);
return -1;
}
} }
pop = true; pop = true;
@ -625,7 +654,7 @@ virFDStreamThread(void *opaque)
length, total, length, total,
&dataLen, buflen); &dataLen, buflen);
else else
got = virFDStreamThreadDoWrite(fdst, sparse, got = virFDStreamThreadDoWrite(fdst, sparse, isBlock,
fdin, fdout, fdin, fdout,
fdinname, fdoutname); fdinname, fdoutname);