diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 4754c9101a4c..27adb8a36701 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -4079,7 +4079,7 @@ void btrfs_extend_item(struct btrfs_path *path, u32 data_size) * Main purpose is to save stack depth by doing the bulk of the work in a * function that doesn't call btrfs_search_slot */ -static void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path, +void btrfs_setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path, const struct btrfs_item_batch *batch) { struct btrfs_fs_info *fs_info = root->fs_info; @@ -4186,7 +4186,7 @@ void btrfs_setup_item_for_insert(struct btrfs_root *root, batch.total_data_size = data_size; batch.nr = 1; - setup_items_for_insert(root, path, &batch); + btrfs_setup_items_for_insert(root, path, &batch); } /* @@ -4212,7 +4212,7 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, slot = path->slots[0]; BUG_ON(slot < 0); - setup_items_for_insert(root, path, batch); + btrfs_setup_items_for_insert(root, path, batch); return 0; } diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 6965703a81b6..46e5780787d6 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -608,6 +608,8 @@ void btrfs_setup_item_for_insert(struct btrfs_root *root, struct btrfs_path *path, const struct btrfs_key *key, u32 data_size); +void btrfs_setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path, + const struct btrfs_item_batch *batch); int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, const struct btrfs_key *key, void *data, u32 data_size); int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index baad1ed7e111..6877ae6c591c 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -59,6 +59,7 @@ static void generic_err(const struct extent_buffer *eb, int slot, struct va_format vaf; va_list args; + WARN_ON(1); va_start(args, fmt); vaf.fmt = fmt; diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index fb52aa060093..8c7de783dc0a 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3580,6 +3580,30 @@ static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans, return 0; } +static int insert_index_batch(struct btrfs_trans_handle *trans, + struct btrfs_root *log, + struct btrfs_path *path, + const struct btrfs_item_batch *batch, + struct extent_buffer **leaf_before) +{ + int ret; + u32 total_size; + + total_size = batch->total_data_size + (batch->nr * sizeof(struct btrfs_item)); + ret = btrfs_search_slot(trans, log, &batch->keys[0], path, total_size, 1); + + if (path->nodes[0]) + *leaf_before = btrfs_clone_extent_buffer(path->nodes[0]); + + if (ret == 0) + return -EEXIST; + if (ret < 0) + return ret; + + btrfs_setup_items_for_insert(log, path, batch); + return 0; +} + static int flush_dir_items_batch(struct btrfs_trans_handle *trans, struct btrfs_root *log, struct extent_buffer *src, @@ -3587,6 +3611,7 @@ static int flush_dir_items_batch(struct btrfs_trans_handle *trans, int start_slot, int count) { + struct extent_buffer *leaf_before = NULL; char *ins_data = NULL; struct btrfs_item_batch batch; struct extent_buffer *dst; @@ -3630,7 +3655,7 @@ static int flush_dir_items_batch(struct btrfs_trans_handle *trans, } } - ret = btrfs_insert_empty_items(trans, log, dst_path, &batch); + ret = insert_index_batch(trans, log, dst_path, &batch, &leaf_before); if (ret) goto out; @@ -3648,9 +3673,26 @@ static int flush_dir_items_batch(struct btrfs_trans_handle *trans, dst_offset = btrfs_item_ptr_offset(dst, dst_path->slots[0] + count - 1); src_offset = btrfs_item_ptr_offset(src, start_slot + count - 1); copy_extent_buffer(dst, src, dst_offset, src_offset, batch.total_data_size); + + ret = btrfs_check_leaf_relaxed(dst_path->nodes[0]); + if (WARN_ON(ret)) { + if (leaf_before) { + btrfs_err(trans->fs_info, "corrupt leaf batch insert (count %d), slot %d, leaf before:", + batch.nr, dst_path->slots[0]); + btrfs_print_leaf(leaf_before); + } else { + btrfs_err(trans->fs_info, "corrupt leaf batch insert (count %d), slot %d, leaf before missing", + batch.nr, dst_path->slots[0]); + } + btrfs_err(trans->fs_info, "batch items:"); + for (i = 0; i < batch.nr; i++) + btrfs_err(trans->fs_info, "item %d index %llu", i, batch.keys[i].offset); + } + btrfs_release_path(dst_path); out: kfree(ins_data); + free_extent_buffer(leaf_before); return ret; } @@ -5948,12 +5990,15 @@ static int insert_delayed_items_batch(struct btrfs_trans_handle *trans, const struct btrfs_delayed_item *first_item) { const struct btrfs_delayed_item *curr = first_item; + struct extent_buffer *leaf_before = NULL; + int orig_slot; int ret; - ret = btrfs_insert_empty_items(trans, log, path, batch); + ret = insert_index_batch(trans, log, path, batch, &leaf_before); if (ret) - return ret; + goto out; + orig_slot = path->slots[0]; for (int i = 0; i < batch->nr; i++) { char *data_ptr; @@ -5964,9 +6009,31 @@ static int insert_delayed_items_batch(struct btrfs_trans_handle *trans, path->slots[0]++; } +out: + if (ret == 0) { + ret = btrfs_check_leaf_relaxed(path->nodes[0]); + if (WARN_ON(ret)) { + if (leaf_before) { + btrfs_err(trans->fs_info, "corrupt leaf delayed batch insert (count %d), orig_slot %d, leaf before:", + batch->nr, orig_slot); + btrfs_print_leaf(leaf_before); + } else { + btrfs_err(trans->fs_info, "corrupt leaf delayed batch insert (count %d), orig_slot %d, leaf before missing", + batch->nr, orig_slot); + } + btrfs_err(trans->fs_info, "batch items:"); + curr = first_item; + for (int i = 0; i < batch->nr; i++) { + btrfs_err(trans->fs_info, "item %d index %llu ptr %px", i, curr->index, curr); + curr = list_next_entry(curr, log_list); + } + } + } + btrfs_release_path(path); + free_extent_buffer(leaf_before); - return 0; + return ret; } static int log_delayed_insertion_items(struct btrfs_trans_handle *trans,