[libvirt] [PATCH 2/6] Add public APIs for storage volume upload/download

Eric Blake eblake at redhat.com
Mon Mar 21 21:04:39 UTC 2011


On 03/18/2011 10:36 AM, Daniel P. Berrange wrote:
> New APIs are added allowing streaming of content to/from
> storage volumes. A new API for creating volumes is also
> added allowing the content to be provided immediately at
> time of creation

Delete this last sentence; it's stale information from an earlier
version of the commit.

> 
> * include/libvirt/libvirt.h.in: Add virStorageVolUpload and
>   virStorageVolDownload APIs
> * src/driver.h, src/libvirt.c, src/libvirt_public.syms: Stub
>   code for new APIs
> * src/storage/storage_driver.c, src/esx/esx_storage_driver.c:
>   Add dummy entries in driver table for new APIs
> ---
>  include/libvirt/libvirt.h.in |   10 ++++
>  include/libvirt/virterror.h  |    1 +
>  src/driver.h                 |   14 +++++
>  src/esx/esx_storage_driver.c |    2 +
>  src/libvirt.c                |  123 ++++++++++++++++++++++++++++++++++++++++++
>  src/libvirt_public.syms      |    2 +
>  src/storage/storage_driver.c |    2 +
>  src/util/virterror.c         |    6 ++
>  8 files changed, 160 insertions(+), 0 deletions(-)

> 
> +++ b/src/libvirt.c
> @@ -9065,6 +9065,129 @@ error:
>  
>  
>  /**
> + * virStorageVolDownload:
> + * @pool: pointer to volume to download
> + * @stream: stream to use as output
> + * @offset: position to start reading from

Since there are two effective files (the stream and the volume), it
would help to make it clear which file the offset applies to (it can
somewhat be implied, because streams are not seekable and thus do not
have an offset, but more wording never hurts).

> + * @length: limit on amount of data to download
> + * @flags: flags for creation (unused, pass 0)

What is being created?  The stream and volume already exist.

> + *
> + * Download the content of the volume as a stream. If @length
> + * is zero, then the entire file contents will be downloaded.

You have to use offset=0 to get the entire file.

Also, mention that it is an error if length+offset > size of volume.

What happens if the stream hits EOF before all data read from the volume
has been written to the stream?  Should the API support a way to tell
how many bytes were successfully downloaded in the case of a short
stream?  That is, instead of returning 0 on success, should Upload and
Download return a ull with how many bytes were transferred in/out of the
stream?

These days, efficient sparse handling is a cool kernel feature waiting
to be exploited (see coreutils 8.10 use of FIEMAP in cp).  Should we
make it easier to detect holes in a volume, by exposing some of this
information back through this API?

> +
> +/**
> + * virStorageVolUpload:
> + * @pool: pointer to volume to download
> + * @stream: stream to use as output

Two lines with too much copy and paste.

> + * @offset: position to start writing to
> + * @length: limit on amount of data to upload
> + * @flags: flags for creation (unused, pass 0)
> + *
> + * Upload new content to the volume from a stream. If @length
> + * is non-zero, and an error will be raised if an attempt is
> + * made to upload greater than @length bytes of data.

I'm still a bit confused on the semantics.  Is this the desired
interpretation:

Suppose the volume has size S > 1.
offset=0 length=0 => read S bytes from stream to fill S bytes of volume
offset=1 length=0 => read S-1 bytes from stream
offset=1 length=S => error (length+offset > S)
offset=0 length=1 => read 1 byte from stream, write 1 byte to volume

In all cases, if stream supplies fewer bytes than the resulting size to
be written to the volume, then does this fail after writing all supplied
bytes?  Should the API tell how many bytes were successfully transferred
to the volume in the case of a short stream?  Is this a case where it
might be worth letting flags=1 imply that all remaining bytes of volume
should be set to NUL (that is, when uploading from a smaller source to a
larger destination volume, do we want to guarantee that the tail end of
volume has been wiped)?  I'm thinking that if we return the length of
bytes read from the stream, then anyone that cares can do a subsequent
upload starting from that offset to upload NULs to any further bytes.

For that matter, that sounds like a great use case for wiping a portion
of a volume (aka punching holes into an image).  virStorageVolWipe can
only wipe the entire volume, but virStorageVolUpload could be used to
intentionally wipe any given offset and length via a flag.

So, does this look any better as a proposed API?

/**
 * virStorageVolDownload:
 * @pool: pointer to volume to download from
 * @stream: stream to use as output
 * @offset: position in @pool to start reading from
 * @length: limit on amount of data to download
 * @flags: future flags (unused, pass 0)
 *
 * Download the content of the volume as a stream. If @length
 * is zero, then the remaining contents after @offset will be
 * downloaded.  It is an error if @length + @offset exceeds
 * the size of the volume.
 *
 * Returns number of bytes written to stream, or -1 upon error.
 */
unsigned long long
virStorageVolDownload(virStorageVolPtr vol,
                      virStreamPtr stream,
                      unsigned long long offset,
                      unsigned long long length,
                      unsigned int flags);

enum {
    VIR_STORAGE_VOLUME_UPLOAD_WIPE = 1,
};

/**
 * virStorageVolUpload:
 * @pool: pointer to volume to upload to
 * @stream: stream to use as input
 * @offset: position in @pool to start writing to
 * @length: limit on amount of data to upload
 * @flags: VIR_STORAGE_VOLUME_UPLOAD flags
 *
 * Upload new content to the volume from a stream. It is an
 * error if @length + @offset exceeds the size of the
 * volume.  If @length is zero, then use the volume size minus
 * @length bytes of data.
 *
 * If @flags is zero, data is read from stream; if it is
 * VIR_STORAGE_VOLUME_UPLOAD_WIPE, NUL bytes are written
 * instead and @stream may be NULL.
 *
 * Returns the bytes 0, or -1 upon error.
 */
int
virStorageVolUpload(virStorageVolPtr vol,
                    virStreamPtr stream,
                    unsigned long long offset,
                    unsigned long long length,
                    unsigned int flags);

virStorageVolWipe(vol, flags) is shorthand for virStorageVolUpload(vol,
NULL, 0, 0, VIR_STORAGE_VOLUME_UPLOAD_WIPE | flags)

The rest of this patch looks great, but I think we have to nail the
right API in libvirt.c (with possible fallout to the types of the driver
callback functions) before committing anything, so this will need a v3.

-- 
Eric Blake   eblake at redhat.com    +1-801-349-2682
Libvirt virtualization library http://libvirt.org

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 619 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20110321/122f7e8f/attachment-0001.sig>


More information about the libvir-list mailing list