From patchwork Thu Jul 7 02:11:59 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 9217717 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 0806A60467 for ; Thu, 7 Jul 2016 02:12:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E082328607 for ; Thu, 7 Jul 2016 02:12:16 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D2C492861C; Thu, 7 Jul 2016 02:12:16 +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=-6.9 required=2.0 tests=BAYES_00,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 47ED228607 for ; Thu, 7 Jul 2016 02:12:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756068AbcGGCMM (ORCPT ); Wed, 6 Jul 2016 22:12:12 -0400 Received: from cn.fujitsu.com ([222.73.24.84]:59404 "EHLO song.cn.fujitsu.com" rhost-flags-OK-FAIL-OK-OK) by vger.kernel.org with ESMTP id S1754702AbcGGCML (ORCPT ); Wed, 6 Jul 2016 22:12:11 -0400 X-IronPort-AV: E=Sophos;i="5.20,367,1444665600"; d="scan'208";a="658374" Received: from unknown (HELO cn.fujitsu.com) ([10.167.250.3]) by song.cn.fujitsu.com with ESMTP; 07 Jul 2016 10:12:03 +0800 Received: from adam-work.localdomain (unknown [10.167.226.34]) by cn.fujitsu.com (Postfix) with ESMTP id B798C4056403 for ; Thu, 7 Jul 2016 10:11:59 +0800 (CST) From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH v1] btrfs: Avoid reading out unnecessary extent tree blocks when mounting Date: Thu, 7 Jul 2016 10:11:59 +0800 Message-Id: <20160707021159.10335-1-quwenruo@cn.fujitsu.com> X-Mailer: git-send-email 2.9.0 MIME-Version: 1.0 X-yoursite-MailScanner-ID: B798C4056403.ACFD0 X-yoursite-MailScanner: Found to be clean X-yoursite-MailScanner-From: quwenruo@cn.fujitsu.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 Btrfs_read_block_groups() function is the most time consuming function if the fs is large and filled with small extents. For a btrfs filled with 100,000,000 16K sized files, mount the fs takes about 10 seconds. While ftrace shows that, btrfs_read_block_groups() takes about 9 seconds, taking up 90% of the mount time. So it's worthy to speedup btrfs_read_block_groups(), to reduce the overall mount time. Btrfs_read_block_groups() calls btrfs_search_slot() to find block group items. However the search key is (, BLOCK_GROUP_KEY, 0). This makes search_slot() always returns previous slot. Under most case, it's OK since the block group item and previous slot are in the same leaf. But for cases where block group item are the first item of a leaf, we must read out next leaf to get block group item. This needs extra IO and makes btrfs_read_block_groups() slower. In fact, before we call btrfs_read_block_groups(), we have already read out all chunks, which are 1:1 mapped with block group items. So we can get the exact block group length for btrfs_search_slot(), to avoid any possible btrfs_next_leaf() to speedup btrfs_read_block_groups(). With this patch, time spent on btrfs_read_block_groups() is reduced to 7.56s, compared to old 8.94s, about 15% improvement. Reported-by: Tsutomu Itoh Signed-off-by: Qu Wenruo --- v2: Update commit message --- fs/btrfs/extent-tree.c | 61 ++++++++++++++++++++------------------------------ fs/btrfs/extent_map.h | 22 ++++++++++++++++++ 2 files changed, 46 insertions(+), 37 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 82b912a..874f5b3 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -9648,39 +9648,20 @@ out: return ret; } -static int find_first_block_group(struct btrfs_root *root, - struct btrfs_path *path, struct btrfs_key *key) +int find_block_group(struct btrfs_root *root, + struct btrfs_path *path, + struct extent_map *chunk_em) { int ret = 0; - struct btrfs_key found_key; - struct extent_buffer *leaf; - int slot; - - ret = btrfs_search_slot(NULL, root, key, path, 0, 0); - if (ret < 0) - goto out; + struct btrfs_key key; - while (1) { - slot = path->slots[0]; - leaf = path->nodes[0]; - if (slot >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret == 0) - continue; - if (ret < 0) - goto out; - break; - } - btrfs_item_key_to_cpu(leaf, &found_key, slot); + key.objectid = chunk_em->start; + key.offset = chunk_em->len; + key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; - if (found_key.objectid >= key->objectid && - found_key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) { - ret = 0; - goto out; - } - path->slots[0]++; - } -out: + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret > 0) + ret = -ENOENT; return ret; } @@ -9899,16 +9880,14 @@ int btrfs_read_block_groups(struct btrfs_root *root) struct btrfs_block_group_cache *cache; struct btrfs_fs_info *info = root->fs_info; struct btrfs_space_info *space_info; - struct btrfs_key key; + struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; + struct extent_map *chunk_em; struct btrfs_key found_key; struct extent_buffer *leaf; int need_clear = 0; u64 cache_gen; root = info->extent_root; - key.objectid = 0; - key.offset = 0; - key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; path = btrfs_alloc_path(); if (!path) return -ENOMEM; @@ -9921,10 +9900,16 @@ int btrfs_read_block_groups(struct btrfs_root *root) if (btrfs_test_opt(root, CLEAR_CACHE)) need_clear = 1; + /* Here we don't lock the map tree, as we are the only reader */ + chunk_em = first_extent_mapping(&map_tree->map_tree); + /* Not really possible */ + if (!chunk_em) { + ret = -ENOENT; + goto error; + } + while (1) { - ret = find_first_block_group(root, path, &key); - if (ret > 0) - break; + ret = find_block_group(root, path, chunk_em); if (ret != 0) goto error; @@ -9958,7 +9943,6 @@ int btrfs_read_block_groups(struct btrfs_root *root) sizeof(cache->item)); cache->flags = btrfs_block_group_flags(&cache->item); - key.objectid = found_key.objectid + found_key.offset; btrfs_release_path(path); /* @@ -10039,6 +10023,9 @@ int btrfs_read_block_groups(struct btrfs_root *root) } spin_unlock(&info->unused_bgs_lock); } + chunk_em = next_extent_mapping(chunk_em); + if (!chunk_em) + break; } list_for_each_entry_rcu(space_info, &root->fs_info->space_info, list) { diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index eb8b8fa..9358e3e 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h @@ -90,4 +90,26 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, u64 gen void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em); struct extent_map *search_extent_mapping(struct extent_map_tree *tree, u64 start, u64 len); + +static inline struct extent_map * +first_extent_mapping(struct extent_map_tree *tree) +{ + struct rb_node *node; + + node = rb_first(&tree->map); + if (!node) + return NULL; + return rb_entry(node, struct extent_map, rb_node); +} + +static inline struct extent_map * +next_extent_mapping(struct extent_map *map) +{ + struct rb_node *node; + + node = rb_next(&map->rb_node); + if (!node) + return NULL; + return rb_entry(node, struct extent_map, rb_node); +} #endif