From: Yu Yang <[email protected]>

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 <[email protected]>
---
 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

-- 
sheepdog mailing list
[email protected]
https://lists.wpkg.org/mailman/listinfo/sheepdog

Reply via email to