Commit 76c7f887 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-6.4-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux

Pull more btrfs fixes from David Sterba:

 - fix incorrect number of bitmap entries for space cache if loading is
   interrupted by some error

 - fix backref walking, this breaks a mode of LOGICAL_INO_V2 ioctl that
   is used in deduplication tools

 - zoned mode fixes:
      - properly finish zone reserved for relocation
      - correctly calculate super block zone end on ZNS
      - properly initialize new extent buffer for redirty

 - make mount option clear_cache work with block-group-tree, to rebuild
   free-space-tree instead of temporarily disabling it that would lead
   to a forced read-only mount

 - fix alignment check for offset when printing extent item

* tag 'for-6.4-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: make clear_cache mount option to rebuild FST without disabling it
  btrfs: zero the buffer before marking it dirty in btrfs_redirty_list_add
  btrfs: zoned: fix full zone super block reading on ZNS
  btrfs: zoned: zone finish data relocation BG with last IO
  btrfs: fix backref walking not returning all inode refs
  btrfs: fix space cache inconsistency after error loading it from disk
  btrfs: print-tree: parent bytenr must be aligned to sector size
parents fd88f147 1d6a4fc8
...@@ -45,7 +45,8 @@ static int check_extent_in_eb(struct btrfs_backref_walk_ctx *ctx, ...@@ -45,7 +45,8 @@ static int check_extent_in_eb(struct btrfs_backref_walk_ctx *ctx,
int root_count; int root_count;
bool cached; bool cached;
if (!btrfs_file_extent_compression(eb, fi) && if (!ctx->ignore_extent_item_pos &&
!btrfs_file_extent_compression(eb, fi) &&
!btrfs_file_extent_encryption(eb, fi) && !btrfs_file_extent_encryption(eb, fi) &&
!btrfs_file_extent_other_encoding(eb, fi)) { !btrfs_file_extent_other_encoding(eb, fi)) {
u64 data_offset; u64 data_offset;
...@@ -552,7 +553,7 @@ static int add_all_parents(struct btrfs_backref_walk_ctx *ctx, ...@@ -552,7 +553,7 @@ static int add_all_parents(struct btrfs_backref_walk_ctx *ctx,
count++; count++;
else else
goto next; goto next;
if (!ctx->ignore_extent_item_pos) { if (!ctx->skip_inode_ref_list) {
ret = check_extent_in_eb(ctx, &key, eb, fi, &eie); ret = check_extent_in_eb(ctx, &key, eb, fi, &eie);
if (ret == BTRFS_ITERATE_EXTENT_INODES_STOP || if (ret == BTRFS_ITERATE_EXTENT_INODES_STOP ||
ret < 0) ret < 0)
...@@ -564,7 +565,7 @@ static int add_all_parents(struct btrfs_backref_walk_ctx *ctx, ...@@ -564,7 +565,7 @@ static int add_all_parents(struct btrfs_backref_walk_ctx *ctx,
eie, (void **)&old, GFP_NOFS); eie, (void **)&old, GFP_NOFS);
if (ret < 0) if (ret < 0)
break; break;
if (!ret && !ctx->ignore_extent_item_pos) { if (!ret && !ctx->skip_inode_ref_list) {
while (old->next) while (old->next)
old = old->next; old = old->next;
old->next = eie; old->next = eie;
...@@ -1606,7 +1607,7 @@ static int find_parent_nodes(struct btrfs_backref_walk_ctx *ctx, ...@@ -1606,7 +1607,7 @@ static int find_parent_nodes(struct btrfs_backref_walk_ctx *ctx,
goto out; goto out;
} }
if (ref->count && ref->parent) { if (ref->count && ref->parent) {
if (!ctx->ignore_extent_item_pos && !ref->inode_list && if (!ctx->skip_inode_ref_list && !ref->inode_list &&
ref->level == 0) { ref->level == 0) {
struct btrfs_tree_parent_check check = { 0 }; struct btrfs_tree_parent_check check = { 0 };
struct extent_buffer *eb; struct extent_buffer *eb;
...@@ -1647,7 +1648,7 @@ static int find_parent_nodes(struct btrfs_backref_walk_ctx *ctx, ...@@ -1647,7 +1648,7 @@ static int find_parent_nodes(struct btrfs_backref_walk_ctx *ctx,
(void **)&eie, GFP_NOFS); (void **)&eie, GFP_NOFS);
if (ret < 0) if (ret < 0)
goto out; goto out;
if (!ret && !ctx->ignore_extent_item_pos) { if (!ret && !ctx->skip_inode_ref_list) {
/* /*
* We've recorded that parent, so we must extend * We've recorded that parent, so we must extend
* its inode list here. * its inode list here.
...@@ -1743,7 +1744,7 @@ int btrfs_find_all_leafs(struct btrfs_backref_walk_ctx *ctx) ...@@ -1743,7 +1744,7 @@ int btrfs_find_all_leafs(struct btrfs_backref_walk_ctx *ctx)
static int btrfs_find_all_roots_safe(struct btrfs_backref_walk_ctx *ctx) static int btrfs_find_all_roots_safe(struct btrfs_backref_walk_ctx *ctx)
{ {
const u64 orig_bytenr = ctx->bytenr; const u64 orig_bytenr = ctx->bytenr;
const bool orig_ignore_extent_item_pos = ctx->ignore_extent_item_pos; const bool orig_skip_inode_ref_list = ctx->skip_inode_ref_list;
bool roots_ulist_allocated = false; bool roots_ulist_allocated = false;
struct ulist_iterator uiter; struct ulist_iterator uiter;
int ret = 0; int ret = 0;
...@@ -1764,7 +1765,7 @@ static int btrfs_find_all_roots_safe(struct btrfs_backref_walk_ctx *ctx) ...@@ -1764,7 +1765,7 @@ static int btrfs_find_all_roots_safe(struct btrfs_backref_walk_ctx *ctx)
roots_ulist_allocated = true; roots_ulist_allocated = true;
} }
ctx->ignore_extent_item_pos = true; ctx->skip_inode_ref_list = true;
ULIST_ITER_INIT(&uiter); ULIST_ITER_INIT(&uiter);
while (1) { while (1) {
...@@ -1789,7 +1790,7 @@ static int btrfs_find_all_roots_safe(struct btrfs_backref_walk_ctx *ctx) ...@@ -1789,7 +1790,7 @@ static int btrfs_find_all_roots_safe(struct btrfs_backref_walk_ctx *ctx)
ulist_free(ctx->refs); ulist_free(ctx->refs);
ctx->refs = NULL; ctx->refs = NULL;
ctx->bytenr = orig_bytenr; ctx->bytenr = orig_bytenr;
ctx->ignore_extent_item_pos = orig_ignore_extent_item_pos; ctx->skip_inode_ref_list = orig_skip_inode_ref_list;
return ret; return ret;
} }
...@@ -1912,7 +1913,7 @@ int btrfs_is_data_extent_shared(struct btrfs_inode *inode, u64 bytenr, ...@@ -1912,7 +1913,7 @@ int btrfs_is_data_extent_shared(struct btrfs_inode *inode, u64 bytenr,
goto out_trans; goto out_trans;
} }
walk_ctx.ignore_extent_item_pos = true; walk_ctx.skip_inode_ref_list = true;
walk_ctx.trans = trans; walk_ctx.trans = trans;
walk_ctx.fs_info = fs_info; walk_ctx.fs_info = fs_info;
walk_ctx.refs = &ctx->refs; walk_ctx.refs = &ctx->refs;
......
...@@ -60,6 +60,12 @@ struct btrfs_backref_walk_ctx { ...@@ -60,6 +60,12 @@ struct btrfs_backref_walk_ctx {
* @extent_item_pos is ignored. * @extent_item_pos is ignored.
*/ */
bool ignore_extent_item_pos; bool ignore_extent_item_pos;
/*
* If true and bytenr corresponds to a data extent, then the inode list
* (each member describing inode number, file offset and root) is not
* added to each reference added to the @refs ulist.
*/
bool skip_inode_ref_list;
/* A valid transaction handle or NULL. */ /* A valid transaction handle or NULL. */
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
/* /*
......
...@@ -3121,23 +3121,34 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info) ...@@ -3121,23 +3121,34 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info)
{ {
int ret; int ret;
const bool cache_opt = btrfs_test_opt(fs_info, SPACE_CACHE); const bool cache_opt = btrfs_test_opt(fs_info, SPACE_CACHE);
bool clear_free_space_tree = false; bool rebuild_free_space_tree = false;
if (btrfs_test_opt(fs_info, CLEAR_CACHE) && if (btrfs_test_opt(fs_info, CLEAR_CACHE) &&
btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
clear_free_space_tree = true; rebuild_free_space_tree = true;
} else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) && } else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) { !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) {
btrfs_warn(fs_info, "free space tree is invalid"); btrfs_warn(fs_info, "free space tree is invalid");
clear_free_space_tree = true; rebuild_free_space_tree = true;
} }
if (clear_free_space_tree) { if (rebuild_free_space_tree) {
btrfs_info(fs_info, "clearing free space tree"); btrfs_info(fs_info, "rebuilding free space tree");
ret = btrfs_clear_free_space_tree(fs_info); ret = btrfs_rebuild_free_space_tree(fs_info);
if (ret) { if (ret) {
btrfs_warn(fs_info, btrfs_warn(fs_info,
"failed to clear free space tree: %d", ret); "failed to rebuild free space tree: %d", ret);
goto out;
}
}
if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
!btrfs_test_opt(fs_info, FREE_SPACE_TREE)) {
btrfs_info(fs_info, "disabling free space tree");
ret = btrfs_delete_free_space_tree(fs_info);
if (ret) {
btrfs_warn(fs_info,
"failed to disable free space tree: %d", ret);
goto out; goto out;
} }
} }
......
...@@ -870,15 +870,16 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode, ...@@ -870,15 +870,16 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
} }
spin_lock(&ctl->tree_lock); spin_lock(&ctl->tree_lock);
ret = link_free_space(ctl, e); ret = link_free_space(ctl, e);
ctl->total_bitmaps++;
recalculate_thresholds(ctl);
spin_unlock(&ctl->tree_lock);
if (ret) { if (ret) {
spin_unlock(&ctl->tree_lock);
btrfs_err(fs_info, btrfs_err(fs_info,
"Duplicate entries in free space cache, dumping"); "Duplicate entries in free space cache, dumping");
kmem_cache_free(btrfs_free_space_cachep, e); kmem_cache_free(btrfs_free_space_cachep, e);
goto free_cache; goto free_cache;
} }
ctl->total_bitmaps++;
recalculate_thresholds(ctl);
spin_unlock(&ctl->tree_lock);
list_add_tail(&e->list, &bitmaps); list_add_tail(&e->list, &bitmaps);
} }
......
...@@ -1252,7 +1252,7 @@ static int clear_free_space_tree(struct btrfs_trans_handle *trans, ...@@ -1252,7 +1252,7 @@ static int clear_free_space_tree(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) int btrfs_delete_free_space_tree(struct btrfs_fs_info *fs_info)
{ {
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_root *tree_root = fs_info->tree_root;
...@@ -1298,6 +1298,54 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) ...@@ -1298,6 +1298,54 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
return ret; return ret;
} }
int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
{
struct btrfs_trans_handle *trans;
struct btrfs_key key = {
.objectid = BTRFS_FREE_SPACE_TREE_OBJECTID,
.type = BTRFS_ROOT_ITEM_KEY,
.offset = 0,
};
struct btrfs_root *free_space_root = btrfs_global_root(fs_info, &key);
struct rb_node *node;
int ret;
trans = btrfs_start_transaction(free_space_root, 1);
if (IS_ERR(trans))
return PTR_ERR(trans);
set_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
set_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
ret = clear_free_space_tree(trans, free_space_root);
if (ret)
goto abort;
node = rb_first_cached(&fs_info->block_group_cache_tree);
while (node) {
struct btrfs_block_group *block_group;
block_group = rb_entry(node, struct btrfs_block_group,
cache_node);
ret = populate_free_space_tree(trans, block_group);
if (ret)
goto abort;
node = rb_next(node);
}
btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE);
btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID);
clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
ret = btrfs_commit_transaction(trans);
clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
return ret;
abort:
btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans);
return ret;
}
static int __add_block_group_free_space(struct btrfs_trans_handle *trans, static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
struct btrfs_block_group *block_group, struct btrfs_block_group *block_group,
struct btrfs_path *path) struct btrfs_path *path)
......
...@@ -18,7 +18,8 @@ struct btrfs_caching_control; ...@@ -18,7 +18,8 @@ struct btrfs_caching_control;
void set_free_space_tree_thresholds(struct btrfs_block_group *block_group); void set_free_space_tree_thresholds(struct btrfs_block_group *block_group);
int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info); int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info);
int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info); int btrfs_delete_free_space_tree(struct btrfs_fs_info *fs_info);
int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info);
int load_free_space_tree(struct btrfs_caching_control *caching_ctl); int load_free_space_tree(struct btrfs_caching_control *caching_ctl);
int add_block_group_free_space(struct btrfs_trans_handle *trans, int add_block_group_free_space(struct btrfs_trans_handle *trans,
struct btrfs_block_group *block_group); struct btrfs_block_group *block_group);
......
...@@ -3108,6 +3108,9 @@ int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) ...@@ -3108,6 +3108,9 @@ int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
btrfs_rewrite_logical_zoned(ordered_extent); btrfs_rewrite_logical_zoned(ordered_extent);
btrfs_zone_finish_endio(fs_info, ordered_extent->disk_bytenr, btrfs_zone_finish_endio(fs_info, ordered_extent->disk_bytenr,
ordered_extent->disk_num_bytes); ordered_extent->disk_num_bytes);
} else if (btrfs_is_data_reloc_root(inode->root)) {
btrfs_zone_finish_endio(fs_info, ordered_extent->disk_bytenr,
ordered_extent->disk_num_bytes);
} }
if (test_bit(BTRFS_ORDERED_TRUNCATED, &ordered_extent->flags)) { if (test_bit(BTRFS_ORDERED_TRUNCATED, &ordered_extent->flags)) {
......
...@@ -151,10 +151,10 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) ...@@ -151,10 +151,10 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
pr_cont("shared data backref parent %llu count %u\n", pr_cont("shared data backref parent %llu count %u\n",
offset, btrfs_shared_data_ref_count(eb, sref)); offset, btrfs_shared_data_ref_count(eb, sref));
/* /*
* offset is supposed to be a tree block which * Offset is supposed to be a tree block which must be
* must be aligned to nodesize. * aligned to sectorsize.
*/ */
if (!IS_ALIGNED(offset, eb->fs_info->nodesize)) if (!IS_ALIGNED(offset, eb->fs_info->sectorsize))
pr_info( pr_info(
"\t\t\t(parent %llu not aligned to sectorsize %u)\n", "\t\t\t(parent %llu not aligned to sectorsize %u)\n",
offset, eb->fs_info->sectorsize); offset, eb->fs_info->sectorsize);
......
...@@ -3422,7 +3422,7 @@ int add_data_references(struct reloc_control *rc, ...@@ -3422,7 +3422,7 @@ int add_data_references(struct reloc_control *rc,
btrfs_release_path(path); btrfs_release_path(path);
ctx.bytenr = extent_key->objectid; ctx.bytenr = extent_key->objectid;
ctx.ignore_extent_item_pos = true; ctx.skip_inode_ref_list = true;
ctx.fs_info = rc->extent_root->fs_info; ctx.fs_info = rc->extent_root->fs_info;
ret = btrfs_find_all_leafs(&ctx); ret = btrfs_find_all_leafs(&ctx);
......
...@@ -828,8 +828,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options, ...@@ -828,8 +828,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
ret = -EINVAL; ret = -EINVAL;
} }
if (btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE) && if (btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE) &&
(btrfs_test_opt(info, CLEAR_CACHE) || !btrfs_test_opt(info, FREE_SPACE_TREE)) {
!btrfs_test_opt(info, FREE_SPACE_TREE))) {
btrfs_err(info, "cannot disable free space tree with block-group-tree feature"); btrfs_err(info, "cannot disable free space tree with block-group-tree feature");
ret = -EINVAL; ret = -EINVAL;
} }
......
...@@ -122,10 +122,9 @@ static int sb_write_pointer(struct block_device *bdev, struct blk_zone *zones, ...@@ -122,10 +122,9 @@ static int sb_write_pointer(struct block_device *bdev, struct blk_zone *zones,
int i; int i;
for (i = 0; i < BTRFS_NR_SB_LOG_ZONES; i++) { for (i = 0; i < BTRFS_NR_SB_LOG_ZONES; i++) {
u64 bytenr; u64 zone_end = (zones[i].start + zones[i].capacity) << SECTOR_SHIFT;
u64 bytenr = ALIGN_DOWN(zone_end, BTRFS_SUPER_INFO_SIZE) -
bytenr = ((zones[i].start + zones[i].len) BTRFS_SUPER_INFO_SIZE;
<< SECTOR_SHIFT) - BTRFS_SUPER_INFO_SIZE;
page[i] = read_cache_page_gfp(mapping, page[i] = read_cache_page_gfp(mapping,
bytenr >> PAGE_SHIFT, GFP_NOFS); bytenr >> PAGE_SHIFT, GFP_NOFS);
...@@ -1610,11 +1609,11 @@ void btrfs_redirty_list_add(struct btrfs_transaction *trans, ...@@ -1610,11 +1609,11 @@ void btrfs_redirty_list_add(struct btrfs_transaction *trans,
!list_empty(&eb->release_list)) !list_empty(&eb->release_list))
return; return;
memzero_extent_buffer(eb, 0, eb->len);
set_bit(EXTENT_BUFFER_NO_CHECK, &eb->bflags);
set_extent_buffer_dirty(eb); set_extent_buffer_dirty(eb);
set_extent_bits_nowait(&trans->dirty_pages, eb->start, set_extent_bits_nowait(&trans->dirty_pages, eb->start,
eb->start + eb->len - 1, EXTENT_DIRTY); eb->start + eb->len - 1, EXTENT_DIRTY);
memzero_extent_buffer(eb, 0, eb->len);
set_bit(EXTENT_BUFFER_NO_CHECK, &eb->bflags);
spin_lock(&trans->releasing_ebs_lock); spin_lock(&trans->releasing_ebs_lock);
list_add_tail(&eb->release_list, &trans->releasing_ebs); list_add_tail(&eb->release_list, &trans->releasing_ebs);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment