[sheepdog] [PATCH 1/5] shared lib: add VDI operation: snapshot

Yu Yang yuyanggg at gmail.com
Thu Jun 4 14:31:45 CEST 2015


From: Yu Yang <yuyang at cmss.chinamobile.com>

Take a snapshot of a working VDI.
We do NOT import snapshot id for lib user, and snapshot tag
is necessary for any snapshot VDI.

Signed-off-by: Yu Yang <yuyang at cmss.chinamobile.com>
---
 lib/shared/sheepdog.h |   11 +++
 lib/shared/vdi.c      |  209 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 220 insertions(+)

diff --git a/lib/shared/sheepdog.h b/lib/shared/sheepdog.h
index 01efbd9..dd36bbe 100644
--- a/lib/shared/sheepdog.h
+++ b/lib/shared/sheepdog.h
@@ -126,4 +126,15 @@ int sd_vdi_write(struct sd_vdi *vdi, void *buf, size_t count, off_t offset);
  */
 int sd_vdi_close(struct sd_vdi *vdi);
 
+/*
+ * Create a snapshot of a VDI
+ *
+ * @c: pointer to the cluster descriptor
+ * @name: the name of the VDI to snapshot
+ * @tag: the tag of the snapshot
+ *
+ * Return error code defined in sheepdog_proto.h.
+ */
+int sd_vdi_snapshot(struct sd_cluster *c, char *name, char *tag);
+
 #endif
diff --git a/lib/shared/vdi.c b/lib/shared/vdi.c
index 7375094..2646d6f 100644
--- a/lib/shared/vdi.c
+++ b/lib/shared/vdi.c
@@ -13,6 +13,17 @@
 
 #include "sheepdog.h"
 #include "internal.h"
+#include "sheep.h"
+
+static int write_object(struct sd_cluster *c, uint64_t oid, uint64_t cow_oid,
+	void *data, unsigned int datalen, uint64_t offset, uint32_t flags,
+	uint8_t copies, uint8_t copy_policy, bool create, bool direct);
+
+static int read_object(struct sd_cluster *c, uint64_t oid, void *data,
+		unsigned int datalen, uint64_t offset, bool direct);
+
+static int vdi_read_inode(struct sd_cluster *c, char *name,
+	char *tag, struct sd_inode *inode, bool header);
 
 static int lock_vdi(struct sd_vdi *vdi)
 {
@@ -187,3 +198,201 @@ int sd_vdi_close(struct sd_vdi *vdi)
 	free_vdi(vdi);
 	return 0;
 }
+
+static int do_vdi_create(struct sd_cluster *c, char *name, uint64_t vdi_size,
+	uint32_t base_vid, bool snapshot,
+	uint8_t nr_copies, uint8_t copy_policy,
+	uint8_t store_policy, uint8_t block_size_shift)
+{
+	struct sd_req hdr = {};
+	int ret;
+
+	sd_init_req(&hdr, SD_OP_NEW_VDI);
+	hdr.flags = SD_FLAG_CMD_WRITE;
+	hdr.data_length = SD_MAX_VDI_LEN;
+
+	hdr.vdi.base_vdi_id = base_vid;
+	hdr.vdi.snapid = snapshot ? 1 : 0;
+	hdr.vdi.vdi_size = vdi_size;
+	hdr.vdi.copies = nr_copies;
+	hdr.vdi.copy_policy = copy_policy;
+	hdr.vdi.store_policy = store_policy;
+	hdr.vdi.block_size_shift = block_size_shift;
+
+	ret = sd_run_sdreq(c, &hdr, name);
+
+	return ret;
+}
+
+static int write_object(struct sd_cluster *c, uint64_t oid, uint64_t cow_oid,
+	void *data, unsigned int datalen, uint64_t offset, uint32_t flags,
+	uint8_t copies, uint8_t copy_policy, bool create, bool direct)
+{
+	struct sd_req hdr = {};
+	int ret;
+
+	if (create)
+		sd_init_req(&hdr, SD_OP_CREATE_AND_WRITE_OBJ);
+	else
+		sd_init_req(&hdr, SD_OP_WRITE_OBJ);
+
+	hdr.data_length = datalen;
+	hdr.flags = flags | SD_FLAG_CMD_WRITE;
+
+	if (cow_oid)
+		hdr.flags |= SD_FLAG_CMD_COW;
+	if (direct)
+		hdr.flags |= SD_FLAG_CMD_DIRECT;
+
+	hdr.obj.copies = copies;
+	hdr.obj.copy_policy = copy_policy;
+	hdr.obj.oid = oid;
+	hdr.obj.cow_oid = cow_oid;
+	hdr.obj.offset = offset;
+
+	ret = sd_run_sdreq(c, &hdr, data);
+
+	return ret;
+}
+
+static int read_object(struct sd_cluster *c, uint64_t oid, void *data,
+		unsigned int datalen, uint64_t offset, bool direct)
+{
+	struct sd_req hdr = {};
+	int ret;
+
+	sd_init_req(&hdr, SD_OP_READ_OBJ);
+	hdr.data_length = datalen;
+	hdr.obj.oid = oid;
+	hdr.obj.offset = offset;
+	if (direct)
+		hdr.flags |= SD_FLAG_CMD_DIRECT;
+
+	ret = sd_run_sdreq(c, &hdr, data);
+
+	return ret;
+}
+
+static int find_vdi(struct sd_cluster *c, char *name,
+		char *tag, uint32_t *vid)
+{
+	struct sd_req hdr = {};
+	struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+	char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
+	int ret;
+
+	memset(buf, 0, sizeof(buf));
+	pstrcpy(buf, SD_MAX_VDI_LEN, name);
+	if (tag)
+		pstrcpy(buf + SD_MAX_VDI_LEN, SD_MAX_VDI_TAG_LEN, tag);
+
+	sd_init_req(&hdr, SD_OP_GET_VDI_INFO);
+	hdr.data_length = SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN;
+	hdr.flags = SD_FLAG_CMD_WRITE;
+
+	ret = sd_run_sdreq(c, &hdr, buf);
+	if (ret != SD_RES_SUCCESS)
+		return ret;
+
+	if (vid)
+		*vid = rsp->vdi.vdi_id;
+
+	return ret;
+}
+
+static int vdi_read_inode(struct sd_cluster *c, char *name,
+		char *tag, struct sd_inode *inode, bool onlyheader)
+{
+	int ret;
+	uint32_t vid = 0;
+	size_t len;
+
+	ret = find_vdi(c, name, tag, &vid);
+	if (ret != SD_RES_SUCCESS)
+		return ret;
+
+	if (onlyheader)
+		len = SD_INODE_HEADER_SIZE;
+	else
+		len = SD_INODE_SIZE;
+
+	ret = read_object(c, vid_to_vdi_oid(vid), inode, len, 0, true);
+
+	return SD_RES_SUCCESS;
+}
+
+/** FIXME: tgtd multi-path support **/
+int sd_vdi_snapshot(struct sd_cluster *c, char *name, char *snap_tag)
+{
+	struct sd_req hdr = {};
+	char buf[SD_INODE_HEADER_SIZE];
+	struct sd_inode *inode = (struct sd_inode *)buf;
+	int ret = 0;
+
+	if (!name || *name == '\0') {
+		fprintf(stderr, "VDI name can NOT be null\n");
+		return SD_RES_INVALID_PARMS;
+	}
+	if (!snap_tag || *snap_tag == '\0') {
+		fprintf(stderr, "Snapshot tag can NOT be null for snapshot\n");
+		return SD_RES_INVALID_PARMS;
+	}
+
+	ret = find_vdi(c, name, snap_tag, NULL);
+	if (ret == SD_RES_SUCCESS) {
+			fprintf(stderr, "VDI %s(tag: %s) is already existed\n",
+				name, snap_tag);
+			return SD_RES_INVALID_PARMS;
+
+	} else if (ret == SD_RES_NO_TAG) {
+		ret = vdi_read_inode(c, name, NULL, inode, true);
+		if (ret != SD_RES_SUCCESS)
+			return ret;
+
+	} else {
+		fprintf(stderr, "Failed to create snapshot:%s\n",
+				sd_strerror(ret));
+		return ret;
+	}
+
+	if (inode->store_policy) {
+		fprintf(stderr, "Creating a snapshot of hypervolume"
+				" is not supported\n");
+		return SD_RES_INVALID_PARMS;
+	}
+
+	sd_init_req(&hdr, SD_OP_PREVENT_INODE_UPDATE);
+	ret = sd_run_sdreq(c, &hdr, NULL);
+	if (ret != SD_RES_SUCCESS) {
+		fprintf(stderr, "Failed to prevent inode update: %s\n",
+				sd_strerror(ret));
+		return ret;
+	}
+
+	ret = write_object(c, vid_to_vdi_oid(inode->vdi_id), 0, snap_tag,
+			SD_MAX_VDI_TAG_LEN, offsetof(struct sd_inode, tag), 0,
+			inode->nr_copies, inode->copy_policy, false, false);
+	if (ret != SD_RES_SUCCESS) {
+		fprintf(stderr, "Failed to write object: %s\n",
+				sd_strerror(ret));
+		goto out;
+	}
+
+	ret = do_vdi_create(c, inode->name, inode->vdi_size,
+			inode->vdi_id, true, inode->nr_copies,
+			inode->copy_policy,	inode->store_policy,
+			inode->block_size_shift);
+	if (ret != SD_RES_SUCCESS) {
+		fprintf(stderr, "Failed to create VDI: %s\n", sd_strerror(ret));
+		goto out;
+	}
+
+out:
+	sd_init_req(&hdr, SD_OP_ALLOW_INODE_UPDATE);
+	int ret2 = sd_run_sdreq(c, &hdr, NULL);
+	if (ret2 != SD_RES_SUCCESS)
+		fprintf(stderr, "allowing inode update failed:%s\n",
+				sd_strerror(ret));
+
+	return ret;
+}
-- 
1.7.9.5



More information about the sheepdog mailing list