Skip to content

Commit f616751

Browse files
committed
Merge branch 'for-linus-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Pull btrfs fixes from Chris Mason: "My patch fixes the btrfs list_head abuse that we tracked down during Dave Jones' memory corruption investigation. With both Jens and my patches in place, I'm no longer able to trigger problems. Filipe is fixing a difficult old bug between snapshots, balance and send. Dave is cooking a few more for the next rc, but these are tested and ready" * 'for-linus-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: btrfs: fix races on root_log_ctx lists btrfs: fix incremental send failure caused by balance
2 parents 2cd0b50 + 570dd45 commit f616751

2 files changed

Lines changed: 64 additions & 14 deletions

File tree

fs/btrfs/send.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5805,6 +5805,64 @@ static int changed_extent(struct send_ctx *sctx,
58055805
int ret = 0;
58065806

58075807
if (sctx->cur_ino != sctx->cmp_key->objectid) {
5808+
5809+
if (result == BTRFS_COMPARE_TREE_CHANGED) {
5810+
struct extent_buffer *leaf_l;
5811+
struct extent_buffer *leaf_r;
5812+
struct btrfs_file_extent_item *ei_l;
5813+
struct btrfs_file_extent_item *ei_r;
5814+
5815+
leaf_l = sctx->left_path->nodes[0];
5816+
leaf_r = sctx->right_path->nodes[0];
5817+
ei_l = btrfs_item_ptr(leaf_l,
5818+
sctx->left_path->slots[0],
5819+
struct btrfs_file_extent_item);
5820+
ei_r = btrfs_item_ptr(leaf_r,
5821+
sctx->right_path->slots[0],
5822+
struct btrfs_file_extent_item);
5823+
5824+
/*
5825+
* We may have found an extent item that has changed
5826+
* only its disk_bytenr field and the corresponding
5827+
* inode item was not updated. This case happens due to
5828+
* very specific timings during relocation when a leaf
5829+
* that contains file extent items is COWed while
5830+
* relocation is ongoing and its in the stage where it
5831+
* updates data pointers. So when this happens we can
5832+
* safely ignore it since we know it's the same extent,
5833+
* but just at different logical and physical locations
5834+
* (when an extent is fully replaced with a new one, we
5835+
* know the generation number must have changed too,
5836+
* since snapshot creation implies committing the current
5837+
* transaction, and the inode item must have been updated
5838+
* as well).
5839+
* This replacement of the disk_bytenr happens at
5840+
* relocation.c:replace_file_extents() through
5841+
* relocation.c:btrfs_reloc_cow_block().
5842+
*/
5843+
if (btrfs_file_extent_generation(leaf_l, ei_l) ==
5844+
btrfs_file_extent_generation(leaf_r, ei_r) &&
5845+
btrfs_file_extent_ram_bytes(leaf_l, ei_l) ==
5846+
btrfs_file_extent_ram_bytes(leaf_r, ei_r) &&
5847+
btrfs_file_extent_compression(leaf_l, ei_l) ==
5848+
btrfs_file_extent_compression(leaf_r, ei_r) &&
5849+
btrfs_file_extent_encryption(leaf_l, ei_l) ==
5850+
btrfs_file_extent_encryption(leaf_r, ei_r) &&
5851+
btrfs_file_extent_other_encoding(leaf_l, ei_l) ==
5852+
btrfs_file_extent_other_encoding(leaf_r, ei_r) &&
5853+
btrfs_file_extent_type(leaf_l, ei_l) ==
5854+
btrfs_file_extent_type(leaf_r, ei_r) &&
5855+
btrfs_file_extent_disk_bytenr(leaf_l, ei_l) !=
5856+
btrfs_file_extent_disk_bytenr(leaf_r, ei_r) &&
5857+
btrfs_file_extent_disk_num_bytes(leaf_l, ei_l) ==
5858+
btrfs_file_extent_disk_num_bytes(leaf_r, ei_r) &&
5859+
btrfs_file_extent_offset(leaf_l, ei_l) ==
5860+
btrfs_file_extent_offset(leaf_r, ei_r) &&
5861+
btrfs_file_extent_num_bytes(leaf_l, ei_l) ==
5862+
btrfs_file_extent_num_bytes(leaf_r, ei_r))
5863+
return 0;
5864+
}
5865+
58085866
inconsistent_snapshot_error(sctx, result, "extent");
58095867
return -EIO;
58105868
}

fs/btrfs/tree-log.c

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,14 +2713,12 @@ static inline void btrfs_remove_all_log_ctxs(struct btrfs_root *root,
27132713
int index, int error)
27142714
{
27152715
struct btrfs_log_ctx *ctx;
2716+
struct btrfs_log_ctx *safe;
27162717

2717-
if (!error) {
2718-
INIT_LIST_HEAD(&root->log_ctxs[index]);
2719-
return;
2720-
}
2721-
2722-
list_for_each_entry(ctx, &root->log_ctxs[index], list)
2718+
list_for_each_entry_safe(ctx, safe, &root->log_ctxs[index], list) {
2719+
list_del_init(&ctx->list);
27232720
ctx->log_ret = error;
2721+
}
27242722

27252723
INIT_LIST_HEAD(&root->log_ctxs[index]);
27262724
}
@@ -2961,13 +2959,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
29612959
mutex_unlock(&root->log_mutex);
29622960

29632961
out_wake_log_root:
2964-
/*
2965-
* We needn't get log_mutex here because we are sure all
2966-
* the other tasks are blocked.
2967-
*/
2962+
mutex_lock(&log_root_tree->log_mutex);
29682963
btrfs_remove_all_log_ctxs(log_root_tree, index2, ret);
29692964

2970-
mutex_lock(&log_root_tree->log_mutex);
29712965
log_root_tree->log_transid_committed++;
29722966
atomic_set(&log_root_tree->log_commit[index2], 0);
29732967
mutex_unlock(&log_root_tree->log_mutex);
@@ -2978,10 +2972,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
29782972
if (waitqueue_active(&log_root_tree->log_commit_wait[index2]))
29792973
wake_up(&log_root_tree->log_commit_wait[index2]);
29802974
out:
2981-
/* See above. */
2982-
btrfs_remove_all_log_ctxs(root, index1, ret);
2983-
29842975
mutex_lock(&root->log_mutex);
2976+
btrfs_remove_all_log_ctxs(root, index1, ret);
29852977
root->log_transid_committed++;
29862978
atomic_set(&root->log_commit[index1], 0);
29872979
mutex_unlock(&root->log_mutex);

0 commit comments

Comments
 (0)