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
