Skip to content

Commit

Permalink
btrfs-progs: check: detect deprecated inode cache
Browse files Browse the repository at this point in the history
[BUG]
There are reports about deprecated inode cache causing newer kernels to
rejecting them.

Such inode cache is rarely utilized and already fully deprecated since
v5.11, and newer kernel will reject data extents of inode cache since
v6.11.

But original mode btrfs check won't detect nor report them as error.
Meanwhile lowmem mode can properly detect and report them:

 ERROR: root 5 INODE[18446744073709551604] nlink(1) not equal to inode_refs(0)
 ERROR: invalid imode mode bits: 00
 ERROR: invalid inode generation 18446744073709551604 or transid 1 for ino 18446744073709551605, expect [0, 72)
 ERROR: root 5 INODE[18446744073709551605] is orphan item

Since those inode cache paid no attention to properly maintain all the
numbers, they are easy targets for more recent lowmem mode.

[CAUSE]
For original mode, it has extra hardcoded hacks to avoid nlink checks
for inode cache inode.
Furthermore original mode doesn't check the mode bits nor its
generation.

[FIX]
For original mode, remove the hack for inode cache so that the
deprecated inode cache can be reported as an error.

For both modes, add extra global message to direct the affected users to
use 'btrfs rescue clear-ino-cache' to clear the deprecated cache.

Pull-request: #891
Signed-off-by: Qu Wenruo <wqu@suse.com>
  • Loading branch information
adam900710 authored and kdave committed Sep 12, 2024
1 parent 2c87982 commit 30a1398
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 3 deletions.
13 changes: 10 additions & 3 deletions check/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ bool no_holes = false;
bool is_free_space_tree = false;
bool init_extent_tree = false;
bool check_data_csum = false;
static bool found_free_ino_cache = false;
struct cache_tree *roots_info_cache = NULL;

enum btrfs_check_mode {
Expand Down Expand Up @@ -606,6 +607,8 @@ static void print_inode_error(struct btrfs_root *root, struct inode_record *rec)
fprintf(stderr, "root %llu inode %llu errors %x",
root_objectid, rec->ino, rec->errors);

if (errors & I_ERR_DEPRECATED_FREE_INO)
fprintf(stderr, ", deprecated free inode cache");
if (errors & I_ERR_NO_INODE_ITEM)
fprintf(stderr, ", no inode item");
if (errors & I_ERR_NO_ORPHAN_ITEM)
Expand Down Expand Up @@ -773,9 +776,6 @@ static struct inode_record *get_inode_rec(struct cache_tree *inode_cache,
node->cache.size = 1;
node->data = rec;

if (ino == BTRFS_FREE_INO_OBJECTID)
rec->found_link = 1;

ret = insert_cache_extent(inode_cache, &node->cache);
if (ret) {
free(rec);
Expand Down Expand Up @@ -3224,6 +3224,10 @@ static int check_inode_recs(struct btrfs_root *root,
}
}

if (rec->ino == BTRFS_FREE_INO_OBJECTID) {
rec->errors |= I_ERR_DEPRECATED_FREE_INO;
found_free_ino_cache = true;
}
if (!rec->found_inode_item)
rec->errors |= I_ERR_NO_INODE_ITEM;
if (rec->found_link != rec->nlink)
Expand Down Expand Up @@ -10832,6 +10836,9 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)

ret = do_check_fs_roots(&root_cache);
task_stop(g_task_ctx.info);
if (found_free_ino_cache)
pr_verbose(LOG_DEFAULT,
"deprecated inode cache can be removed by 'btrfs rescue clear-ino-cache'\n");
err |= !!ret;
if (ret) {
error("errors found in fs roots");
Expand Down
10 changes: 10 additions & 0 deletions check/mode-lowmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

static u64 last_allocated_chunk;
static u64 total_used = 0;
static bool found_free_ino_cache = false;

static int calc_extent_flag(struct btrfs_root *root, struct extent_buffer *eb,
u64 *flags_ret)
Expand Down Expand Up @@ -2629,6 +2630,12 @@ static int check_inode_item(struct btrfs_root *root, struct btrfs_path *path)
return err;
}

if (inode_id == BTRFS_FREE_INO_OBJECTID) {
warning("subvolume %lld has deprecated inode cache",
root->root_key.objectid);
found_free_ino_cache = true;
}

is_orphan = has_orphan_item(root, inode_id);
ii = btrfs_item_ptr(node, slot, struct btrfs_inode_item);
isize = btrfs_inode_size(node, ii);
Expand Down Expand Up @@ -5616,6 +5623,9 @@ int check_fs_roots_lowmem(void)

out:
btrfs_release_path(&path);
if (found_free_ino_cache)
pr_verbose(LOG_DEFAULT,
"deprecated inode cache can be removed by 'btrfs rescue clear-ino-cache'\n");
return err;
}

Expand Down
1 change: 1 addition & 0 deletions check/mode-original.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ struct unaligned_extent_rec_t {
#define I_ERR_INVALID_GEN (1U << 20)
#define I_ERR_INVALID_NLINK (1U << 21)
#define I_ERR_INVALID_XATTR (1U << 22)
#define I_ERR_DEPRECATED_FREE_INO (1U << 23)

struct inode_record {
struct list_head backrefs;
Expand Down

0 comments on commit 30a1398

Please sign in to comment.