Similarly to previous commit, implement sparse streams feature for vol-upload. This is, however, slightly different approach, because we must implement a function that will tell us whether we are in a data section or in a hole. But there's no magic hidden in here. Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> --- tools/virsh-volume.c | 25 +++++++++++++++++- tools/virsh.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.h | 9 +++++++ tools/virsh.pod | 3 ++- 4 files changed, 106 insertions(+), 2 deletions(-) diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c index 018e0f3..9a6a695 100644 --- a/tools/virsh-volume.c +++ b/tools/virsh-volume.c @@ -659,6 +659,10 @@ static const vshCmdOptDef opts_vol_upload[] = { .type = VSH_OT_INT, .help = N_("amount of data to upload") }, + {.name = "sparse", + .type = VSH_OT_BOOL, + .help = N_("preserve sparseness of volume") + }, {.name = NULL} }; @@ -682,6 +686,8 @@ cmdVolUpload(vshControl *ctl, const vshCmd *cmd) const char *name = NULL; unsigned long long offset = 0, length = 0; virshControlPtr priv = ctl->privData; + unsigned int flags = 0; + struct _virshStreamInData cbData; if (vshCommandOptULongLong(ctl, cmd, "offset", &offset) < 0) return false; @@ -705,7 +711,24 @@ cmdVolUpload(vshControl *ctl, const vshCmd *cmd) goto cleanup; } - if (virStorageVolUpload(vol, st, offset, length, 0) < 0) { + if (vshCommandOptBool(cmd, "sparse")) { + flags |= VIR_STORAGE_VOL_UPLOAD_SPARSE_STREAM; + + cbData.ctl = ctl; + cbData.fd = fd; + + if (virStreamRegisterInData(st, virshStreamInData, &cbData) < 0) { + vshError(ctl, _("cannot register stream inData callback")); + goto cleanup; + } + + if (virStreamRegisterSkip(st, virshStreamSkip, &fd) < 0) { + vshError(ctl, _("cannot register stream skip handling function")); + goto cleanup; + } + } + + if (virStorageVolUpload(vol, st, offset, length, flags) < 0) { vshError(ctl, _("cannot upload to volume %s"), name); goto cleanup; } diff --git a/tools/virsh.c b/tools/virsh.c index af4f9d1..b68b8a3 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -265,6 +265,77 @@ int virshStreamSkip(virStreamPtr st ATTRIBUTE_UNUSED, return lseek(*fd, offset, SEEK_CUR) == (off_t) -1 ? -1 : 0; } +int virshStreamInData(virStreamPtr st ATTRIBUTE_UNUSED, + int *inData, + unsigned long long *offset, + void *opaque) +{ + struct _virshStreamInData *cbData = opaque; + vshControl *ctl = cbData->ctl; + int fd = cbData->fd; + off_t cur, data, hole; + int ret = -1; + + /* Get current position */ + cur = lseek(fd, 0, SEEK_CUR); + if (cur == (off_t) -1) { + vshError(ctl, "%s", _("Unable to get current position in stream")); + goto cleanup; + } + + /* Now try to get data and hole offsets */ + data = lseek(fd, cur, SEEK_DATA); + + /* There are four options: + * 1) data == cur; @cur is in data + * 2) data > cur; @cur is in a hole, next data at @data + * 3) data < 0, errno = ENXIO; either @cur is in trailing hole, or @cur is beyond EOF. + * 4) data < 0, errno != ENXIO; we learned nothing + */ + + if (data == (off_t) -1) { + /* cases 3 and 4 */ + if (errno != ENXIO) { + vshError(ctl, "%s", _("Unable to seek to data")); + goto cleanup; + } + *inData = 0; + *offset = 0; + } else if (data > cur) { + /* case 2 */ + *inData = 0; + *offset = data - cur; + } else { + /* case 1 */ + *inData = 1; + + /* We don't know where does the next hole start. Let's + * find out. Here we get the same 4 possibilities as + * described above.*/ + hole = lseek(fd, data, SEEK_HOLE); + if (hole == (off_t) -1 || hole == data) { + /* cases 1, 3 and 4 */ + /* Wait a second. The reason why we are here is + * because we are in data. But at the same time we + * are in a trailing hole? Wut!? Do the best what we + * can do here. */ + vshError(ctl, "%s", _("unable to seek to hole")); + goto cleanup; + } else { + /* case 2 */ + *offset = (hole - data); + } + } + + ret = 0; + cleanup: + /* At any rate, reposition back to where we started. */ + if (cur != (off_t) -1) + ignore_value(lseek(fd, cur, SEEK_SET)); + return ret; +} + + /* --------------- * Command Connect * --------------- diff --git a/tools/virsh.h b/tools/virsh.h index 5c382ef..cd70699 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -153,4 +153,13 @@ int virshStreamSink(virStreamPtr st, const char *bytes, size_t nbytes, int virshStreamSkip(virStreamPtr st, unsigned long long offset, void *opaque); +struct _virshStreamInData { + vshControl *ctl; + int fd; +}; + +int virshStreamInData(virStreamPtr st, + int *data, + unsigned long long *offset, + void *opaque); #endif /* VIRSH_H */ diff --git a/tools/virsh.pod b/tools/virsh.pod index 64f0f5f..56eda28 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -3557,13 +3557,14 @@ the storage volume should be deleted as well. Not all storage drivers support this option, presently only rbd. =item B<vol-upload> [I<--pool> I<pool-or-uuid>] [I<--offset> I<bytes>] -[I<--length> I<bytes>] I<vol-name-or-key-or-path> I<local-file> +[I<--length> I<bytes>] [I<--sparse>] I<vol-name-or-key-or-path> I<local-file> Upload the contents of I<local-file> to a storage volume. I<--pool> I<pool-or-uuid> is the name or UUID of the storage pool the volume is in. I<vol-name-or-key-or-path> is the name or key or path of the volume where the file will be uploaded. +If I<--sparse> is specified, this command will preserve volume sparseness. I<--offset> is the position in the storage volume at which to start writing the data. The value must be 0 or larger. I<--length> is an upper bound of the amount of data to be uploaded. A negative value is interpreted -- 2.8.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list