Skip to content

Commit

Permalink
Btrfs: fix snapshot vs nocow writting
Browse files Browse the repository at this point in the history
While running fsstress and snapshots concurrently, we will hit something
like followings:

Thread 1			Thread 2

|->fallocate
  |->write pages
    |->join transaction
       |->add ordered extent
    |->end transaction
				|->flushing data
				  |->creating pending snapshots
|->write data into src root's
   fallocated space

After above work flows finished, we will get a state that source and
snapshot root share same space, but source root have written data into
fallocated space, this will make fsck fail to verify checksums for
snapshot root's preallocating file extent data.Nocow writting also
has this same problem.

Fix this problem by syncing snapshots with nocow writting:

 1.for nocow writting,if there are pending snapshots, we will
 fall into COW way.

 2.if there are pending nocow writes, snapshots for this root
 will be blocked until nocow writting finish.

Reported-by: Gui Hecheng <[email protected]>
Signed-off-by: Wang Shilong <[email protected]>
Signed-off-by: Chris Mason <[email protected]>
  • Loading branch information
Wang Shilong authored and masoncl committed Apr 7, 2014
1 parent 3ac0d7b commit e9894fd
Showing 1 changed file with 21 additions and 2 deletions.
23 changes: 21 additions & 2 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,15 @@ static noinline int run_delalloc_nocow(struct inode *inode,
disk_bytenr += extent_offset;
disk_bytenr += cur_offset - found_key.offset;
num_bytes = min(end + 1, extent_end) - cur_offset;
/*
* if there are pending snapshots for this root,
* we fall into common COW way.
*/
if (!nolock) {
err = btrfs_start_nocow_write(root);
if (!err)
goto out_check;
}
/*
* force cow if csum exists in the range.
* this ensure that csum for a given extent are
Expand All @@ -1289,6 +1298,8 @@ static noinline int run_delalloc_nocow(struct inode *inode,
out_check:
if (extent_end <= start) {
path->slots[0]++;
if (!nolock && nocow)
btrfs_end_nocow_write(root);
goto next_slot;
}
if (!nocow) {
Expand All @@ -1306,8 +1317,11 @@ static noinline int run_delalloc_nocow(struct inode *inode,
ret = cow_file_range(inode, locked_page,
cow_start, found_key.offset - 1,
page_started, nr_written, 1);
if (ret)
if (ret) {
if (!nolock && nocow)
btrfs_end_nocow_write(root);
goto error;
}
cow_start = (u64)-1;
}

Expand Down Expand Up @@ -1354,15 +1368,20 @@ static noinline int run_delalloc_nocow(struct inode *inode,
BTRFS_DATA_RELOC_TREE_OBJECTID) {
ret = btrfs_reloc_clone_csums(inode, cur_offset,
num_bytes);
if (ret)
if (ret) {
if (!nolock && nocow)
btrfs_end_nocow_write(root);
goto error;
}
}

extent_clear_unlock_delalloc(inode, cur_offset,
cur_offset + num_bytes - 1,
locked_page, EXTENT_LOCKED |
EXTENT_DELALLOC, PAGE_UNLOCK |
PAGE_SET_PRIVATE2);
if (!nolock && nocow)
btrfs_end_nocow_write(root);
cur_offset = extent_end;
if (cur_offset > end)
break;
Expand Down

0 comments on commit e9894fd

Please sign in to comment.