diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 46 |
1 files changed, 37 insertions, 9 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 87fac9a21ea5..fc03aa60b684 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -333,12 +333,14 @@ start_transaction(struct btrfs_root *root, u64 num_items, int type, | |||
333 | &root->fs_info->trans_block_rsv, | 333 | &root->fs_info->trans_block_rsv, |
334 | num_bytes, flush); | 334 | num_bytes, flush); |
335 | if (ret) | 335 | if (ret) |
336 | return ERR_PTR(ret); | 336 | goto reserve_fail; |
337 | } | 337 | } |
338 | again: | 338 | again: |
339 | h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); | 339 | h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); |
340 | if (!h) | 340 | if (!h) { |
341 | return ERR_PTR(-ENOMEM); | 341 | ret = -ENOMEM; |
342 | goto alloc_fail; | ||
343 | } | ||
342 | 344 | ||
343 | /* | 345 | /* |
344 | * If we are JOIN_NOLOCK we're already committing a transaction and | 346 | * If we are JOIN_NOLOCK we're already committing a transaction and |
@@ -365,11 +367,7 @@ again: | |||
365 | if (ret < 0) { | 367 | if (ret < 0) { |
366 | /* We must get the transaction if we are JOIN_NOLOCK. */ | 368 | /* We must get the transaction if we are JOIN_NOLOCK. */ |
367 | BUG_ON(type == TRANS_JOIN_NOLOCK); | 369 | BUG_ON(type == TRANS_JOIN_NOLOCK); |
368 | 370 | goto join_fail; | |
369 | if (type < TRANS_JOIN_NOLOCK) | ||
370 | sb_end_intwrite(root->fs_info->sb); | ||
371 | kmem_cache_free(btrfs_trans_handle_cachep, h); | ||
372 | return ERR_PTR(ret); | ||
373 | } | 371 | } |
374 | 372 | ||
375 | cur_trans = root->fs_info->running_transaction; | 373 | cur_trans = root->fs_info->running_transaction; |
@@ -410,6 +408,19 @@ got_it: | |||
410 | if (!current->journal_info && type != TRANS_USERSPACE) | 408 | if (!current->journal_info && type != TRANS_USERSPACE) |
411 | current->journal_info = h; | 409 | current->journal_info = h; |
412 | return h; | 410 | return h; |
411 | |||
412 | join_fail: | ||
413 | if (type < TRANS_JOIN_NOLOCK) | ||
414 | sb_end_intwrite(root->fs_info->sb); | ||
415 | kmem_cache_free(btrfs_trans_handle_cachep, h); | ||
416 | alloc_fail: | ||
417 | if (num_bytes) | ||
418 | btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv, | ||
419 | num_bytes); | ||
420 | reserve_fail: | ||
421 | if (qgroup_reserved) | ||
422 | btrfs_qgroup_free(root, qgroup_reserved); | ||
423 | return ERR_PTR(ret); | ||
413 | } | 424 | } |
414 | 425 | ||
415 | struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, | 426 | struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, |
@@ -1468,7 +1479,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1468 | goto cleanup_transaction; | 1479 | goto cleanup_transaction; |
1469 | } | 1480 | } |
1470 | 1481 | ||
1471 | if (cur_trans->aborted) { | 1482 | /* Stop the commit early if ->aborted is set */ |
1483 | if (unlikely(ACCESS_ONCE(cur_trans->aborted))) { | ||
1472 | ret = cur_trans->aborted; | 1484 | ret = cur_trans->aborted; |
1473 | goto cleanup_transaction; | 1485 | goto cleanup_transaction; |
1474 | } | 1486 | } |
@@ -1574,6 +1586,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1574 | wait_event(cur_trans->writer_wait, | 1586 | wait_event(cur_trans->writer_wait, |
1575 | atomic_read(&cur_trans->num_writers) == 1); | 1587 | atomic_read(&cur_trans->num_writers) == 1); |
1576 | 1588 | ||
1589 | /* ->aborted might be set after the previous check, so check it */ | ||
1590 | if (unlikely(ACCESS_ONCE(cur_trans->aborted))) { | ||
1591 | ret = cur_trans->aborted; | ||
1592 | goto cleanup_transaction; | ||
1593 | } | ||
1577 | /* | 1594 | /* |
1578 | * the reloc mutex makes sure that we stop | 1595 | * the reloc mutex makes sure that we stop |
1579 | * the balancing code from coming in and moving | 1596 | * the balancing code from coming in and moving |
@@ -1657,6 +1674,17 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1657 | goto cleanup_transaction; | 1674 | goto cleanup_transaction; |
1658 | } | 1675 | } |
1659 | 1676 | ||
1677 | /* | ||
1678 | * The tasks which save the space cache and inode cache may also | ||
1679 | * update ->aborted, check it. | ||
1680 | */ | ||
1681 | if (unlikely(ACCESS_ONCE(cur_trans->aborted))) { | ||
1682 | ret = cur_trans->aborted; | ||
1683 | mutex_unlock(&root->fs_info->tree_log_mutex); | ||
1684 | mutex_unlock(&root->fs_info->reloc_mutex); | ||
1685 | goto cleanup_transaction; | ||
1686 | } | ||
1687 | |||
1660 | btrfs_prepare_extent_commit(trans, root); | 1688 | btrfs_prepare_extent_commit(trans, root); |
1661 | 1689 | ||
1662 | cur_trans = root->fs_info->running_transaction; | 1690 | cur_trans = root->fs_info->running_transaction; |