[libvirt] [RFC] Storage volume clone API

Cole Robinson crobinso at redhat.com
Thu Apr 16 14:51:23 UTC 2009


Daniel Veillard wrote:
> On Wed, Apr 15, 2009 at 03:28:54PM -0400, Cole Robinson wrote:
>> Hi all,
>>
>> Attached is a stab at an API for cloning a storage volume. This patch
>> implements the command for FS volumes, along with a virsh command
>> 'vol-clone'. This builds on the previously posted 'drop pool lock during
>> volume creation' work.
>>
>> The new API call looks like:
>>
>> /**
>>  * virStorageVolClone:
>>  * @vol: pointer to storage vol to clone
>>  * @xmldesc: description of volume to create
>>  * @flags: flags for creation (unused, pass 0)
>>  *
>>  * Clone a storage volume within the parent pool.
>>  * Information for the new volume (name, perms)
>>  * are passed via a typical volume XML description
>>  * Not all pools support cloning of volumes
>>  *
>>  * return the storage volume, or NULL on error
>>  */
>> virStorageVolPtr
>> virStorageVolClone(virStorageVolPtr vol,
>>                    const char *xmldesc,
>>                    unsigned int flags)
> 
>   I was initially surprized by the xmldesc, but I think it makes perfect
> sense, based on existing APIs and the fact we may augment the amount of
> metadata and it's simpler to build the API directly with room for the
> extensions.
>   I wonder if the entry point could be made to accept NULL as the input,
> then libvirt generate a name/uuid, keep other attributes the same and
> the returned object can be inspected to discover name/uuid.
> 

That seems reasonable. If people think it's useful behavior, I can add it.

>> The user passes information about the new volume via <volume> XML.
>> Currently we only use the passed name and permissions values, but
>> backingStore info could also be relevant, and 'format' if we allow
>> cloning between image formats.
> 
>   We don't have an UUID for a volume ?
> 

No, the unique identifier is the <key> field which is the absolute path
to the volume on the host. I don't think any of the storage drivers
actually allow manually setting this field, it is either generated using
the parent pool path and the new volume name, or dictated by storage
(/dev/sda3 or similar).

>> Current limitations:
>>
>> - Parsing the 'clone' xml will complain if the 'capacity' element hasn't
>> been specified, even though it is meaningless for the new volume. Not
>> too sure what the right thing to do here is.
> 
>   add an argument to the parsing routine asking to disable that check ?
> 

Yeah I figured i'd end up down that route. I'll check it out.

>> - A clone of a raw sparse file will turn out fully allocated. Could
>> probably borrow code from 'cp' to try and get this right.
> 
>   I would not consider this a blocker though a change in behaviour there
> later on might be considered disruptive (or a great improvement
> depending who you're asking !)
> 

Agreed, not critical.

>> - Doesn't handle backing stores. I think we would need to call out to
>> 'qemu-img convert' to have any chance of getting this right. And if we
>> do that, we could also allow cloning from one image format to another.
>>
>> A lot of the patch is just plumbing, which I will break out into
>> separate patches on the next post. For now, most of the interesting bits
>> are at near the bottom.
> 
>   No need to keep the generated doc files in the patch IMHO
> 

Okay, I'll drop them.

Thanks,
Cole

> [...]
>> diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
>> index a028b21..0f4dd27 100644
>> --- a/include/libvirt/libvirt.h.in
>> +++ b/include/libvirt/libvirt.h.in
>> @@ -1047,6 +1047,9 @@ const char*             virStorageVolGetKey             (virStorageVolPtr vol);
>>  virStorageVolPtr        virStorageVolCreateXML          (virStoragePoolPtr pool,
>>                                                           const char *xmldesc,
>>                                                           unsigned int flags);
>> +virStorageVolPtr        virStorageVolClone              (virStorageVolPtr vol,
>> +                                                         const char *xmldesc,
>> +                                                         unsigned int flags);
>>  int                     virStorageVolDelete             (virStorageVolPtr vol,
>>                                                           unsigned int flags);
>>  int                     virStorageVolRef                (virStorageVolPtr vol);
> 
>   Fine
> 
> [...]
>> +/**
>> + * virStorageVolClone:
>> + * @vol: pointer to storage vol to clone
>> + * @xmldesc: description of volume to create
>> + * @flags: flags for creation (unused, pass 0)
>> + *
>> + * Clone a storage volume within the parent pool.
>> + * Information for the new volume (name, perms)
>> + * are passed via a typical volume XML description
>> + * Not all pools support cloning of volumes
>> + *
>> + * return the storage volume, or NULL on error
>> + */
>> +virStorageVolPtr
>> +virStorageVolClone(virStorageVolPtr vol,
>> +                   const char *xmldesc,
>> +                   unsigned int flags)
>> +{
>> +    DEBUG("vol=%p, flags=%u", vol, flags);
>> +
>> +    virResetLastError();
>> +
>> +    if (!VIR_IS_STORAGE_VOL(vol)) {
>> +        virLibConnError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
>> +        return (NULL);
>> +    }
>> +
>> +    if (vol->conn->flags & VIR_CONNECT_RO) {
>> +        virLibConnError(vol->conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
>> +        goto error;
>> +    }
>> +
>> +    if (vol->conn->storageDriver && vol->conn->storageDriver->volClone) {
>> +        virStorageVolPtr ret;
>> +        ret = vol->conn->storageDriver->volClone (vol, xmldesc, flags);
>> +        if (!ret)
>> +            goto error;
>> +        return ret;
>> +    }
>> +
>> +    virLibConnError (vol->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
>> +
>> +error:
>> +    /* Copy to connection error object for back compatability */
>> +    virSetConnError(vol->conn);
>> +    return NULL;
>> +}
> 
>   okay too
> 
> [...]
>> +static int
>> +virStorageBackendFileSystemVolClone(virConnectPtr conn,
>> +                                    virStorageVolDefPtr origvol,
>> +                                    virStorageVolDefPtr newvol,
>> +                                    unsigned int flags ATTRIBUTE_UNUSED)
>> +{
>> +
>> +    int origfd = -1;
>> +    int newfd = -1;
>> +    int ret = -1;
>> +    size_t bytes = 1024 * 1024;
> 
>   so the copy is done megabytes by megabytes
> That sounds a reasonable intermediate compromize between the daemon
> memory usage and the I/O efficiency, feedback from an I/O expert or
> based on cp or tar code could be interesting.
> 
>    In general patch looks good to me, I got a bit lost in the pool
> locking, but finally it sounds fine.
> 
> Daniel
> 




More information about the libvir-list mailing list