diff options
Diffstat (limited to 'fs/btrfs/ctree.c')
| -rw-r--r-- | fs/btrfs/ctree.c | 17 | 
1 files changed, 16 insertions, 1 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 0fe615e4ea3..dede441bdee 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -514,10 +514,25 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,  				   struct btrfs_root *root,  				   struct extent_buffer *buf)  { +	/* ensure we can see the force_cow */ +	smp_rmb(); + +	/* +	 * We do not need to cow a block if +	 * 1) this block is not created or changed in this transaction; +	 * 2) this block does not belong to TREE_RELOC tree; +	 * 3) the root is not forced COW. +	 * +	 * What is forced COW: +	 *    when we create snapshot during commiting the transaction, +	 *    after we've finished coping src root, we must COW the shared +	 *    block to ensure the metadata consistency. +	 */  	if (btrfs_header_generation(buf) == trans->transid &&  	    !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) &&  	    !(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID && -	      btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))) +	      btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)) && +	    !root->force_cow)  		return 0;  	return 1;  }  |