All of lore.kernel.org
 help / color / mirror / Atom feed
From: Qu Wenruo <quwenruo@cn.fujitsu.com>
To: linux-btrfs@vger.kernel.org
Subject: [PATCH v3 4/6] btrfs-progs: convert: Introduce new function to check if we can rollback
Date: Mon, 19 Dec 2016 14:56:40 +0800	[thread overview]
Message-ID: <20161219065642.25078-5-quwenruo@cn.fujitsu.com> (raw)
In-Reply-To: <20161219065642.25078-1-quwenruo@cn.fujitsu.com>

Introduce new function, check_rollback(), to collect data and check if
we can rollback the image.

The check part is quite straight forward:
Ensure all the file extents, except the ones inside reserved ranges, are
mapped 1:1 on disk.

The ones inside reserved ranges, 0~1M, 1st sb +64K, 2nd sb +64K, can be
mapped to anywhere, as btrfs needs to put super blocks in them.

Such behavir can meet both old convert(one large chunk) and new
convert(only old image file is 1:1 mapped).

Also, the function will read out the data in btrfs reserved ranges for
later rollback usage.

Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
---
 convert/main.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 214 insertions(+)

diff --git a/convert/main.c b/convert/main.c
index 87c52c1..5b9141b 100644
--- a/convert/main.c
+++ b/convert/main.c
@@ -2781,6 +2781,220 @@ static int record_reloc_data(struct btrfs_fs_info *fs_info,
 	return 0;
 }
 
+static int check_image_file_extents(struct btrfs_root *image_root, u64 ino,
+				    u64 total_size, char *reloc_ranges[3])
+{
+	struct btrfs_key key;
+	struct btrfs_path path;
+	struct btrfs_fs_info *fs_info = image_root->fs_info;
+	u64 checked_bytes = 0;
+	int ret;
+
+	key.objectid = ino;
+	key.offset = 0;
+	key.type = BTRFS_EXTENT_DATA_KEY;
+
+	btrfs_init_path(&path);
+	ret = btrfs_search_slot(NULL, image_root, &key, &path, 0, 0);
+	/*
+	 * It's possible that some fs doesn't store any(including sb)
+	 * data into 0~1M range, and NO_HOLES is enabled.
+	 *
+	 * So only needs to check ret < 0 case
+	 */
+	if (ret < 0) {
+		error("failed to iterate file extents at offset 0: %s",
+			strerror(-ret));
+		btrfs_release_path(&path);
+		return ret;
+	}
+
+	/* Loop from the first file extents */
+	while (1) {
+		struct btrfs_file_extent_item *fi;
+		struct extent_buffer *leaf = path.nodes[0];
+		u64 disk_bytenr;
+		u64 file_offset;
+		u64 ram_bytes;
+		u64 extent_offset;
+		int slot = path.slots[0];
+
+		if (slot >= btrfs_header_nritems(leaf))
+			goto next;
+		btrfs_item_key_to_cpu(leaf, &key, slot);
+
+		/*
+		 * Iteration is done, exit normally, we have extra check out of
+		 * the loop
+		 */
+		if (key.objectid != ino || key.type != BTRFS_EXTENT_DATA_KEY) {
+			ret = 0;
+			break;
+		}
+		file_offset = key.offset;
+		fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
+		if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_REG) {
+			ret = -EINVAL;
+			error(
+		"ino %llu offset %llu doesn't have a regular file extent",
+				ino, file_offset);
+			break;
+		}
+		if (btrfs_file_extent_compression(leaf, fi) ||
+		    btrfs_file_extent_encryption(leaf, fi) ||
+		    btrfs_file_extent_other_encoding(leaf, fi)) {
+			ret = -EINVAL;
+			error(
+			"ino %llu offset %llu doesn't have a plain file extent",
+				ino, file_offset);
+			break;
+		}
+
+		disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
+		ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi);
+		extent_offset = btrfs_file_extent_offset(leaf, fi);
+
+		checked_bytes += ram_bytes;
+		/* Skip hole */
+		if (disk_bytenr == 0)
+			goto next;
+
+		if (file_offset != disk_bytenr) {
+			/*
+			 * Only file extent in btrfs reserved ranges are allow
+			 * non-1:1 mapped
+			 */
+			if (!is_range_subset_of_reserved_ranges(file_offset,
+							ram_bytes)) {
+				ret = -EINVAL;
+				error(
+		"ino %llu offset %llu file extent should not be relocated",
+					ino, file_offset);
+				break;
+			}
+		}
+		ret = record_reloc_data(fs_info, file_offset,
+				disk_bytenr + extent_offset, ram_bytes,
+				reloc_ranges);
+		if (ret < 0) {
+			error("ino %llu offset %llu failed to read extent data",
+				ino, file_offset);
+			break;
+		}
+next:
+		ret = btrfs_next_item(image_root, &path);
+		if (ret) {
+			if (ret > 0)
+				ret = 0;
+			break;
+		}
+	}
+	btrfs_release_path(&path);
+	/*
+	 * For HOLES mode (without NO_HOLES), we must ensure file extents
+	 * cover the whole range of the image
+	 */
+	if (!ret && !btrfs_fs_incompat(fs_info, NO_HOLES)) {
+		if (checked_bytes != total_size) {
+			ret = -EINVAL;
+			error("inode %llu has some file extents not checked",
+				ino);
+		}
+	}
+	return ret;
+}
+
+/*
+ * Check and record needed blocks for rollback.
+ *
+ * It will record data for superblock and reserved ranges to reloc_ranges[].
+ * So we can rollback the fs after close_ctree().
+ */
+static int check_rollback(struct btrfs_fs_info *fs_info, char *reloc_ranges[3])
+{
+	struct btrfs_root *image_root;
+	struct btrfs_dir_item *dir;
+	struct btrfs_path path;
+	struct btrfs_key key;
+	struct btrfs_inode_item *inode_item;
+	char *image_name = "image";
+	u64 ino;
+	u64 root_dir;
+	u64 total_bytes;
+	int ret;
+
+	btrfs_init_path(&path);
+
+	/*
+	 * Search for root backref, or after subvolume delete(orphan),
+	 * we can still rollback if the subvolume is just orphan.
+	 */
+	key.objectid = CONV_IMAGE_SUBVOL_OBJECTID;
+	key.type = BTRFS_ROOT_BACKREF_KEY;
+	key.offset = BTRFS_FS_TREE_OBJECTID;
+
+	ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, &path, 0, 0);
+	btrfs_release_path(&path);
+	if (ret > 0) {
+		error("unable to convert ext2 image subvolume, is it deleted?");
+		return -ENOENT;
+	} else if (ret < 0) {
+		error("failed to find ext2 image subvolume: %s",
+			strerror(-ret));
+		return ret;
+	}
+
+	/* Search convert subvolume */
+	key.objectid = CONV_IMAGE_SUBVOL_OBJECTID;
+	key.type = BTRFS_ROOT_ITEM_KEY;
+	key.offset = (u64)-1;
+
+	image_root = btrfs_read_fs_root(fs_info, &key);
+	if (IS_ERR(image_root)) {
+		ret = PTR_ERR(image_root);
+		error("failed to open convert image subvolume: %s",
+			strerror(-ret));
+		return ret;
+	}
+
+	/* Search the image file */
+	root_dir = btrfs_root_dirid(&image_root->root_item);
+	dir = btrfs_lookup_dir_item(NULL, image_root, &path, root_dir,
+			image_name, strlen(image_name), 0);
+
+	if (!dir || IS_ERR(dir)) {
+		btrfs_release_path(&path);
+		if (dir)
+			ret = PTR_ERR(dir);
+		else
+			ret = -ENOENT;
+		error("failed to locate file %s: %s", image_name,
+			strerror(-ret));
+		return ret;
+	}
+	btrfs_dir_item_key_to_cpu(path.nodes[0], dir, &key);
+	btrfs_release_path(&path);
+
+	/* Get total size of the original image */
+	ino = key.objectid;
+
+	ret = btrfs_lookup_inode(NULL, image_root, &path, &key, 0);
+	if (ret < 0) {
+		btrfs_release_path(&path);
+		error("unable to find inode %llu: %s", ino, strerror(-ret));
+		return ret;
+	}
+	inode_item = btrfs_item_ptr(path.nodes[0], path.slots[0],
+				    struct btrfs_inode_item);
+	total_bytes = btrfs_inode_size(path.nodes[0], inode_item);
+	btrfs_release_path(&path);
+
+	/* Main function to check every file extent of the image file */
+	ret = check_image_file_extents(image_root, ino, total_bytes,
+					reloc_ranges);
+	return ret;
+}
+
 static int do_rollback(const char *devname)
 {
 	int fd = -1;
-- 
2.10.2




  parent reply	other threads:[~2016-12-19  6:57 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-19  6:56 [PATCH v3 0/6] Convert rollback rework for v4.9 Qu Wenruo
2016-12-19  6:56 ` [PATCH v3 1/6] btrfs-progs: file-item: Fix wrong file extents inserted Qu Wenruo
2016-12-19  6:56 ` [PATCH v3 2/6] btrfs-progs: utils: Introduce basic set operations for range Qu Wenruo
2017-01-23 17:28   ` David Sterba
2017-01-24  0:40     ` Qu Wenruo
2017-01-23 17:40   ` David Sterba
2016-12-19  6:56 ` [PATCH v3 3/6] btrfs-progs: convert: Introduce function to record relocated ranges Qu Wenruo
2016-12-19  6:56 ` Qu Wenruo [this message]
2016-12-19  6:56 ` [PATCH v3 5/6] btrfs-progs: convert: Switch to new rollback function Qu Wenruo
2016-12-20  5:36   ` Chandan Rajendra
2017-01-23 17:54   ` David Sterba
2017-01-24  0:44     ` Qu Wenruo
2017-01-24 16:37       ` David Sterba
2017-01-25  0:42         ` Qu Wenruo
2017-01-30 14:55           ` David Sterba
2016-12-19  6:56 ` [PATCH v3 6/6] btrfs-progs: convert-test: trigger chunk allocation after convert Qu Wenruo
2016-12-21 14:35 ` [PATCH v3 0/6] Convert rollback rework for v4.9 David Sterba
2016-12-22  1:53   ` Qu Wenruo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161219065642.25078-5-quwenruo@cn.fujitsu.com \
    --to=quwenruo@cn.fujitsu.com \
    --cc=linux-btrfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.