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 } },
};