Commit f1ebcc74d5b2159f44c96b479b6eb8afc7829095

Authored by Liu Bo
Committed by Chris Mason
1 parent 8965593e41

Btrfs: fix tree corruption after multi-thread snapshots and inode_cache flush

The btrfs snapshotting code requires that once a root has been
snapshotted, we don't change it during a commit.

But there are two cases to lead to tree corruptions:

1) multi-thread snapshots can commit serveral snapshots in a transaction,
   and this may change the src root when processing the following pending
   snapshots, which lead to the former snapshots corruptions;

2) the free inode cache was changing the roots when it root the cache,
   which lead to corruptions.

This fixes things by making sure we force COW the block after we create a
snapshot during commiting a transaction, then any changes to the roots
will result in COW, and we get all the fs roots and snapshot roots to be
consistent.

Signed-off-by: Liu Bo <liubo2009@cn.fujitsu.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>

Showing 3 changed files with 26 additions and 1 deletions Side-by-side Diff

... ... @@ -514,10 +514,25 @@
514 514 struct btrfs_root *root,
515 515 struct extent_buffer *buf)
516 516 {
  517 + /* ensure we can see the force_cow */
  518 + smp_rmb();
  519 +
  520 + /*
  521 + * We do not need to cow a block if
  522 + * 1) this block is not created or changed in this transaction;
  523 + * 2) this block does not belong to TREE_RELOC tree;
  524 + * 3) the root is not forced COW.
  525 + *
  526 + * What is forced COW:
  527 + * when we create snapshot during commiting the transaction,
  528 + * after we've finished coping src root, we must COW the shared
  529 + * block to ensure the metadata consistency.
  530 + */
517 531 if (btrfs_header_generation(buf) == trans->transid &&
518 532 !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) &&
519 533 !(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID &&
520   - btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)))
  534 + btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)) &&
  535 + !root->force_cow)
521 536 return 0;
522 537 return 1;
523 538 }
... ... @@ -1271,6 +1271,8 @@
1271 1271 * for stat. It may be used for more later
1272 1272 */
1273 1273 dev_t anon_dev;
  1274 +
  1275 + int force_cow;
1274 1276 };
1275 1277  
1276 1278 struct btrfs_ioctl_defrag_range_args {
fs/btrfs/transaction.c
... ... @@ -785,6 +785,10 @@
785 785  
786 786 btrfs_save_ino_cache(root, trans);
787 787  
  788 + /* see comments in should_cow_block() */
  789 + root->force_cow = 0;
  790 + smp_wmb();
  791 +
788 792 if (root->commit_root != root->node) {
789 793 mutex_lock(&root->fs_commit_mutex);
790 794 switch_commit_root(root);
... ... @@ -946,6 +950,10 @@
946 950 btrfs_copy_root(trans, root, old, &tmp, objectid);
947 951 btrfs_tree_unlock(old);
948 952 free_extent_buffer(old);
  953 +
  954 + /* see comments in should_cow_block() */
  955 + root->force_cow = 1;
  956 + smp_wmb();
949 957  
950 958 btrfs_set_root_node(new_root_item, tmp);
951 959 /* record when the snapshot was created in key.offset */