[sheepdog] [PATCH 3/4] collie: vdi restore support
MORITA Kazutaka
morita.kazutaka at lab.ntt.co.jp
Sun Sep 9 18:41:33 CEST 2012
This enables us to restore vdi images with backup files created by
'vdi backup' command.
$ collie vdi restore
Usage: collie vdi restore [-s snapshot] [-a address] [-p port] [-h] <vdiname> <backup>
Options:
-s, --snapshot specify a snapshot id or tag name
-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/common.c | 2 +
collie/vdi.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
man/collie.8 | 3 +
3 files changed, 158 insertions(+), 3 deletions(-)
diff --git a/collie/common.c b/collie/common.c
index baae9bd..46f0123 100644
--- a/collie/common.c
+++ b/collie/common.c
@@ -100,6 +100,8 @@ int sd_write_object(uint64_t oid, uint64_t cow_oid, void *data, unsigned int dat
hdr.data_length = wlen;
hdr.flags = flags | SD_FLAG_CMD_WRITE;
+ if (cow_oid)
+ hdr.flags |= SD_FLAG_CMD_COW;
hdr.obj.copies = copies;
hdr.obj.oid = oid;
diff --git a/collie/vdi.c b/collie/vdi.c
index d580450..13c758a 100644
--- a/collie/vdi.c
+++ b/collie/vdi.c
@@ -1294,7 +1294,6 @@ static int vdi_write(int argc, char **argv)
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;
}
if (vdi_cmd_data.writeback)
@@ -1334,8 +1333,7 @@ static int vdi_write(int argc, char **argv)
if (create) {
ret = sd_write_object(vid_to_vdi_oid(vid), 0, &vid, sizeof(vid),
SD_INODE_HEADER_SIZE + sizeof(vid) * idx,
- flags & ~SD_FLAG_CMD_COW,
- inode->nr_copies, 0);
+ flags, inode->nr_copies, 0);
if (ret) {
ret = EXIT_FAILURE;
goto out;
@@ -1698,6 +1696,155 @@ out:
return ret;
}
+/* restore backup data to vdi */
+static int restore_obj(struct obj_backup *backup, uint32_t vid,
+ struct sheepdog_inode *parent_inode)
+{
+ int ret;
+ uint32_t parent_vid = parent_inode->data_vdi_id[backup->idx];
+ uint64_t parent_oid = 0;
+
+ if (parent_vid)
+ parent_oid = vid_to_data_oid(parent_vid, backup->idx);
+
+ /* send a copy-on-write request */
+ ret = sd_write_object(vid_to_data_oid(vid, backup->idx), parent_oid,
+ backup->data, backup->length, backup->offset,
+ 0, parent_inode->nr_copies, 1);
+ if (ret != SD_RES_SUCCESS)
+ return ret;
+
+ return sd_write_object(vid_to_vdi_oid(vid), 0, &vid, sizeof(vid),
+ SD_INODE_HEADER_SIZE + sizeof(vid) * backup->idx,
+ 0, parent_inode->nr_copies, 0);
+}
+
+static uint32_t do_restore(char *vdiname, int snapid, const char *tag,
+ const char *backup_file)
+{
+ int fd, i, ret;
+ uint32_t vid;
+ struct backup_hdr hdr;
+ struct obj_backup *backup = xzalloc(sizeof(*backup));
+ struct sheepdog_inode *inode = xzalloc(sizeof(*inode));
+
+ printf("restoring %s... ", backup_file);
+
+ fd = open(backup_file, O_RDONLY);
+ if (fd < 0) {
+ printf("Cannot open the backup file\n");
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ xread(fd, &hdr, sizeof(hdr));
+
+ if (hdr.version != VDI_BACKUP_FORMAT_VERSION ||
+ hdr.magic != VDI_BACKUP_MAGIC) {
+ printf("The backup file is corrupted\n");
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ ret = read_vdi_obj(vdiname, snapid, tag, NULL, inode, SD_INODE_SIZE);
+ if (ret != EXIT_SUCCESS)
+ goto out;
+
+ ret = do_vdi_create(vdiname, inode->vdi_size, inode->vdi_id, &vid, 1,
+ inode->nr_copies);
+ if (ret != EXIT_SUCCESS) {
+ printf("Failed to read VDI\n");
+ goto out;
+ }
+
+ for (i = 0; i < hdr.nr_obj_backups; i++) {
+ xread(fd, backup, sizeof(*backup) - sizeof(backup->data));
+ xread(fd, backup->data, backup->length);
+
+ ret = restore_obj(backup, vid, inode);
+ if (ret != SD_RES_SUCCESS) {
+ printf("error\n");
+ do_vdi_delete(vdiname, 0, NULL);
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+ }
+
+ ret = EXIT_SUCCESS;
+ printf("done\n");
+out:
+ free(backup);
+ free(inode);
+
+ return ret;
+}
+
+static int vdi_restore(int argc, char **argv)
+{
+ char *vdiname = argv[optind++], *backup_file;
+ int ret;
+ char buf[SD_INODE_HEADER_SIZE] = {0};
+ struct sheepdog_inode *current_inode = xzalloc(sizeof(*current_inode));
+ struct sheepdog_inode *parent_inode = (struct sheepdog_inode *)buf;
+ bool need_current_recovery = false;
+
+ backup_file = argv[optind++];
+ if (!backup_file) {
+ fprintf(stderr, "Please specify a backup to be restored\n");
+ ret = EXIT_USAGE;
+ goto out;
+ }
+
+ if (!vdi_cmd_data.snapshot_id && !vdi_cmd_data.snapshot_tag[0]) {
+ fprintf(stderr, "We can restore a backup file only to"
+ "snapshots\n");
+ fprintf(stderr, "Please specify the '-s' option\n");
+ ret = EXIT_USAGE;
+ goto out;
+ }
+
+ /* delete the current vdi temporarily first to avoid making
+ * the current state become snapshot */
+ ret = read_vdi_obj(vdiname, 0, "", NULL, current_inode,
+ SD_INODE_HEADER_SIZE);
+ if (ret != EXIT_SUCCESS)
+ goto out;
+
+ ret = sd_read_object(vid_to_vdi_oid(current_inode->parent_vdi_id),
+ parent_inode, SD_INODE_HEADER_SIZE, 0);
+ if (ret != SD_RES_SUCCESS) {
+ printf("error\n");
+ goto out;
+ }
+
+ ret = do_vdi_delete(vdiname, 0, NULL);
+ if (ret != SD_RES_SUCCESS) {
+ fprintf(stderr, "Failed to delete the current state\n");
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+ need_current_recovery = true;
+
+ /* restore backup data */
+ ret = do_restore(vdiname, vdi_cmd_data.snapshot_id,
+ vdi_cmd_data.snapshot_tag, backup_file);
+out:
+ if (need_current_recovery) {
+ int recovery_ret;
+ /* recreate the current vdi object */
+ recovery_ret = do_vdi_create(vdiname, current_inode->vdi_size,
+ current_inode->parent_vdi_id, NULL,
+ parent_inode->snap_id,
+ current_inode->nr_copies);
+ if (recovery_ret != EXIT_SUCCESS) {
+ fprintf(stderr, "failed to resume the current vdi\n");
+ ret = recovery_ret;
+ }
+ }
+ free(current_inode);
+ return ret;
+}
+
static struct subcommand vdi_cmd[] = {
{"check", "<vdiname>", "saph", "check and repair image's consistency",
NULL, SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG,
@@ -1750,6 +1897,9 @@ static struct subcommand vdi_cmd[] = {
{"backup", "<vdiname> <backup>", "sFaph", "create an incremental backup between two snapshots",
NULL, SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG,
vdi_backup, vdi_options},
+ {"restore", "<vdiname> <backup>", "saph", "restore snapshot images from a backup",
+ NULL, SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG,
+ vdi_restore, vdi_options},
{NULL,},
};
diff --git a/man/collie.8 b/man/collie.8
index 7659e07..bcb9ffe 100644
--- a/man/collie.8
+++ b/man/collie.8
@@ -112,6 +112,9 @@ This command writes data to an image.
.BI "vdi backup [-s snapshot] [-F from] [-a address] [-p port] [-h] <vdiname> <backup>"
This command creates an incremental backup between two snapshots.
.TP
+.BI "vdi restore [-s snapshot] [-a address] [-p port] [-h] <vdiname> <backup>"
+This command restores snapshot images from a backup.
+.TP
.BI "node kill [-a address] [-p port] [-r] [-h] <node id>"
This command kills the specified node.
.TP
--
1.7.2.5
More information about the sheepdog
mailing list