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:
parent
9e0ba037cd
commit
fd6b531cb2
@ -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);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user