aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorWang Shilong <wangsl.fnst@cn.fujitsu.com>2014-03-26 23:12:25 -0400
committerChris Mason <clm@fb.com>2014-04-07 12:08:43 -0400
commite9894fd3e3b3c5ecaa096d32c2d2b79db8e64433 (patch)
tree44c6c453a793fec1a8f83b4d0d14768d2f71260e /fs/btrfs
parent3ac0d7b96a268a98bd474cab8bce3a9f125aaccf (diff)
Btrfs: fix snapshot vs nocow writting
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 <guihc.fnst@cn.fujitsu.com> Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/inode.c23
1 files changed, 21 insertions, 2 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 0ec876657923..251db68148b2 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1271,6 +1271,15 @@ next_slot:
1271 disk_bytenr += cur_offset - found_key.offset; 1271 disk_bytenr += cur_offset - found_key.offset;
1272 num_bytes = min(end + 1, extent_end) - cur_offset; 1272 num_bytes = min(end + 1, extent_end) - cur_offset;
1273 /* 1273 /*
1274 * if there are pending snapshots for this root,
1275 * we fall into common COW way.
1276 */
1277 if (!nolock) {
1278 err = btrfs_start_nocow_write(root);
1279 if (!err)
1280 goto out_check;
1281 }
1282 /*
1274 * force cow if csum exists in the range. 1283 * force cow if csum exists in the range.
1275 * this ensure that csum for a given extent are 1284 * this ensure that csum for a given extent are
1276 * either valid or do not exist. 1285 * either valid or do not exist.
@@ -1289,6 +1298,8 @@ next_slot:
1289out_check: 1298out_check:
1290 if (extent_end <= start) { 1299 if (extent_end <= start) {
1291 path->slots[0]++; 1300 path->slots[0]++;
1301 if (!nolock && nocow)
1302 btrfs_end_nocow_write(root);
1292 goto next_slot; 1303 goto next_slot;
1293 } 1304 }
1294 if (!nocow) { 1305 if (!nocow) {
@@ -1306,8 +1317,11 @@ out_check:
1306 ret = cow_file_range(inode, locked_page, 1317 ret = cow_file_range(inode, locked_page,
1307 cow_start, found_key.offset - 1, 1318 cow_start, found_key.offset - 1,
1308 page_started, nr_written, 1); 1319 page_started, nr_written, 1);
1309 if (ret) 1320 if (ret) {
1321 if (!nolock && nocow)
1322 btrfs_end_nocow_write(root);
1310 goto error; 1323 goto error;
1324 }
1311 cow_start = (u64)-1; 1325 cow_start = (u64)-1;
1312 } 1326 }
1313 1327
@@ -1354,8 +1368,11 @@ out_check:
1354 BTRFS_DATA_RELOC_TREE_OBJECTID) { 1368 BTRFS_DATA_RELOC_TREE_OBJECTID) {
1355 ret = btrfs_reloc_clone_csums(inode, cur_offset, 1369 ret = btrfs_reloc_clone_csums(inode, cur_offset,
1356 num_bytes); 1370 num_bytes);
1357 if (ret) 1371 if (ret) {
1372 if (!nolock && nocow)
1373 btrfs_end_nocow_write(root);
1358 goto error; 1374 goto error;
1375 }
1359 } 1376 }
1360 1377
1361 extent_clear_unlock_delalloc(inode, cur_offset, 1378 extent_clear_unlock_delalloc(inode, cur_offset,
@@ -1363,6 +1380,8 @@ out_check:
1363 locked_page, EXTENT_LOCKED | 1380 locked_page, EXTENT_LOCKED |
1364 EXTENT_DELALLOC, PAGE_UNLOCK | 1381 EXTENT_DELALLOC, PAGE_UNLOCK |
1365 PAGE_SET_PRIVATE2); 1382 PAGE_SET_PRIVATE2);
1383 if (!nolock && nocow)
1384 btrfs_end_nocow_write(root);
1366 cur_offset = extent_end; 1385 cur_offset = extent_end;
1367 if (cur_offset > end) 1386 if (cur_offset > end)
1368 break; 1387 break;