This patch adds a new command "dog upgrade" and its subcommand convert-inode for converting old inode file to new version.
Example: $ dog upgrade inode-convert -o v0.7 original_inode_file new_inode_file Currently, snapshot isn't supported. Cc: Masahiro Tsuji <[email protected]> Signed-off-by: Hitoshi Mitake <[email protected]> --- dog/Makefile.am | 3 +- dog/dog.c | 1 + dog/dog.h | 1 + dog/upgrade.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++ include/sheepdog_proto.h | 48 +++++++++++++ 5 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 dog/upgrade.c diff --git a/dog/Makefile.am b/dog/Makefile.am index 1bb1b14..9615468 100644 --- a/dog/Makefile.am +++ b/dog/Makefile.am @@ -25,7 +25,8 @@ sbin_PROGRAMS = dog dog_SOURCES = farm/object_tree.c farm/sha1_file.c farm/snap.c \ farm/trunk.c farm/farm.c farm/slice.c \ - dog.c common.c treeview.c vdi.c node.c cluster.c + dog.c common.c treeview.c vdi.c node.c cluster.c \ + upgrade.c if BUILD_TRACE dog_SOURCES += trace.c diff --git a/dog/dog.c b/dog/dog.c index 77aa27b..916ce5e 100644 --- a/dog/dog.c +++ b/dog/dog.c @@ -182,6 +182,7 @@ static void init_commands(const struct command **commands) #ifdef HAVE_NFS nfs_command, #endif + upgrade_command, {NULL,} }; diff --git a/dog/dog.h b/dog/dog.h index d603328..b099a31 100644 --- a/dog/dog.h +++ b/dog/dog.h @@ -115,6 +115,7 @@ extern struct command vdi_command; extern struct command node_command; extern struct command cluster_command; extern struct command alter_command; +extern struct command upgrade_command; #ifdef HAVE_TRACE extern struct command trace_command; diff --git a/dog/upgrade.c b/dog/upgrade.c new file mode 100644 index 0000000..88d87fe --- /dev/null +++ b/dog/upgrade.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +#include "dog.h" + +static struct sd_option upgrade_options[] = { + {'o', "orig-version", true, "version of converting inode file"}, + { 0, NULL, false, NULL }, +}; + +enum orig_version { + ORIG_VERSION_0_7 = 1, + ORIG_VERSION_0_8, +}; + +static struct upgrade_cmd_data { + enum orig_version orig; +} upgrade_cmd_data = { ~0, }; + +static int upgrade_inode_convert(int argc, char **argv) +{ + const char *orig_file = argv[optind++], *dst_file = NULL; + int orig_fd, dst_fd, ret; + struct sd_inode_0_7 *orig_0_7; + struct sd_inode_0_8 *orig_0_8; + struct stat orig_stat; + struct sd_inode *dst; + + if (optind < argc) + dst_file = argv[optind++]; + else { + sd_info("please specify destination file path"); + return EXIT_USAGE; + } + + orig_fd = open(orig_file, O_RDONLY); + if (orig_fd < 0) { + sd_err("failed to open original inode file: %m"); + return EXIT_SYSFAIL; + } + + memset(&orig_stat, 0, sizeof(orig_stat)); + ret = fstat(orig_fd, &orig_stat); + if (ret < 0) { + sd_err("failed to stat original inode file: %m"); + return EXIT_SYSFAIL; + } + + dst = xzalloc(sizeof(*dst)); + + if (upgrade_cmd_data.orig == ORIG_VERSION_0_7) { + orig_0_7 = xzalloc(sizeof(*orig_0_7)); + ret = xread(orig_fd, orig_0_7, orig_stat.st_size); + if (ret != orig_stat.st_size) { + sd_err("failed to read original inode file: %m"); + return EXIT_SYSFAIL; + } + + if (orig_0_7->snap_ctime) { + sd_err("snapshot cannot be converted"); + return EXIT_USAGE; + } + + memcpy(dst->name, orig_0_7->name, SD_MAX_VDI_LEN); + memcpy(dst->tag, orig_0_7->tag, SD_MAX_VDI_TAG_LEN); + dst->create_time = orig_0_7->create_time; + dst->vm_clock_nsec = orig_0_7->vm_clock_nsec; + dst->vdi_size = orig_0_7->vdi_size; + dst->vm_state_size = orig_0_7->vm_state_size; + dst->copy_policy = orig_0_7->copy_policy; + dst->nr_copies = orig_0_7->nr_copies; + dst->block_size_shift = orig_0_7->block_size_shift; + dst->vdi_id = orig_0_7->vdi_id; + + memcpy(dst->data_vdi_id, orig_0_7->data_vdi_id, + sizeof(uint32_t) * SD_INODE_DATA_INDEX); + } else if (upgrade_cmd_data.orig == ORIG_VERSION_0_8) { + orig_0_8 = xzalloc(sizeof(*orig_0_8)); + ret = xread(orig_fd, orig_0_8, orig_stat.st_size); + + if (ret != orig_stat.st_size) { + sd_err("failed to read original inode file: %m"); + return EXIT_SYSFAIL; + } + + if (orig_0_8->snap_ctime) { + sd_err("snapshot cannot be converted"); + return EXIT_USAGE; + } + + memcpy(dst->name, orig_0_8->name, SD_MAX_VDI_LEN); + memcpy(dst->tag, orig_0_8->tag, SD_MAX_VDI_TAG_LEN); + dst->create_time = orig_0_8->create_time; + dst->vm_clock_nsec = orig_0_8->vm_clock_nsec; + dst->vdi_size = orig_0_8->vdi_size; + dst->vm_state_size = orig_0_8->vm_state_size; + dst->copy_policy = orig_0_8->copy_policy; + dst->nr_copies = orig_0_8->nr_copies; + dst->block_size_shift = orig_0_8->block_size_shift; + dst->vdi_id = orig_0_8->vdi_id; + + memcpy(dst->data_vdi_id, orig_0_8->data_vdi_id, + sizeof(uint32_t) * SD_INODE_DATA_INDEX); + } else { + sd_info("please specify original version of inode file"); + return EXIT_FAILURE; + } + + dst_fd = open(dst_file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + if (dst_fd < 0) { + sd_err("failed to create converted inode file: %m"); + return EXIT_SYSFAIL; + } + + ret = xwrite(dst_fd, dst, sizeof(*dst)); + if (ret != sizeof(*dst)) { + sd_err("failed to write converted inode file: %m"); + return EXIT_SYSFAIL; + } + + return EXIT_SUCCESS; +} + +static struct subcommand upgrade_cmd[] = { + {"inode-convert", "<path of original inode file>" + " <path of new inode file>", + "hTo", "check and repair image's consistency", + NULL, CMD_NEED_ARG, upgrade_inode_convert, upgrade_options}, + {NULL,}, +}; + +static int upgrade_parser(int ch, const char *opt) +{ + switch (ch) { + case 'o': + if (!strcmp(opt, "v0.7")) + upgrade_cmd_data.orig = ORIG_VERSION_0_7; + else if (!strcmp(opt, "v0.8")) + upgrade_cmd_data.orig = ORIG_VERSION_0_8; + else { + sd_info("unknown original version: %s", opt); + sd_info("valid versions are v0.7 or v0.8"); + exit(EXIT_FAILURE); + } + + break; + } + + return 0; +} + +struct command upgrade_command = { + "upgrade", + upgrade_cmd, + upgrade_parser +}; + diff --git a/include/sheepdog_proto.h b/include/sheepdog_proto.h index af9b24f..60e61c0 100644 --- a/include/sheepdog_proto.h +++ b/include/sheepdog_proto.h @@ -262,6 +262,54 @@ struct sd_rsp { }; }; +#define MAX_CHILDREN 1024U + +/* + * struct sd_inode_0_7: old inode format used in v0.7.x + * Just used by upgrade tools. + */ +struct sd_inode_0_7 { + char name[SD_MAX_VDI_LEN]; + char tag[SD_MAX_VDI_TAG_LEN]; + uint64_t create_time; + uint64_t snap_ctime; + uint64_t vm_clock_nsec; + uint64_t vdi_size; + uint64_t vm_state_size; + uint16_t copy_policy; + uint8_t nr_copies; + uint8_t block_size_shift; + uint32_t snap_id; + uint32_t vdi_id; + uint32_t parent_vdi_id; + uint32_t child_vdi_id[MAX_CHILDREN]; + uint32_t data_vdi_id[MAX_DATA_OBJS]; +}; + +/* + * struct sd_inode_0_8: old inode format used in v0.8.x + * Just used by upgrade tools. + */ +struct sd_inode_0_8 { + char name[SD_MAX_VDI_LEN]; + char tag[SD_MAX_VDI_TAG_LEN]; + uint64_t create_time; + uint64_t snap_ctime; + uint64_t vm_clock_nsec; + uint64_t vdi_size; + uint64_t vm_state_size; + uint8_t copy_policy; + uint8_t store_policy; + uint8_t nr_copies; + uint8_t block_size_shift; + uint32_t snap_id; + uint32_t vdi_id; + uint32_t parent_vdi_id; + uint32_t child_vdi_id[MAX_CHILDREN]; + uint32_t data_vdi_id[SD_INODE_DATA_INDEX]; + uint32_t btree_counter; +}; + /* * Historical notes: previous version of sheepdog (< v0.9.0) has a limit of * maximum number of children which can be created from single VDI. So the inode -- 1.9.1 -- sheepdog mailing list [email protected] https://lists.wpkg.org/mailman/listinfo/sheepdog
