From patchwork Thu Feb 8 03:27:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Su Yue X-Patchwork-Id: 10206561 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 0A27F60247 for ; Thu, 8 Feb 2018 03:23:20 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EF21C2916C for ; Thu, 8 Feb 2018 03:23:19 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E40752919B; Thu, 8 Feb 2018 03:23:19 +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 60B622916C for ; Thu, 8 Feb 2018 03:23:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752189AbeBHDXR (ORCPT ); Wed, 7 Feb 2018 22:23:17 -0500 Received: from mail.cn.fujitsu.com ([183.91.158.132]:43146 "EHLO heian.cn.fujitsu.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752111AbeBHDXN (ORCPT ); Wed, 7 Feb 2018 22:23:13 -0500 X-IronPort-AV: E=Sophos;i="5.43,368,1503331200"; d="scan'208";a="36914169" Received: from bogon (HELO cn.fujitsu.com) ([10.167.33.5]) by heian.cn.fujitsu.com with ESMTP; 08 Feb 2018 11:23:08 +0800 Received: from G08CNEXCHPEKD03.g08.fujitsu.local (unknown [10.167.33.85]) by cn.fujitsu.com (Postfix) with ESMTP id A2BDC48AE761 for ; Thu, 8 Feb 2018 11:23:04 +0800 (CST) Received: from archlinux.g08.fujitsu.local (10.167.226.31) by G08CNEXCHPEKD03.g08.fujitsu.local (10.167.33.89) with Microsoft SMTP Server (TLS) id 14.3.361.1; Thu, 8 Feb 2018 11:23:03 +0800 From: Su Yue To: CC: Subject: [PATCH v4 06/18] btrfs-progs: lowmem check: introduce try_force_cow_in_new_chunk() Date: Thu, 8 Feb 2018 11:27:25 +0800 Message-ID: <20180208032737.31561-7-suy.fnst@cn.fujitsu.com> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180208032737.31561-1-suy.fnst@cn.fujitsu.com> References: <20180208032737.31561-1-suy.fnst@cn.fujitsu.com> MIME-Version: 1.0 X-Originating-IP: [10.167.226.31] X-yoursite-MailScanner-ID: A2BDC48AE761.AC38D X-yoursite-MailScanner: Found to be clean X-yoursite-MailScanner-From: suy.fnst@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 Introduce create_chunk_and_block_block_group() to allocate new chunk and corresponding block group. The new function force_cow_in_new_chunk() first allocates new chunk and records its start. Then it modifies all metadata block groups cached and full. Finally it marks the new block group uncached and unfree. In the next CoW, extents states will be updated automatically by cache_block_group(). New function try_to_force_cow_in_new_chunk() will try to mark block groups full, allocate a new chunk and records the start. If the last allocated chunk is almost full, a new chunk will be allocated. Suggested-by: Qu Wenruo Signed-off-by: Su Yue --- check/mode-lowmem.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/check/mode-lowmem.c b/check/mode-lowmem.c index a200c28a9cf7..3649d570e11c 100644 --- a/check/mode-lowmem.c +++ b/check/mode-lowmem.c @@ -326,6 +326,171 @@ static int clear_block_groups_full(struct btrfs_fs_info *fs_info, u64 flags) return modify_block_groups_cache(fs_info, flags, 0); } +static int create_chunk_and_block_group(struct btrfs_fs_info *fs_info, + u64 flags, u64 *start, u64 *nbytes) +{ + struct btrfs_trans_handle *trans; + struct btrfs_root *root = fs_info->extent_root; + int ret; + + if ((flags & BTRFS_BLOCK_GROUP_TYPE_MASK) == 0) + return -EINVAL; + + trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + error("error starting transaction %s", strerror(-ret)); + return ret; + } + ret = btrfs_alloc_chunk(trans, fs_info, start, nbytes, flags); + if (ret) { + error("fail to allocate new chunk %s", strerror(-ret)); + goto out; + } + ret = btrfs_make_block_group(trans, fs_info, 0, flags, *start, + *nbytes); + if (ret) { + error("fail to make block group for chunk %llu %llu %s", + *start, *nbytes, strerror(-ret)); + goto out; + } +out: + btrfs_commit_transaction(trans, root); + return ret; +} + +static int force_cow_in_new_chunk(struct btrfs_fs_info *fs_info, + u64 *start_ret) +{ + struct btrfs_block_group_cache *bg; + u64 start; + u64 nbytes; + u64 alloc_profile; + u64 flags; + int ret; + + alloc_profile = (fs_info->avail_metadata_alloc_bits & + fs_info->metadata_alloc_profile); + flags = BTRFS_BLOCK_GROUP_METADATA | alloc_profile; + if (btrfs_fs_incompat(fs_info, MIXED_GROUPS)) + flags |= BTRFS_BLOCK_GROUP_DATA; + + ret = create_chunk_and_block_group(fs_info, flags, &start, &nbytes); + if (ret) + goto err; + printf("Created new chunk [%llu %llu]\n", start, nbytes); + + flags = BTRFS_BLOCK_GROUP_METADATA; + /* Mark all metadata block groups cached and full in free space*/ + ret = mark_block_groups_full(fs_info, flags); + if (ret) + goto clear_bgs_full; + + bg = btrfs_lookup_block_group(fs_info, start); + if (!bg) { + ret = -ENOENT; + error("fail to look up block group %llu %llu", start, nbytes); + goto clear_bgs_full; + } + + /* Clear block group cache just allocated */ + ret = modify_block_group_cache(fs_info, bg, 0); + if (ret) + goto clear_bgs_full; + if (start_ret) + *start_ret = start; + return 0; + +clear_bgs_full: + clear_block_groups_full(fs_info, flags); +err: + return ret; +} + +/* + * Returns 0 means not almost full. + * Returns >0 means almost full. + * Returns <0 means fatal error. + */ +static int is_chunk_almost_full(struct btrfs_fs_info *fs_info, u64 start) +{ + struct btrfs_path path; + struct btrfs_key key; + struct btrfs_root *root = fs_info->extent_root; + struct btrfs_block_group_item *bi; + struct btrfs_block_group_item bg_item; + struct extent_buffer *eb; + u64 used; + u64 total; + u64 min_free; + int ret; + int slot; + + key.objectid = start; + key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; + key.offset = (u64)-1; + + btrfs_init_path(&path); + ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); + if (!ret) + ret = -EIO; + if (ret < 0) + goto out; + ret = btrfs_previous_item(root, &path, start, + BTRFS_BLOCK_GROUP_ITEM_KEY); + if (ret) { + error("failed to find block group %llu", start); + ret = -ENOENT; + goto out; + } + + eb = path.nodes[0]; + slot = path.slots[0]; + btrfs_item_key_to_cpu(eb, &key, slot); + if (key.objectid != start) { + ret = -ENOENT; + goto out; + } + + total = key.offset; + bi = btrfs_item_ptr(eb, slot, struct btrfs_block_group_item); + read_extent_buffer(eb, &bg_item, (unsigned long)bi, sizeof(bg_item)); + used = btrfs_block_group_used(&bg_item); + + /* + * if the free space in the chunk is less than %10 of total, + * or not not enough for CoW once, we think the chunk is almost full. + */ + min_free = max_t(u64, (BTRFS_MAX_LEVEL + 1) * fs_info->nodesize, + div_factor(total, 1)); + + if ((total - used) > min_free) + ret = 0; + else + ret = 1; +out: + btrfs_release_path(&path); + return ret; +} + +/* + * Returns <0 for error. + * Returns 0 for success. + */ +static int try_to_force_cow_in_new_chunk(struct btrfs_fs_info *fs_info, + u64 old_start, u64 *new_start) +{ + int ret; + + if (old_start) { + ret = is_chunk_almost_full(fs_info, old_start); + if (ret <= 0) + return ret; + } + ret = force_cow_in_new_chunk(fs_info, new_start); + return ret; +} + /* * This function only handles BACKREF_MISSING, * If corresponding extent item exists, increase the ref, else insert an extent