[2/2] btrfs-progs: debug-tree: Add option to show ondisk block without open_ctree
diff mbox

Message ID 1446712380-7654-2-git-send-email-quwenruo@cn.fujitsu.com
State New
Headers show

Commit Message

Qu Wenruo Nov. 5, 2015, 8:33 a.m. UTC
Add new option '-B' to show tree block without calling open_ctree.
It's very useful to debug non-standard super or heavily damaged case.

As it needs nodesize, also adds a new option '-n' to specify nodesize.

Normal user should avoid calling it on random bytes, as it won't check
the validation of the tree block.

Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
---
 Documentation/btrfs-debug-tree.asciidoc | 12 ++++-
 btrfs-debug-tree.c                      | 81 +++++++++++++++++++++++++++++----
 2 files changed, 82 insertions(+), 11 deletions(-)

Comments

David Sterba Nov. 5, 2015, 12:45 p.m. UTC | #1
On Thu, Nov 05, 2015 at 04:33:00PM +0800, Qu Wenruo wrote:
> Add new option '-B' to show tree block without calling open_ctree.
> It's very useful to debug non-standard super or heavily damaged case.
> 
> As it needs nodesize, also adds a new option '-n' to specify nodesize.
> 
> Normal user should avoid calling it on random bytes, as it won't check
> the validation of the tree block.
> 
> Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>

I'm going to postpone this patch for next development cycle. It's
likely that we'll add more options so I'd like to not make it a mess
(similar to what btrfs-corrupt-block options are).
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch
diff mbox

diff --git a/Documentation/btrfs-debug-tree.asciidoc b/Documentation/btrfs-debug-tree.asciidoc
index 23fc115..a5528cb 100644
--- a/Documentation/btrfs-debug-tree.asciidoc
+++ b/Documentation/btrfs-debug-tree.asciidoc
@@ -25,8 +25,16 @@  Print detailed extents info.
 Print info of btrfs device and root tree dirs only.
 -r::
 Print info of roots only.
--b <block_num>::
-Print info of the specified block only.
+-b <bytenr>::
+Print info of the specified block at logical bytenr.
+-B <bytenr>::
+Print info of the specified block at on-disk bytenr.
+Need to use with '-n <nodesize>' option.
++
+Use with caution, as it won't do normal tree block check.
+
+-n <nodesize>::
+Specify the nodesize for '-B <bytenr>' option.
 
 EXIT STATUS
 -----------
diff --git a/btrfs-debug-tree.c b/btrfs-debug-tree.c
index 8adc39f..52e3de3 100644
--- a/btrfs-debug-tree.c
+++ b/btrfs-debug-tree.c
@@ -21,6 +21,8 @@ 
 #include <unistd.h>
 #include <uuid/uuid.h>
 #include <getopt.h>
+#include <fcntl.h>
+#include <sys/stat.h>
 
 #include "kerncompat.h"
 #include "radix-tree.h"
@@ -41,8 +43,11 @@  static int print_usage(int ret)
 	fprintf(stderr, "\t-r : print info of roots only\n");
 	fprintf(stderr, "\t-R : print info of roots and root backups\n");
 	fprintf(stderr, "\t-u : print info of uuid tree only\n");
-	fprintf(stderr, "\t-b block_num : print info of the specified block"
-                    " only\n");
+	fprintf(stderr, "\t-b bytenr: print info of the specified block"
+                    " at logical bytenr only\n");
+	fprintf(stderr, "\t-B bytenr: print info of the specified block"
+                    " at disk bytenr only, need -n option(use with caution)\n");
+	fprintf(stderr, "\t-n nodesize: specify the nodesize to use with -B\n");
 	fprintf(stderr,
 		"\t-t tree_id : print only the tree with the given id\n");
 	fprintf(stderr, "%s\n", PACKAGE_STRING);
@@ -122,6 +127,41 @@  static void print_old_roots(struct btrfs_super_block *super)
 	}
 }
 
+static int print_ondisk_leaf(const char *device, u64 ondisk_bytenr,
+			     u32 nodesize)
+{
+	struct extent_buffer *buf = NULL;
+	int fd;
+	int ret;
+
+	buf = malloc(sizeof(*buf) + nodesize);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	memset(buf, 0, sizeof(buf) + nodesize);
+	buf->start = ondisk_bytenr;
+	buf->len = nodesize;
+	buf->refs = 1;
+	fd = open(device, O_RDONLY);
+	if (fd < 0) {
+		ret = -errno;
+		goto out;
+	}
+
+	ret = pread(fd, buf->data, nodesize, ondisk_bytenr);
+	if (ret < nodesize) {
+		ret = (ret < 0 ? ret : -EIO);
+		goto out;
+	}
+
+	/* We don't check anything, user should be responsible for it */
+	btrfs_print_leaf(NULL, buf);
+out:
+	free(buf);
+	return ret;
+}
+
 int main(int ac, char **av)
 {
 	struct btrfs_root *root;
@@ -140,7 +180,9 @@  int main(int ac, char **av)
 	int uuid_tree_only = 0;
 	int roots_only = 0;
 	int root_backups = 0;
-	u64 block_only = 0;
+	u64 logical_only = 0;
+	u64 ondisk_only = 0;
+	u32 nodesize = 0;
 	struct btrfs_root *tree_root_scan;
 	u64 tree_id = 0;
 
@@ -153,7 +195,7 @@  int main(int ac, char **av)
 			{ NULL, 0, NULL, 0 }
 		};
 
-		c = getopt_long(ac, av, "deb:rRut:", long_options, NULL);
+		c = getopt_long(ac, av, "deb:B:rRut:n:", long_options, NULL);
 		if (c < 0)
 			break;
 		switch(c) {
@@ -174,7 +216,13 @@  int main(int ac, char **av)
 				root_backups = 1;
 				break;
 			case 'b':
-				block_only = arg_strtou64(optarg);
+				logical_only = arg_strtou64(optarg);
+				break;
+			case 'B':
+				ondisk_only = arg_strtou64(optarg);
+				break;
+			case 'n':
+				nodesize = arg_strtou64(optarg);
 				break;
 			case 't':
 				tree_id = arg_strtou64(optarg);
@@ -196,6 +244,21 @@  int main(int ac, char **av)
 		exit(1);
 	}
 
+	/* Ondisk_only means we won't need to go through open_ctree */
+	if (ondisk_only) {
+		if (!nodesize) {
+			fprintf(stderr, "-n <nodesize> must be specified\n");
+			exit(1);
+		}
+		ret = print_ondisk_leaf(av[optind], ondisk_only, nodesize);
+		if (ret < 0) {
+			fprintf(stderr,
+				"failed to print leaf at ondisk bytenr: %llu, %s\n",
+				ondisk_only, strerror(-ret));
+			ret = 1;
+		}
+		exit(ret);
+	}
 	info = open_ctree_fs_info(av[optind], 0, 0, OPEN_CTREE_PARTIAL);
 	if (!info) {
 		fprintf(stderr, "unable to open %s\n", av[optind]);
@@ -208,9 +271,9 @@  int main(int ac, char **av)
 		exit(1);
 	}
 
-	if (block_only) {
+	if (logical_only) {
 		leaf = read_tree_block(root,
-				      block_only,
+				      logical_only,
 				      root->leafsize, 0);
 
 		if (extent_buffer_uptodate(leaf) &&
@@ -221,12 +284,12 @@  int main(int ac, char **av)
 
 		if (!leaf) {
 			leaf = read_tree_block(root,
-					      block_only,
+					      logical_only,
 					      root->nodesize, 0);
 		}
 		if (!extent_buffer_uptodate(leaf)) {
 			fprintf(stderr, "failed to read %llu\n",
-				(unsigned long long)block_only);
+				(unsigned long long)logical_only);
 			goto close_root;
 		}
 		btrfs_print_tree(root, leaf, 0);