NOTE: THIS DOES NOT WORK YET, PURE PROTOTYPE
This patch adds support for creating, deleting, reverting and listing
snapshots of storage volumes.
This allows for snapshotting volumes managed by libvirt without talking
directly to the backing storage.
---
include/libvirt/libvirt-storage.h | 38 ++++++++++
src/conf/storage_conf.c | 111 +++++++++++++++++++++++++++++
src/conf/storage_conf.h | 30 ++++++++
src/datatypes.h | 16 +++++
src/driver-storage.h | 28 ++++++++
src/libvirt-storage.c | 143 ++++++++++++++++++++++++++++++++++++++
src/storage/storage_backend.h | 21 ++++++
src/storage/storage_driver.c | 102 +++++++++++++++++++++++++++
8 files changed, 489 insertions(+)
diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h
index 2c55c93..3e72fb5 100644
--- a/include/libvirt/libvirt-storage.h
+++ b/include/libvirt/libvirt-storage.h
@@ -177,6 +177,31 @@ typedef enum {
VIR_STORAGE_XML_INACTIVE = (1 << 0), /* dump inactive pool/volume
information */
} virStorageXMLFlags;
+
+/**
+ * virStorageVolSnap:
+ *
+ * a virStorageVolSnap is a private structure representing a storage volume snapshot
+ */
+typedef struct _virStorageVolSnap virStorageVolSnap;
+
+/**
+ * virStorageVolSnapPtr:
+ *
+ * a virStorageVolSnapPtr is pointer to a virStorageVolSnap private structure, this is
the
+ * type used to reference a volume snapshot in the API.
+ */
+typedef virStorageVolSnap *virStorageVolSnapPtr;
+
+typedef struct _virStorageVolSnapInfo virStorageVolSnapInfo;
+
+struct _virStorageVolSnapInfo {
+ int type; /* virStorageVolType flags */
+ unsigned long long allocated; /* Current size of snapshot in bytes */
+};
+
+typedef virStorageVolSnapInfo *virStorageVolSnapInfoPtr;
+
/*
* Get connection from pool.
*/
@@ -350,6 +375,19 @@ int virStorageVolWipe
(virStorageVolPtr vol,
int virStorageVolWipePattern (virStorageVolPtr vol,
unsigned int algorithm,
unsigned int flags);
+virStorageVolSnapPtr virStorageVolSnapCreate (virStorageVolPtr vol,
+ const char *xmldesc,
+ unsigned int flags);
+int virStorageVolSnapDelete (virStorageVolSnapPtr snap,
+ unsigned int flags);
+int virStorageVolSnapRevert (virStorageVolSnapPtr snap,
+ unsigned int flags);
+int virStorageVolSnapList (virStorageVolPtr vol,
+ virStorageVolSnapPtr **snaps,
+ unsigned int flags);
+int virStorageVolSnapGetInfo (virStorageVolSnapPtr snap,
+ virStorageVolSnapInfoPtr info,
+ unsigned int flags);
int virStorageVolRef (virStorageVolPtr vol);
int virStorageVolFree (virStorageVolPtr vol);
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index 9b8abea..acf9410 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -326,6 +326,18 @@ virStorageVolDefFree(virStorageVolDefPtr def)
VIR_FREE(def);
}
+void
+virStorageVolSnapDefFree(virStorageVolSnapDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def->name);
+ VIR_FREE(def->key);
+
+ VIR_FREE(def);
+}
+
static void
virStoragePoolSourceAdapterClear(virStoragePoolSourceAdapterPtr adapter)
{
@@ -1484,6 +1496,105 @@ virStorageVolDefParseFile(virStoragePoolDefPtr pool,
return virStorageVolDefParse(pool, NULL, filename, flags);
}
+static virStorageVolSnapDefPtr
+virStorageVolSnapDefParseXML(virStoragePoolDefPtr pool,
+ xmlXPathContextPtr ctxt,
+ unsigned int flags)
+{
+ virStorageVolSnapDefPtr ret;
+
+ virCheckFlags(0, NULL);
+
+ if (VIR_ALLOC(ret) < 0)
+ return NULL;
+
+ if (pool == NULL)
+ return NULL;
+
+ ret->name = virXPathString("string(./name)", ctxt);
+ if (ret->name == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing snapshot name element"));
+ goto error;
+ }
+
+ ret->key = virXPathString("string(./key)", ctxt);
+
+
+ cleanup:
+ return ret;
+
+ error:
+ virStorageVolSnapDefFree(ret);
+ ret = NULL;
+ goto cleanup;
+}
+
+virStorageVolSnapDefPtr
+virStorageVolSnapDefParseNode(virStoragePoolDefPtr pool,
+ xmlDocPtr xml,
+ xmlNodePtr root,
+ unsigned int flags)
+{
+ xmlXPathContextPtr ctxt = NULL;
+ virStorageVolSnapDefPtr def = NULL;
+
+ if (!xmlStrEqual(root->name, BAD_CAST "snapshot")) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unexpected root element <%s>, "
+ "expecting <snapshot>"),
+ root->name);
+ goto cleanup;
+ }
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ctxt->node = root;
+ def = virStorageVolSnapDefParseXML(pool, ctxt, flags);
+
+ cleanup:
+ xmlXPathFreeContext(ctxt);
+ return def;
+}
+
+static virStorageVolSnapDefPtr
+virStorageVolSnapDefParse(virStoragePoolDefPtr pool,
+ const char *xmlStr,
+ const char *filename,
+ unsigned int flags)
+{
+ virStorageVolSnapDefPtr ret = NULL;
+ xmlDocPtr xml;
+
+ if ((xml = virXMLParse(filename, xmlStr,
_("(storage_volume_snapshot_definition)")))) {
+ ret = virStorageVolSnapDefParseNode(pool, xml, xmlDocGetRootElement(xml),
flags);
+ xmlFreeDoc(xml);
+ }
+
+ return ret;
+}
+
+virStorageVolSnapDefPtr
+virStorageVolSnapDefParseString(virStoragePoolDefPtr pool,
+ const char *xmlStr,
+ unsigned int flags)
+{
+ return virStorageVolSnapDefParse(pool, xmlStr, NULL, flags);
+}
+
+virStorageVolSnapDefPtr
+virStorageVolSnapDefParseFile(virStoragePoolDefPtr pool,
+ const char *filename,
+ unsigned int flags)
+{
+ return virStorageVolSnapDefParse(pool, NULL, filename, flags);
+}
+
+
static void
virStorageVolTimestampFormat(virBufferPtr buf, const char *name,
struct timespec *ts)
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h
index ec59c17..82b55c4 100644
--- a/src/conf/storage_conf.h
+++ b/src/conf/storage_conf.h
@@ -79,6 +79,22 @@ struct _virStorageVolDefList {
virStorageVolDefPtr *objs;
};
+typedef struct _virStorageVolSnapDef virStorageVolSnapDef;
+typedef virStorageVolSnapDef *virStorageVolSnapDefPtr;
+struct _virStorageVolSnapDef {
+ char *name;
+ char *key;
+
+ virStorageVolDef vol;
+};
+
+typedef struct _virStorageVolSnapDefList virStorageVolSnapDefList;
+typedef virStorageVolSnapDefList *virStorageVolSnapDefListPtr;
+struct _virStorageVolSnapDefList {
+ size_t count;
+ virStorageVolSnapDefPtr *objs;
+};
+
VIR_ENUM_DECL(virStorageVol)
typedef enum {
@@ -363,15 +379,28 @@ virStorageVolDefPtr
virStorageVolDefParseString(virStoragePoolDefPtr pool,
const char *xml,
unsigned int flags);
+virStorageVolSnapDefPtr
+virStorageVolSnapDefParseString(virStoragePoolDefPtr pool,
+ const char *xml,
+ unsigned int flags);
virStorageVolDefPtr
virStorageVolDefParseFile(virStoragePoolDefPtr pool,
const char *filename,
unsigned int flags);
+virStorageVolSnapDefPtr
+virStorageVolSnapDefParseFile(virStoragePoolDefPtr pool,
+ const char *filename,
+ unsigned int flags);
virStorageVolDefPtr
virStorageVolDefParseNode(virStoragePoolDefPtr pool,
xmlDocPtr xml,
xmlNodePtr root,
unsigned int flags);
+virStorageVolSnapDefPtr
+virStorageVolSnapDefParseNode(virStoragePoolDefPtr pool,
+ xmlDocPtr xml,
+ xmlNodePtr root,
+ unsigned int flags);
char *virStorageVolDefFormat(virStoragePoolDefPtr pool,
virStorageVolDefPtr def);
@@ -389,6 +418,7 @@ int virStoragePoolObjSaveDef(virStorageDriverStatePtr driver,
int virStoragePoolObjDeleteDef(virStoragePoolObjPtr pool);
void virStorageVolDefFree(virStorageVolDefPtr def);
+void virStorageVolSnapDefFree(virStorageVolSnapDefPtr def);
void virStoragePoolSourceClear(virStoragePoolSourcePtr source);
void virStoragePoolSourceDeviceClear(virStoragePoolSourceDevicePtr dev);
void virStoragePoolSourceFree(virStoragePoolSourcePtr source);
diff --git a/src/datatypes.h b/src/datatypes.h
index 1b1777d..b387b8f 100644
--- a/src/datatypes.h
+++ b/src/datatypes.h
@@ -495,6 +495,22 @@ struct _virStorageVol {
};
/**
+ * _virStorageVolSnap:
+ *
+ * Internal structure associated to a storage volume snapshot
+ */
+struct _virStorageVolSnap {
+ virObject object;
+ virConnectPtr conn;
+ char *vol; /* Name of the parent volume */
+ char *name; /* Name of the snapshot */
+ char *key; /* unique key of the snapshot */
+
+ void *privateData;
+ virFreeCallback privateDataFreeFunc;
+};
+
+/**
* _virNodeDevice:
*
* Internal structure associated with a node device
diff --git a/src/driver-storage.h b/src/driver-storage.h
index 0489647..0283571 100644
--- a/src/driver-storage.h
+++ b/src/driver-storage.h
@@ -154,6 +154,29 @@ typedef int
unsigned int algorithm,
unsigned int flags);
+typedef virStorageVolSnapPtr
+(*virDrvStorageVolSnapCreate)(virStorageVolPtr vol,
+ const char *xmldesc,
+ unsigned int flags);
+
+typedef int
+(*virDrvStorageVolSnapDelete)(virStorageVolSnapPtr snap,
+ unsigned int flags);
+
+typedef int
+(*virDrvStorageVolSnapRevert)(virStorageVolSnapPtr snap,
+ unsigned int flags);
+
+typedef int
+(*virDrvStorageVolSnapList)(virStorageVolPtr vol,
+ virStorageVolSnapPtr **snaps,
+ unsigned int flags);
+
+typedef int
+(*virDrvStorageVolSnapGetInfo)(virStorageVolSnapPtr snap,
+ virStorageVolSnapInfoPtr info,
+ unsigned int flags);
+
typedef int
(*virDrvStorageVolGetInfo)(virStorageVolPtr vol,
virStorageVolInfoPtr info);
@@ -243,6 +266,11 @@ struct _virStorageDriver {
virDrvStorageVolDelete storageVolDelete;
virDrvStorageVolWipe storageVolWipe;
virDrvStorageVolWipePattern storageVolWipePattern;
+ virDrvStorageVolSnapCreate storageVolSnapCreate;
+ virDrvStorageVolSnapDelete storageVolSnapDelete;
+ virDrvStorageVolSnapRevert storageVolSnapRevert;
+ virDrvStorageVolSnapList storageVolSnapList;
+ virDrvStorageVolSnapGetInfo storageVolSnapGetInfo;
virDrvStorageVolGetInfo storageVolGetInfo;
virDrvStorageVolGetXMLDesc storageVolGetXMLDesc;
virDrvStorageVolGetPath storageVolGetPath;
diff --git a/src/libvirt-storage.c b/src/libvirt-storage.c
index 1ce6745..a2492fe 100644
--- a/src/libvirt-storage.c
+++ b/src/libvirt-storage.c
@@ -1810,6 +1810,149 @@ virStorageVolWipePattern(virStorageVolPtr vol,
return -1;
}
+/**
+ * virStorageVolSnapCreate
+ * @vol: pointer to storage volume
+ * @name: the name of the snapshot
+ * @flags: future flags, use 0 for now
+ *
+ * Create a snapshot of the volume on the backing storage
+ *
+ * Return virStorageVolSnapPtr or NULL on error
+ */
+virStorageVolSnapPtr
+virStorageVolSnapCreate(virStorageVolPtr vol,
+ const char *xmldesc,
+ unsigned int flags) {
+ virConnectPtr conn;
+ VIR_DEBUG("vol=%p, xmldesc=%s, flags=%x", vol, xmldesc, flags);
+
+ virResetLastError();
+
+ conn = vol->conn;
+
+ virCheckReadOnlyGoto(conn->flags, error);
+
+ if (conn->storageDriver &&
conn->storageDriver->storageVolSnapCreate) {
+ virStorageVolSnapPtr snap;
+ snap = conn->storageDriver->storageVolSnapCreate(vol, xmldesc, flags);
+ if (snap == NULL)
+ goto error;
+ return snap;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(vol->conn);
+ return NULL;
+}
+
+/**
+ * virStorageVolSnapDelete
+ * @snap: The snapshot to remove
+ * @flags: future flags, use 0 for now
+ *
+ * Removes the snapshot of a volume
+ *
+ * Return 0 on success, -1 on error
+ */
+int
+virStorageVolSnapDelete(virStorageVolSnapPtr snap,
+ unsigned int flags)
+{
+ if (snap == NULL)
+ goto error;
+
+ virCheckFlags(0, -1);
+
+ return 0;
+
+ error:
+ return -1;
+}
+
+/**
+ * virStorageVolSnapRevert
+ * @snap: The snapshot to revert a volume to
+ * @flags: future flags, use 0 for now
+ *
+ * Revert a volume to the specified snapshot
+ *
+ * Return 0 on succes, -1 on error
+ */
+int
+virStorageVolSnapRevert(virStorageVolSnapPtr snap,
+ unsigned int flags)
+{
+ virCheckFlags(0, -1);
+
+ if (snap == NULL)
+ goto error;
+
+ return 0;
+
+ error:
+ return -1;
+}
+
+/**
+ * virStorageVolSnapList
+ * @vol: The volume to list the snapshots of
+ * @snaps: The snapshots of the volume. NULL if none found
+ * @flags: future flags, use 0 for now
+ *
+ * Lists all snapshots of a volume
+ *
+ * Returns 0 on succes or -1 on error. On error snaps will be set to NULL
+ */
+int
+virStorageVolSnapList(virStorageVolPtr vol,
+ virStorageVolSnapPtr **snaps,
+ unsigned int flags)
+{
+ virCheckFlags(0, -1);
+
+ if (vol == NULL || snaps == NULL)
+ goto error;
+
+ snaps = NULL;
+
+ return 0;
+
+ error:
+ snaps = NULL;
+ return -1;
+}
+
+/**
+ * virStorageVolSnapGetInfo
+ * @snap: Pointer to the snapshot
+ * @info: Will be filled with information about the snapshot
+ * @flags: future flags, use 0 for now
+ *
+ * Give back information about a snapshot
+ *
+ * Returns 0 on succes and -1 on error. On error info will be set to NULL
+ */
+int
+virStorageVolSnapGetInfo(virStorageVolSnapPtr snap,
+ virStorageVolSnapInfoPtr info,
+ unsigned int flags)
+{
+ virCheckFlags(0, -1);
+
+ if (snap == NULL || info == NULL)
+ goto error;
+
+ info = NULL;
+
+ return 0;
+
+ error:
+ info = NULL;
+ return -1;
+}
/**
* virStorageVolFree:
diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h
index 20e6079..8954cbf 100644
--- a/src/storage/storage_backend.h
+++ b/src/storage/storage_backend.h
@@ -102,6 +102,24 @@ typedef int (*virStorageBackendVolumeWipe)(virConnectPtr conn,
unsigned int algorithm,
unsigned int flags);
+typedef int (*virStorageBackendVolumeSnapCreate)(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol,
+ virStorageVolSnapDefPtr snap,
+ unsigned int flags);
+
+typedef int (*virStorageBackendVolumeSnapDelete)(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol,
+ virStorageVolSnapDefPtr snap,
+ unsigned int flags);
+
+typedef int (*virStorageBackendVolumeSnapRevert)(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol,
+ virStorageVolSnapDefPtr snap,
+ unsigned int flags);
+
/* File creation/cloning functions used for cloning between backends */
int virStorageBackendCreateRaw(virConnectPtr conn,
virStoragePoolObjPtr pool,
@@ -165,6 +183,9 @@ struct _virStorageBackend {
virStorageBackendVolumeUpload uploadVol;
virStorageBackendVolumeDownload downloadVol;
virStorageBackendVolumeWipe wipeVol;
+ virStorageBackendVolumeSnapCreate volSnapCreate;
+ virStorageBackendVolumeSnapDelete volSnapDelete;
+ virStorageBackendVolumeSnapRevert volSnapRevert;
};
virStorageBackendPtr virStorageBackendForType(int type);
diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c
index 0bb577f..aed9621 100644
--- a/src/storage/storage_driver.c
+++ b/src/storage/storage_driver.c
@@ -50,6 +50,7 @@
#include "virstring.h"
#include "viraccessapicheck.h"
#include "dirname.h"
+#include "../../include/libvirt/libvirt-storage.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
@@ -2502,6 +2503,102 @@ storageVolWipe(virStorageVolPtr obj,
return storageVolWipePattern(obj, VIR_STORAGE_VOL_WIPE_ALG_ZERO, flags);
}
+static virStorageVolSnapPtr
+storageVolSnapCreate(virStorageVolPtr obj,
+ const char *xmldesc,
+ unsigned int flags)
+{
+ virStorageBackendPtr backend;
+ virStoragePoolObjPtr pool = NULL;
+ virStorageVolSnapPtr ret = NULL;
+ virStorageVolSnapDefPtr snap = NULL;
+ virStorageVolDefPtr vol = NULL;
+
+ virCheckFlags(0, NULL);
+
+ if (!(vol = virStorageVolDefFromVol(obj, &pool, &backend)))
+ goto cleanup;
+
+ snap = virStorageVolSnapDefParseString(pool->def, xmldesc,
+ VIR_VOL_XML_PARSE_OPT_CAPACITY);
+
+ if (backend->volSnapCreate(obj->conn, pool, vol, snap, flags) < 0)
+ goto cleanup;
+
+
+ cleanup:
+ return ret;
+}
+
+static int
+storageVolSnapDelete(virStorageVolSnapPtr snap,
+ unsigned int flags)
+{
+ int ret = -1;
+ virCheckFlags(0, -1);
+
+ if (snap == NULL)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ return ret;
+}
+
+static int
+storageVolSnapRevert(virStorageVolSnapPtr snap,
+ unsigned int flags)
+{
+ int ret = -1;
+ virCheckFlags(0, -1);
+
+ if (snap == NULL)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ return ret;
+}
+
+static int
+storageVolSnapList(virStorageVolPtr vol,
+ virStorageVolSnapPtr **snaps,
+ unsigned int flags)
+{
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ if (vol == NULL || snaps == NULL)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ return ret;
+}
+
+static int
+storageVolSnapGetInfo(virStorageVolSnapPtr snap,
+ virStorageVolSnapInfoPtr info,
+ unsigned int flags)
+{
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ if (snap == NULL || info == NULL)
+ goto cleanup;
+
+ info = NULL;
+
+ ret = 0;
+
+ cleanup:
+ return ret;
+}
static int
storageVolGetInfo(virStorageVolPtr obj,
@@ -2642,6 +2739,11 @@ static virStorageDriver storageDriver = {
.storageVolDelete = storageVolDelete, /* 0.4.0 */
.storageVolWipe = storageVolWipe, /* 0.8.0 */
.storageVolWipePattern = storageVolWipePattern, /* 0.9.10 */
+ .storageVolSnapCreate = storageVolSnapCreate, /* 1.3.2 */
+ .storageVolSnapDelete = storageVolSnapDelete, /* 1.3.2 */
+ .storageVolSnapRevert = storageVolSnapRevert, /* 1.3.2 */
+ .storageVolSnapList = storageVolSnapList, /* 1.3.2 */
+ .storageVolSnapGetInfo = storageVolSnapGetInfo, /* 1.3.2 */
.storageVolGetInfo = storageVolGetInfo, /* 0.4.0 */
.storageVolGetXMLDesc = storageVolGetXMLDesc, /* 0.4.0 */
.storageVolGetPath = storageVolGetPath, /* 0.4.0 */
--
1.9.1