aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2012-11-01 03:32:18 -0400
committerJosef Bacik <jbacik@fusionio.com>2012-12-12 17:15:20 -0500
commitb7d5b0a819498a9c04e1d18201a42468f7edd92a (patch)
treeac708a897951993954b0e52b33641c4ee19bfa2c /fs/btrfs/inode.c
parent4fde183d8c755f8a8bdffcb03a8d947e62ccea6a (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.c77
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 */
807static noinline int cow_file_range(struct inode *inode, 807static 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;
957out: 941out:
958 btrfs_end_transaction(trans, root);
959
960 return ret; 942 return ret;
943
961out_unlock: 944out_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
958static 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;