From patchwork Thu Sep 12 03:11:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 11142079 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C9EF513BD for ; Thu, 12 Sep 2019 03:11:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A87D22084F for ; Thu, 12 Sep 2019 03:11:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729240AbfILDLn (ORCPT ); Wed, 11 Sep 2019 23:11:43 -0400 Received: from mx2.suse.de ([195.135.220.15]:33204 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726157AbfILDLn (ORCPT ); Wed, 11 Sep 2019 23:11:43 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 36C91B00E for ; Thu, 12 Sep 2019 03:11:42 +0000 (UTC) From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH v3 1/6] btrfs-progs: check: Export btrfs_type_to_imode Date: Thu, 12 Sep 2019 11:11:30 +0800 Message-Id: <20190912031135.79696-2-wqu@suse.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190912031135.79696-1-wqu@suse.com> References: <20190912031135.79696-1-wqu@suse.com> MIME-Version: 1.0 Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org This function will be later used by common mode code, so export it. Signed-off-by: Qu Wenruo Reviewed-by: Nikolay Borisov but see one nit below. --- check/main.c | 15 --------------- check/mode-common.h | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/check/main.c b/check/main.c index 2e16b4e6f05b..902279740589 100644 --- a/check/main.c +++ b/check/main.c @@ -2448,21 +2448,6 @@ out: return ret; } -static u32 btrfs_type_to_imode(u8 type) -{ - static u32 imode_by_btrfs_type[] = { - [BTRFS_FT_REG_FILE] = S_IFREG, - [BTRFS_FT_DIR] = S_IFDIR, - [BTRFS_FT_CHRDEV] = S_IFCHR, - [BTRFS_FT_BLKDEV] = S_IFBLK, - [BTRFS_FT_FIFO] = S_IFIFO, - [BTRFS_FT_SOCK] = S_IFSOCK, - [BTRFS_FT_SYMLINK] = S_IFLNK, - }; - - return imode_by_btrfs_type[(type)]; -} - static int repair_inode_no_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, diff --git a/check/mode-common.h b/check/mode-common.h index 161b84a8deb0..6c8d6d7578a6 100644 --- a/check/mode-common.h +++ b/check/mode-common.h @@ -156,4 +156,19 @@ static inline bool is_valid_imode(u32 imode) } int recow_extent_buffer(struct btrfs_root *root, struct extent_buffer *eb); + +static inline u32 btrfs_type_to_imode(u8 type) +{ + static u32 imode_by_btrfs_type[] = { + [BTRFS_FT_REG_FILE] = S_IFREG, + [BTRFS_FT_DIR] = S_IFDIR, + [BTRFS_FT_CHRDEV] = S_IFCHR, + [BTRFS_FT_BLKDEV] = S_IFBLK, + [BTRFS_FT_FIFO] = S_IFIFO, + [BTRFS_FT_SOCK] = S_IFSOCK, + [BTRFS_FT_SYMLINK] = S_IFLNK, + }; + + return imode_by_btrfs_type[(type)]; +} #endif From patchwork Thu Sep 12 03:11:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 11142081 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 658CE14ED for ; Thu, 12 Sep 2019 03:11:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4D1D7206CD for ; Thu, 12 Sep 2019 03:11:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729256AbfILDLp (ORCPT ); Wed, 11 Sep 2019 23:11:45 -0400 Received: from mx2.suse.de ([195.135.220.15]:33224 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726157AbfILDLp (ORCPT ); Wed, 11 Sep 2019 23:11:45 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 65DECB033 for ; Thu, 12 Sep 2019 03:11:43 +0000 (UTC) From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH v3 2/6] btrfs-progs: check/common: Introduce a function to find imode using info from INODE_REF item Date: Thu, 12 Sep 2019 11:11:31 +0800 Message-Id: <20190912031135.79696-3-wqu@suse.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190912031135.79696-1-wqu@suse.com> References: <20190912031135.79696-1-wqu@suse.com> MIME-Version: 1.0 Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org Introduce a function, find_file_type(), to find filetype using info from INODE_REF, including dir_id from key index/name from inode_ref_item. This function will: - Search DIR_INDEX first DIR_INDEX is easier since there is only one item in it. - Validate the DIR_INDEX item If the DIR_INDEX is valid, use the filetype and call it a day. - Search DIR_ITEM then It needs extra iteration since it's possible to have hash collision. - Validate the DIR_ITEM If valid, call it a day. Or return -ENOENT; This would be used as the primary method to determine the imode in later imode repair code. Signed-off-by: Qu Wenruo --- check/mode-common.c | 129 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/check/mode-common.c b/check/mode-common.c index 195b6efaa7aa..9ccde5cdc2e5 100644 --- a/check/mode-common.c +++ b/check/mode-common.c @@ -16,6 +16,7 @@ #include #include "ctree.h" +#include "hash.h" #include "common/internal.h" #include "common/messages.h" #include "transaction.h" @@ -836,6 +837,134 @@ int reset_imode(struct btrfs_trans_handle *trans, struct btrfs_root *root, return ret; } +static int find_file_type_dir_index(struct btrfs_root *root, u64 ino, u64 dirid, + u64 index, const char *name, u32 name_len, + u32 *imode_ret) +{ + struct btrfs_path path; + struct btrfs_key key; + struct btrfs_key location; + struct btrfs_dir_item *di; + char namebuf[BTRFS_NAME_LEN] = {0}; + bool found = false; + u8 filetype; + u32 len; + int ret; + + btrfs_init_path(&path); + key.objectid = dirid; + key.offset = index; + key.type = BTRFS_DIR_INDEX_KEY; + + ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); + if (ret > 0) { + ret = -ENOENT; + goto out; + } + if (ret < 0) + goto out; + di = btrfs_item_ptr(path.nodes[0], path.slots[0], + struct btrfs_dir_item); + btrfs_dir_item_key_to_cpu(path.nodes[0], di, &location); + + /* Various basic check */ + if (location.objectid != ino || location.type != BTRFS_INODE_ITEM_KEY || + location.offset != 0) + goto out; + filetype = btrfs_dir_type(path.nodes[0], di); + if (filetype >= BTRFS_FT_MAX || filetype == BTRFS_FT_UNKNOWN) + goto out; + len = min_t(u32, BTRFS_NAME_LEN, + btrfs_item_size_nr(path.nodes[0], path.slots[0]) - sizeof(*di)); + len = min_t(u32, len, btrfs_dir_name_len(path.nodes[0], di)); + read_extent_buffer(path.nodes[0], namebuf, (unsigned long)(di + 1), len); + if (name_len != len || memcmp(namebuf, name, len)) + goto out; + found = true; + *imode_ret = btrfs_type_to_imode(filetype); +out: + btrfs_release_path(&path); + if (!found && !ret) + ret = -ENOENT; + return ret; +} + +static int find_file_type_dir_item(struct btrfs_root *root, u64 ino, u64 dirid, + const char *name, u32 name_len, + u32 *imode_ret) +{ + struct btrfs_path path; + struct btrfs_key key; + struct btrfs_key location; + struct btrfs_dir_item *di; + char namebuf[BTRFS_NAME_LEN] = {0}; + bool found = false; + unsigned long cur; + unsigned long end; + u8 filetype; + u32 len; + int ret; + + btrfs_init_path(&path); + key.objectid = dirid; + key.offset = btrfs_name_hash(name, name_len); + key.type = BTRFS_DIR_INDEX_KEY; + + ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); + if (ret > 0) { + ret = -ENOENT; + goto out; + } + if (ret < 0) + goto out; + + cur = btrfs_item_ptr_offset(path.nodes[0], path.slots[0]); + end = cur + btrfs_item_size_nr(path.nodes[0], path.slots[0]); + while (cur < end) { + di = (struct btrfs_dir_item *)cur; + cur += btrfs_dir_name_len(path.nodes[0], di) + sizeof(*di); + + btrfs_dir_item_key_to_cpu(path.nodes[0], di, &location); + /* Various basic check */ + if (location.objectid != ino || + location.type != BTRFS_INODE_ITEM_KEY || + location.offset != 0) + continue; + filetype = btrfs_dir_type(path.nodes[0], di); + if (filetype >= BTRFS_FT_MAX || filetype == BTRFS_FT_UNKNOWN) + continue; + len = min_t(u32, BTRFS_NAME_LEN, + btrfs_item_size_nr(path.nodes[0], path.slots[0]) - + sizeof(*di)); + len = min_t(u32, len, btrfs_dir_name_len(path.nodes[0], di)); + read_extent_buffer(path.nodes[0], namebuf, + (unsigned long)(di + 1), len); + if (name_len != len || memcmp(namebuf, name, len)) + continue; + *imode_ret = btrfs_type_to_imode(filetype); + found = true; + goto out; + } +out: + btrfs_release_path(&path); + if (!found && !ret) + ret = -ENOENT; + return ret; +} + +static int find_file_type(struct btrfs_root *root, u64 ino, u64 dirid, + u64 index, const char *name, u32 name_len, + u32 *imode_ret) +{ + int ret; + ret = find_file_type_dir_index(root, ino, dirid, index, name, name_len, + imode_ret); + if (ret == 0) + return ret; + return find_file_type_dir_item(root, ino, dirid, name, name_len, + imode_ret); +} + /* * Reset the inode mode of the inode specified by @path. * From patchwork Thu Sep 12 03:11:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 11142083 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4F00114ED for ; Thu, 12 Sep 2019 03:11:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2CF77206CD for ; Thu, 12 Sep 2019 03:11:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729294AbfILDLr (ORCPT ); Wed, 11 Sep 2019 23:11:47 -0400 Received: from mx2.suse.de ([195.135.220.15]:33242 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1729242AbfILDLr (ORCPT ); Wed, 11 Sep 2019 23:11:47 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 97C2CB00E for ; Thu, 12 Sep 2019 03:11:44 +0000 (UTC) From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH v3 3/6] btrfs-progs: check/common: Make repair_imode_common() to handle inodes in subvolume trees Date: Thu, 12 Sep 2019 11:11:32 +0800 Message-Id: <20190912031135.79696-4-wqu@suse.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190912031135.79696-1-wqu@suse.com> References: <20190912031135.79696-1-wqu@suse.com> MIME-Version: 1.0 Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org [[PROBLEM]] Before this patch, repair_imode_common() can only handle two types of inodes: - Free space cache inodes - ROOT DIR inodes For inodes in subvolume trees, the core complexity is how to determine the correct imode, thus it was not implemented. However there are more reports of incorrect imode in subvolume trees, we need to support such fix. [[ENHANCEMENT]] So this patch adds a new function, detect_imode(), to detect imode for inodes in subvolume trees. The policy here is, try our best to find a valid imode to recovery. If no convicing info can be found, fail out. That function will determine imode by: 1) Search for INODE_REF of the inode If we have INODE_REF, we will then try to find DIR_ITEM/DIR_INDEX. As long as one valid DIR_ITEM or DIR_INDEX can be found, we convert the BTRFS_FT_* to imode, then call it a day. This should be the most accurate way. 2) Search for DIR_INDEX/DIR_ITEM belongs to this inode If above search fails, we falls back to locate the DIR_INDEX/DIR_ITEM just after the INODE_ITEM. Thus this only works for non-empty directory. If any can be found, it's definitely a directory. 3) Search for EXTENT_DATA belongs to this inode If EXTENT_DATA can be found, it's either REG or LNK. Thus this only works for non-empty file or soft link. For this case, we default to REG, as user can inspect the file to determine if it's a file or just a path. 4) Use rdev to detect BLK/CHR If all above fails, but INODE_ITEM has non-zero rdev, then it's either a BLK or CHR file. Then we default to BLK. 5) Fail out if none of above methods succeeded No educated guess to make things worse. [[SHORTCOMING]] The above search is not perfect, there are cases where we can't repair: E.g. orphan empty regular inode. Since it's already orphan, it has no INODE_REF. And it's regular empty file, it has no DIR_INDEX nor EXTENT_DATA nor rdev. Thus we can't recover. Although for this case, it really doesn't matter as it's already orphan and will be deleted anyway. Furthermore, due to the DIR_ITEM/DIR_INDEX/INODE_REF repair code which can happen before imode repair, it's possible that DIR_ITEM search code may not be executed. If there is only DIR_ITEM remaining, repair code will remove the DIR_ITEM completely and move the inode to lost+found, leaving us no info to rebuild imode. If there is DIR_INDEX missing, repair code will re-insert the DIR_INDEX, then imode repair code will go DIR_INDEX directly. But overall, the repair code should handle the invalid imode caused by older kernels without problem. Signed-off-by: Qu Wenruo --- check/mode-common.c | 133 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 120 insertions(+), 13 deletions(-) diff --git a/check/mode-common.c b/check/mode-common.c index 9ccde5cdc2e5..bc566e4aa03e 100644 --- a/check/mode-common.c +++ b/check/mode-common.c @@ -965,6 +965,116 @@ static int find_file_type(struct btrfs_root *root, u64 ino, u64 dirid, imode_ret); } +static int detect_imode(struct btrfs_root *root, struct btrfs_path *path, + u32 *imode_ret) +{ + struct btrfs_key key; + struct btrfs_inode_item iitem; + bool found = false; + u64 ino; + u32 imode; + int ret = 0; + + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + ino = key.objectid; + read_extent_buffer(path->nodes[0], &iitem, + btrfs_item_ptr_offset(path->nodes[0], path->slots[0]), + sizeof(iitem)); + /* root inode */ + if (ino == BTRFS_FIRST_FREE_OBJECTID) { + imode = S_IFDIR; + found = true; + goto out; + } + + while (1) { + struct btrfs_inode_ref *iref; + struct extent_buffer *leaf; + unsigned long cur; + unsigned long end; + char namebuf[BTRFS_NAME_LEN] = {0}; + u64 index; + u32 namelen; + int slot; + + ret = btrfs_next_item(root, path); + if (ret > 0) { + /* falls back to rdev check */ + ret = 0; + goto out; + } + if (ret < 0) + goto out; + leaf = path->nodes[0]; + slot = path->slots[0]; + btrfs_item_key_to_cpu(leaf, &key, slot); + if (key.objectid != ino) + goto out; + + /* + * We ignore some types to make life easier: + * - XATTR + * Both REG and DIR can have xattr, so not useful + */ + switch (key.type) { + case BTRFS_INODE_REF_KEY: + /* The most accurate way to determine filetype */ + cur = btrfs_item_ptr_offset(leaf, slot); + end = cur + btrfs_item_size_nr(leaf, slot); + while (cur < end) { + iref = (struct btrfs_inode_ref *)cur; + namelen = min_t(u32, end - cur - sizeof(&iref), + btrfs_inode_ref_name_len(leaf, iref)); + index = btrfs_inode_ref_index(leaf, iref); + read_extent_buffer(leaf, namebuf, + (unsigned long)(iref + 1), namelen); + ret = find_file_type(root, ino, key.offset, + index, namebuf, namelen, + &imode); + if (ret == 0) { + found = true; + goto out; + } + cur += sizeof(*iref) + namelen; + } + break; + case BTRFS_DIR_ITEM_KEY: + case BTRFS_DIR_INDEX_KEY: + imode = S_IFDIR; + found = true; + goto out; + case BTRFS_EXTENT_DATA_KEY: + /* + * Both REG and LINK could have EXTENT_DATA. + * We just fall back to REG as user can inspect the + * content. + */ + imode = S_IFREG; + found = true; + goto out; + } + } + +out: + /* + * Both CHR and BLK uses rdev, no way to distinguish them, so fall back + * to BLK. But either way it doesn't really matter, as CHR/BLK on btrfs + * should be pretty rare, and no real data will be lost. + */ + if (!found && btrfs_stack_inode_rdev(&iitem) != 0) { + imode = S_IFBLK; + found = true; + } + + if (found) { + ret = 0; + *imode_ret = (imode | 0700); + } else { + ret = -ENOENT; + } + return ret; +} + /* * Reset the inode mode of the inode specified by @path. * @@ -981,22 +1091,19 @@ int repair_imode_common(struct btrfs_root *root, struct btrfs_path *path) u32 imode; int ret; - if (root->root_key.objectid != BTRFS_ROOT_TREE_OBJECTID) { - error( - "repair inode mode outside of root tree is not supported yet"); - return -ENOTTY; - } btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); ASSERT(key.type == BTRFS_INODE_ITEM_KEY); - if (key.objectid != BTRFS_ROOT_TREE_DIR_OBJECTID && - !is_fstree(key.objectid)) { - error("unsupported ino %llu", key.objectid); - return -ENOTTY; + if (root->objectid == BTRFS_ROOT_TREE_OBJECTID) { + /* In root tree we only have two possible imode */ + if (key.objectid == BTRFS_ROOT_TREE_OBJECTID) + imode = S_IFDIR | 0755; + else + imode = S_IFREG | 0600; + } else { + ret = detect_imode(root, path, &imode); + if (ret < 0) + return ret; } - if (key.objectid == BTRFS_ROOT_TREE_DIR_OBJECTID) - imode = 040755; - else - imode = 0100600; trans = btrfs_start_transaction(root, 1); if (IS_ERR(trans)) { From patchwork Thu Sep 12 03:11:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 11142085 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 23C2513BD for ; Thu, 12 Sep 2019 03:11:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 00FD82084F for ; Thu, 12 Sep 2019 03:11:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729275AbfILDLr (ORCPT ); Wed, 11 Sep 2019 23:11:47 -0400 Received: from mx2.suse.de ([195.135.220.15]:33224 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726157AbfILDLr (ORCPT ); Wed, 11 Sep 2019 23:11:47 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id C8FA0B009 for ; Thu, 12 Sep 2019 03:11:45 +0000 (UTC) From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH v3 4/6] btrfs-progs: check/lowmem: Repair bad imode early Date: Thu, 12 Sep 2019 11:11:33 +0800 Message-Id: <20190912031135.79696-5-wqu@suse.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190912031135.79696-1-wqu@suse.com> References: <20190912031135.79696-1-wqu@suse.com> MIME-Version: 1.0 Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org For lowmem mode, if we hit a bad inode mode, normally it is reported when we checking the DIR_INDEX/DIR_ITEM of the parent inode. If we didn't repair at that timing, the error will be recorded even we fixed it later. So this patch will check for INODE_ITEM_MISMATCH error type, and if it's really caused by invalid imode, repair it and clear the error. Signed-off-by: Qu Wenruo --- check/mode-lowmem.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/check/mode-lowmem.c b/check/mode-lowmem.c index 5f7f101daab1..5d0c520217fa 100644 --- a/check/mode-lowmem.c +++ b/check/mode-lowmem.c @@ -1550,6 +1550,35 @@ static int lowmem_delete_corrupted_dir_item(struct btrfs_root *root, return ret; } +static int try_repair_imode(struct btrfs_root *root, u64 ino) +{ + struct btrfs_inode_item *iitem; + struct btrfs_path path; + struct btrfs_key key; + int ret; + + key.objectid = ino; + key.type = BTRFS_INODE_ITEM_KEY; + key.offset = 0; + btrfs_init_path(&path); + + ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); + if (ret > 0) + ret = -ENOENT; + if (ret < 0) + goto out; + iitem = btrfs_item_ptr(path.nodes[0], path.slots[0], + struct btrfs_inode_item); + if (!is_valid_imode(btrfs_inode_mode(path.nodes[0], iitem))) { + ret = repair_imode_common(root, &path); + } else { + ret = -ENOTTY; + } +out: + btrfs_release_path(&path); + return ret; +} + /* * Call repair_inode_item_missing and repair_ternary_lowmem to repair * @@ -1574,6 +1603,16 @@ static int repair_dir_item(struct btrfs_root *root, struct btrfs_key *di_key, err &= ~(INODE_ITEM_MISMATCH | INODE_ITEM_MISSING); } + if (err & INODE_ITEM_MISMATCH) { + /* + * INODE_ITEM mismatch can be caused by bad imode, + * so check if it's a bad imode, then repair if possible. + */ + ret = try_repair_imode(root, ino); + if (!ret) + err &= ~INODE_ITEM_MISMATCH; + } + if (err & ~(INODE_ITEM_MISMATCH | INODE_ITEM_MISSING)) { ret = repair_ternary_lowmem(root, dirid, ino, index, namebuf, name_len, filetype, err); From patchwork Thu Sep 12 03:11:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 11142087 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2172113BD for ; Thu, 12 Sep 2019 03:11:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0940B206CD for ; Thu, 12 Sep 2019 03:11:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729310AbfILDLt (ORCPT ); Wed, 11 Sep 2019 23:11:49 -0400 Received: from mx2.suse.de ([195.135.220.15]:33256 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1729277AbfILDLs (ORCPT ); Wed, 11 Sep 2019 23:11:48 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 05ABAAFA8 for ; Thu, 12 Sep 2019 03:11:47 +0000 (UTC) From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH v3 5/6] btrfs-progs: check/original: Fix inode mode in subvolume trees Date: Thu, 12 Sep 2019 11:11:34 +0800 Message-Id: <20190912031135.79696-6-wqu@suse.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190912031135.79696-1-wqu@suse.com> References: <20190912031135.79696-1-wqu@suse.com> MIME-Version: 1.0 Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org To make original mode to repair imode error in subvolume trees, this patch will do: - Remove the show-stopper checks for root->objectid. Now repair_imode_original() will accept inodes in subvolume trees. - Export detect_imode() for original mode Due to the call requirement, original mode must use an existing trans handler to do the repair, thus we need to re-implement most of the work done in repair_imode_common(). - Make repair_imode_original() to use detect_imode(). - Free the path after reset_imode() reset_imode() keeps the path, as lowmem mode uses path to locate its current check position. But for original mode, the unreleased path can cause later repair to report warning, so we need to manually release the path. - Update rec->imode after imode reset So later repair depending on rec->imode can get correct value. - Move the repair before repair_inode_nlinks() repair_inode_nlinks() needs correct imode to add DIR_INDEX/DIR_ITEM. So moving the repair before repair_inode_nlinks() makes the latter repair happier. Signed-off-by: Qu Wenruo --- check/main.c | 41 ++++++++++++++++++++++++++++++----------- check/mode-common.c | 2 +- check/mode-common.h | 2 ++ 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/check/main.c b/check/main.c index 902279740589..8bdc9c69fa46 100644 --- a/check/main.c +++ b/check/main.c @@ -2756,22 +2756,40 @@ static int repair_imode_original(struct btrfs_trans_handle *trans, struct btrfs_path *path, struct inode_record *rec) { + struct btrfs_key key; int ret; u32 imode; - if (root->root_key.objectid != BTRFS_ROOT_TREE_OBJECTID) - return -ENOTTY; - if (rec->ino != BTRFS_ROOT_TREE_DIR_OBJECTID || !is_fstree(rec->ino)) - return -ENOTTY; + key.objectid = rec->ino; + key.type = BTRFS_INODE_ITEM_KEY; + key.offset = 0; - if (rec->ino == BTRFS_ROOT_TREE_DIR_OBJECTID) - imode = 040755; - else - imode = 0100600; + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret > 0) + ret = -ENOENT; + if (ret < 0) + return ret; + + if (root->objectid == BTRFS_ROOT_TREE_OBJECTID) { + /* In root tree we only have two possible imode */ + if (rec->ino == BTRFS_ROOT_TREE_OBJECTID) + imode = S_IFDIR | 0755; + else + imode = S_IFREG | 0600; + } else { + ret = detect_imode(root, path, &imode); + if (ret < 0) { + btrfs_release_path(path); + return ret; + } + } + btrfs_release_path(path); ret = reset_imode(trans, root, path, rec->ino, imode); + btrfs_release_path(path); if (ret < 0) return ret; rec->errors &= ~I_ERR_INVALID_IMODE; + rec->imode = imode; return ret; } @@ -2795,7 +2813,8 @@ static int try_repair_inode(struct btrfs_root *root, struct inode_record *rec) I_ERR_FILE_NBYTES_WRONG | I_ERR_INLINE_RAM_BYTES_WRONG | I_ERR_MISMATCH_DIR_HASH | - I_ERR_UNALIGNED_EXTENT_REC))) + I_ERR_UNALIGNED_EXTENT_REC | + I_ERR_INVALID_IMODE))) return rec->errors; /* @@ -2812,6 +2831,8 @@ static int try_repair_inode(struct btrfs_root *root, struct inode_record *rec) btrfs_init_path(&path); if (!ret && rec->errors & I_ERR_MISMATCH_DIR_HASH) ret = repair_mismatch_dir_hash(trans, root, rec); + if (!ret && rec->errors & I_ERR_INVALID_IMODE) + ret = repair_imode_original(trans, root, &path, rec); if (rec->errors & I_ERR_NO_INODE_ITEM) ret = repair_inode_no_item(trans, root, &path, rec); if (!ret && rec->errors & I_ERR_FILE_EXTENT_DISCOUNT) @@ -2828,8 +2849,6 @@ static int try_repair_inode(struct btrfs_root *root, struct inode_record *rec) ret = repair_inline_ram_bytes(trans, root, &path, rec); if (!ret && rec->errors & I_ERR_UNALIGNED_EXTENT_REC) ret = repair_unaligned_extent_recs(trans, root, &path, rec); - if (!ret && rec->errors & I_ERR_INVALID_IMODE) - ret = repair_imode_original(trans, root, &path, rec); btrfs_commit_transaction(trans, root); btrfs_release_path(&path); return ret; diff --git a/check/mode-common.c b/check/mode-common.c index bc566e4aa03e..10ad6d228a03 100644 --- a/check/mode-common.c +++ b/check/mode-common.c @@ -965,7 +965,7 @@ static int find_file_type(struct btrfs_root *root, u64 ino, u64 dirid, imode_ret); } -static int detect_imode(struct btrfs_root *root, struct btrfs_path *path, +int detect_imode(struct btrfs_root *root, struct btrfs_path *path, u32 *imode_ret) { struct btrfs_key key; diff --git a/check/mode-common.h b/check/mode-common.h index 6c8d6d7578a6..edf9257edaf0 100644 --- a/check/mode-common.h +++ b/check/mode-common.h @@ -126,6 +126,8 @@ int delete_corrupted_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *di_key, char *namebuf, u32 namelen); +int detect_imode(struct btrfs_root *root, struct btrfs_path *path, + u32 *imode_ret); int reset_imode(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 ino, u32 mode); int repair_imode_common(struct btrfs_root *root, struct btrfs_path *path); From patchwork Thu Sep 12 03:11:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 11142089 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8815714ED for ; Thu, 12 Sep 2019 03:11:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6FDCC206CD for ; Thu, 12 Sep 2019 03:11:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729333AbfILDLu (ORCPT ); Wed, 11 Sep 2019 23:11:50 -0400 Received: from mx2.suse.de ([195.135.220.15]:33224 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1729242AbfILDLu (ORCPT ); Wed, 11 Sep 2019 23:11:50 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 3D0ACAFFE for ; Thu, 12 Sep 2019 03:11:48 +0000 (UTC) From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH v3 6/6] btrfs-progs: tests/fsck: Add new images for inode mode repair functionality Date: Thu, 12 Sep 2019 11:11:35 +0800 Message-Id: <20190912031135.79696-7-wqu@suse.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190912031135.79696-1-wqu@suse.com> References: <20190912031135.79696-1-wqu@suse.com> MIME-Version: 1.0 Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org Add new test image for imode repair in subvolume trees. The new test cases including the following cases: - Regular file with bad imode It still has the valid INODE_REF and parent dir has correct DIR_INDEX and DIR_ITEM. In this case, no matter if the file is empty or not, it should be repaired using the info from DIR_INDEX of parent dir. - Non-empty regular file with bad imode, and without INODE_REF The file should be mostly an orphan, so no INODE_REF for imode lookup. But it has EXTENT_DATA which should be enough for imode repair. The repair also involves moving the orphan to lost+found dir. - Non-empty dir with bad imode, and without INODE_REF Pretty much the same case, but now a directory. The repair also involves moving the orphan to lost+found dir. Also rename the existing test case 039-bad-free-space-cache-inode-mode to 039-bad-inode-mode, since now we can fix all bad imode. Signed-off-by: Qu Wenruo --- .../039-bad-inode-mode/.lowmem_repairable | 0 .../bad_free_space_cache_imode.raw.xz} | Bin .../bad_imodes_in_subvolume_tree.img.xz | Bin 0 -> 2956 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/fsck-tests/039-bad-inode-mode/.lowmem_repairable rename tests/fsck-tests/{039-bad-free-space-cache-inode-mode/test.raw.xz => 039-bad-inode-mode/bad_free_space_cache_imode.raw.xz} (100%) create mode 100644 tests/fsck-tests/039-bad-inode-mode/bad_imodes_in_subvolume_tree.img.xz GIT binary patch literal 2956 zcmV;73v=}SH+ooF000E$*0e?f03iV!0000G&sfah5C02HT>wRyj;C3^v%$$4d1wdA zhA1@4m*CN4=JF(pu<{lZu#3rJ{x`%OunHJR_+hWlU+8THA!o)hf&JdREq$B_jm%57 z$k$@1L{^~@)eO=~d}4!Pg}&?=WZA7?y^i8Ts&#ea0yyltsLU^Gf(TifcWf2aWO^hn zT;ywyIWc#F)mQ1BE%<IyvimyUvJNB2|Mo)Fslt`UpOQyH!=GhdIIJ&nXNptS z5>-zoXN+mR|Kd!b>C`pZDeSL|dDc0q=cne=*q|$_u;Mtdv?NB&jsm4$!H89N@6MB_s-=sZq}74cMD0lH(sU%^^o(ot<{|r ztKcf34B*6NDzb{6fNLhf#qlKT$4j{W?U3x@9tTUgT-SQV!UupoQ0*1oJ%yJ2AJpTq z)t*CBp6+TJ<_{;}@x`nd|M|6rNs7b8o3*)M4V)W!cBsPyse$nadTV-@mRqa*8RJ6T zN;J^~^kAFH)?Yp!@{r0RfVvKLB648Rw>FfV&>>sPR@3sL-8$vOW*Xp*pk6KqU-Xu= z{c;{BM3?BGNh`Zo7f3aGos=%*7AcwH>)0H*&cn?Z)eV9%X3UUy2=&{9w;hyR#n; z^vqkBZJT!$=Si(K zXmuumG*qGca*78hB`%Qr-9e=$wk*5W#FT@FDgT$zyoq`&e5c&Z|myJLIen*rd~ z?U9nHIiX zHr2jRZOlBcw~4T}&bOi^*fRD&d4`;@WoO7WfZ85%*TAh7Sh)BI>CT_J4@qLDUKcAi zI2J_;@x;{-?iKAO1|G|c)&sC#l5|FJYxTQ0l+-iFC5D@A1Ss+Khw)wjEgp-t5)utZPx2rs6;DKf|h;Ye#hdOjHXI zxGp7R2=d_&J`%<#g@`UXKZ%%jf>fXypwGrw85h@0ladmG#P-s7Ei3_9%QecKvFzSc+kW;(Aj5DtBhUzL7I7YzYMI*7d4 zdei!p`B@H-9yX_6wMTYlEZB;yZqU*l_S;nb^f6g(n+x1ba_syY@HSA!S{;ll4T#&6 zIkR17^8szM34JM2{pf0{$dDapIl_fkt@fzGC#Q)({dl7L(m?Tx&ugkV_;Appdrr-40fb{*^&9rrN1IZfjhLzPjf-wW7Z2o#Il6cjwY zS3^##ZhCq;5tpKbpj%H-BfPnozDvE8_U(fP;c@lOY0x4N!rpz^unWR@jz*#w=Pqld z#w)YGT9Q2teu~KV`#mwUnnNWlf!dZ8-?X1sWP_GGzaX!=XH1Q54g}X-)4SAes5F=t zYb|<3M_0O9NM4zVoy>Ssu@|9EtiedrJ*D(#%sVbV0nNO*Opf$5dig?|#laB%X2O2l zD)Y)25AT~8!!-tN55(F5jWxFY4qhVf{vE>op~l;)i21M7{#*Fx)t>cN`6{;7a|_}d zV325VM4fuWc~-mI*cdsVV0{-WOo4AT`W^;t8lpYI3gP(-OWK!Ggokqfaig=mYN-$V z#oLJtita+7wE=Zzr=P@>EBC&5-P0qH_38{tp9*QXMOb9}dNQr&LL^j1l3b|kyL_wL{SckE zbuUQ%1a1XYgkmr{d7xC~=~7qs?1CXN;@fYZ^Sb@1ej&O3y!iiMG3KHG)ie%y=LTr} zShAxfDEoWO$D(Way2no^hku8Pz1pWbZuL+;U>H23;O zPL7o4aJ|KzTvxL1NzwZd=+$Xo;laWSMA%^oj{=QiiKM?8bI?5yetUrl7zxj*2&-y` zJt7RLK}Ra%xm&Dx*esCUbgs2^?_I4?KU8~fk1IIWMYu$@krs~4uE9z)2;2m*6-n>v zv}GC4O-`b51PG|-ihyj=15#l?)S~T4chV>Rxjq}2LL3R9Q+vt1jU<5-NDyd|gtWWB zPWvZ=#`d1IP(ZcMGGP0+oz$w|%XxC{Sqb)?*^*&;8Lh#)ml)@g&Vyq$@PaJZ=Xfi3g^0q7QhAOHZ%-}VEs#Ao{g000001X)^D C1kMfs literal 0 HcmV?d00001 diff --git a/tests/fsck-tests/039-bad-inode-mode/.lowmem_repairable b/tests/fsck-tests/039-bad-inode-mode/.lowmem_repairable new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/fsck-tests/039-bad-free-space-cache-inode-mode/test.raw.xz b/tests/fsck-tests/039-bad-inode-mode/bad_free_space_cache_imode.raw.xz similarity index 100% rename from tests/fsck-tests/039-bad-free-space-cache-inode-mode/test.raw.xz rename to tests/fsck-tests/039-bad-inode-mode/bad_free_space_cache_imode.raw.xz diff --git a/tests/fsck-tests/039-bad-inode-mode/bad_imodes_in_subvolume_tree.img.xz b/tests/fsck-tests/039-bad-inode-mode/bad_imodes_in_subvolume_tree.img.xz new file mode 100644 index 0000000000000000000000000000000000000000..8c51ceb7703de8ab36ca8cdd95117c0e13174a04