btrfs-progs: check/lowmem: Check and repair root generation
Since kernel is going to reject any root item which is newer than super block generation, we need to provide a way to fix such problem in btrfs-check. This patch addes the ability to report and repair root generation in lowmem mode. This is done by cowing the root node, so we will update the root generation along with the root node generation at commit transaction time. Reviewed-by: Nikolay Borisov <nborisov@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
f972ef650b
commit
ebf29e39c3
36
check/main.c
36
check/main.c
|
@ -9024,42 +9024,6 @@ again:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int recow_extent_buffer(struct btrfs_root *root, struct extent_buffer *eb)
|
||||
{
|
||||
struct btrfs_path path;
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_key key;
|
||||
int ret;
|
||||
|
||||
printf("Recowing metadata block %llu\n", eb->start);
|
||||
key.objectid = btrfs_header_owner(eb);
|
||||
key.type = BTRFS_ROOT_ITEM_KEY;
|
||||
key.offset = (u64)-1;
|
||||
|
||||
root = btrfs_read_fs_root(root->fs_info, &key);
|
||||
if (IS_ERR(root)) {
|
||||
fprintf(stderr, "Couldn't find owner root %llu\n",
|
||||
key.objectid);
|
||||
return PTR_ERR(root);
|
||||
}
|
||||
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
if (IS_ERR(trans))
|
||||
return PTR_ERR(trans);
|
||||
|
||||
btrfs_init_path(&path);
|
||||
path.lowest_level = btrfs_header_level(eb);
|
||||
if (path.lowest_level)
|
||||
btrfs_node_key_to_cpu(eb, &key, 0);
|
||||
else
|
||||
btrfs_item_key_to_cpu(eb, &key, 0);
|
||||
|
||||
ret = btrfs_search_slot(trans, root, &key, &path, 0, 1);
|
||||
btrfs_commit_transaction(trans, root);
|
||||
btrfs_release_path(&path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int delete_bad_item(struct btrfs_root *root, struct bad_item *bad)
|
||||
{
|
||||
struct btrfs_path path;
|
||||
|
|
|
@ -924,3 +924,39 @@ int check_repair_free_space_inode(struct btrfs_fs_info *fs_info,
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int recow_extent_buffer(struct btrfs_root *root, struct extent_buffer *eb)
|
||||
{
|
||||
struct btrfs_path path;
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_key key;
|
||||
int ret;
|
||||
|
||||
printf("Recowing metadata block %llu\n", eb->start);
|
||||
key.objectid = btrfs_header_owner(eb);
|
||||
key.type = BTRFS_ROOT_ITEM_KEY;
|
||||
key.offset = (u64)-1;
|
||||
|
||||
root = btrfs_read_fs_root(root->fs_info, &key);
|
||||
if (IS_ERR(root)) {
|
||||
fprintf(stderr, "Couldn't find owner root %llu\n",
|
||||
key.objectid);
|
||||
return PTR_ERR(root);
|
||||
}
|
||||
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
if (IS_ERR(trans))
|
||||
return PTR_ERR(trans);
|
||||
|
||||
btrfs_init_path(&path);
|
||||
path.lowest_level = btrfs_header_level(eb);
|
||||
if (path.lowest_level)
|
||||
btrfs_node_key_to_cpu(eb, &key, 0);
|
||||
else
|
||||
btrfs_item_key_to_cpu(eb, &key, 0);
|
||||
|
||||
ret = btrfs_search_slot(trans, root, &key, &path, 0, 1);
|
||||
btrfs_commit_transaction(trans, root);
|
||||
btrfs_release_path(&path);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -155,4 +155,5 @@ static inline bool is_valid_imode(u32 imode)
|
|||
return true;
|
||||
}
|
||||
|
||||
int recow_extent_buffer(struct btrfs_root *root, struct extent_buffer *eb);
|
||||
#endif
|
||||
|
|
|
@ -4957,6 +4957,7 @@ static int check_btrfs_root(struct btrfs_root *root, int check_all)
|
|||
struct btrfs_path path;
|
||||
struct node_refs nrefs;
|
||||
struct btrfs_root_item *root_item = &root->root_item;
|
||||
u64 super_generation = btrfs_super_generation(root->fs_info->super_copy);
|
||||
int ret;
|
||||
int level;
|
||||
int err = 0;
|
||||
|
@ -4978,6 +4979,22 @@ static int check_btrfs_root(struct btrfs_root *root, int check_all)
|
|||
level = btrfs_header_level(root->node);
|
||||
btrfs_init_path(&path);
|
||||
|
||||
if (btrfs_root_generation(root_item) > super_generation + 1) {
|
||||
error(
|
||||
"invalid root generation for root %llu, have %llu expect (0, %llu)",
|
||||
root->root_key.objectid, btrfs_root_generation(root_item),
|
||||
super_generation + 1);
|
||||
err |= INVALID_GENERATION;
|
||||
if (repair) {
|
||||
root->node->flags |= EXTENT_BAD_TRANSID;
|
||||
ret = recow_extent_buffer(root, root->node);
|
||||
if (!ret) {
|
||||
printf("Reset generation for root %llu\n",
|
||||
root->root_key.objectid);
|
||||
err &= ~INVALID_GENERATION;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (btrfs_root_refs(root_item) > 0 ||
|
||||
btrfs_disk_key_objectid(&root_item->drop_progress) == 0) {
|
||||
path.nodes[level] = root->node;
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#define INODE_FLAGS_ERROR (1<<23) /* Invalid inode flags */
|
||||
#define DIR_ITEM_HASH_MISMATCH (1<<24) /* Dir item hash mismatch */
|
||||
#define INODE_MODE_ERROR (1<<25) /* Bad inode mode */
|
||||
#define INVALID_GENERATION (1<<26) /* Generation is too new */
|
||||
|
||||
/*
|
||||
* Error bit for low memory mode check.
|
||||
|
|
Loading…
Reference in New Issue