diff options
author | Miao Xie <miaox@cn.fujitsu.com> | 2012-11-01 03:32:18 -0400 |
---|---|---|
committer | Josef Bacik <jbacik@fusionio.com> | 2012-12-12 17:15:20 -0500 |
commit | b7d5b0a819498a9c04e1d18201a42468f7edd92a (patch) | |
tree | ac708a897951993954b0e52b33641c4ee19bfa2c /fs/btrfs/inode.c | |
parent | 4fde183d8c755f8a8bdffcb03a8d947e62ccea6a (diff) |
Btrfs: fix joining the same transaction handler more than 2 times
If we flush inodes with pending delalloc in a transaction, we may join
the same transaction handler more than 2 times.
The reason is:
Task use_count of trans handle
commit_transaction 1
|-> btrfs_start_delalloc_inodes 1
|-> run_delalloc_nocow 1
|-> join_transaction 2
|-> cow_file_range 2
|-> join_transaction 3
In fact, cow_file_range needn't join the transaction again because the caller
have joined the transaction, so we fix this problem by this way.
Reported-by: Liu Bo <bo.li.liu@oracle.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 77 |
1 files changed, 47 insertions, 30 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index dce9e218b845..96d20903beeb 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -804,14 +804,14 @@ static u64 get_extent_allocation_hint(struct inode *inode, u64 start, | |||
804 | * required to start IO on it. It may be clean and already done with | 804 | * required to start IO on it. It may be clean and already done with |
805 | * IO when we return. | 805 | * IO when we return. |
806 | */ | 806 | */ |
807 | static noinline int cow_file_range(struct inode *inode, | 807 | static noinline int __cow_file_range(struct btrfs_trans_handle *trans, |
808 | struct page *locked_page, | 808 | struct inode *inode, |
809 | u64 start, u64 end, int *page_started, | 809 | struct btrfs_root *root, |
810 | unsigned long *nr_written, | 810 | struct page *locked_page, |
811 | int unlock) | 811 | u64 start, u64 end, int *page_started, |
812 | unsigned long *nr_written, | ||
813 | int unlock) | ||
812 | { | 814 | { |
813 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
814 | struct btrfs_trans_handle *trans; | ||
815 | u64 alloc_hint = 0; | 815 | u64 alloc_hint = 0; |
816 | u64 num_bytes; | 816 | u64 num_bytes; |
817 | unsigned long ram_size; | 817 | unsigned long ram_size; |
@@ -824,25 +824,10 @@ static noinline int cow_file_range(struct inode *inode, | |||
824 | int ret = 0; | 824 | int ret = 0; |
825 | 825 | ||
826 | BUG_ON(btrfs_is_free_space_inode(inode)); | 826 | BUG_ON(btrfs_is_free_space_inode(inode)); |
827 | trans = btrfs_join_transaction(root); | ||
828 | if (IS_ERR(trans)) { | ||
829 | extent_clear_unlock_delalloc(inode, | ||
830 | &BTRFS_I(inode)->io_tree, | ||
831 | start, end, locked_page, | ||
832 | EXTENT_CLEAR_UNLOCK_PAGE | | ||
833 | EXTENT_CLEAR_UNLOCK | | ||
834 | EXTENT_CLEAR_DELALLOC | | ||
835 | EXTENT_CLEAR_DIRTY | | ||
836 | EXTENT_SET_WRITEBACK | | ||
837 | EXTENT_END_WRITEBACK); | ||
838 | return PTR_ERR(trans); | ||
839 | } | ||
840 | trans->block_rsv = &root->fs_info->delalloc_block_rsv; | ||
841 | 827 | ||
842 | num_bytes = (end - start + blocksize) & ~(blocksize - 1); | 828 | num_bytes = (end - start + blocksize) & ~(blocksize - 1); |
843 | num_bytes = max(blocksize, num_bytes); | 829 | num_bytes = max(blocksize, num_bytes); |
844 | disk_num_bytes = num_bytes; | 830 | disk_num_bytes = num_bytes; |
845 | ret = 0; | ||
846 | 831 | ||
847 | /* if this is a small write inside eof, kick off defrag */ | 832 | /* if this is a small write inside eof, kick off defrag */ |
848 | if (num_bytes < 64 * 1024 && | 833 | if (num_bytes < 64 * 1024 && |
@@ -953,11 +938,9 @@ static noinline int cow_file_range(struct inode *inode, | |||
953 | alloc_hint = ins.objectid + ins.offset; | 938 | alloc_hint = ins.objectid + ins.offset; |
954 | start += cur_alloc_size; | 939 | start += cur_alloc_size; |
955 | } | 940 | } |
956 | ret = 0; | ||
957 | out: | 941 | out: |
958 | btrfs_end_transaction(trans, root); | ||
959 | |||
960 | return ret; | 942 | return ret; |
943 | |||
961 | out_unlock: | 944 | out_unlock: |
962 | extent_clear_unlock_delalloc(inode, | 945 | extent_clear_unlock_delalloc(inode, |
963 | &BTRFS_I(inode)->io_tree, | 946 | &BTRFS_I(inode)->io_tree, |
@@ -972,6 +955,39 @@ out_unlock: | |||
972 | goto out; | 955 | goto out; |
973 | } | 956 | } |
974 | 957 | ||
958 | static noinline int cow_file_range(struct inode *inode, | ||
959 | struct page *locked_page, | ||
960 | u64 start, u64 end, int *page_started, | ||
961 | unsigned long *nr_written, | ||
962 | int unlock) | ||
963 | { | ||
964 | struct btrfs_trans_handle *trans; | ||
965 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
966 | int ret; | ||
967 | |||
968 | trans = btrfs_join_transaction(root); | ||
969 | if (IS_ERR(trans)) { | ||
970 | extent_clear_unlock_delalloc(inode, | ||
971 | &BTRFS_I(inode)->io_tree, | ||
972 | start, end, locked_page, | ||
973 | EXTENT_CLEAR_UNLOCK_PAGE | | ||
974 | EXTENT_CLEAR_UNLOCK | | ||
975 | EXTENT_CLEAR_DELALLOC | | ||
976 | EXTENT_CLEAR_DIRTY | | ||
977 | EXTENT_SET_WRITEBACK | | ||
978 | EXTENT_END_WRITEBACK); | ||
979 | return PTR_ERR(trans); | ||
980 | } | ||
981 | trans->block_rsv = &root->fs_info->delalloc_block_rsv; | ||
982 | |||
983 | ret = __cow_file_range(trans, inode, root, locked_page, start, end, | ||
984 | page_started, nr_written, unlock); | ||
985 | |||
986 | btrfs_end_transaction(trans, root); | ||
987 | |||
988 | return ret; | ||
989 | } | ||
990 | |||
975 | /* | 991 | /* |
976 | * work queue call back to started compression on a file and pages | 992 | * work queue call back to started compression on a file and pages |
977 | */ | 993 | */ |
@@ -1282,9 +1298,9 @@ out_check: | |||
1282 | 1298 | ||
1283 | btrfs_release_path(path); | 1299 | btrfs_release_path(path); |
1284 | if (cow_start != (u64)-1) { | 1300 | if (cow_start != (u64)-1) { |
1285 | ret = cow_file_range(inode, locked_page, cow_start, | 1301 | ret = __cow_file_range(trans, inode, root, locked_page, |
1286 | found_key.offset - 1, page_started, | 1302 | cow_start, found_key.offset - 1, |
1287 | nr_written, 1); | 1303 | page_started, nr_written, 1); |
1288 | if (ret) { | 1304 | if (ret) { |
1289 | btrfs_abort_transaction(trans, root, ret); | 1305 | btrfs_abort_transaction(trans, root, ret); |
1290 | goto error; | 1306 | goto error; |
@@ -1353,8 +1369,9 @@ out_check: | |||
1353 | } | 1369 | } |
1354 | 1370 | ||
1355 | if (cow_start != (u64)-1) { | 1371 | if (cow_start != (u64)-1) { |
1356 | ret = cow_file_range(inode, locked_page, cow_start, end, | 1372 | ret = __cow_file_range(trans, inode, root, locked_page, |
1357 | page_started, nr_written, 1); | 1373 | cow_start, end, |
1374 | page_started, nr_written, 1); | ||
1358 | if (ret) { | 1375 | if (ret) { |
1359 | btrfs_abort_transaction(trans, root, ret); | 1376 | btrfs_abort_transaction(trans, root, ret); |
1360 | goto error; | 1377 | goto error; |