mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 05:04:09 +08:00
btrfs: tree-checker: Refactor prev_key check for ino into a function
Refactor the check for prev_key->objectid of the following key types into one function, check_prev_ino(): - EXTENT_DATA - INODE_REF - DIR_INDEX - DIR_ITEM - XATTR_ITEM Also add the check of prev_key for INODE_REF. Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
dbb70becde
commit
80d7fd1e09
@ -125,6 +125,74 @@ static u64 file_extent_end(struct extent_buffer *leaf,
|
|||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Customized report for dir_item, the only new important information is
|
||||||
|
* key->objectid, which represents inode number
|
||||||
|
*/
|
||||||
|
__printf(3, 4)
|
||||||
|
__cold
|
||||||
|
static void dir_item_err(const struct extent_buffer *eb, int slot,
|
||||||
|
const char *fmt, ...)
|
||||||
|
{
|
||||||
|
const struct btrfs_fs_info *fs_info = eb->fs_info;
|
||||||
|
struct btrfs_key key;
|
||||||
|
struct va_format vaf;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
btrfs_item_key_to_cpu(eb, &key, slot);
|
||||||
|
va_start(args, fmt);
|
||||||
|
|
||||||
|
vaf.fmt = fmt;
|
||||||
|
vaf.va = &args;
|
||||||
|
|
||||||
|
btrfs_crit(fs_info,
|
||||||
|
"corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
|
||||||
|
btrfs_header_level(eb) == 0 ? "leaf" : "node",
|
||||||
|
btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
|
||||||
|
key.objectid, &vaf);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This functions checks prev_key->objectid, to ensure current key and prev_key
|
||||||
|
* share the same objectid as inode number.
|
||||||
|
*
|
||||||
|
* This is to detect missing INODE_ITEM in subvolume trees.
|
||||||
|
*
|
||||||
|
* Return true if everything is OK or we don't need to check.
|
||||||
|
* Return false if anything is wrong.
|
||||||
|
*/
|
||||||
|
static bool check_prev_ino(struct extent_buffer *leaf,
|
||||||
|
struct btrfs_key *key, int slot,
|
||||||
|
struct btrfs_key *prev_key)
|
||||||
|
{
|
||||||
|
/* No prev key, skip check */
|
||||||
|
if (slot == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Only these key->types needs to be checked */
|
||||||
|
ASSERT(key->type == BTRFS_XATTR_ITEM_KEY ||
|
||||||
|
key->type == BTRFS_INODE_REF_KEY ||
|
||||||
|
key->type == BTRFS_DIR_INDEX_KEY ||
|
||||||
|
key->type == BTRFS_DIR_ITEM_KEY ||
|
||||||
|
key->type == BTRFS_EXTENT_DATA_KEY);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only subvolume trees along with their reloc trees need this check.
|
||||||
|
* Things like log tree doesn't follow this ino requirement.
|
||||||
|
*/
|
||||||
|
if (!is_fstree(btrfs_header_owner(leaf)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (key->objectid == prev_key->objectid)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Error found */
|
||||||
|
dir_item_err(leaf, slot,
|
||||||
|
"invalid previous key objectid, have %llu expect %llu",
|
||||||
|
prev_key->objectid, key->objectid);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
static int check_extent_data_item(struct extent_buffer *leaf,
|
static int check_extent_data_item(struct extent_buffer *leaf,
|
||||||
struct btrfs_key *key, int slot,
|
struct btrfs_key *key, int slot,
|
||||||
struct btrfs_key *prev_key)
|
struct btrfs_key *prev_key)
|
||||||
@ -148,13 +216,8 @@ static int check_extent_data_item(struct extent_buffer *leaf,
|
|||||||
* But if objectids mismatch, it means we have a missing
|
* But if objectids mismatch, it means we have a missing
|
||||||
* INODE_ITEM.
|
* INODE_ITEM.
|
||||||
*/
|
*/
|
||||||
if (slot > 0 && is_fstree(btrfs_header_owner(leaf)) &&
|
if (!check_prev_ino(leaf, key, slot, prev_key))
|
||||||
prev_key->objectid != key->objectid) {
|
|
||||||
file_extent_err(leaf, slot,
|
|
||||||
"invalid previous key objectid, have %llu expect %llu",
|
|
||||||
prev_key->objectid, key->objectid);
|
|
||||||
return -EUCLEAN;
|
return -EUCLEAN;
|
||||||
}
|
|
||||||
|
|
||||||
fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
|
fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
|
||||||
|
|
||||||
@ -285,34 +348,6 @@ static int check_csum_item(struct extent_buffer *leaf, struct btrfs_key *key,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Customized reported for dir_item, only important new info is key->objectid,
|
|
||||||
* which represents inode number
|
|
||||||
*/
|
|
||||||
__printf(3, 4)
|
|
||||||
__cold
|
|
||||||
static void dir_item_err(const struct extent_buffer *eb, int slot,
|
|
||||||
const char *fmt, ...)
|
|
||||||
{
|
|
||||||
const struct btrfs_fs_info *fs_info = eb->fs_info;
|
|
||||||
struct btrfs_key key;
|
|
||||||
struct va_format vaf;
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
btrfs_item_key_to_cpu(eb, &key, slot);
|
|
||||||
va_start(args, fmt);
|
|
||||||
|
|
||||||
vaf.fmt = fmt;
|
|
||||||
vaf.va = &args;
|
|
||||||
|
|
||||||
btrfs_crit(fs_info,
|
|
||||||
"corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
|
|
||||||
btrfs_header_level(eb) == 0 ? "leaf" : "node",
|
|
||||||
btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
|
|
||||||
key.objectid, &vaf);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int check_dir_item(struct extent_buffer *leaf,
|
static int check_dir_item(struct extent_buffer *leaf,
|
||||||
struct btrfs_key *key, struct btrfs_key *prev_key,
|
struct btrfs_key *key, struct btrfs_key *prev_key,
|
||||||
int slot)
|
int slot)
|
||||||
@ -322,14 +357,8 @@ static int check_dir_item(struct extent_buffer *leaf,
|
|||||||
u32 item_size = btrfs_item_size_nr(leaf, slot);
|
u32 item_size = btrfs_item_size_nr(leaf, slot);
|
||||||
u32 cur = 0;
|
u32 cur = 0;
|
||||||
|
|
||||||
/* Same check as in check_extent_data_item() */
|
if (!check_prev_ino(leaf, key, slot, prev_key))
|
||||||
if (slot > 0 && is_fstree(btrfs_header_owner(leaf)) &&
|
|
||||||
prev_key->objectid != key->objectid) {
|
|
||||||
dir_item_err(leaf, slot,
|
|
||||||
"invalid previous key objectid, have %llu expect %llu",
|
|
||||||
prev_key->objectid, key->objectid);
|
|
||||||
return -EUCLEAN;
|
return -EUCLEAN;
|
||||||
}
|
|
||||||
di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
|
di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
|
||||||
while (cur < item_size) {
|
while (cur < item_size) {
|
||||||
u32 name_len;
|
u32 name_len;
|
||||||
@ -1258,6 +1287,8 @@ static int check_inode_ref(struct extent_buffer *leaf,
|
|||||||
unsigned long ptr;
|
unsigned long ptr;
|
||||||
unsigned long end;
|
unsigned long end;
|
||||||
|
|
||||||
|
if (!check_prev_ino(leaf, key, slot, prev_key))
|
||||||
|
return -EUCLEAN;
|
||||||
/* namelen can't be 0, so item_size == sizeof() is also invalid */
|
/* namelen can't be 0, so item_size == sizeof() is also invalid */
|
||||||
if (btrfs_item_size_nr(leaf, slot) <= sizeof(*iref)) {
|
if (btrfs_item_size_nr(leaf, slot) <= sizeof(*iref)) {
|
||||||
inode_ref_err(fs_info, leaf, slot,
|
inode_ref_err(fs_info, leaf, slot,
|
||||||
|
Loading…
Reference in New Issue
Block a user