diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 138 |
1 files changed, 112 insertions, 26 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 43885e51b882..5b0b758a3f79 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -311,10 +311,11 @@ loop: | |||
311 | * when the transaction commits | 311 | * when the transaction commits |
312 | */ | 312 | */ |
313 | static int record_root_in_trans(struct btrfs_trans_handle *trans, | 313 | static int record_root_in_trans(struct btrfs_trans_handle *trans, |
314 | struct btrfs_root *root) | 314 | struct btrfs_root *root, |
315 | int force) | ||
315 | { | 316 | { |
316 | if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) && | 317 | if ((test_bit(BTRFS_ROOT_REF_COWS, &root->state) && |
317 | root->last_trans < trans->transid) { | 318 | root->last_trans < trans->transid) || force) { |
318 | WARN_ON(root == root->fs_info->extent_root); | 319 | WARN_ON(root == root->fs_info->extent_root); |
319 | WARN_ON(root->commit_root != root->node); | 320 | WARN_ON(root->commit_root != root->node); |
320 | 321 | ||
@@ -331,7 +332,7 @@ static int record_root_in_trans(struct btrfs_trans_handle *trans, | |||
331 | smp_wmb(); | 332 | smp_wmb(); |
332 | 333 | ||
333 | spin_lock(&root->fs_info->fs_roots_radix_lock); | 334 | spin_lock(&root->fs_info->fs_roots_radix_lock); |
334 | if (root->last_trans == trans->transid) { | 335 | if (root->last_trans == trans->transid && !force) { |
335 | spin_unlock(&root->fs_info->fs_roots_radix_lock); | 336 | spin_unlock(&root->fs_info->fs_roots_radix_lock); |
336 | return 0; | 337 | return 0; |
337 | } | 338 | } |
@@ -402,7 +403,7 @@ int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans, | |||
402 | return 0; | 403 | return 0; |
403 | 404 | ||
404 | mutex_lock(&root->fs_info->reloc_mutex); | 405 | mutex_lock(&root->fs_info->reloc_mutex); |
405 | record_root_in_trans(trans, root); | 406 | record_root_in_trans(trans, root, 0); |
406 | mutex_unlock(&root->fs_info->reloc_mutex); | 407 | mutex_unlock(&root->fs_info->reloc_mutex); |
407 | 408 | ||
408 | return 0; | 409 | return 0; |
@@ -1310,6 +1311,97 @@ int btrfs_defrag_root(struct btrfs_root *root) | |||
1310 | return ret; | 1311 | return ret; |
1311 | } | 1312 | } |
1312 | 1313 | ||
1314 | /* Bisesctability fixup, remove in 4.8 */ | ||
1315 | #ifndef btrfs_std_error | ||
1316 | #define btrfs_std_error btrfs_handle_fs_error | ||
1317 | #endif | ||
1318 | |||
1319 | /* | ||
1320 | * Do all special snapshot related qgroup dirty hack. | ||
1321 | * | ||
1322 | * Will do all needed qgroup inherit and dirty hack like switch commit | ||
1323 | * roots inside one transaction and write all btree into disk, to make | ||
1324 | * qgroup works. | ||
1325 | */ | ||
1326 | static int qgroup_account_snapshot(struct btrfs_trans_handle *trans, | ||
1327 | struct btrfs_root *src, | ||
1328 | struct btrfs_root *parent, | ||
1329 | struct btrfs_qgroup_inherit *inherit, | ||
1330 | u64 dst_objectid) | ||
1331 | { | ||
1332 | struct btrfs_fs_info *fs_info = src->fs_info; | ||
1333 | int ret; | ||
1334 | |||
1335 | /* | ||
1336 | * Save some performance in the case that qgroups are not | ||
1337 | * enabled. If this check races with the ioctl, rescan will | ||
1338 | * kick in anyway. | ||
1339 | */ | ||
1340 | mutex_lock(&fs_info->qgroup_ioctl_lock); | ||
1341 | if (!fs_info->quota_enabled) { | ||
1342 | mutex_unlock(&fs_info->qgroup_ioctl_lock); | ||
1343 | return 0; | ||
1344 | } | ||
1345 | mutex_unlock(&fs_info->qgroup_ioctl_lock); | ||
1346 | |||
1347 | /* | ||
1348 | * We are going to commit transaction, see btrfs_commit_transaction() | ||
1349 | * comment for reason locking tree_log_mutex | ||
1350 | */ | ||
1351 | mutex_lock(&fs_info->tree_log_mutex); | ||
1352 | |||
1353 | ret = commit_fs_roots(trans, src); | ||
1354 | if (ret) | ||
1355 | goto out; | ||
1356 | ret = btrfs_qgroup_prepare_account_extents(trans, fs_info); | ||
1357 | if (ret < 0) | ||
1358 | goto out; | ||
1359 | ret = btrfs_qgroup_account_extents(trans, fs_info); | ||
1360 | if (ret < 0) | ||
1361 | goto out; | ||
1362 | |||
1363 | /* Now qgroup are all updated, we can inherit it to new qgroups */ | ||
1364 | ret = btrfs_qgroup_inherit(trans, fs_info, | ||
1365 | src->root_key.objectid, dst_objectid, | ||
1366 | inherit); | ||
1367 | if (ret < 0) | ||
1368 | goto out; | ||
1369 | |||
1370 | /* | ||
1371 | * Now we do a simplified commit transaction, which will: | ||
1372 | * 1) commit all subvolume and extent tree | ||
1373 | * To ensure all subvolume and extent tree have a valid | ||
1374 | * commit_root to accounting later insert_dir_item() | ||
1375 | * 2) write all btree blocks onto disk | ||
1376 | * This is to make sure later btree modification will be cowed | ||
1377 | * Or commit_root can be populated and cause wrong qgroup numbers | ||
1378 | * In this simplified commit, we don't really care about other trees | ||
1379 | * like chunk and root tree, as they won't affect qgroup. | ||
1380 | * And we don't write super to avoid half committed status. | ||
1381 | */ | ||
1382 | ret = commit_cowonly_roots(trans, src); | ||
1383 | if (ret) | ||
1384 | goto out; | ||
1385 | switch_commit_roots(trans->transaction, fs_info); | ||
1386 | ret = btrfs_write_and_wait_transaction(trans, src); | ||
1387 | if (ret) | ||
1388 | btrfs_std_error(fs_info, ret, | ||
1389 | "Error while writing out transaction for qgroup"); | ||
1390 | |||
1391 | out: | ||
1392 | mutex_unlock(&fs_info->tree_log_mutex); | ||
1393 | |||
1394 | /* | ||
1395 | * Force parent root to be updated, as we recorded it before so its | ||
1396 | * last_trans == cur_transid. | ||
1397 | * Or it won't be committed again onto disk after later | ||
1398 | * insert_dir_item() | ||
1399 | */ | ||
1400 | if (!ret) | ||
1401 | record_root_in_trans(trans, parent, 1); | ||
1402 | return ret; | ||
1403 | } | ||
1404 | |||
1313 | /* | 1405 | /* |
1314 | * new snapshots need to be created at a very specific time in the | 1406 | * new snapshots need to be created at a very specific time in the |
1315 | * transaction commit. This does the actual creation. | 1407 | * transaction commit. This does the actual creation. |
@@ -1383,7 +1475,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1383 | dentry = pending->dentry; | 1475 | dentry = pending->dentry; |
1384 | parent_inode = pending->dir; | 1476 | parent_inode = pending->dir; |
1385 | parent_root = BTRFS_I(parent_inode)->root; | 1477 | parent_root = BTRFS_I(parent_inode)->root; |
1386 | record_root_in_trans(trans, parent_root); | 1478 | record_root_in_trans(trans, parent_root, 0); |
1387 | 1479 | ||
1388 | cur_time = current_fs_time(parent_inode->i_sb); | 1480 | cur_time = current_fs_time(parent_inode->i_sb); |
1389 | 1481 | ||
@@ -1420,7 +1512,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1420 | goto fail; | 1512 | goto fail; |
1421 | } | 1513 | } |
1422 | 1514 | ||
1423 | record_root_in_trans(trans, root); | 1515 | record_root_in_trans(trans, root, 0); |
1424 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | 1516 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); |
1425 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); | 1517 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); |
1426 | btrfs_check_and_init_root_item(new_root_item); | 1518 | btrfs_check_and_init_root_item(new_root_item); |
@@ -1516,6 +1608,17 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1516 | goto fail; | 1608 | goto fail; |
1517 | } | 1609 | } |
1518 | 1610 | ||
1611 | /* | ||
1612 | * Do special qgroup accounting for snapshot, as we do some qgroup | ||
1613 | * snapshot hack to do fast snapshot. | ||
1614 | * To co-operate with that hack, we do hack again. | ||
1615 | * Or snapshot will be greatly slowed down by a subtree qgroup rescan | ||
1616 | */ | ||
1617 | ret = qgroup_account_snapshot(trans, root, parent_root, | ||
1618 | pending->inherit, objectid); | ||
1619 | if (ret < 0) | ||
1620 | goto fail; | ||
1621 | |||
1519 | ret = btrfs_insert_dir_item(trans, parent_root, | 1622 | ret = btrfs_insert_dir_item(trans, parent_root, |
1520 | dentry->d_name.name, dentry->d_name.len, | 1623 | dentry->d_name.name, dentry->d_name.len, |
1521 | parent_inode, &key, | 1624 | parent_inode, &key, |
@@ -1559,23 +1662,6 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1559 | goto fail; | 1662 | goto fail; |
1560 | } | 1663 | } |
1561 | 1664 | ||
1562 | /* | ||
1563 | * account qgroup counters before qgroup_inherit() | ||
1564 | */ | ||
1565 | ret = btrfs_qgroup_prepare_account_extents(trans, fs_info); | ||
1566 | if (ret) | ||
1567 | goto fail; | ||
1568 | ret = btrfs_qgroup_account_extents(trans, fs_info); | ||
1569 | if (ret) | ||
1570 | goto fail; | ||
1571 | ret = btrfs_qgroup_inherit(trans, fs_info, | ||
1572 | root->root_key.objectid, | ||
1573 | objectid, pending->inherit); | ||
1574 | if (ret) { | ||
1575 | btrfs_abort_transaction(trans, root, ret); | ||
1576 | goto fail; | ||
1577 | } | ||
1578 | |||
1579 | fail: | 1665 | fail: |
1580 | pending->error = ret; | 1666 | pending->error = ret; |
1581 | dir_item_existed: | 1667 | dir_item_existed: |
@@ -1821,7 +1907,7 @@ static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info) | |||
1821 | static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info) | 1907 | static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info) |
1822 | { | 1908 | { |
1823 | if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT)) | 1909 | if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT)) |
1824 | btrfs_wait_ordered_roots(fs_info, -1); | 1910 | btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1); |
1825 | } | 1911 | } |
1826 | 1912 | ||
1827 | static inline void | 1913 | static inline void |
@@ -2145,7 +2231,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
2145 | 2231 | ||
2146 | ret = btrfs_write_and_wait_transaction(trans, root); | 2232 | ret = btrfs_write_and_wait_transaction(trans, root); |
2147 | if (ret) { | 2233 | if (ret) { |
2148 | btrfs_std_error(root->fs_info, ret, | 2234 | btrfs_handle_fs_error(root->fs_info, ret, |
2149 | "Error while writing out transaction"); | 2235 | "Error while writing out transaction"); |
2150 | mutex_unlock(&root->fs_info->tree_log_mutex); | 2236 | mutex_unlock(&root->fs_info->tree_log_mutex); |
2151 | goto scrub_continue; | 2237 | goto scrub_continue; |