diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 70 |
1 files changed, 58 insertions, 12 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 2616491a5c5b..6217bb6d516a 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -321,10 +321,36 @@ void btrfs_throttle(struct btrfs_root *root) | |||
321 | mutex_unlock(&root->fs_info->trans_mutex); | 321 | mutex_unlock(&root->fs_info->trans_mutex); |
322 | } | 322 | } |
323 | 323 | ||
324 | static int should_end_transaction(struct btrfs_trans_handle *trans, | ||
325 | struct btrfs_root *root) | ||
326 | { | ||
327 | int ret; | ||
328 | ret = btrfs_block_rsv_check(trans, root, | ||
329 | &root->fs_info->global_block_rsv, 0, 5); | ||
330 | return ret ? 1 : 0; | ||
331 | } | ||
332 | |||
333 | int btrfs_should_end_transaction(struct btrfs_trans_handle *trans, | ||
334 | struct btrfs_root *root) | ||
335 | { | ||
336 | struct btrfs_transaction *cur_trans = trans->transaction; | ||
337 | int updates; | ||
338 | |||
339 | if (cur_trans->blocked || cur_trans->delayed_refs.flushing) | ||
340 | return 1; | ||
341 | |||
342 | updates = trans->delayed_ref_updates; | ||
343 | trans->delayed_ref_updates = 0; | ||
344 | if (updates) | ||
345 | btrfs_run_delayed_refs(trans, root, updates); | ||
346 | |||
347 | return should_end_transaction(trans, root); | ||
348 | } | ||
349 | |||
324 | static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | 350 | static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, |
325 | struct btrfs_root *root, int throttle) | 351 | struct btrfs_root *root, int throttle) |
326 | { | 352 | { |
327 | struct btrfs_transaction *cur_trans; | 353 | struct btrfs_transaction *cur_trans = trans->transaction; |
328 | struct btrfs_fs_info *info = root->fs_info; | 354 | struct btrfs_fs_info *info = root->fs_info; |
329 | int count = 0; | 355 | int count = 0; |
330 | 356 | ||
@@ -350,9 +376,19 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
350 | 376 | ||
351 | btrfs_trans_release_metadata(trans, root); | 377 | btrfs_trans_release_metadata(trans, root); |
352 | 378 | ||
379 | if (!root->fs_info->open_ioctl_trans && | ||
380 | should_end_transaction(trans, root)) | ||
381 | trans->transaction->blocked = 1; | ||
382 | |||
383 | if (cur_trans->blocked && !cur_trans->in_commit) { | ||
384 | if (throttle) | ||
385 | return btrfs_commit_transaction(trans, root); | ||
386 | else | ||
387 | wake_up_process(info->transaction_kthread); | ||
388 | } | ||
389 | |||
353 | mutex_lock(&info->trans_mutex); | 390 | mutex_lock(&info->trans_mutex); |
354 | cur_trans = info->running_transaction; | 391 | WARN_ON(cur_trans != info->running_transaction); |
355 | WARN_ON(cur_trans != trans->transaction); | ||
356 | WARN_ON(cur_trans->num_writers < 1); | 392 | WARN_ON(cur_trans->num_writers < 1); |
357 | cur_trans->num_writers--; | 393 | cur_trans->num_writers--; |
358 | 394 | ||
@@ -664,30 +700,30 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans, | |||
664 | int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) | 700 | int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) |
665 | { | 701 | { |
666 | struct btrfs_fs_info *info = root->fs_info; | 702 | struct btrfs_fs_info *info = root->fs_info; |
667 | int ret; | ||
668 | struct btrfs_trans_handle *trans; | 703 | struct btrfs_trans_handle *trans; |
704 | int ret; | ||
669 | unsigned long nr; | 705 | unsigned long nr; |
670 | 706 | ||
671 | smp_mb(); | 707 | if (xchg(&root->defrag_running, 1)) |
672 | if (root->defrag_running) | ||
673 | return 0; | 708 | return 0; |
674 | trans = btrfs_start_transaction(root, 1); | 709 | |
675 | while (1) { | 710 | while (1) { |
676 | root->defrag_running = 1; | 711 | trans = btrfs_start_transaction(root, 0); |
712 | if (IS_ERR(trans)) | ||
713 | return PTR_ERR(trans); | ||
714 | |||
677 | ret = btrfs_defrag_leaves(trans, root, cacheonly); | 715 | ret = btrfs_defrag_leaves(trans, root, cacheonly); |
716 | |||
678 | nr = trans->blocks_used; | 717 | nr = trans->blocks_used; |
679 | btrfs_end_transaction(trans, root); | 718 | btrfs_end_transaction(trans, root); |
680 | btrfs_btree_balance_dirty(info->tree_root, nr); | 719 | btrfs_btree_balance_dirty(info->tree_root, nr); |
681 | cond_resched(); | 720 | cond_resched(); |
682 | 721 | ||
683 | trans = btrfs_start_transaction(root, 1); | ||
684 | if (root->fs_info->closing || ret != -EAGAIN) | 722 | if (root->fs_info->closing || ret != -EAGAIN) |
685 | break; | 723 | break; |
686 | } | 724 | } |
687 | root->defrag_running = 0; | 725 | root->defrag_running = 0; |
688 | smp_mb(); | 726 | return ret; |
689 | btrfs_end_transaction(trans, root); | ||
690 | return 0; | ||
691 | } | 727 | } |
692 | 728 | ||
693 | #if 0 | 729 | #if 0 |
@@ -924,6 +960,16 @@ int btrfs_transaction_in_commit(struct btrfs_fs_info *info) | |||
924 | return ret; | 960 | return ret; |
925 | } | 961 | } |
926 | 962 | ||
963 | int btrfs_transaction_blocked(struct btrfs_fs_info *info) | ||
964 | { | ||
965 | int ret = 0; | ||
966 | spin_lock(&info->new_trans_lock); | ||
967 | if (info->running_transaction) | ||
968 | ret = info->running_transaction->blocked; | ||
969 | spin_unlock(&info->new_trans_lock); | ||
970 | return ret; | ||
971 | } | ||
972 | |||
927 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | 973 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, |
928 | struct btrfs_root *root) | 974 | struct btrfs_root *root) |
929 | { | 975 | { |