Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions check/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ bool is_free_space_tree = false;
bool init_extent_tree = false;
bool check_data_csum = false;
static bool found_free_ino_cache = false;
static bool found_unknown_key = false;
struct cache_tree *roots_info_cache = NULL;

enum btrfs_check_mode {
Expand Down Expand Up @@ -1895,6 +1896,10 @@ static int process_one_leaf(struct btrfs_root *root, struct extent_buffer *eb,
ret = process_xattr_item(eb, i, &key, active_node);
break;
default:
error("Unknown key (%llu %u %llu) found in leaf %llu",
key.objectid, key.type, key.offset,
eb->start);
found_unknown_key = true;
break;
};
}
Expand Down Expand Up @@ -2346,6 +2351,42 @@ static int create_inode_item(struct btrfs_root *root,
return 0;
}

static int create_inode_ref(struct btrfs_root *root,
struct inode_record *i_rec,
struct inode_backref *backref)
{
struct btrfs_trans_handle *trans;
int ret;

trans = btrfs_start_transaction(root, 1);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
errno = -ret;
error_msg(ERROR_MSG_START_TRANS, "%m");
return ret;
}

ret = btrfs_insert_inode_ref(trans, root, backref->name, backref->namelen,
i_rec->ino, backref->dir, backref->index);
if (ret < 0) {
btrfs_commit_transaction(trans, root);
return ret;
}
ret = btrfs_commit_transaction(trans, root);
if (ret < 0) {
ret = PTR_ERR(trans);
errno = -ret;
error_msg(ERROR_MSG_COMMIT_TRANS, "%m");
return ret;
}
backref->found_inode_ref = 1;
backref->errors &= ~REF_ERR_NO_INODE_REF;
printf("Added INODE_REF for root %lld ino %llu parent %llu index %llu name %.*s\n",
btrfs_root_id(root), i_rec->ino, backref->dir, backref->index,
backref->namelen, backref->name);
return 0;
}

static int repair_inode_backrefs(struct btrfs_root *root,
struct inode_record *rec,
struct cache_tree *inode_cache,
Expand All @@ -2370,6 +2411,21 @@ static int repair_inode_backrefs(struct btrfs_root *root,
if (rec->ino == root_dirid && backref->index == 0)
continue;

/*
* Have DIR_INDEX, DIR_ITEM and INODE_ITEM, and even nlinks
* matches with only missing INODE_REF.
*/
if (!backref->found_inode_ref && backref->found_dir_item &&
backref->found_dir_index && rec->found_inode_item &&
rec->found_link == rec->nlink) {
ret = create_inode_ref(root, rec, backref);
if (ret)
break;
repaired++;
list_del(&backref->list);
free(backref);
continue;
}
if (delete &&
((backref->found_dir_index && !backref->found_inode_ref) ||
(backref->found_dir_index && backref->found_inode_ref &&
Expand Down Expand Up @@ -4027,6 +4083,8 @@ static int check_fs_roots(struct cache_tree *root_cache)
free_extent_cache_tree(&wc.shared);
if (!cache_tree_empty(&wc.shared))
fprintf(stderr, "warning line %d\n", __LINE__);
if (!err && found_unknown_key)
err = 1;

return err;
}
Expand Down
16 changes: 14 additions & 2 deletions check/mode-lowmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,17 @@ static int repair_ternary_lowmem(struct btrfs_root *root, u64 dir_ino, u64 ino,
int stage = 0;
int ret = 0;

/*
* We miss an INODE_REF, and we're checking DIR_ITEM and hasn't yet
* find the DIR_INDEX, thus there is no reliable index.
* Try to locate one, this can be slow as we need to locate the DIR_INDEX
* item from the directory.
*/
if (index == (u64)-1 && (err & INODE_REF_MISSING)) {
ret = find_dir_index(root, dir_ino, ino, &index, name, name_len, filetype);
if (ret < 0)
err |= DIR_INDEX_MISSING;
}
/*
* stage shall be one of following valild values:
* 0: Fine, nothing to do.
Expand Down Expand Up @@ -2808,8 +2819,9 @@ static int check_inode_item(struct btrfs_root *root, struct btrfs_path *path)
case BTRFS_XATTR_ITEM_KEY:
break;
default:
error("ITEM[%llu %u %llu] UNKNOWN TYPE",
key.objectid, key.type, key.offset);
error("ITEM[%llu %u %llu] UNKNOWN TYPE in leaf %llu",
key.objectid, key.type, key.offset, node->start);
err |= UNKNOWN_KEY;
}
}

Expand Down
1 change: 1 addition & 0 deletions check/mode-lowmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#define INVALID_GENERATION (1U << 26) /* Generation is too new */
#define SUPER_BYTES_USED_ERROR (1U << 27) /* Super bytes_used is invalid */
#define DUP_FILENAME_ERROR (1U << 28) /* DIR_ITEM contains duplicate names */
#define UNKNOWN_KEY (1U << 29) /* Found unknown key type in fs trees */

/*
* Error bit for low memory mode check.
Expand Down
14 changes: 14 additions & 0 deletions tests/fsck-tests/069-unknown-fs-tree-key/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash
#
# Verify that check can report unknown key types in subvolume trees

source "$TEST_TOP/common" || exit

check_prereq btrfs

check_image() {
run_mustfail "unknown keys in subvolume trees not reported as error" \
"$TOP/btrfs" check "$1"
}

check_all_images
Binary file not shown.
Empty file.
Binary file not shown.