From e41ca5897489b1c18af75ff0cc8f5c80260b3281 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Wed, 6 Jun 2018 15:41:49 +0800 Subject: btrfs: Get rid of the confusing btrfs_file_extent_inline_len We used to call btrfs_file_extent_inline_len() to get the uncompressed data size of an inlined extent. However this function is hiding evil, for compressed extent, it has no choice but to directly read out ram_bytes from btrfs_file_extent_item. While for uncompressed extent, it uses item size to calculate the real data size, and ignoring ram_bytes completely. In fact, for corrupted ram_bytes, due to above behavior kernel btrfs_print_leaf() can't even print correct ram_bytes to expose the bug. Since we have the tree-checker to verify all EXTENT_DATA, such mismatch can be detected pretty easily, thus we can trust ram_bytes without the evil btrfs_file_extent_inline_len(). Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/print-tree.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/btrfs/print-tree.c') diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index a4e11cf04671..59efcf2e0de8 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -267,8 +267,8 @@ void btrfs_print_leaf(struct extent_buffer *l) struct btrfs_file_extent_item); if (btrfs_file_extent_type(l, fi) == BTRFS_FILE_EXTENT_INLINE) { - pr_info("\t\tinline extent data size %u\n", - btrfs_file_extent_inline_len(l, i, fi)); + pr_info("\t\tinline extent data size %llu\n", + btrfs_file_extent_ram_bytes(l, fi)); break; } pr_info("\t\textent data disk bytenr %llu nr %llu\n", -- cgit From a79865c680d81220a1355cd13098e75227dc2994 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Thu, 21 Jun 2018 09:45:00 +0300 Subject: btrfs: Remove V0 extent support The v0 compat code was introduced in commit 5d4f98a28c7d ("Btrfs: Mixed back reference (FORWARD ROLLING FORMAT CHANGE)") 9 years ago, which was merged in 2.6.31. This means that the code is there to support filesystems which are _VERY_ old and if you are using btrfs on such an old kernel, you have much bigger problems. This coupled with the fact that no one is likely testing/maintining this code likely means it has bugs lurking. All things considered I think 43 kernel releases later it's high time this remnant of the past got removed. This patch removes all code wrapped in #ifdefs but leaves the BUG_ONs in case we have a v0 with no support intact as a sort of safety-net. Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.c | 6 +- fs/btrfs/ctree.h | 2 - fs/btrfs/extent-tree.c | 209 +------------------------------------------------ fs/btrfs/print-tree.c | 30 +------ fs/btrfs/relocation.c | 151 +---------------------------------- 5 files changed, 4 insertions(+), 394 deletions(-) (limited to 'fs/btrfs/print-tree.c') diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 18f1ca1c5bd9..d436fb4c002e 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -888,11 +888,7 @@ int btrfs_block_can_be_shared(struct btrfs_root *root, btrfs_root_last_snapshot(&root->root_item) || btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))) return 1; -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) && - btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV) - return 1; -#endif + return 0; } diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 41ba770b9db9..9fa958ed065e 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -55,8 +55,6 @@ struct btrfs_ordered_sum; #define BTRFS_OLDEST_GENERATION 0ULL -#define BTRFS_COMPAT_EXTENT_TREE_V0 - /* * the max metadata block size. This limit is somewhat artificial, * but the memmove costs go through the roof for larger blocks. diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index b28fa3d20ef7..6a73d2698807 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -867,17 +867,7 @@ search_again: num_refs = btrfs_extent_refs(leaf, ei); extent_flags = btrfs_extent_flags(leaf, ei); } else { -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - struct btrfs_extent_item_v0 *ei0; - BUG_ON(item_size != sizeof(*ei0)); - ei0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_item_v0); - num_refs = btrfs_extent_refs_v0(leaf, ei0); - /* FIXME: this isn't correct for data */ - extent_flags = BTRFS_BLOCK_FLAG_FULL_BACKREF; -#else BUG(); -#endif } BUG_ON(num_refs == 0); } else { @@ -1036,89 +1026,6 @@ out_free: * tree block info structure. */ -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 -static int convert_extent_item_v0(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_path *path, - u64 owner, u32 extra_size) -{ - struct btrfs_root *root = fs_info->extent_root; - struct btrfs_extent_item *item; - struct btrfs_extent_item_v0 *ei0; - struct btrfs_extent_ref_v0 *ref0; - struct btrfs_tree_block_info *bi; - struct extent_buffer *leaf; - struct btrfs_key key; - struct btrfs_key found_key; - u32 new_size = sizeof(*item); - u64 refs; - int ret; - - leaf = path->nodes[0]; - BUG_ON(btrfs_item_size_nr(leaf, path->slots[0]) != sizeof(*ei0)); - - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - ei0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_item_v0); - refs = btrfs_extent_refs_v0(leaf, ei0); - - if (owner == (u64)-1) { - while (1) { - if (path->slots[0] >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - return ret; - BUG_ON(ret > 0); /* Corruption */ - leaf = path->nodes[0]; - } - btrfs_item_key_to_cpu(leaf, &found_key, - path->slots[0]); - BUG_ON(key.objectid != found_key.objectid); - if (found_key.type != BTRFS_EXTENT_REF_V0_KEY) { - path->slots[0]++; - continue; - } - ref0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_ref_v0); - owner = btrfs_ref_objectid_v0(leaf, ref0); - break; - } - } - btrfs_release_path(path); - - if (owner < BTRFS_FIRST_FREE_OBJECTID) - new_size += sizeof(*bi); - - new_size -= sizeof(*ei0); - ret = btrfs_search_slot(trans, root, &key, path, - new_size + extra_size, 1); - if (ret < 0) - return ret; - BUG_ON(ret); /* Corruption */ - - btrfs_extend_item(fs_info, path, new_size); - - leaf = path->nodes[0]; - item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); - btrfs_set_extent_refs(leaf, item, refs); - /* FIXME: get real generation */ - btrfs_set_extent_generation(leaf, item, 0); - if (owner < BTRFS_FIRST_FREE_OBJECTID) { - btrfs_set_extent_flags(leaf, item, - BTRFS_EXTENT_FLAG_TREE_BLOCK | - BTRFS_BLOCK_FLAG_FULL_BACKREF); - bi = (struct btrfs_tree_block_info *)(item + 1); - /* FIXME: get first key of the block */ - memzero_extent_buffer(leaf, (unsigned long)bi, sizeof(*bi)); - btrfs_set_tree_block_level(leaf, bi, (int)owner); - } else { - btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_DATA); - } - btrfs_mark_buffer_dirty(leaf); - return 0; -} -#endif - /* * is_data == BTRFS_REF_TYPE_BLOCK, tree block type is required, * is_data == BTRFS_REF_TYPE_DATA, data type is requried, @@ -1247,17 +1154,6 @@ again: if (parent) { if (!ret) return 0; -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - key.type = BTRFS_EXTENT_REF_V0_KEY; - btrfs_release_path(path); - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret < 0) { - err = ret; - goto fail; - } - if (!ret) - return 0; -#endif goto fail; } @@ -1400,13 +1296,6 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans, ref2 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_shared_data_ref); num_refs = btrfs_shared_data_ref_count(leaf, ref2); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { - struct btrfs_extent_ref_v0 *ref0; - ref0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_ref_v0); - num_refs = btrfs_ref_count_v0(leaf, ref0); -#endif } else { BUG(); } @@ -1422,14 +1311,6 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans, btrfs_set_extent_data_ref_count(leaf, ref1, num_refs); else if (key.type == BTRFS_SHARED_DATA_REF_KEY) btrfs_set_shared_data_ref_count(leaf, ref2, num_refs); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - else { - struct btrfs_extent_ref_v0 *ref0; - ref0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_ref_v0); - btrfs_set_ref_count_v0(leaf, ref0, num_refs); - } -#endif btrfs_mark_buffer_dirty(leaf); } return ret; @@ -1469,13 +1350,6 @@ static noinline u32 extent_data_ref_count(struct btrfs_path *path, ref2 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_shared_data_ref); num_refs = btrfs_shared_data_ref_count(leaf, ref2); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { - struct btrfs_extent_ref_v0 *ref0; - ref0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_ref_v0); - num_refs = btrfs_ref_count_v0(leaf, ref0); -#endif } else { WARN_ON(1); } @@ -1503,15 +1377,6 @@ static noinline int lookup_tree_block_ref(struct btrfs_trans_handle *trans, ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret > 0) ret = -ENOENT; -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (ret == -ENOENT && parent) { - btrfs_release_path(path); - key.type = BTRFS_EXTENT_REF_V0_KEY; - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret > 0) - ret = -ENOENT; - } -#endif return ret; } @@ -1676,22 +1541,6 @@ again: leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - if (!insert) { - err = -ENOENT; - goto out; - } - ret = convert_extent_item_v0(trans, fs_info, path, owner, - extra_size); - if (ret < 0) { - err = ret; - goto out; - } - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - } -#endif BUG_ON(item_size < sizeof(*ei)); ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); @@ -2416,17 +2265,6 @@ again: leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - ret = convert_extent_item_v0(trans, fs_info, path, (u64)-1, 0); - if (ret < 0) { - err = ret; - goto out; - } - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - } -#endif BUG_ON(item_size < sizeof(*ei)); ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); __run_delayed_extent_op(extent_op, leaf, ei); @@ -3238,12 +3076,6 @@ static noinline int check_committed_ref(struct btrfs_root *root, ret = 1; item_size = btrfs_item_size_nr(leaf, path->slots[0]); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - WARN_ON(item_size != sizeof(struct btrfs_extent_item_v0)); - goto out; - } -#endif ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); if (item_size != sizeof(*ei) + @@ -6888,11 +6720,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, break; extent_slot--; } -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - item_size = btrfs_item_size_nr(path->nodes[0], extent_slot); - if (found_extent && item_size < sizeof(*ei)) - found_extent = 0; -#endif + if (!found_extent) { BUG_ON(iref); ret = remove_extent_backref(trans, path, NULL, @@ -6968,41 +6796,6 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, extent_slot); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - BUG_ON(found_extent || extent_slot != path->slots[0]); - ret = convert_extent_item_v0(trans, info, path, owner_objectid, - 0); - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - btrfs_release_path(path); - path->leave_spinning = 1; - - key.objectid = bytenr; - key.type = BTRFS_EXTENT_ITEM_KEY; - key.offset = num_bytes; - - ret = btrfs_search_slot(trans, extent_root, &key, path, - -1, 1); - if (ret) { - btrfs_err(info, - "umm, got %d back from search, was looking for %llu", - ret, bytenr); - btrfs_print_leaf(path->nodes[0]); - } - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - extent_slot = path->slots[0]; - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, extent_slot); - } -#endif BUG_ON(item_size < sizeof(*ei)); ei = btrfs_item_ptr(leaf, extent_slot, struct btrfs_extent_item); diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index 59efcf2e0de8..c0dac9d7ce33 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -52,18 +52,8 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) u64 offset; int ref_index = 0; - if (item_size < sizeof(*ei)) { -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - struct btrfs_extent_item_v0 *ei0; - BUG_ON(item_size != sizeof(*ei0)); - ei0 = btrfs_item_ptr(eb, slot, struct btrfs_extent_item_v0); - pr_info("\t\textent refs %u\n", - btrfs_extent_refs_v0(eb, ei0)); - return; -#else + if (item_size < sizeof(*ei)) BUG(); -#endif - } ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item); flags = btrfs_extent_flags(eb, ei); @@ -133,20 +123,6 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) WARN_ON(ptr > end); } -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 -static void print_extent_ref_v0(struct extent_buffer *eb, int slot) -{ - struct btrfs_extent_ref_v0 *ref0; - - ref0 = btrfs_item_ptr(eb, slot, struct btrfs_extent_ref_v0); - printk("\t\textent back ref root %llu gen %llu owner %llu num_refs %lu\n", - btrfs_ref_root_v0(eb, ref0), - btrfs_ref_generation_v0(eb, ref0), - btrfs_ref_objectid_v0(eb, ref0), - (unsigned long)btrfs_ref_count_v0(eb, ref0)); -} -#endif - static void print_uuid_item(struct extent_buffer *l, unsigned long offset, u32 item_size) { @@ -280,11 +256,7 @@ void btrfs_print_leaf(struct extent_buffer *l) btrfs_file_extent_ram_bytes(l, fi)); break; case BTRFS_EXTENT_REF_V0_KEY: -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - print_extent_ref_v0(l, i); -#else BUG(); -#endif break; case BTRFS_BLOCK_GROUP_ITEM_KEY: bi = btrfs_item_ptr(l, i, diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 44722e939e34..6dfa92e5ceed 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -586,29 +586,6 @@ static struct btrfs_root *read_fs_root(struct btrfs_fs_info *fs_info, return btrfs_get_fs_root(fs_info, &key, false); } -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 -static noinline_for_stack -struct btrfs_root *find_tree_root(struct reloc_control *rc, - struct extent_buffer *leaf, - struct btrfs_extent_ref_v0 *ref0) -{ - struct btrfs_root *root; - u64 root_objectid = btrfs_ref_root_v0(leaf, ref0); - u64 generation = btrfs_ref_generation_v0(leaf, ref0); - - BUG_ON(root_objectid == BTRFS_TREE_RELOC_OBJECTID); - - root = read_fs_root(rc->extent_root->fs_info, root_objectid); - BUG_ON(IS_ERR(root)); - - if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) && - generation != btrfs_root_generation(&root->root_item)) - return NULL; - - return root; -} -#endif - static noinline_for_stack int find_inline_backref(struct extent_buffer *leaf, int slot, unsigned long *ptr, unsigned long *end) @@ -621,12 +598,6 @@ int find_inline_backref(struct extent_buffer *leaf, int slot, btrfs_item_key_to_cpu(leaf, &key, slot); item_size = btrfs_item_size_nr(leaf, slot); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - WARN_ON(item_size != sizeof(struct btrfs_extent_item_v0)); - return 1; - } -#endif ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item); WARN_ON(!(btrfs_extent_flags(leaf, ei) & BTRFS_EXTENT_FLAG_TREE_BLOCK)); @@ -811,29 +782,8 @@ again: goto next; } -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (key.type == BTRFS_SHARED_BLOCK_REF_KEY || - key.type == BTRFS_EXTENT_REF_V0_KEY) { - if (key.type == BTRFS_EXTENT_REF_V0_KEY) { - struct btrfs_extent_ref_v0 *ref0; - ref0 = btrfs_item_ptr(eb, path1->slots[0], - struct btrfs_extent_ref_v0); - if (key.objectid == key.offset) { - root = find_tree_root(rc, eb, ref0); - if (root && !should_ignore_root(root)) - cur->root = root; - else - list_add(&cur->list, &useless); - break; - } - if (is_cowonly_root(btrfs_ref_root_v0(eb, - ref0))) - cur->cowonly = 1; - } -#else ASSERT(key.type != BTRFS_EXTENT_REF_V0_KEY); if (key.type == BTRFS_SHARED_BLOCK_REF_KEY) { -#endif if (key.objectid == key.offset) { /* * only root blocks of reloc trees use @@ -3333,48 +3283,6 @@ int relocate_data_extent(struct inode *inode, struct btrfs_key *extent_key, return 0; } -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 -static int get_ref_objectid_v0(struct reloc_control *rc, - struct btrfs_path *path, - struct btrfs_key *extent_key, - u64 *ref_objectid, int *path_change) -{ - struct btrfs_key key; - struct extent_buffer *leaf; - struct btrfs_extent_ref_v0 *ref0; - int ret; - int slot; - - leaf = path->nodes[0]; - slot = path->slots[0]; - while (1) { - if (slot >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(rc->extent_root, path); - if (ret < 0) - return ret; - BUG_ON(ret > 0); - leaf = path->nodes[0]; - slot = path->slots[0]; - if (path_change) - *path_change = 1; - } - btrfs_item_key_to_cpu(leaf, &key, slot); - if (key.objectid != extent_key->objectid) - return -ENOENT; - - if (key.type != BTRFS_EXTENT_REF_V0_KEY) { - slot++; - continue; - } - ref0 = btrfs_item_ptr(leaf, slot, - struct btrfs_extent_ref_v0); - *ref_objectid = btrfs_ref_objectid_v0(leaf, ref0); - break; - } - return 0; -} -#endif - /* * helper to add a tree block to the list. * the major work is getting the generation and level of the block @@ -3408,22 +3316,7 @@ static int add_tree_block(struct reloc_control *rc, } generation = btrfs_extent_generation(eb, ei); } else { -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - u64 ref_owner; - int ret; - - BUG_ON(item_size != sizeof(struct btrfs_extent_item_v0)); - ret = get_ref_objectid_v0(rc, path, extent_key, - &ref_owner, NULL); - if (ret < 0) - return ret; - BUG_ON(ref_owner >= BTRFS_MAX_LEVEL); - level = (int)ref_owner; - /* FIXME: get real generation */ - generation = 0; -#else BUG(); -#endif } btrfs_release_path(path); @@ -3781,12 +3674,7 @@ int add_data_references(struct reloc_control *rc, eb = path->nodes[0]; ptr = btrfs_item_ptr_offset(eb, path->slots[0]); end = ptr + btrfs_item_size_nr(eb, path->slots[0]); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (ptr + sizeof(struct btrfs_extent_item_v0) == end) - ptr = end; - else -#endif - ptr += sizeof(struct btrfs_extent_item); + ptr += sizeof(struct btrfs_extent_item); while (ptr < end) { iref = (struct btrfs_extent_inline_ref *)ptr; @@ -3832,13 +3720,8 @@ int add_data_references(struct reloc_control *rc, if (key.objectid != extent_key->objectid) break; -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (key.type == BTRFS_SHARED_DATA_REF_KEY || - key.type == BTRFS_EXTENT_REF_V0_KEY) { -#else BUG_ON(key.type == BTRFS_EXTENT_REF_V0_KEY); if (key.type == BTRFS_SHARED_DATA_REF_KEY) { -#endif ret = __add_tree_block(rc, key.offset, blocksize, blocks); } else if (key.type == BTRFS_EXTENT_DATA_REF_KEY) { @@ -4086,39 +3969,7 @@ restart: BUG_ON(ret); } else { -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - u64 ref_owner; - int path_change = 0; - - BUG_ON(item_size != - sizeof(struct btrfs_extent_item_v0)); - ret = get_ref_objectid_v0(rc, path, &key, &ref_owner, - &path_change); - if (ret < 0) { - err = ret; - break; - } - if (ref_owner < BTRFS_FIRST_FREE_OBJECTID) - flags = BTRFS_EXTENT_FLAG_TREE_BLOCK; - else - flags = BTRFS_EXTENT_FLAG_DATA; - - if (path_change) { - btrfs_release_path(path); - - path->search_commit_root = 1; - path->skip_locking = 1; - ret = btrfs_search_slot(NULL, rc->extent_root, - &key, path, 0, 0); - if (ret < 0) { - err = ret; - break; - } - BUG_ON(ret > 0); - } -#else BUG(); -#endif } if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { -- cgit From ba3c2b196bf59ba8574808fe6f8fd88d0fed7510 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Tue, 26 Jun 2018 16:57:36 +0300 Subject: btrfs: Add graceful handling of V0 extents Following the removal of the v0 handling code let's be courteous and print an error message when such extents are handled. In the cases where we have a transaction just abort it, otherwise just call btrfs_handle_fs_error. Both cases result in the FS being re-mounted RO. In case the error handling would be too intrusive, leave the BUG_ON in place, like extent_data_ref_count, other proper handling would catch that earlier. Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 7 +++++++ fs/btrfs/extent-tree.c | 39 +++++++++++++++++++++++++++++++++++---- fs/btrfs/print-tree.c | 9 ++++++--- fs/btrfs/relocation.c | 27 ++++++++++++++++++++++++--- 4 files changed, 72 insertions(+), 10 deletions(-) (limited to 'fs/btrfs/print-tree.c') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 9fa958ed065e..427ca5de8542 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3432,6 +3432,13 @@ static inline void assfail(char *expr, char *file, int line) #define ASSERT(expr) ((void)0) #endif +__cold +static inline void btrfs_print_v0_err(struct btrfs_fs_info *fs_info) +{ + btrfs_err(fs_info, +"Unsupported V0 extent filesystem detected. Aborting. Please re-create your filesystem with a newer kernel"); +} + __printf(5, 6) __cold void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function, diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 6a73d2698807..71283faa85e2 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -867,8 +867,16 @@ search_again: num_refs = btrfs_extent_refs(leaf, ei); extent_flags = btrfs_extent_flags(leaf, ei); } else { - BUG(); + ret = -EINVAL; + btrfs_print_v0_err(fs_info); + if (trans) + btrfs_abort_transaction(trans, ret); + else + btrfs_handle_fs_error(fs_info, ret, NULL); + + goto out_free; } + BUG_ON(num_refs == 0); } else { num_refs = 0; @@ -1296,6 +1304,10 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans, ref2 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_shared_data_ref); num_refs = btrfs_shared_data_ref_count(leaf, ref2); + } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { + btrfs_print_v0_err(trans->fs_info); + btrfs_abort_transaction(trans, -EINVAL); + return -EINVAL; } else { BUG(); } @@ -1328,6 +1340,8 @@ static noinline u32 extent_data_ref_count(struct btrfs_path *path, leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + + BUG_ON(key.type == BTRFS_EXTENT_REF_V0_KEY); if (iref) { /* * If type is invalid, we should have bailed out earlier than @@ -1541,7 +1555,12 @@ again: leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); - BUG_ON(item_size < sizeof(*ei)); + if (item_size < sizeof(*ei)) { + err = -EINVAL; + btrfs_print_v0_err(fs_info); + btrfs_abort_transaction(trans, err); + goto out; + } ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); flags = btrfs_extent_flags(leaf, ei); @@ -2265,7 +2284,14 @@ again: leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); - BUG_ON(item_size < sizeof(*ei)); + + if (item_size < sizeof(*ei)) { + err = -EINVAL; + btrfs_print_v0_err(fs_info); + btrfs_abort_transaction(trans, err); + goto out; + } + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); __run_delayed_extent_op(extent_op, leaf, ei); @@ -6796,7 +6822,12 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, extent_slot); - BUG_ON(item_size < sizeof(*ei)); + if (item_size < sizeof(*ei)) { + ret = -EINVAL; + btrfs_print_v0_err(info); + btrfs_abort_transaction(trans, ret); + goto out; + } ei = btrfs_item_ptr(leaf, extent_slot, struct btrfs_extent_item); if (owner_objectid < BTRFS_FIRST_FREE_OBJECTID && diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index c0dac9d7ce33..cc945376c244 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -52,8 +52,10 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) u64 offset; int ref_index = 0; - if (item_size < sizeof(*ei)) - BUG(); + if (item_size < sizeof(*ei)) { + btrfs_print_v0_err(eb->fs_info); + btrfs_handle_fs_error(eb->fs_info, -EINVAL, NULL); + } ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item); flags = btrfs_extent_flags(eb, ei); @@ -256,7 +258,8 @@ void btrfs_print_leaf(struct extent_buffer *l) btrfs_file_extent_ram_bytes(l, fi)); break; case BTRFS_EXTENT_REF_V0_KEY: - BUG(); + btrfs_print_v0_err(fs_info); + btrfs_handle_fs_error(fs_info, -EINVAL, NULL); break; case BTRFS_BLOCK_GROUP_ITEM_KEY: bi = btrfs_item_ptr(l, i, diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 6dfa92e5ceed..eaf59c742dc8 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -598,6 +598,11 @@ int find_inline_backref(struct extent_buffer *leaf, int slot, btrfs_item_key_to_cpu(leaf, &key, slot); item_size = btrfs_item_size_nr(leaf, slot); + if (item_size < sizeof(*ei)) { + btrfs_print_v0_err(leaf->fs_info); + btrfs_handle_fs_error(leaf->fs_info, -EINVAL, NULL); + return 1; + } ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item); WARN_ON(!(btrfs_extent_flags(leaf, ei) & BTRFS_EXTENT_FLAG_TREE_BLOCK)); @@ -782,7 +787,6 @@ again: goto next; } - ASSERT(key.type != BTRFS_EXTENT_REF_V0_KEY); if (key.type == BTRFS_SHARED_BLOCK_REF_KEY) { if (key.objectid == key.offset) { /* @@ -826,6 +830,12 @@ again: edge->node[UPPER] = upper; goto next; + } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { + err = -EINVAL; + btrfs_print_v0_err(rc->extent_root->fs_info); + btrfs_handle_fs_error(rc->extent_root->fs_info, err, + NULL); + goto out; } else if (key.type != BTRFS_TREE_BLOCK_REF_KEY) { goto next; } @@ -3315,6 +3325,10 @@ static int add_tree_block(struct reloc_control *rc, level = (int)extent_key->offset; } generation = btrfs_extent_generation(eb, ei); + } else if (item_size == sizeof(struct btrfs_extent_item_v0)) { + btrfs_print_v0_err(eb->fs_info); + btrfs_handle_fs_error(eb->fs_info, -EINVAL, NULL); + return -EINVAL; } else { BUG(); } @@ -3720,7 +3734,6 @@ int add_data_references(struct reloc_control *rc, if (key.objectid != extent_key->objectid) break; - BUG_ON(key.type == BTRFS_EXTENT_REF_V0_KEY); if (key.type == BTRFS_SHARED_DATA_REF_KEY) { ret = __add_tree_block(rc, key.offset, blocksize, blocks); @@ -3729,6 +3742,10 @@ int add_data_references(struct reloc_control *rc, struct btrfs_extent_data_ref); ret = find_data_references(rc, extent_key, eb, dref, blocks); + } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { + btrfs_print_v0_err(eb->fs_info); + btrfs_handle_fs_error(eb->fs_info, -EINVAL, NULL); + ret = -EINVAL; } else { ret = 0; } @@ -3967,7 +3984,11 @@ restart: flags = btrfs_extent_flags(path->nodes[0], ei); ret = check_extent_flags(flags); BUG_ON(ret); - + } else if (item_size == sizeof(struct btrfs_extent_item_v0)) { + err = -EINVAL; + btrfs_print_v0_err(trans->fs_info); + btrfs_abort_transaction(trans, err); + break; } else { BUG(); } -- cgit From 6d8ff4e4584cd84093b751671351c8103ead551d Mon Sep 17 00:00:00 2001 From: David Sterba Date: Tue, 26 Jun 2018 16:20:59 +0200 Subject: btrfs: annotate unlikely branches after V0 extent type removal The v0 extent type checks are the right case for the unlikely annotations as we don't expect to ever see them, so let's give the compiler some hint. Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 8 ++++---- fs/btrfs/print-tree.c | 2 +- fs/btrfs/relocation.c | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'fs/btrfs/print-tree.c') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 71283faa85e2..352b7e95f657 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1304,7 +1304,7 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans, ref2 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_shared_data_ref); num_refs = btrfs_shared_data_ref_count(leaf, ref2); - } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { + } else if (unlikely(key.type == BTRFS_EXTENT_REF_V0_KEY)) { btrfs_print_v0_err(trans->fs_info); btrfs_abort_transaction(trans, -EINVAL); return -EINVAL; @@ -1555,7 +1555,7 @@ again: leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); - if (item_size < sizeof(*ei)) { + if (unlikely(item_size < sizeof(*ei))) { err = -EINVAL; btrfs_print_v0_err(fs_info); btrfs_abort_transaction(trans, err); @@ -2285,7 +2285,7 @@ again: leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); - if (item_size < sizeof(*ei)) { + if (unlikely(item_size < sizeof(*ei))) { err = -EINVAL; btrfs_print_v0_err(fs_info); btrfs_abort_transaction(trans, err); @@ -6822,7 +6822,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, extent_slot); - if (item_size < sizeof(*ei)) { + if (unlikely(item_size < sizeof(*ei))) { ret = -EINVAL; btrfs_print_v0_err(info); btrfs_abort_transaction(trans, ret); diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index cc945376c244..df49931ffe92 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -52,7 +52,7 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) u64 offset; int ref_index = 0; - if (item_size < sizeof(*ei)) { + if (unlikely(item_size < sizeof(*ei))) { btrfs_print_v0_err(eb->fs_info); btrfs_handle_fs_error(eb->fs_info, -EINVAL, NULL); } diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index eaf59c742dc8..229f721cbde9 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -830,7 +830,7 @@ again: edge->node[UPPER] = upper; goto next; - } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { + } else if (unlikely(key.type == BTRFS_EXTENT_REF_V0_KEY)) { err = -EINVAL; btrfs_print_v0_err(rc->extent_root->fs_info); btrfs_handle_fs_error(rc->extent_root->fs_info, err, @@ -3325,7 +3325,7 @@ static int add_tree_block(struct reloc_control *rc, level = (int)extent_key->offset; } generation = btrfs_extent_generation(eb, ei); - } else if (item_size == sizeof(struct btrfs_extent_item_v0)) { + } else if (unlikely(item_size == sizeof(struct btrfs_extent_item_v0))) { btrfs_print_v0_err(eb->fs_info); btrfs_handle_fs_error(eb->fs_info, -EINVAL, NULL); return -EINVAL; @@ -3742,7 +3742,7 @@ int add_data_references(struct reloc_control *rc, struct btrfs_extent_data_ref); ret = find_data_references(rc, extent_key, eb, dref, blocks); - } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { + } else if (unlikely(key.type == BTRFS_EXTENT_REF_V0_KEY)) { btrfs_print_v0_err(eb->fs_info); btrfs_handle_fs_error(eb->fs_info, -EINVAL, NULL); ret = -EINVAL; @@ -3984,7 +3984,7 @@ restart: flags = btrfs_extent_flags(path->nodes[0], ei); ret = check_extent_flags(flags); BUG_ON(ret); - } else if (item_size == sizeof(struct btrfs_extent_item_v0)) { + } else if (unlikely(item_size == sizeof(struct btrfs_extent_item_v0))) { err = -EINVAL; btrfs_print_v0_err(trans->fs_info); btrfs_abort_transaction(trans, err); -- cgit