diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
| -rw-r--r-- | fs/btrfs/transaction.c | 160 |
1 files changed, 70 insertions, 90 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 7dc36fab4afc..81376d94cd3c 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
| @@ -55,6 +55,7 @@ static noinline int join_transaction(struct btrfs_root *root, int nofail) | |||
| 55 | struct btrfs_transaction *cur_trans; | 55 | struct btrfs_transaction *cur_trans; |
| 56 | 56 | ||
| 57 | spin_lock(&root->fs_info->trans_lock); | 57 | spin_lock(&root->fs_info->trans_lock); |
| 58 | loop: | ||
| 58 | if (root->fs_info->trans_no_join) { | 59 | if (root->fs_info->trans_no_join) { |
| 59 | if (!nofail) { | 60 | if (!nofail) { |
| 60 | spin_unlock(&root->fs_info->trans_lock); | 61 | spin_unlock(&root->fs_info->trans_lock); |
| @@ -75,16 +76,18 @@ static noinline int join_transaction(struct btrfs_root *root, int nofail) | |||
| 75 | cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS); | 76 | cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS); |
| 76 | if (!cur_trans) | 77 | if (!cur_trans) |
| 77 | return -ENOMEM; | 78 | return -ENOMEM; |
| 79 | |||
| 78 | spin_lock(&root->fs_info->trans_lock); | 80 | spin_lock(&root->fs_info->trans_lock); |
| 79 | if (root->fs_info->running_transaction) { | 81 | if (root->fs_info->running_transaction) { |
| 82 | /* | ||
| 83 | * someone started a transaction after we unlocked. Make sure | ||
| 84 | * to redo the trans_no_join checks above | ||
| 85 | */ | ||
| 80 | kmem_cache_free(btrfs_transaction_cachep, cur_trans); | 86 | kmem_cache_free(btrfs_transaction_cachep, cur_trans); |
| 81 | cur_trans = root->fs_info->running_transaction; | 87 | cur_trans = root->fs_info->running_transaction; |
| 82 | atomic_inc(&cur_trans->use_count); | 88 | goto loop; |
| 83 | atomic_inc(&cur_trans->num_writers); | ||
| 84 | cur_trans->num_joined++; | ||
| 85 | spin_unlock(&root->fs_info->trans_lock); | ||
| 86 | return 0; | ||
| 87 | } | 89 | } |
| 90 | |||
| 88 | atomic_set(&cur_trans->num_writers, 1); | 91 | atomic_set(&cur_trans->num_writers, 1); |
| 89 | cur_trans->num_joined = 0; | 92 | cur_trans->num_joined = 0; |
| 90 | init_waitqueue_head(&cur_trans->writer_wait); | 93 | init_waitqueue_head(&cur_trans->writer_wait); |
| @@ -275,7 +278,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, | |||
| 275 | */ | 278 | */ |
| 276 | if (num_items > 0 && root != root->fs_info->chunk_root) { | 279 | if (num_items > 0 && root != root->fs_info->chunk_root) { |
| 277 | num_bytes = btrfs_calc_trans_metadata_size(root, num_items); | 280 | num_bytes = btrfs_calc_trans_metadata_size(root, num_items); |
| 278 | ret = btrfs_block_rsv_add(NULL, root, | 281 | ret = btrfs_block_rsv_add(root, |
| 279 | &root->fs_info->trans_block_rsv, | 282 | &root->fs_info->trans_block_rsv, |
| 280 | num_bytes); | 283 | num_bytes); |
| 281 | if (ret) | 284 | if (ret) |
| @@ -418,8 +421,8 @@ static int should_end_transaction(struct btrfs_trans_handle *trans, | |||
| 418 | struct btrfs_root *root) | 421 | struct btrfs_root *root) |
| 419 | { | 422 | { |
| 420 | int ret; | 423 | int ret; |
| 421 | ret = btrfs_block_rsv_check(trans, root, | 424 | |
| 422 | &root->fs_info->global_block_rsv, 0, 5); | 425 | ret = btrfs_block_rsv_check(root, &root->fs_info->global_block_rsv, 5); |
| 423 | return ret ? 1 : 0; | 426 | return ret ? 1 : 0; |
| 424 | } | 427 | } |
| 425 | 428 | ||
| @@ -427,17 +430,26 @@ int btrfs_should_end_transaction(struct btrfs_trans_handle *trans, | |||
| 427 | struct btrfs_root *root) | 430 | struct btrfs_root *root) |
| 428 | { | 431 | { |
| 429 | struct btrfs_transaction *cur_trans = trans->transaction; | 432 | struct btrfs_transaction *cur_trans = trans->transaction; |
| 433 | struct btrfs_block_rsv *rsv = trans->block_rsv; | ||
| 430 | int updates; | 434 | int updates; |
| 431 | 435 | ||
| 432 | smp_mb(); | 436 | smp_mb(); |
| 433 | if (cur_trans->blocked || cur_trans->delayed_refs.flushing) | 437 | if (cur_trans->blocked || cur_trans->delayed_refs.flushing) |
| 434 | return 1; | 438 | return 1; |
| 435 | 439 | ||
| 440 | /* | ||
| 441 | * We need to do this in case we're deleting csums so the global block | ||
| 442 | * rsv get's used instead of the csum block rsv. | ||
| 443 | */ | ||
| 444 | trans->block_rsv = NULL; | ||
| 445 | |||
| 436 | updates = trans->delayed_ref_updates; | 446 | updates = trans->delayed_ref_updates; |
| 437 | trans->delayed_ref_updates = 0; | 447 | trans->delayed_ref_updates = 0; |
| 438 | if (updates) | 448 | if (updates) |
| 439 | btrfs_run_delayed_refs(trans, root, updates); | 449 | btrfs_run_delayed_refs(trans, root, updates); |
| 440 | 450 | ||
| 451 | trans->block_rsv = rsv; | ||
| 452 | |||
| 441 | return should_end_transaction(trans, root); | 453 | return should_end_transaction(trans, root); |
| 442 | } | 454 | } |
| 443 | 455 | ||
| @@ -453,6 +465,8 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
| 453 | return 0; | 465 | return 0; |
| 454 | } | 466 | } |
| 455 | 467 | ||
| 468 | btrfs_trans_release_metadata(trans, root); | ||
| 469 | trans->block_rsv = NULL; | ||
| 456 | while (count < 4) { | 470 | while (count < 4) { |
| 457 | unsigned long cur = trans->delayed_ref_updates; | 471 | unsigned long cur = trans->delayed_ref_updates; |
| 458 | trans->delayed_ref_updates = 0; | 472 | trans->delayed_ref_updates = 0; |
| @@ -473,8 +487,6 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
| 473 | count++; | 487 | count++; |
| 474 | } | 488 | } |
| 475 | 489 | ||
| 476 | btrfs_trans_release_metadata(trans, root); | ||
| 477 | |||
| 478 | if (lock && !atomic_read(&root->fs_info->open_ioctl_trans) && | 490 | if (lock && !atomic_read(&root->fs_info->open_ioctl_trans) && |
| 479 | should_end_transaction(trans, root)) { | 491 | should_end_transaction(trans, root)) { |
| 480 | trans->transaction->blocked = 1; | 492 | trans->transaction->blocked = 1; |
| @@ -562,50 +574,21 @@ int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans, | |||
| 562 | int btrfs_write_marked_extents(struct btrfs_root *root, | 574 | int btrfs_write_marked_extents(struct btrfs_root *root, |
| 563 | struct extent_io_tree *dirty_pages, int mark) | 575 | struct extent_io_tree *dirty_pages, int mark) |
| 564 | { | 576 | { |
| 565 | int ret; | ||
| 566 | int err = 0; | 577 | int err = 0; |
| 567 | int werr = 0; | 578 | int werr = 0; |
| 568 | struct page *page; | 579 | struct address_space *mapping = root->fs_info->btree_inode->i_mapping; |
| 569 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
| 570 | u64 start = 0; | 580 | u64 start = 0; |
| 571 | u64 end; | 581 | u64 end; |
| 572 | unsigned long index; | ||
| 573 | |||
| 574 | while (1) { | ||
| 575 | ret = find_first_extent_bit(dirty_pages, start, &start, &end, | ||
| 576 | mark); | ||
| 577 | if (ret) | ||
| 578 | break; | ||
| 579 | while (start <= end) { | ||
| 580 | cond_resched(); | ||
| 581 | |||
| 582 | index = start >> PAGE_CACHE_SHIFT; | ||
| 583 | start = (u64)(index + 1) << PAGE_CACHE_SHIFT; | ||
| 584 | page = find_get_page(btree_inode->i_mapping, index); | ||
| 585 | if (!page) | ||
| 586 | continue; | ||
| 587 | |||
| 588 | btree_lock_page_hook(page); | ||
| 589 | if (!page->mapping) { | ||
| 590 | unlock_page(page); | ||
| 591 | page_cache_release(page); | ||
| 592 | continue; | ||
| 593 | } | ||
| 594 | 582 | ||
| 595 | if (PageWriteback(page)) { | 583 | while (!find_first_extent_bit(dirty_pages, start, &start, &end, |
| 596 | if (PageDirty(page)) | 584 | mark)) { |
| 597 | wait_on_page_writeback(page); | 585 | convert_extent_bit(dirty_pages, start, end, EXTENT_NEED_WAIT, mark, |
| 598 | else { | 586 | GFP_NOFS); |
| 599 | unlock_page(page); | 587 | err = filemap_fdatawrite_range(mapping, start, end); |
| 600 | page_cache_release(page); | 588 | if (err) |
| 601 | continue; | 589 | werr = err; |
| 602 | } | 590 | cond_resched(); |
| 603 | } | 591 | start = end + 1; |
| 604 | err = write_one_page(page, 0); | ||
| 605 | if (err) | ||
| 606 | werr = err; | ||
| 607 | page_cache_release(page); | ||
| 608 | } | ||
| 609 | } | 592 | } |
| 610 | if (err) | 593 | if (err) |
| 611 | werr = err; | 594 | werr = err; |
| @@ -621,39 +604,20 @@ int btrfs_write_marked_extents(struct btrfs_root *root, | |||
| 621 | int btrfs_wait_marked_extents(struct btrfs_root *root, | 604 | int btrfs_wait_marked_extents(struct btrfs_root *root, |
| 622 | struct extent_io_tree *dirty_pages, int mark) | 605 | struct extent_io_tree *dirty_pages, int mark) |
| 623 | { | 606 | { |
| 624 | int ret; | ||
| 625 | int err = 0; | 607 | int err = 0; |
| 626 | int werr = 0; | 608 | int werr = 0; |
| 627 | struct page *page; | 609 | struct address_space *mapping = root->fs_info->btree_inode->i_mapping; |
| 628 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
| 629 | u64 start = 0; | 610 | u64 start = 0; |
| 630 | u64 end; | 611 | u64 end; |
| 631 | unsigned long index; | ||
| 632 | |||
| 633 | while (1) { | ||
| 634 | ret = find_first_extent_bit(dirty_pages, start, &start, &end, | ||
| 635 | mark); | ||
| 636 | if (ret) | ||
| 637 | break; | ||
| 638 | 612 | ||
| 639 | clear_extent_bits(dirty_pages, start, end, mark, GFP_NOFS); | 613 | while (!find_first_extent_bit(dirty_pages, start, &start, &end, |
| 640 | while (start <= end) { | 614 | EXTENT_NEED_WAIT)) { |
| 641 | index = start >> PAGE_CACHE_SHIFT; | 615 | clear_extent_bits(dirty_pages, start, end, EXTENT_NEED_WAIT, GFP_NOFS); |
| 642 | start = (u64)(index + 1) << PAGE_CACHE_SHIFT; | 616 | err = filemap_fdatawait_range(mapping, start, end); |
| 643 | page = find_get_page(btree_inode->i_mapping, index); | 617 | if (err) |
| 644 | if (!page) | 618 | werr = err; |
| 645 | continue; | 619 | cond_resched(); |
| 646 | if (PageDirty(page)) { | 620 | start = end + 1; |
| 647 | btree_lock_page_hook(page); | ||
| 648 | wait_on_page_writeback(page); | ||
| 649 | err = write_one_page(page, 0); | ||
| 650 | if (err) | ||
| 651 | werr = err; | ||
| 652 | } | ||
| 653 | wait_on_page_writeback(page); | ||
| 654 | page_cache_release(page); | ||
| 655 | cond_resched(); | ||
| 656 | } | ||
| 657 | } | 621 | } |
| 658 | if (err) | 622 | if (err) |
| 659 | werr = err; | 623 | werr = err; |
| @@ -673,7 +637,12 @@ int btrfs_write_and_wait_marked_extents(struct btrfs_root *root, | |||
| 673 | 637 | ||
| 674 | ret = btrfs_write_marked_extents(root, dirty_pages, mark); | 638 | ret = btrfs_write_marked_extents(root, dirty_pages, mark); |
| 675 | ret2 = btrfs_wait_marked_extents(root, dirty_pages, mark); | 639 | ret2 = btrfs_wait_marked_extents(root, dirty_pages, mark); |
| 676 | return ret || ret2; | 640 | |
| 641 | if (ret) | ||
| 642 | return ret; | ||
| 643 | if (ret2) | ||
| 644 | return ret2; | ||
| 645 | return 0; | ||
| 677 | } | 646 | } |
| 678 | 647 | ||
| 679 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, | 648 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, |
| @@ -816,6 +785,10 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans, | |||
| 816 | 785 | ||
| 817 | btrfs_save_ino_cache(root, trans); | 786 | btrfs_save_ino_cache(root, trans); |
| 818 | 787 | ||
| 788 | /* see comments in should_cow_block() */ | ||
| 789 | root->force_cow = 0; | ||
| 790 | smp_wmb(); | ||
| 791 | |||
| 819 | if (root->commit_root != root->node) { | 792 | if (root->commit_root != root->node) { |
| 820 | mutex_lock(&root->fs_commit_mutex); | 793 | mutex_lock(&root->fs_commit_mutex); |
| 821 | switch_commit_root(root); | 794 | switch_commit_root(root); |
| @@ -884,6 +857,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 884 | struct btrfs_root *tree_root = fs_info->tree_root; | 857 | struct btrfs_root *tree_root = fs_info->tree_root; |
| 885 | struct btrfs_root *root = pending->root; | 858 | struct btrfs_root *root = pending->root; |
| 886 | struct btrfs_root *parent_root; | 859 | struct btrfs_root *parent_root; |
| 860 | struct btrfs_block_rsv *rsv; | ||
| 887 | struct inode *parent_inode; | 861 | struct inode *parent_inode; |
| 888 | struct dentry *parent; | 862 | struct dentry *parent; |
| 889 | struct dentry *dentry; | 863 | struct dentry *dentry; |
| @@ -895,6 +869,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 895 | u64 objectid; | 869 | u64 objectid; |
| 896 | u64 root_flags; | 870 | u64 root_flags; |
| 897 | 871 | ||
| 872 | rsv = trans->block_rsv; | ||
| 873 | |||
| 898 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 874 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); |
| 899 | if (!new_root_item) { | 875 | if (!new_root_item) { |
| 900 | pending->error = -ENOMEM; | 876 | pending->error = -ENOMEM; |
| @@ -908,11 +884,10 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 908 | } | 884 | } |
| 909 | 885 | ||
| 910 | btrfs_reloc_pre_snapshot(trans, pending, &to_reserve); | 886 | btrfs_reloc_pre_snapshot(trans, pending, &to_reserve); |
| 911 | btrfs_orphan_pre_snapshot(trans, pending, &to_reserve); | ||
| 912 | 887 | ||
| 913 | if (to_reserve > 0) { | 888 | if (to_reserve > 0) { |
| 914 | ret = btrfs_block_rsv_add(trans, root, &pending->block_rsv, | 889 | ret = btrfs_block_rsv_add_noflush(root, &pending->block_rsv, |
| 915 | to_reserve); | 890 | to_reserve); |
| 916 | if (ret) { | 891 | if (ret) { |
| 917 | pending->error = ret; | 892 | pending->error = ret; |
| 918 | goto fail; | 893 | goto fail; |
| @@ -976,6 +951,10 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 976 | btrfs_tree_unlock(old); | 951 | btrfs_tree_unlock(old); |
| 977 | free_extent_buffer(old); | 952 | free_extent_buffer(old); |
| 978 | 953 | ||
| 954 | /* see comments in should_cow_block() */ | ||
| 955 | root->force_cow = 1; | ||
| 956 | smp_wmb(); | ||
| 957 | |||
| 979 | btrfs_set_root_node(new_root_item, tmp); | 958 | btrfs_set_root_node(new_root_item, tmp); |
| 980 | /* record when the snapshot was created in key.offset */ | 959 | /* record when the snapshot was created in key.offset */ |
| 981 | key.offset = trans->transid; | 960 | key.offset = trans->transid; |
| @@ -999,9 +978,9 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 999 | BUG_ON(IS_ERR(pending->snap)); | 978 | BUG_ON(IS_ERR(pending->snap)); |
| 1000 | 979 | ||
| 1001 | btrfs_reloc_post_snapshot(trans, pending); | 980 | btrfs_reloc_post_snapshot(trans, pending); |
| 1002 | btrfs_orphan_post_snapshot(trans, pending); | ||
| 1003 | fail: | 981 | fail: |
| 1004 | kfree(new_root_item); | 982 | kfree(new_root_item); |
| 983 | trans->block_rsv = rsv; | ||
| 1005 | btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1); | 984 | btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1); |
| 1006 | return 0; | 985 | return 0; |
| 1007 | } | 986 | } |
| @@ -1028,7 +1007,7 @@ static void update_super_roots(struct btrfs_root *root) | |||
| 1028 | struct btrfs_root_item *root_item; | 1007 | struct btrfs_root_item *root_item; |
| 1029 | struct btrfs_super_block *super; | 1008 | struct btrfs_super_block *super; |
| 1030 | 1009 | ||
| 1031 | super = &root->fs_info->super_copy; | 1010 | super = root->fs_info->super_copy; |
| 1032 | 1011 | ||
| 1033 | root_item = &root->fs_info->chunk_root->root_item; | 1012 | root_item = &root->fs_info->chunk_root->root_item; |
| 1034 | super->chunk_root = root_item->bytenr; | 1013 | super->chunk_root = root_item->bytenr; |
| @@ -1039,7 +1018,7 @@ static void update_super_roots(struct btrfs_root *root) | |||
| 1039 | super->root = root_item->bytenr; | 1018 | super->root = root_item->bytenr; |
| 1040 | super->generation = root_item->generation; | 1019 | super->generation = root_item->generation; |
| 1041 | super->root_level = root_item->level; | 1020 | super->root_level = root_item->level; |
| 1042 | if (super->cache_generation != 0 || btrfs_test_opt(root, SPACE_CACHE)) | 1021 | if (btrfs_test_opt(root, SPACE_CACHE)) |
| 1043 | super->cache_generation = root_item->generation; | 1022 | super->cache_generation = root_item->generation; |
| 1044 | } | 1023 | } |
| 1045 | 1024 | ||
| @@ -1164,14 +1143,15 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 1164 | 1143 | ||
| 1165 | btrfs_run_ordered_operations(root, 0); | 1144 | btrfs_run_ordered_operations(root, 0); |
| 1166 | 1145 | ||
| 1146 | btrfs_trans_release_metadata(trans, root); | ||
| 1147 | trans->block_rsv = NULL; | ||
| 1148 | |||
| 1167 | /* make a pass through all the delayed refs we have so far | 1149 | /* make a pass through all the delayed refs we have so far |
| 1168 | * any runnings procs may add more while we are here | 1150 | * any runnings procs may add more while we are here |
| 1169 | */ | 1151 | */ |
| 1170 | ret = btrfs_run_delayed_refs(trans, root, 0); | 1152 | ret = btrfs_run_delayed_refs(trans, root, 0); |
| 1171 | BUG_ON(ret); | 1153 | BUG_ON(ret); |
| 1172 | 1154 | ||
| 1173 | btrfs_trans_release_metadata(trans, root); | ||
| 1174 | |||
| 1175 | cur_trans = trans->transaction; | 1155 | cur_trans = trans->transaction; |
| 1176 | /* | 1156 | /* |
| 1177 | * set the flushing flag so procs in this transaction have to | 1157 | * set the flushing flag so procs in this transaction have to |
| @@ -1337,12 +1317,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 1337 | update_super_roots(root); | 1317 | update_super_roots(root); |
| 1338 | 1318 | ||
| 1339 | if (!root->fs_info->log_root_recovering) { | 1319 | if (!root->fs_info->log_root_recovering) { |
| 1340 | btrfs_set_super_log_root(&root->fs_info->super_copy, 0); | 1320 | btrfs_set_super_log_root(root->fs_info->super_copy, 0); |
| 1341 | btrfs_set_super_log_root_level(&root->fs_info->super_copy, 0); | 1321 | btrfs_set_super_log_root_level(root->fs_info->super_copy, 0); |
| 1342 | } | 1322 | } |
| 1343 | 1323 | ||
| 1344 | memcpy(&root->fs_info->super_for_commit, &root->fs_info->super_copy, | 1324 | memcpy(root->fs_info->super_for_commit, root->fs_info->super_copy, |
| 1345 | sizeof(root->fs_info->super_copy)); | 1325 | sizeof(*root->fs_info->super_copy)); |
| 1346 | 1326 | ||
| 1347 | trans->transaction->blocked = 0; | 1327 | trans->transaction->blocked = 0; |
| 1348 | spin_lock(&root->fs_info->trans_lock); | 1328 | spin_lock(&root->fs_info->trans_lock); |
