[PATCH 0/9] Allow sparse streams for block devices

Michal Privoznik mprivozn at redhat.com
Fri Jul 3 10:28:41 UTC 2020

The way our sparse streams are implemented is:

1) user facing APIs (virStreamSparseRecvAll() and virStreamSparseSendAll()) take
   callbacks as arguments. These callbacks read/write data or determine if there
   is a hole in the underlying file and big it is.

2) libvirtd has something similar - virFDStream, except here the functions for
   read/write of data and hole handling are called directly.

Sparse streams were originally implemented for regular files only => both ends
of stream has to be regular files. This limitation exists because the callbacks
from 1) (implemented in virsh for vol-download/vol-upload commands) and also
from 2) (which is basically the same code) uses lseek(..., SEEK_DATA) and/or
lseek(..., SEEK_HOLE) to get map of allocated file blocks. They also take a
shortcut (valid for regular files) - when one side of the stream is asked to
create a hole it merely lseek() + ftruncate(). For regular files this creates a
hole and later, when somebody reads it all they get is zeroes.

Neither of these two approaches work for block devices. Block devices have no
notion of data/hole sections [1], nor can they be truncated. What we can do
instead is read data from the block device and check if its full of zeroes. And
for "creating a hole" we just write zeroes of requested size.

There is a follow up patch that I am working on: this implementation I'm
posting here has one disadvantage: after some blocks are read from the
block device and they are found to contain data, the whole buffer is
freed only to be read again. For instance, when uploading volume,
virshStreamInData() is called at the beginning to check if the file
containing data to upload doesn't start with a hole. If the file is a
block device, then virFileInDataDetectZeroes() is called which reads
1MiB from it, finds (say) data and throws the buffer away. Then
virshStreamSource() is called, which reads the 1MiB buffer again.
The patch is still under development though.

1: Okay, SSDs keep list of free blocks for wear levelling, but the list is kept
private by the SSD controller and I am not aware of any way of getting it.

Michal Prívozník (9):
  libvirt-storage: Document volume upload/download stream format
  virstring: Introduce virStringIsNull()
  virfile: Introduce virFileInDataDetectZeroes()
  virsh: Pass virshStreamCallbackDataPtr to virshStreamSink() and
  virsh: Track if vol-upload or vol-download work over a block device
  virshStreamSkip: Emulate skip for block devices
  virfdstream: Allow sparse stream vol-download
  virshStreamInData: Handle block devices
  virfdstream: Emulate skip for block devices

 src/libvirt-storage.c    |  8 +++--
 src/libvirt_private.syms |  2 ++
 src/util/virfdstream.c   | 74 ++++++++++++++++++++++++++++++----------
 src/util/virfile.c       | 67 ++++++++++++++++++++++++++++++++++++
 src/util/virfile.h       |  4 +++
 src/util/virstring.c     | 40 ++++++++++++++++++++++
 src/util/virstring.h     |  2 ++
 tools/virsh-util.c       | 52 ++++++++++++++++++++++------
 tools/virsh-util.h       |  1 +
 tools/virsh-volume.c     | 20 ++++++++++-
 10 files changed, 238 insertions(+), 32 deletions(-)


More information about the libvir-list mailing list