[libvirt] RFC (V2) New virDomainBlockPull API family to libvirt

Adam Litke agl at us.ibm.com
Fri Jul 15 15:18:39 UTC 2011


In light of discussion on V1 of this API, here is V2 of the next generation BlockPull API.  In this series we make the abort and info operations more generic so that they may apply to future block jobs (such as compression, live block copy, etc).  We also add in a mechanism to set the maximum bandwidth of an operation.

Changes since V1:
 - Make virDomainBlockPullAbort() and virDomainGetBlockPullInfo() into a
   generic BlockJob interface.
 - Added virDomainBlockJobSetSpeed()
 - Rename VIR_DOMAIN_EVENT_ID_BLOCK_PULL event to fit into block job API
 - Add bandwidth argument to virDomainBlockPull()

Summary of changes since first generation patch series:
 - Qemu dropped incremental streaming so remove libvirt incremental
   BlockPull() API
 - Rename virDomainBlockPullAll() to virDomainBlockPull()
 - Changes required to qemu monitor handlers for changed command names

--

To help speed the provisioning process for large domains, new QED disks are
created with backing to a template image.  These disks are configured with 
copy on read such that blocks that are read from the backing file are copied
to the new disk.  This reduces I/O over a potentially costly path to the
backing image.

In such a configuration, there is a desire to remove the dependency on the
backing image as the domain runs.  To accomplish this, qemu will provide an
interface to perform sequential copy on read operations during normal VM
operation.  Once all data has been copied, the disk image's link to the 
backing file is removed.

The virDomainBlockPull API family brings this functionality to libvirt.

virDomainBlockPull() instructs the hypervisor to stream the entire device in
the background.  Progress of this operation can be checked with the function
virDomainBlockJobInfo().  An ongoing stream can be cancelled with
virDomainBlockJobAbort().  virDomainBlockJobSetSpeed() allows you to limit the
bandwidth that the operation may consume. 

An event (VIR_DOMAIN_EVENT_ID_BLOCK_JOB) will be emitted when a disk has been
fully populated or if a BlockPull() operation was terminated due to an error.
This event is useful to avoid polling on virDomainBlockJobInfo() for
completion and could also be used by the security driver to revoke access to
the backing file when it is no longer needed.

/*
 * BlockJob API
 */

/**
 * virDomainBlockJobType:
 *
 * VIR_DOMAIN_BLOCK_JOB_TYPE_PULL: Block Pull (virDomainBlockPull)
 */
typedef enum {
    VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN = -1,
    VIR_DOMAIN_BLOCK_JOB_TYPE_PULL = 0,
} virDomainBlockJobType;

/* An iterator for monitoring block job operations */
typedef unsigned long long virDomainBlockJobCursor;

typedef struct _virDomainBlockJobInfo virDomainBlockJobInfo;
struct _virDomainBlockJobInfo {
    virDomainBlockJobType type;
    /*
     * The following fields provide an indication of block job progress.  @cur
     * indicates the current position and will be between 0 and @end.  @end is
     * the final cursor position for this operation and represents completion.
     * To approximate progress, divide @cur by @end.
     */
    virDomainBlockJobCursor cur;
    virDomainBlockJobCursor end;
};
typedef virDomainBlockJobInfo *virDomainBlockJobInfoPtr;

/**
 * virDomainBlockJobAbort:
 * @dom: pointer to domain object
 * @path: fully-qualified filename of disk
 * @flags: currently unused, for future extension
 *
 * Cancel the active block job on the given disk.
 *
 * Returns -1 in case of failure, 0 when successful.
 */
int                 virDomainBlockJobAbort(virDomainPtr dom,
                                           const char *path,
                                           unsigned int flags);

/**
 * virDomainGetBlockJobInfo:
 * @dom: pointer to domain object
 * @path: fully-qualified filename of disk
 * @info: pointer to a virDomainBlockJobInfo structure
 * @flags: currently unused, for future extension
 *
 * Request block job information for the given disk.  If an operation is active
 * @info will be updated with the current progress.
 *
 * Returns -1 in case of failure, 0 when successful.
 */
int                 virDomainGetBlockJobInfo(virDomainPtr dom,
                                             const char *path,
                                             virDomainBlockJobInfoPtr info,
                                             unsigned int flags);

/**
 * virDomainBlockJobSetSpeed:
 * @dom: pointer to domain object
 * @path: fully-qualified filename of disk
 * @bandwidth: specify bandwidth limit in Mbps
 * @flags: currently unused, for future extension
 *
 * Set the maximimum allowable bandwidth that a block job may consume.  If
 * bandwidth is 0, the limit will revert to the hypervisor default.
 *
 * Returns -1 in case of failure, 0 when successful.
 */
int                 virDomainBlockJobSetSpeed(virDomainPtr dom,
                                              const char *path,
                                              unsigned long bandwidth,
                                              unsigned int flags);

/**
 * virConnectDomainEventBlockJobStatus:
 *
 * The final status of a block job
 */
typedef enum {
    VIR_DOMAIN_BLOCK_JOB_COMPLETED = 0,
    VIR_DOMAIN_BLOCK_JOB_FAILED = 1,
} virConnectDomainEventBlockJobStatus;

/**
 * virConnectDomainEventBlockPullCallback:
 * @conn: connection object
 * @dom: domain on which the event occurred
 * @path: fully-qualified filename of the affected disk
 * @type: type of block job (virDomainBlockJobType)
 * @status: final status of the operation (virConnectDomainEventBlockPullStatus)
 * @opaque: callback context
 *
 * The callback signature to use when registering for an event of type
 * VIR_DOMAIN_EVENT_ID_BLOCK_PULL with virConnectDomainEventRegisterAny()
 */
typedef void (*virConnectDomainEventBlockPullCallback)(virConnectPtr conn,
                                                       virDomainPtr dom,
                                                       const char *path,
                                                       int type,
                                                       int status,
                                                       void *opaque);

/**
 * virDomainBlockPull:
 * @dom: pointer to domain object
 * @path: Fully-qualified filename of disk
 * @bandwidth: (optional) specify copy bandwidth limit in Mbps
 * @flags: currently unused, for future extension
 *
 * Populate a disk image with data from its backing image.  Once all data from
 * its backing image has been pulled, the disk no longer depends on a backing
 * image.  This function pulls data for the entire device in the background.
 * Progress of the operation can be checked with virDomainGetBlockJobInfo() and
 * the operation can be aborted with virDomainBlockJobAbort().  When finished,
 * an asynchronous event is raised to indicate the final status.
 *
 * The maximum bandwidth (in Mbps) that will be used to do the copy can be
 * specified with the bandwidth parameter.  If set to 0, libvirt will choose a
 * suitable default.  Some hypervisors do not support this feature and will
 * return an error if bandwidth is not 0.
 *
 * Returns 0 if the operation has started, -1 on failure.
 */
int                 virDomainBlockPull(virDomainPtr dom,
                                       const char *path,
                                       unsigned long bandwidth,
                                       unsigned int flags);

-- 
Adam Litke
IBM Linux Technology Center




More information about the libvir-list mailing list