This command reads data from the standard input, and writes the data to the Sheepdog virtual disk image. Note that Sheepdog doesn't allow concurrent write accesses from multiple clients; you cannot use this command when another VM uses the disk image. $ collie vdi write -h vdi write - write data to a image Usage: collie vdi write <vdiname> <offset> <len> [-a address] [-p port] [-h] Command parameters: -a, --address specify the daemon address (default: localhost) -p, --port specify the daemon port -h, --help display this help and exit Signed-off-by: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp> --- collie/collie.h | 2 +- collie/common.c | 3 +- collie/vdi.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 119 insertions(+), 10 deletions(-) diff --git a/collie/collie.h b/collie/collie.h index 98fba4c..b814751 100644 --- a/collie/collie.h +++ b/collie/collie.h @@ -67,7 +67,7 @@ typedef void (*vdi_parser_func_t)(uint32_t vid, char *name, char *tag, int parse_vdi(vdi_parser_func_t func, size_t size, void *data); int sd_read_object(uint64_t oid, void *data, unsigned int datalen, uint64_t offset); -int sd_write_object(uint64_t oid, void *data, unsigned int datalen, +int sd_write_object(uint64_t oid, uint64_t cow_oid, void *data, unsigned int datalen, uint64_t offset, uint32_t flags, int copies, int create); extern struct command vdi_command; diff --git a/collie/common.c b/collie/common.c index b58c192..e139dfb 100644 --- a/collie/common.c +++ b/collie/common.c @@ -88,7 +88,7 @@ int sd_read_object(uint64_t oid, void *data, unsigned int datalen, return SD_RES_SUCCESS; } -int sd_write_object(uint64_t oid, void *data, unsigned int datalen, +int sd_write_object(uint64_t oid, uint64_t cow_oid, void *data, unsigned int datalen, uint64_t offset, uint32_t flags, int copies, int create) { struct sd_obj_req hdr; @@ -109,6 +109,7 @@ int sd_write_object(uint64_t oid, void *data, unsigned int datalen, else hdr.opcode = SD_OP_WRITE_OBJ; hdr.oid = oid; + hdr.cow_oid = cow_oid; hdr.copies = copies; hdr.data_length = wlen; hdr.flags = (flags & ~SD_FLAG_CMD_DIRECT) | SD_FLAG_CMD_WRITE; diff --git a/collie/vdi.c b/collie/vdi.c index 1547e15..f3f6b07 100644 --- a/collie/vdi.c +++ b/collie/vdi.c @@ -480,7 +480,7 @@ static int vdi_create(int argc, char **argv) for (idx = 0; idx < max_idx; idx++) { oid = vid_to_data_oid(vid, idx); - ret = sd_write_object(oid, buf, SD_DATA_OBJ_SIZE, 0, 0, + ret = sd_write_object(oid, 0, buf, SD_DATA_OBJ_SIZE, 0, 0, inode->nr_copies, 1); if (ret != SD_RES_SUCCESS) { ret = EXIT_FAILURE; @@ -488,7 +488,7 @@ static int vdi_create(int argc, char **argv) } inode->data_vdi_id[idx] = vid; - ret = sd_write_object(vid_to_vdi_oid(vid), &vid, sizeof(vid), + ret = sd_write_object(vid_to_vdi_oid(vid), 0, &vid, sizeof(vid), SD_INODE_HEADER_SIZE + sizeof(vid) * idx, 0, inode->nr_copies, 0); if (ret) { @@ -530,7 +530,7 @@ static int vdi_snapshot(int argc, char **argv) } if (vdi_cmd_data.snapshot_tag[0]) { - ret = sd_write_object(vid_to_vdi_oid(vid), vdi_cmd_data.snapshot_tag, + ret = sd_write_object(vid_to_vdi_oid(vid), 0, vdi_cmd_data.snapshot_tag, SD_MAX_VDI_TAG_LEN, offsetof(struct sheepdog_inode, tag), 0, inode->nr_copies, 0); @@ -609,14 +609,14 @@ static int vdi_clone(int argc, char **argv) memset(buf, 0, SD_DATA_OBJ_SIZE); oid = vid_to_data_oid(new_vid, idx); - ret = sd_write_object(oid, buf, SD_DATA_OBJ_SIZE, 0, 0, + ret = sd_write_object(oid, 0, buf, SD_DATA_OBJ_SIZE, 0, 0, inode->nr_copies, 1); if (ret != SD_RES_SUCCESS) { ret = EXIT_FAILURE; goto out; } - ret = sd_write_object(vid_to_vdi_oid(new_vid), &new_vid, sizeof(new_vid), + ret = sd_write_object(vid_to_vdi_oid(new_vid), 0, &new_vid, sizeof(new_vid), SD_INODE_HEADER_SIZE + sizeof(new_vid) * idx, 0, inode->nr_copies, 0); if (ret) { @@ -670,7 +670,7 @@ static int vdi_resize(int argc, char **argv) } inode->vdi_size = new_size; - ret = sd_write_object(vid_to_vdi_oid(vid), inode, SD_INODE_HEADER_SIZE, 0, + ret = sd_write_object(vid_to_vdi_oid(vid), 0, inode, SD_INODE_HEADER_SIZE, 0, 0, inode->nr_copies, 0); if (ret != SD_RES_SUCCESS) { fprintf(stderr, "failed to update an inode header\n"); @@ -901,11 +901,11 @@ reread: oid = attr_oid; if (vdi_cmd_data.delete) - ret = sd_write_object(oid, (char *)"", 1, + ret = sd_write_object(oid, 0, (char *)"", 1, offsetof(struct sheepdog_inode, name), 0, nr_copies, 0); else - ret = sd_write_object(oid, value, strlen(value), + ret = sd_write_object(oid, 0, value, strlen(value), SD_ATTR_HEADER_SIZE, SD_FLAG_CMD_TRUNCATE, nr_copies, 0); @@ -1049,6 +1049,112 @@ out: return ret; } +static int vdi_write(int argc, char **argv) +{ + char *vdiname = argv[optind++]; + uint32_t vid, flags; + int ret, idx; + struct sheepdog_inode *inode = NULL; + uint64_t offset, oid, old_oid, done = 0, total; + unsigned int len; + char *buf = NULL; + int create; + + if (!argv[optind]) { + fprintf(stderr, "please specify a start offset\n"); + return EXIT_USAGE; + } + ret = parse_option_size(argv[optind++], &offset); + if (ret < 0) + return EXIT_USAGE; + + if (!argv[optind]) { + fprintf(stderr, "please specify a length to read\n"); + return EXIT_USAGE; + } + ret = parse_option_size(argv[optind], &total); + if (ret < 0) + return EXIT_USAGE; + + inode = malloc(sizeof(*inode)); + buf = malloc(SD_DATA_OBJ_SIZE); + if (!inode || !buf) { + fprintf(stderr, "oom\n"); + ret = EXIT_SYSFAIL; + goto out; + } + + ret = find_vdi_name(vdiname, 0, "", &vid, 0); + if (ret < 0) { + fprintf(stderr, "failed to open vdi %s\n", vdiname); + ret = EXIT_FAILURE; + goto out; + } + ret = sd_read_object(vid_to_vdi_oid(vid), inode, SD_INODE_SIZE, 0); + if (ret != SD_RES_SUCCESS) { + fprintf(stderr, "failed to read an inode\n"); + ret = EXIT_FAILURE; + goto out; + } + + idx = offset / SD_DATA_OBJ_SIZE; + while (done != total) { + create = 0; + old_oid = 0; + flags = 0; + len = min(total - done, SD_DATA_OBJ_SIZE - offset); + + if (!inode->data_vdi_id[idx]) + create = 1; + else if (!is_data_obj_writeable(inode, idx)) { + create = 1; + old_oid = vid_to_data_oid(inode->data_vdi_id[idx], idx); + flags = SD_FLAG_CMD_COW; + } + + ret = read(STDIN_FILENO, buf, len); + if (ret < 0) { + fprintf(stderr, "%m\n"); + ret = EXIT_SYSFAIL; + goto out; + } + len = ret; + + inode->data_vdi_id[idx] = inode->vdi_id; + oid = vid_to_data_oid(inode->data_vdi_id[idx], idx); + ret = sd_write_object(oid, old_oid, buf, len, offset, flags, + inode->nr_copies, create); + if (ret != SD_RES_SUCCESS) { + fprintf(stderr, "failed to write vdi\n"); + ret = EXIT_FAILURE; + goto out; + } + + if (create) { + ret = sd_write_object(vid_to_vdi_oid(vid), 0, &vid, sizeof(vid), + SD_INODE_HEADER_SIZE + sizeof(vid) * idx, 0, + inode->nr_copies, 0); + if (ret) { + ret = EXIT_FAILURE; + goto out; + } + } + + offset += len; + if (offset == SD_DATA_OBJ_SIZE) { + offset = 0; + idx++; + } + done += len; + } + ret = EXIT_SUCCESS; +out: + free(inode); + free(buf); + + return ret; +} + static struct subcommand vdi_cmd[] = { {"create", "<vdiname> <size>", "Paph", "create a image", SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_create}, @@ -1074,6 +1180,8 @@ static struct subcommand vdi_cmd[] = { SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_resize}, {"read", "<vdiname> <offset> <len>", "saph", "read data from a image", SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_read}, + {"write", "<vdiname> <offset> <len>", "aph", "write data to a image", + SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_write}, {NULL,}, }; -- 1.7.2.5 |