[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