This new API provides additional flexibility over what can be
crammed on top of virDomainBlockRebase, at the expense that it
cannot be backported without bumping the .so version.
* include/libvirt/libvirt.h.in (virDomainBlockCopy): New API.
* src/libvirt.c (virDomainBlockCopy): Implement it.
* src/libvirt_public.syms (LIBVIRT_0.9.12): Export it.
* src/driver.h (virDrvDomainBlockCopy): New driver callback.
* docs/apibuild.py (CParser.parseSignature): Add exception.
---
docs/apibuild.py | 1 +
include/libvirt/libvirt.h.in | 18 ++++++-
src/driver.h | 6 ++
src/libvirt.c | 120 +++++++++++++++++++++++++++++++++++++++++-
src/libvirt_public.syms | 5 ++
5 files changed, 147 insertions(+), 3 deletions(-)
diff --git a/docs/apibuild.py b/docs/apibuild.py
index 1ac0281..bf06f3b 100755
--- a/docs/apibuild.py
+++ b/docs/apibuild.py
@@ -1650,6 +1650,7 @@ class CParser:
"virDomainBlockJobSetSpeed" : (False, ("bandwidth")),
"virDomainBlockPull" : (False, ("bandwidth")),
"virDomainBlockRebase" : (False, ("bandwidth")),
+ "virDomainBlockCopy" : (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 9901a82..9e55307 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1937,7 +1937,7 @@ int virDomainUpdateDeviceFlags(virDomainPtr domain,
* VIR_DOMAIN_BLOCK_JOB_TYPE_PULL: Block Pull (virDomainBlockPull, or
* virDomainBlockRebase without flags), job ends on completion
* VIR_DOMAIN_BLOCK_JOB_TYPE_COPY: Block Copy (virDomainBlockRebase with
- * flags), job exists as long as mirroring is active
+ * flags, or virDomainBlockCopy), job exists as long as mirroring is active
*/
typedef enum {
VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN = 0,
@@ -2006,6 +2006,22 @@ int virDomainBlockRebase(virDomainPtr dom, const char
*disk,
const char *base, unsigned long bandwidth,
unsigned int flags);
+/**
+ * virDomainBlockCopyFlags:
+ *
+ * Flags available for virDomainBlockCopy().
+ */
+typedef enum {
+ VIR_DOMAIN_BLOCK_COPY_SHALLOW = 1 << 0, /* Limit copy to top of source
+ backing chain */
+ VIR_DOMAIN_BLOCK_COPY_REUSE_EXT = 1 << 1, /* Reuse existing external
+ file for a copy */
+} virDomainBlockCopyFlags;
+
+int virDomainBlockCopy(virDomainPtr dom, const char *disk, const char *base,
+ const char *dest, const char *format,
+ unsigned long bandwidth, unsigned int flags);
+
/* Block I/O throttling support */
diff --git a/src/driver.h b/src/driver.h
index 03d249b..37eecbc 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -788,6 +788,11 @@ typedef int
(*virDrvDomainBlockRebase)(virDomainPtr dom, const char *path,
const char *base, unsigned long bandwidth,
unsigned int flags);
+typedef int
+ (*virDrvDomainBlockCopy)(virDomainPtr dom, const char *path,
+ const char *base, const char *dest,
+ const char *format, unsigned long bandwidth,
+ unsigned int flags);
typedef int
(*virDrvSetKeepAlive)(virConnectPtr conn,
@@ -1005,6 +1010,7 @@ struct _virDriver {
virDrvDomainBlockJobSetSpeed domainBlockJobSetSpeed;
virDrvDomainBlockPull domainBlockPull;
virDrvDomainBlockRebase domainBlockRebase;
+ virDrvDomainBlockCopy domainBlockCopy;
virDrvSetKeepAlive setKeepAlive;
virDrvConnectIsAlive isAlive;
virDrvNodeSuspendForDuration nodeSuspendForDuration;
diff --git a/src/libvirt.c b/src/libvirt.c
index 9212c08..a433c30 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -18253,7 +18253,10 @@ error:
* return an error if bandwidth is not 0.
*
* When @base is NULL and @flags is 0, this is identical to
- * virDomainBlockPull().
+ * virDomainBlockPull(). Conversely, when @flags includes
+ * VIR_DOMAIN_BLOCK_REBASE_COPY, this is shorthand for
+ * virDomainBlockCopy(dom, disk, NULL, base, NULL, bandwidth,
+ * flags & ~VIR_DOMAIN_BLOCK_REBASE_COPY).
*
* Returns 0 if the operation has started, -1 on failure.
*/
@@ -18263,7 +18266,7 @@ int virDomainBlockRebase(virDomainPtr dom, const char *disk,
{
virConnectPtr conn;
- VIR_DOMAIN_DEBUG(dom, "disk=%s, base=%s bandwidth=%lu, flags=%x",
+ VIR_DOMAIN_DEBUG(dom, "disk=%s, base=%s, bandwidth=%lu, flags=%x",
disk, NULLSTR(base), bandwidth, flags);
virResetLastError();
@@ -18320,6 +18323,119 @@ error:
/**
+ * virDomainBlockCopy:
+ * @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
+ * @dest: path to the copy destination
+ * @format: format of the destination
+ * @bandwidth: (optional) specify copy bandwidth limit in Mbps
+ * @flags: bitwise-OR of virDomainBlockCopyFlags
+ *
+ * Copy a portion of a backing chain to a new file @dest, where the copy
+ * will have @base as its backing file; or, if @base is NULL, then the
+ * copy will default to being flat, but if @flags includes
+ * VIR_DOMAIN_BLOCK_COPY_SHALLOW, then the copy will have the same backing
+ * fils as the source. The destination file will have the format given by
+ * @format; if this is NULL, then the format will be the same as the
+ * top level of the source chain. By default, if @dest exists as a
+ * non-empty regular file, the copy is rejected to avoid losing content
+ * of that file. However, if @flags additionally includes
+ * VIR_DOMAIN_BLOCK_COPY_REUSE_EXT, then the destination file must
+ * already exist and contain content identical to the source file (this
+ * allows a management app to pre-create files with relative backing
+ * file names, rather than the default of creating with absolute backing
+ * file names). A copy job has two parts; in the first phase, the
+ * @bandwidth parameter affects how fast the source is pulled into the
+ * destination, and the job can only be canceled by reverting to the
+ * source file; progress in this phase can be tracked via the
+ * virDomainBlockJobInfo() command, with a job type of
+ * VIR_DOMAIN_BLOCK_JOB_TYPE_COPY. An asynchronous event is sent when
+ * this phase ends, at which point the job remains alive to indicate
+ * that both source and destination files contain mirrored contents, and
+ * the user must call virDomainBlockJobAbort() to end the mirroring while
+ * choosing whether to revert to source or pivot to the destination.
+ * Some hypervisors will restrict certain actions, such as virDomainSave()
+ * or virDomainDetachDevice(), while a copy job is active; they may
+ * also restrict a copy job to transient domains.
+ *
+ * The @disk parameter is either an unambiguous source name of the
+ * block device (the <source file='...'/> sub-element, such as
+ * "/path/to/image"), or the device target shorthand (the
+ * <target dev='...'/> 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 and @format are NULL, this is equivalent to calling
+ * virDomainBlockRebase() with the VIR_DOMAIN_BLOCK_REBASE_COPY flag.
+ *
+ * Returns 0 if the operation has started, -1 on failure.
+ */
+int virDomainBlockCopy(virDomainPtr dom, const char *disk,
+ const char *base, const char *dest,
+ const char *format, unsigned long bandwidth,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(dom, "disk=%s, base=%s, dest=%s, format=%s, "
+ "bandwidth=%lu, flags=%x", disk, NULLSTR(base),
+ dest, NULLSTR(format), 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 (!dest) {
+ virLibDomainError(VIR_ERR_INVALID_ARG,
+ _("dest is NULL"));
+ goto error;
+ }
+
+ if ((flags & VIR_DOMAIN_BLOCK_COPY_SHALLOW) && base) {
+ virLibDomainError(VIR_ERR_INVALID_ARG,
+ _("base not permitted when doing shallow copy"));
+ goto error;
+ }
+
+ if (conn->driver->domainBlockCopy) {
+ int ret;
+ ret = conn->driver->domainBlockCopy(dom, disk, base, dest, format,
+ 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
* @idx: index of graphics config to open
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 46c13fb..d152ab9 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -534,4 +534,9 @@ LIBVIRT_0.9.11 {
virDomainPMWakeup;
} LIBVIRT_0.9.10;
+LIBVIRT_0.9.12 {
+ global:
+ virDomainBlockCopy;
+} LIBVIRT_0.9.11;
+
# .... define new API here using predicted next version number ....
--
1.7.7.6