From patchwork Fri Apr 6 06:21:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 10325683 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 5CD6260208 for ; Fri, 6 Apr 2018 06:21:48 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 353732945C for ; Fri, 6 Apr 2018 06:21:48 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 13D382948B; Fri, 6 Apr 2018 06:21:48 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 555E52945C for ; Fri, 6 Apr 2018 06:21:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751618AbeDFGVU (ORCPT ); Fri, 6 Apr 2018 02:21:20 -0400 Received: from prv3-mh.provo.novell.com ([137.65.250.26]:49969 "EHLO prv3-mh.provo.novell.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751482AbeDFGVU (ORCPT ); Fri, 6 Apr 2018 02:21:20 -0400 Received: from adam-pc.lan (prv-ext-foundry1int.gns.novell.com [137.65.251.240]) by prv3-mh.provo.novell.com with ESMTP (NOT encrypted); Fri, 06 Apr 2018 00:21:12 -0600 From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH v2 1/1] btrfs-progs: inspect-dump-tree: Allow '-b|--block' to be specified multiple times Date: Fri, 6 Apr 2018 14:21:06 +0800 Message-Id: <20180406062106.9610-1-wqu@suse.com> X-Mailer: git-send-email 2.17.0 Reply-To: <20180406061202.6529-1-wqu@suse.com> Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Reuse extent-cache facility to record multiple bytenr so '-b|--block' can be specified multiple times. Despite that, add a sector size alignment check before we try to print a tree block. (Please note that, nodesize alignment check is not suitable here as meta chunk start bytenr could be unaligned to nodesize) Signed-off-by: Qu Wenruo --- changelog: v2: Fix memory leak detected by asan. Fix NULL pointer derefenrece detected by asan. --- Documentation/btrfs-inspect-internal.asciidoc | 2 +- cmds-inspect-dump-tree.c | 109 +++++++++++++++--- 2 files changed, 91 insertions(+), 20 deletions(-) diff --git a/Documentation/btrfs-inspect-internal.asciidoc b/Documentation/btrfs-inspect-internal.asciidoc index e2db64660b9a..ba8529f57660 100644 --- a/Documentation/btrfs-inspect-internal.asciidoc +++ b/Documentation/btrfs-inspect-internal.asciidoc @@ -86,7 +86,7 @@ the respective tree root block offset -u|--uuid:::: print only the uuid tree information, empty output if the tree does not exist -b :::: -print info of the specified block only +print info of the specified block only, can be specified multiple times. --follow:::: use with '-b', print all children tree blocks of '' -t :::: diff --git a/cmds-inspect-dump-tree.c b/cmds-inspect-dump-tree.c index b0cd49b32664..7defb7164a49 100644 --- a/cmds-inspect-dump-tree.c +++ b/cmds-inspect-dump-tree.c @@ -198,11 +198,92 @@ const char * const cmd_inspect_dump_tree_usage[] = { "-R|--backups same as --roots plus print backup root info", "-u|--uuid print only the uuid tree", "-b|--block print info from the specified block only", + " can be specified multile times", "-t|--tree print only tree with the given id (string or number)", "--follow use with -b, to show all children tree blocks of ", NULL }; +/* + * Helper function to record all tree block bytenr so we don't need to put + * all code into deep indent. + * + * Return >0 if we hit a duplicated bytenr (already recorded) + * Return 0 if nothing went wrong + * Return <0 if error happens (ENOMEM) + * + * For != 0 return value, all warning/error will be outputted by this function. + */ +static int dump_add_tree_block(struct cache_tree *tree, u64 bytenr) +{ + int ret; + + /* + * We don't really care about the size and we don't have + * nodesize before we open the fs, so just use 1 as size here. + */ + ret = add_cache_extent(tree, bytenr, 1); + if (ret == -EEXIST) { + warning("tree block bytenr %llu is duplicated", bytenr); + return 1; + } + if (ret < 0) { + error("failed to record tree block bytenr %llu: %d(%s)", + bytenr, ret, strerror(-ret)); + return ret; + } + return ret; +} + +/* + * Print all tree blocks recorded. + * All tree block bytenr record will also be freed in this function. + * + * Return 0 if nothing wrong happened for *each* tree blocks + * Return <0 if anything wrong happened, and return value will be the last + * error. + */ +static int dump_print_tree_blocks(struct btrfs_fs_info *fs_info, + struct cache_tree *tree, bool follow) +{ + struct cache_extent *ce; + struct extent_buffer *eb; + u64 bytenr; + int ret = 0; + + ce = first_cache_extent(tree); + while (ce) { + bytenr = ce->start; + + /* + * Please note that here we can't check it against nodesize, + * as it's possible a chunk is just aligned to sectorsize but + * not aligned to nodesize. + */ + if (!IS_ALIGNED(bytenr, fs_info->sectorsize)) { + error( + "tree block bytenr %llu is not aligned to sectorsize %u", + bytenr, fs_info->sectorsize); + ret = -EINVAL; + goto next; + } + + eb = read_tree_block(fs_info, bytenr, 0); + if (!extent_buffer_uptodate(eb)) { + error("failed to read tree block %llu", bytenr); + ret = -EIO; + goto next; + } + btrfs_print_tree(eb, follow); + free_extent_buffer(eb); +next: + remove_cache_extent(tree, ce); + free(ce); + ce = first_cache_extent(tree); + } + return ret; +} + int cmd_inspect_dump_tree(int argc, char **argv) { struct btrfs_root *root; @@ -213,6 +294,7 @@ int cmd_inspect_dump_tree(int argc, char **argv) struct extent_buffer *leaf; struct btrfs_disk_key disk_key; struct btrfs_key found_key; + struct cache_tree block_root; /* for multiple --block parameters */ char uuidbuf[BTRFS_UUID_UNPARSED_SIZE]; int ret; int slot; @@ -222,11 +304,12 @@ int cmd_inspect_dump_tree(int argc, char **argv) int roots_only = 0; int root_backups = 0; unsigned open_ctree_flags = OPEN_CTREE_FS_PARTIAL; - u64 block_only = 0; + u64 block_bytenr; struct btrfs_root *tree_root_scan; u64 tree_id = 0; bool follow = false; + cache_tree_init(&block_root); while (1) { int c; enum { GETOPT_VAL_FOLLOW = 256 }; @@ -268,7 +351,10 @@ int cmd_inspect_dump_tree(int argc, char **argv) * other than chunk root */ open_ctree_flags |= __OPEN_CTREE_RETURN_CHUNK_ROOT; - block_only = arg_strtou64(optarg); + block_bytenr = arg_strtou64(optarg); + ret = dump_add_tree_block(&block_root, block_bytenr); + if (ret < 0) + goto out; break; case 't': { const char *end = NULL; @@ -316,24 +402,9 @@ int cmd_inspect_dump_tree(int argc, char **argv) goto out; } - if (block_only) { + if (!cache_tree_empty(&block_root)) { root = info->chunk_root; - leaf = read_tree_block(info, block_only, 0); - if (extent_buffer_uptodate(leaf) && - btrfs_header_level(leaf) != 0) { - free_extent_buffer(leaf); - leaf = NULL; - } - - if (!leaf) - leaf = read_tree_block(info, block_only, 0); - if (!extent_buffer_uptodate(leaf)) { - error("failed to read %llu", - (unsigned long long)block_only); - goto close_root; - } - btrfs_print_tree(leaf, follow); - free_extent_buffer(leaf); + ret = dump_print_tree_blocks(info, &block_root, follow); goto close_root; }