diff --git a/docs/apibuild.py b/docs/apibuild.py index c8b5994d75..1ac0281f09 100755 --- a/docs/apibuild.py +++ b/docs/apibuild.py @@ -1649,6 +1649,7 @@ class CParser: "virDomainSetMemoryFlags" : (False, ("memory")), "virDomainBlockJobSetSpeed" : (False, ("bandwidth")), "virDomainBlockPull" : (False, ("bandwidth")), + "virDomainBlockRebase" : (False, ("bandwidth")), "virDomainMigrateGetMaxSpeed" : (False, ("bandwidth")) } def checkLongLegacyFunction(self, name, return_type, signature): diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 07d03fa160..2b4adda6dc 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1888,7 +1888,8 @@ int virDomainUpdateDeviceFlags(virDomainPtr domain, /** * virDomainBlockJobType: * - * VIR_DOMAIN_BLOCK_JOB_TYPE_PULL: Block Pull (virDomainBlockPull) + * VIR_DOMAIN_BLOCK_JOB_TYPE_PULL: Block Pull (virDomainBlockPull or + * virDomainBlockRebase) */ typedef enum { VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN = 0, @@ -1927,6 +1928,9 @@ int virDomainBlockJobSetSpeed(virDomainPtr dom, const char *disk, int virDomainBlockPull(virDomainPtr dom, const char *disk, unsigned long bandwidth, unsigned int flags); +int virDomainBlockRebase(virDomainPtr dom, const char *disk, + const char *base, unsigned long bandwidth, + unsigned int flags); /* Block I/O throttling support */ @@ -3558,7 +3562,8 @@ typedef void (*virConnectDomainEventGraphicsCallback)(virConnectPtr conn, /** * virConnectDomainEventBlockJobStatus: * - * The final status of a virDomainBlockPullAll() operation + * The final status of a virDomainBlockPull() or virDomainBlockRebase() + * operation */ typedef enum { VIR_DOMAIN_BLOCK_JOB_COMPLETED = 0, diff --git a/src/driver.h b/src/driver.h index d6ee60f498..d27fa99e89 100644 --- a/src/driver.h +++ b/src/driver.h @@ -780,6 +780,10 @@ typedef int typedef int (*virDrvDomainBlockPull)(virDomainPtr dom, const char *path, unsigned long bandwidth, unsigned int flags); +typedef int + (*virDrvDomainBlockRebase)(virDomainPtr dom, const char *path, + const char *base, unsigned long bandwidth, + unsigned int flags); typedef int (*virDrvSetKeepAlive)(virConnectPtr conn, @@ -995,6 +999,7 @@ struct _virDriver { virDrvDomainGetBlockJobInfo domainGetBlockJobInfo; virDrvDomainBlockJobSetSpeed domainBlockJobSetSpeed; virDrvDomainBlockPull domainBlockPull; + virDrvDomainBlockRebase domainBlockRebase; virDrvSetKeepAlive setKeepAlive; virDrvConnectIsAlive isAlive; virDrvNodeSuspendForDuration nodeSuspendForDuration; diff --git a/src/libvirt.c b/src/libvirt.c index 659e5db4e4..f58dfa6a81 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -17768,7 +17768,7 @@ int virDomainBlockJobAbort(virDomainPtr dom, const char *disk, { virConnectPtr conn; - VIR_DOMAIN_DEBUG(dom, "disk=%p, flags=%x", disk, flags); + VIR_DOMAIN_DEBUG(dom, "disk=%s, flags=%x", disk, flags); virResetLastError(); @@ -17829,7 +17829,7 @@ int virDomainGetBlockJobInfo(virDomainPtr dom, const char *disk, { virConnectPtr conn; - VIR_DOMAIN_DEBUG(dom, "disk=%p, info=%p, flags=%x", disk, info, flags); + VIR_DOMAIN_DEBUG(dom, "disk=%s, info=%p, flags=%x", disk, info, flags); virResetLastError(); @@ -17891,7 +17891,7 @@ int virDomainBlockJobSetSpeed(virDomainPtr dom, const char *disk, { virConnectPtr conn; - VIR_DOMAIN_DEBUG(dom, "disk=%p, bandwidth=%lu, flags=%x", + VIR_DOMAIN_DEBUG(dom, "disk=%s, bandwidth=%lu, flags=%x", disk, bandwidth, flags); virResetLastError(); @@ -17955,6 +17955,8 @@ error: * suitable default. Some hypervisors do not support this feature and will * return an error if bandwidth is not 0. * + * This is shorthand for virDomainBlockRebase() with a NULL base. + * * Returns 0 if the operation has started, -1 on failure. */ int virDomainBlockPull(virDomainPtr dom, const char *disk, @@ -17962,7 +17964,7 @@ int virDomainBlockPull(virDomainPtr dom, const char *disk, { virConnectPtr conn; - VIR_DOMAIN_DEBUG(dom, "disk=%p, bandwidth=%lu, flags=%x", + VIR_DOMAIN_DEBUG(dom, "disk=%s, bandwidth=%lu, flags=%x", disk, bandwidth, flags); virResetLastError(); @@ -18001,6 +18003,88 @@ error: } +/** + * virDomainBlockRebase: + * @dom: pointer to domain object + * @disk: path to the block device, or device shorthand + * @base: path to backing file to keep, or NULL for no backing file + * @bandwidth: (optional) specify copy bandwidth limit in Mbps + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Populate a disk image with data from its backing image chain, and + * setting the backing image to @base. @base must be the absolute + * path of one of the backing images further up the chain, or NULL to + * convert the disk image so that it has no backing image. Once all + * data from its backing image chain has been pulled, the disk no + * longer depends on those intermediate backing images. 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 @disk parameter is either an unambiguous source name of the + * block device (the sub-element, such as + * "/path/to/image"), or the device target shorthand (the + * sub-element, such as "xvda"). Valid names + * can be found by calling virDomainGetXMLDesc() and inspecting + * elements within //domain/devices/disk. + * + * 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. + * + * When @base is NULL, this is identical to virDomainBlockPull(). + * + * Returns 0 if the operation has started, -1 on failure. + */ +int virDomainBlockRebase(virDomainPtr dom, const char *disk, + const char *base, unsigned long bandwidth, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(dom, "disk=%s, base=%s bandwidth=%lu, flags=%x", + disk, NULLSTR(base), bandwidth, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN (dom)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + conn = dom->conn; + + if (dom->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + if (!disk) { + virLibDomainError(VIR_ERR_INVALID_ARG, + _("disk is NULL")); + goto error; + } + + if (conn->driver->domainBlockRebase) { + int ret; + ret = conn->driver->domainBlockRebase(dom, disk, base, bandwidth, + flags); + if (ret < 0) + goto error; + return ret; + } + + virLibDomainError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(dom->conn); + return -1; +} + + /** * virDomainOpenGraphics: * @dom: pointer to domain object @@ -18208,7 +18292,7 @@ int virDomainSetBlockIoTune(virDomainPtr dom, { virConnectPtr conn; - VIR_DOMAIN_DEBUG(dom, "disk=%p, params=%p, nparams=%d, flags=%x", + VIR_DOMAIN_DEBUG(dom, "disk=%s, params=%p, nparams=%d, flags=%x", disk, params, nparams, flags); virResetLastError(); @@ -18290,7 +18374,7 @@ int virDomainGetBlockIoTune(virDomainPtr dom, { virConnectPtr conn; - VIR_DOMAIN_DEBUG(dom, "disk=%p, params=%p, nparams=%d, flags=%x", + VIR_DOMAIN_DEBUG(dom, "disk=%s, params=%p, nparams=%d, flags=%x", NULLSTR(disk), params, (nparams) ? *nparams : -1, flags); virResetLastError(); diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 9bbd3082f6..7622b796dd 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -518,6 +518,7 @@ LIBVIRT_0.9.9 { LIBVIRT_0.9.10 { global: + virDomainBlockRebase; virDomainGetCPUStats; virDomainGetDiskErrors; virDomainGetMetadata; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index 446f2290ee..3f37d58420 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -232,6 +232,7 @@ my $long_legacy = { GetVersion => { ret => { hv_ver => 1 } }, NodeGetInfo => { ret => { memory => 1 } }, DomainBlockPull => { arg => { bandwidth => 1 } }, + DomainBlockRebase => { arg => { bandwidth => 1 } }, DomainBlockJobSetSpeed => { arg => { bandwidth => 1 } }, DomainMigrateGetMaxSpeed => { ret => { bandwidth => 1 } }, };