diff options
| -rw-r--r-- | fs/btrfs/ctree.c | 13 | ||||
| -rw-r--r-- | fs/btrfs/ctree.h | 12 | ||||
| -rw-r--r-- | fs/btrfs/disk-io.c | 22 | ||||
| -rw-r--r-- | fs/btrfs/disk-io.h | 1 | ||||
| -rw-r--r-- | fs/btrfs/extent-tree.c | 37 | ||||
| -rw-r--r-- | fs/btrfs/file.c | 15 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 6 | ||||
| -rw-r--r-- | fs/btrfs/transaction.c | 54 |
8 files changed, 112 insertions, 48 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 606a19b5916d..9eb646529edc 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
| @@ -75,6 +75,17 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root | |||
| 75 | struct btrfs_node *cow_node; | 75 | struct btrfs_node *cow_node; |
| 76 | int ret; | 76 | int ret; |
| 77 | 77 | ||
| 78 | WARN_ON(!buffer_uptodate(buf)); | ||
| 79 | if (trans->transaction != root->fs_info->running_transaction) { | ||
| 80 | printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid, | ||
| 81 | root->fs_info->running_transaction->transid); | ||
| 82 | WARN_ON(1); | ||
| 83 | } | ||
| 84 | if (trans->transid != root->fs_info->generation) { | ||
| 85 | printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid, | ||
| 86 | root->fs_info->generation); | ||
| 87 | WARN_ON(1); | ||
| 88 | } | ||
| 78 | if (btrfs_header_generation(btrfs_buffer_header(buf)) == | 89 | if (btrfs_header_generation(btrfs_buffer_header(buf)) == |
| 79 | trans->transid) { | 90 | trans->transid) { |
| 80 | *cow_ret = buf; | 91 | *cow_ret = buf; |
| @@ -107,7 +118,7 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root | |||
| 107 | btrfs_free_extent(trans, root, bh_blocknr(buf), 1, 1); | 118 | btrfs_free_extent(trans, root, bh_blocknr(buf), 1, 1); |
| 108 | } | 119 | } |
| 109 | btrfs_block_release(root, buf); | 120 | btrfs_block_release(root, buf); |
| 110 | mark_buffer_dirty(cow); | 121 | btrfs_mark_buffer_dirty(cow); |
| 111 | *cow_ret = cow; | 122 | *cow_ret = cow; |
| 112 | return 0; | 123 | return 0; |
| 113 | } | 124 | } |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 1998f86df08a..0287bd51d87c 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -1013,18 +1013,13 @@ static inline void btrfs_memmove(struct btrfs_root *root, | |||
| 1013 | memmove(dst, src, nr); | 1013 | memmove(dst, src, nr); |
| 1014 | } | 1014 | } |
| 1015 | 1015 | ||
| 1016 | static inline void btrfs_mark_buffer_dirty(struct buffer_head *bh) | ||
| 1017 | { | ||
| 1018 | WARN_ON(!atomic_read(&bh->b_count)); | ||
| 1019 | mark_buffer_dirty(bh); | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | /* helper function to cast into the data area of the leaf. */ | 1016 | /* helper function to cast into the data area of the leaf. */ |
| 1023 | #define btrfs_item_ptr(leaf, slot, type) \ | 1017 | #define btrfs_item_ptr(leaf, slot, type) \ |
| 1024 | ((type *)(btrfs_leaf_data(leaf) + \ | 1018 | ((type *)(btrfs_leaf_data(leaf) + \ |
| 1025 | btrfs_item_offset((leaf)->items + (slot)))) | 1019 | btrfs_item_offset((leaf)->items + (slot)))) |
| 1026 | 1020 | ||
| 1027 | /* extent-tree.c */ | 1021 | /* extent-tree.c */ |
| 1022 | int btrfs_copy_pinned(struct btrfs_root *root, struct radix_tree_root *copy); | ||
| 1028 | struct btrfs_block_group_cache *btrfs_lookup_block_group(struct | 1023 | struct btrfs_block_group_cache *btrfs_lookup_block_group(struct |
| 1029 | btrfs_fs_info *info, | 1024 | btrfs_fs_info *info, |
| 1030 | u64 blocknr); | 1025 | u64 blocknr); |
| @@ -1044,8 +1039,9 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
| 1044 | struct buffer_head *buf); | 1039 | struct buffer_head *buf); |
| 1045 | int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | 1040 | int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root |
| 1046 | *root, u64 blocknr, u64 num_blocks, int pin); | 1041 | *root, u64 blocknr, u64 num_blocks, int pin); |
| 1047 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | 1042 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, |
| 1048 | btrfs_root *root); | 1043 | struct btrfs_root *root, |
| 1044 | struct radix_tree_root *unpin_radix); | ||
| 1049 | int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, | 1045 | int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, |
| 1050 | struct btrfs_root *root, | 1046 | struct btrfs_root *root, |
| 1051 | u64 blocknr, u64 num_blocks); | 1047 | u64 blocknr, u64 num_blocks); |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 7081729d5b16..d1bf5bc1bc14 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -270,14 +270,6 @@ fail: | |||
| 270 | return NULL; | 270 | return NULL; |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||
| 274 | struct buffer_head *buf) | ||
| 275 | { | ||
| 276 | WARN_ON(atomic_read(&buf->b_count) == 0); | ||
| 277 | mark_buffer_dirty(buf); | ||
| 278 | return 0; | ||
| 279 | } | ||
| 280 | |||
| 281 | int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 273 | int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, |
| 282 | struct buffer_head *buf) | 274 | struct buffer_head *buf) |
| 283 | { | 275 | { |
| @@ -621,6 +613,20 @@ int close_ctree(struct btrfs_root *root) | |||
| 621 | return 0; | 613 | return 0; |
| 622 | } | 614 | } |
| 623 | 615 | ||
| 616 | void btrfs_mark_buffer_dirty(struct buffer_head *bh) | ||
| 617 | { | ||
| 618 | struct btrfs_root *root = BTRFS_I(bh->b_page->mapping->host)->root; | ||
| 619 | u64 transid = btrfs_header_generation(btrfs_buffer_header(bh)); | ||
| 620 | WARN_ON(!atomic_read(&bh->b_count)); | ||
| 621 | if (transid != root->fs_info->generation) { | ||
| 622 | printk(KERN_CRIT "transid mismatch buffer %llu, found %Lu running %Lu\n", | ||
| 623 | (unsigned long long)bh->b_blocknr, | ||
| 624 | transid, root->fs_info->generation); | ||
| 625 | WARN_ON(1); | ||
| 626 | } | ||
| 627 | mark_buffer_dirty(bh); | ||
| 628 | } | ||
| 629 | |||
| 624 | void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf) | 630 | void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf) |
| 625 | { | 631 | { |
| 626 | brelse(buf); | 632 | brelse(buf); |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index c4a695ac44f6..9e2c261b41ae 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
| @@ -78,4 +78,5 @@ int btrfs_map_bh_to_logical(struct btrfs_root *root, struct buffer_head *bh, | |||
| 78 | int btrfs_releasepage(struct page *page, gfp_t flags); | 78 | int btrfs_releasepage(struct page *page, gfp_t flags); |
| 79 | void btrfs_btree_balance_dirty(struct btrfs_root *root); | 79 | void btrfs_btree_balance_dirty(struct btrfs_root *root); |
| 80 | int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root); | 80 | int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root); |
| 81 | void btrfs_mark_buffer_dirty(struct buffer_head *bh); | ||
| 81 | #endif | 82 | #endif |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 01dc30579287..14b93268920e 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
| @@ -523,6 +523,7 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
| 523 | } | 523 | } |
| 524 | return 0; | 524 | return 0; |
| 525 | fail: | 525 | fail: |
| 526 | WARN_ON(1); | ||
| 526 | for (i =0; i < faili; i++) { | 527 | for (i =0; i < faili; i++) { |
| 527 | if (leaf) { | 528 | if (leaf) { |
| 528 | u64 disk_blocknr; | 529 | u64 disk_blocknr; |
| @@ -572,7 +573,7 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans, | |||
| 572 | bi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], | 573 | bi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], |
| 573 | struct btrfs_block_group_item); | 574 | struct btrfs_block_group_item); |
| 574 | memcpy(bi, &cache->item, sizeof(*bi)); | 575 | memcpy(bi, &cache->item, sizeof(*bi)); |
| 575 | mark_buffer_dirty(path->nodes[0]); | 576 | btrfs_mark_buffer_dirty(path->nodes[0]); |
| 576 | btrfs_release_path(extent_root, path); | 577 | btrfs_release_path(extent_root, path); |
| 577 | fail: | 578 | fail: |
| 578 | finish_current_insert(trans, extent_root); | 579 | finish_current_insert(trans, extent_root); |
| @@ -739,8 +740,30 @@ static int try_remove_page(struct address_space *mapping, unsigned long index) | |||
| 739 | return ret; | 740 | return ret; |
| 740 | } | 741 | } |
| 741 | 742 | ||
| 742 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | 743 | int btrfs_copy_pinned(struct btrfs_root *root, struct radix_tree_root *copy) |
| 743 | btrfs_root *root) | 744 | { |
| 745 | unsigned long gang[8]; | ||
| 746 | u64 last = 0; | ||
| 747 | struct radix_tree_root *pinned_radix = &root->fs_info->pinned_radix; | ||
| 748 | int ret; | ||
| 749 | int i; | ||
| 750 | |||
| 751 | while(1) { | ||
| 752 | ret = find_first_radix_bit(pinned_radix, gang, last, | ||
| 753 | ARRAY_SIZE(gang)); | ||
| 754 | if (!ret) | ||
| 755 | break; | ||
| 756 | for (i = 0 ; i < ret; i++) { | ||
| 757 | set_radix_bit(copy, gang[i]); | ||
| 758 | last = gang[i] + 1; | ||
| 759 | } | ||
| 760 | } | ||
| 761 | return 0; | ||
| 762 | } | ||
| 763 | |||
| 764 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, | ||
| 765 | struct btrfs_root *root, | ||
| 766 | struct radix_tree_root *unpin_radix) | ||
| 744 | { | 767 | { |
| 745 | unsigned long gang[8]; | 768 | unsigned long gang[8]; |
| 746 | struct inode *btree_inode = root->fs_info->btree_inode; | 769 | struct inode *btree_inode = root->fs_info->btree_inode; |
| @@ -752,7 +775,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | |||
| 752 | struct radix_tree_root *extent_radix = &root->fs_info->extent_map_radix; | 775 | struct radix_tree_root *extent_radix = &root->fs_info->extent_map_radix; |
| 753 | 776 | ||
| 754 | while(1) { | 777 | while(1) { |
| 755 | ret = find_first_radix_bit(pinned_radix, gang, 0, | 778 | ret = find_first_radix_bit(unpin_radix, gang, 0, |
| 756 | ARRAY_SIZE(gang)); | 779 | ARRAY_SIZE(gang)); |
| 757 | if (!ret) | 780 | if (!ret) |
| 758 | break; | 781 | break; |
| @@ -760,6 +783,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | |||
| 760 | first = gang[0]; | 783 | first = gang[0]; |
| 761 | for (i = 0; i < ret; i++) { | 784 | for (i = 0; i < ret; i++) { |
| 762 | clear_radix_bit(pinned_radix, gang[i]); | 785 | clear_radix_bit(pinned_radix, gang[i]); |
| 786 | clear_radix_bit(unpin_radix, gang[i]); | ||
| 763 | block_group = btrfs_lookup_block_group(root->fs_info, | 787 | block_group = btrfs_lookup_block_group(root->fs_info, |
| 764 | gang[i]); | 788 | gang[i]); |
| 765 | if (block_group) { | 789 | if (block_group) { |
| @@ -1309,6 +1333,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
| 1309 | if (data) { | 1333 | if (data) { |
| 1310 | ret = find_free_extent(trans, root, 0, 0, | 1334 | ret = find_free_extent(trans, root, 0, 0, |
| 1311 | search_end, 0, &prealloc_key, 0, 0, 0); | 1335 | search_end, 0, &prealloc_key, 0, 0, 0); |
| 1336 | BUG_ON(ret); | ||
| 1312 | if (ret) | 1337 | if (ret) |
| 1313 | return ret; | 1338 | return ret; |
| 1314 | exclude_nr = info->extent_tree_prealloc_nr; | 1339 | exclude_nr = info->extent_tree_prealloc_nr; |
| @@ -1319,6 +1344,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
| 1319 | ret = find_free_extent(trans, root, num_blocks, search_start, | 1344 | ret = find_free_extent(trans, root, num_blocks, search_start, |
| 1320 | search_end, hint_block, ins, | 1345 | search_end, hint_block, ins, |
| 1321 | exclude_start, exclude_nr, data); | 1346 | exclude_start, exclude_nr, data); |
| 1347 | BUG_ON(ret); | ||
| 1322 | if (ret) | 1348 | if (ret) |
| 1323 | return ret; | 1349 | return ret; |
| 1324 | 1350 | ||
| @@ -1334,10 +1360,12 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
| 1334 | if (!data) { | 1360 | if (!data) { |
| 1335 | exclude_start = ins->objectid; | 1361 | exclude_start = ins->objectid; |
| 1336 | exclude_nr = ins->offset; | 1362 | exclude_nr = ins->offset; |
| 1363 | hint_block = exclude_start + exclude_nr; | ||
| 1337 | ret = find_free_extent(trans, root, 0, search_start, | 1364 | ret = find_free_extent(trans, root, 0, search_start, |
| 1338 | search_end, hint_block, | 1365 | search_end, hint_block, |
| 1339 | &prealloc_key, exclude_start, | 1366 | &prealloc_key, exclude_start, |
| 1340 | exclude_nr, 0); | 1367 | exclude_nr, 0); |
| 1368 | BUG_ON(ret); | ||
| 1341 | if (ret) | 1369 | if (ret) |
| 1342 | return ret; | 1370 | return ret; |
| 1343 | } | 1371 | } |
| @@ -1348,6 +1376,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
| 1348 | ret = btrfs_insert_item(trans, extent_root, ins, &extent_item, | 1376 | ret = btrfs_insert_item(trans, extent_root, ins, &extent_item, |
| 1349 | sizeof(extent_item)); | 1377 | sizeof(extent_item)); |
| 1350 | 1378 | ||
| 1379 | BUG_ON(ret); | ||
| 1351 | finish_current_insert(trans, extent_root); | 1380 | finish_current_insert(trans, extent_root); |
| 1352 | pending_ret = del_pending_extents(trans, extent_root); | 1381 | pending_ret = del_pending_extents(trans, extent_root); |
| 1353 | if (ret) { | 1382 | if (ret) { |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index fef7ba1e707f..2456cc3e1cfd 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
| @@ -127,7 +127,7 @@ static int insert_inline_extent(struct btrfs_root *root, struct inode *inode, | |||
| 127 | ptr, kaddr + bh_offset(bh), | 127 | ptr, kaddr + bh_offset(bh), |
| 128 | size); | 128 | size); |
| 129 | kunmap_atomic(kaddr, KM_USER0); | 129 | kunmap_atomic(kaddr, KM_USER0); |
| 130 | mark_buffer_dirty(path->nodes[0]); | 130 | btrfs_mark_buffer_dirty(path->nodes[0]); |
| 131 | fail: | 131 | fail: |
| 132 | btrfs_free_path(path); | 132 | btrfs_free_path(path); |
| 133 | ret = btrfs_end_transaction(trans, root); | 133 | ret = btrfs_end_transaction(trans, root); |
| @@ -211,11 +211,13 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, | |||
| 211 | int found_type; | 211 | int found_type; |
| 212 | int found_extent; | 212 | int found_extent; |
| 213 | int found_inline; | 213 | int found_inline; |
| 214 | int recow; | ||
| 214 | 215 | ||
| 215 | path = btrfs_alloc_path(); | 216 | path = btrfs_alloc_path(); |
| 216 | if (!path) | 217 | if (!path) |
| 217 | return -ENOMEM; | 218 | return -ENOMEM; |
| 218 | while(1) { | 219 | while(1) { |
| 220 | recow = 0; | ||
| 219 | btrfs_release_path(root, path); | 221 | btrfs_release_path(root, path); |
| 220 | ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino, | 222 | ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino, |
| 221 | search_start, -1); | 223 | search_start, -1); |
| @@ -244,6 +246,10 @@ next_slot: | |||
| 244 | if (btrfs_key_type(&key) > BTRFS_EXTENT_DATA_KEY) { | 246 | if (btrfs_key_type(&key) > BTRFS_EXTENT_DATA_KEY) { |
| 245 | goto out; | 247 | goto out; |
| 246 | } | 248 | } |
| 249 | if (recow) { | ||
| 250 | search_start = key.offset; | ||
| 251 | continue; | ||
| 252 | } | ||
| 247 | if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) { | 253 | if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) { |
| 248 | extent = btrfs_item_ptr(leaf, slot, | 254 | extent = btrfs_item_ptr(leaf, slot, |
| 249 | struct btrfs_file_extent_item); | 255 | struct btrfs_file_extent_item); |
| @@ -274,6 +280,7 @@ next_slot: | |||
| 274 | nextret = btrfs_next_leaf(root, path); | 280 | nextret = btrfs_next_leaf(root, path); |
| 275 | if (nextret) | 281 | if (nextret) |
| 276 | goto out; | 282 | goto out; |
| 283 | recow = 1; | ||
| 277 | } else { | 284 | } else { |
| 278 | path->slots[0]++; | 285 | path->slots[0]++; |
| 279 | } | 286 | } |
| @@ -321,7 +328,7 @@ next_slot: | |||
| 321 | } | 328 | } |
| 322 | btrfs_set_file_extent_num_blocks(extent, | 329 | btrfs_set_file_extent_num_blocks(extent, |
| 323 | new_num); | 330 | new_num); |
| 324 | mark_buffer_dirty(path->nodes[0]); | 331 | btrfs_mark_buffer_dirty(path->nodes[0]); |
| 325 | } else { | 332 | } else { |
| 326 | WARN_ON(1); | 333 | WARN_ON(1); |
| 327 | } | 334 | } |
| @@ -452,6 +459,8 @@ static int prepare_pages(struct btrfs_root *root, | |||
| 452 | err = -ENOMEM; | 459 | err = -ENOMEM; |
| 453 | goto failed_release; | 460 | goto failed_release; |
| 454 | } | 461 | } |
| 462 | cancel_dirty_page(pages[i], PAGE_CACHE_SIZE); | ||
| 463 | wait_on_page_writeback(pages[i]); | ||
| 455 | } | 464 | } |
| 456 | 465 | ||
| 457 | mutex_lock(&root->fs_info->fs_mutex); | 466 | mutex_lock(&root->fs_info->fs_mutex); |
| @@ -522,8 +531,6 @@ static int prepare_pages(struct btrfs_root *root, | |||
| 522 | mutex_unlock(&root->fs_info->fs_mutex); | 531 | mutex_unlock(&root->fs_info->fs_mutex); |
| 523 | 532 | ||
| 524 | for (i = 0; i < num_pages; i++) { | 533 | for (i = 0; i < num_pages; i++) { |
| 525 | cancel_dirty_page(pages[i], PAGE_CACHE_SIZE); | ||
| 526 | wait_on_page_writeback(pages[i]); | ||
| 527 | offset = pos & (PAGE_CACHE_SIZE -1); | 534 | offset = pos & (PAGE_CACHE_SIZE -1); |
| 528 | this_write = min((size_t)PAGE_CACHE_SIZE - offset, write_bytes); | 535 | this_write = min((size_t)PAGE_CACHE_SIZE - offset, write_bytes); |
| 529 | if (!page_has_buffers(pages[i])) { | 536 | if (!page_has_buffers(pages[i])) { |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index eba06e7cf414..4fc0367d54f2 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -506,7 +506,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
| 506 | extent_num_blocks); | 506 | extent_num_blocks); |
| 507 | inode->i_blocks -= (orig_num_blocks - | 507 | inode->i_blocks -= (orig_num_blocks - |
| 508 | extent_num_blocks) << 3; | 508 | extent_num_blocks) << 3; |
| 509 | mark_buffer_dirty(path->nodes[0]); | 509 | btrfs_mark_buffer_dirty(path->nodes[0]); |
| 510 | } else { | 510 | } else { |
| 511 | extent_start = | 511 | extent_start = |
| 512 | btrfs_file_extent_disk_blocknr(fi); | 512 | btrfs_file_extent_disk_blocknr(fi); |
| @@ -2020,7 +2020,7 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen) | |||
| 2020 | btrfs_set_header_owner(&leaf->header, root->root_key.objectid); | 2020 | btrfs_set_header_owner(&leaf->header, root->root_key.objectid); |
| 2021 | memcpy(leaf->header.fsid, root->fs_info->disk_super->fsid, | 2021 | memcpy(leaf->header.fsid, root->fs_info->disk_super->fsid, |
| 2022 | sizeof(leaf->header.fsid)); | 2022 | sizeof(leaf->header.fsid)); |
| 2023 | mark_buffer_dirty(subvol); | 2023 | btrfs_mark_buffer_dirty(subvol); |
| 2024 | 2024 | ||
| 2025 | inode_item = &root_item.inode; | 2025 | inode_item = &root_item.inode; |
| 2026 | memset(inode_item, 0, sizeof(*inode_item)); | 2026 | memset(inode_item, 0, sizeof(*inode_item)); |
| @@ -2497,7 +2497,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, | |||
| 2497 | ptr = btrfs_file_extent_inline_start(ei); | 2497 | ptr = btrfs_file_extent_inline_start(ei); |
| 2498 | btrfs_memcpy(root, path->nodes[0]->b_data, | 2498 | btrfs_memcpy(root, path->nodes[0]->b_data, |
| 2499 | ptr, symname, name_len); | 2499 | ptr, symname, name_len); |
| 2500 | mark_buffer_dirty(path->nodes[0]); | 2500 | btrfs_mark_buffer_dirty(path->nodes[0]); |
| 2501 | btrfs_free_path(path); | 2501 | btrfs_free_path(path); |
| 2502 | inode->i_op = &btrfs_symlink_inode_operations; | 2502 | inode->i_op = &btrfs_symlink_inode_operations; |
| 2503 | inode->i_mapping->a_ops = &btrfs_symlink_aops; | 2503 | inode->i_mapping->a_ops = &btrfs_symlink_aops; |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 3b2face593e9..bec38ae8aa11 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
| @@ -85,6 +85,8 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, | |||
| 85 | 85 | ||
| 86 | if (root != root->fs_info->tree_root && root->last_trans < | 86 | if (root != root->fs_info->tree_root && root->last_trans < |
| 87 | running_trans_id) { | 87 | running_trans_id) { |
| 88 | WARN_ON(root == root->fs_info->extent_root); | ||
| 89 | WARN_ON(root->ref_cows != 1); | ||
| 88 | if (root->root_item.refs != 0) { | 90 | if (root->root_item.refs != 0) { |
| 89 | radix_tree_tag_set(&root->fs_info->fs_roots_radix, | 91 | radix_tree_tag_set(&root->fs_info->fs_roots_radix, |
| 90 | (unsigned long)root->root_key.objectid, | 92 | (unsigned long)root->root_key.objectid, |
| @@ -113,10 +115,11 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
| 113 | 115 | ||
| 114 | mutex_lock(&root->fs_info->trans_mutex); | 116 | mutex_lock(&root->fs_info->trans_mutex); |
| 115 | cur_trans = root->fs_info->running_transaction; | 117 | cur_trans = root->fs_info->running_transaction; |
| 118 | WARN_ON(cur_trans != trans->transaction); | ||
| 116 | WARN_ON(cur_trans->num_writers < 1); | 119 | WARN_ON(cur_trans->num_writers < 1); |
| 120 | cur_trans->num_writers--; | ||
| 117 | if (waitqueue_active(&cur_trans->writer_wait)) | 121 | if (waitqueue_active(&cur_trans->writer_wait)) |
| 118 | wake_up(&cur_trans->writer_wait); | 122 | wake_up(&cur_trans->writer_wait); |
| 119 | cur_trans->num_writers--; | ||
| 120 | put_transaction(cur_trans); | 123 | put_transaction(cur_trans); |
| 121 | mutex_unlock(&root->fs_info->trans_mutex); | 124 | mutex_unlock(&root->fs_info->trans_mutex); |
| 122 | memset(trans, 0, sizeof(*trans)); | 125 | memset(trans, 0, sizeof(*trans)); |
| @@ -194,6 +197,7 @@ static int wait_for_commit(struct btrfs_root *root, | |||
| 194 | struct btrfs_transaction *commit) | 197 | struct btrfs_transaction *commit) |
| 195 | { | 198 | { |
| 196 | DEFINE_WAIT(wait); | 199 | DEFINE_WAIT(wait); |
| 200 | mutex_lock(&root->fs_info->trans_mutex); | ||
| 197 | while(!commit->commit_done) { | 201 | while(!commit->commit_done) { |
| 198 | prepare_to_wait(&commit->commit_wait, &wait, | 202 | prepare_to_wait(&commit->commit_wait, &wait, |
| 199 | TASK_UNINTERRUPTIBLE); | 203 | TASK_UNINTERRUPTIBLE); |
| @@ -203,6 +207,7 @@ static int wait_for_commit(struct btrfs_root *root, | |||
| 203 | schedule(); | 207 | schedule(); |
| 204 | mutex_lock(&root->fs_info->trans_mutex); | 208 | mutex_lock(&root->fs_info->trans_mutex); |
| 205 | } | 209 | } |
| 210 | mutex_unlock(&root->fs_info->trans_mutex); | ||
| 206 | finish_wait(&commit->commit_wait, &wait); | 211 | finish_wait(&commit->commit_wait, &wait); |
| 207 | return 0; | 212 | return 0; |
| 208 | } | 213 | } |
| @@ -279,7 +284,6 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
| 279 | &root->root_item); | 284 | &root->root_item); |
| 280 | if (err) | 285 | if (err) |
| 281 | break; | 286 | break; |
| 282 | |||
| 283 | refs = btrfs_root_refs(&tmp_item); | 287 | refs = btrfs_root_refs(&tmp_item); |
| 284 | btrfs_set_root_refs(&tmp_item, refs - 1); | 288 | btrfs_set_root_refs(&tmp_item, refs - 1); |
| 285 | err = btrfs_update_root(trans, root->fs_info->tree_root, | 289 | err = btrfs_update_root(trans, root->fs_info->tree_root, |
| @@ -333,31 +337,53 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 333 | struct btrfs_transaction *cur_trans; | 337 | struct btrfs_transaction *cur_trans; |
| 334 | struct btrfs_transaction *prev_trans = NULL; | 338 | struct btrfs_transaction *prev_trans = NULL; |
| 335 | struct list_head dirty_fs_roots; | 339 | struct list_head dirty_fs_roots; |
| 340 | struct radix_tree_root pinned_copy; | ||
| 336 | DEFINE_WAIT(wait); | 341 | DEFINE_WAIT(wait); |
| 337 | 342 | ||
| 343 | init_bit_radix(&pinned_copy); | ||
| 338 | INIT_LIST_HEAD(&dirty_fs_roots); | 344 | INIT_LIST_HEAD(&dirty_fs_roots); |
| 339 | 345 | ||
| 340 | mutex_lock(&root->fs_info->trans_mutex); | 346 | mutex_lock(&root->fs_info->trans_mutex); |
| 341 | if (trans->transaction->in_commit) { | 347 | if (trans->transaction->in_commit) { |
| 342 | cur_trans = trans->transaction; | 348 | cur_trans = trans->transaction; |
| 343 | trans->transaction->use_count++; | 349 | trans->transaction->use_count++; |
| 350 | mutex_unlock(&root->fs_info->trans_mutex); | ||
| 344 | btrfs_end_transaction(trans, root); | 351 | btrfs_end_transaction(trans, root); |
| 352 | |||
| 353 | mutex_unlock(&root->fs_info->fs_mutex); | ||
| 345 | ret = wait_for_commit(root, cur_trans); | 354 | ret = wait_for_commit(root, cur_trans); |
| 346 | BUG_ON(ret); | 355 | BUG_ON(ret); |
| 347 | put_transaction(cur_trans); | 356 | put_transaction(cur_trans); |
| 348 | mutex_unlock(&root->fs_info->trans_mutex); | 357 | mutex_lock(&root->fs_info->fs_mutex); |
| 349 | return 0; | 358 | return 0; |
| 350 | } | 359 | } |
| 351 | cur_trans = trans->transaction; | ||
| 352 | trans->transaction->in_commit = 1; | 360 | trans->transaction->in_commit = 1; |
| 361 | cur_trans = trans->transaction; | ||
| 362 | if (cur_trans->list.prev != &root->fs_info->trans_list) { | ||
| 363 | prev_trans = list_entry(cur_trans->list.prev, | ||
| 364 | struct btrfs_transaction, list); | ||
| 365 | if (!prev_trans->commit_done) { | ||
| 366 | prev_trans->use_count++; | ||
| 367 | mutex_unlock(&root->fs_info->fs_mutex); | ||
| 368 | mutex_unlock(&root->fs_info->trans_mutex); | ||
| 369 | |||
| 370 | wait_for_commit(root, prev_trans); | ||
| 371 | put_transaction(prev_trans); | ||
| 372 | |||
| 373 | mutex_lock(&root->fs_info->fs_mutex); | ||
| 374 | mutex_lock(&root->fs_info->trans_mutex); | ||
| 375 | } | ||
| 376 | } | ||
| 353 | while (trans->transaction->num_writers > 1) { | 377 | while (trans->transaction->num_writers > 1) { |
| 354 | WARN_ON(cur_trans != trans->transaction); | 378 | WARN_ON(cur_trans != trans->transaction); |
| 355 | prepare_to_wait(&trans->transaction->writer_wait, &wait, | 379 | prepare_to_wait(&trans->transaction->writer_wait, &wait, |
| 356 | TASK_UNINTERRUPTIBLE); | 380 | TASK_UNINTERRUPTIBLE); |
| 357 | if (trans->transaction->num_writers <= 1) | 381 | if (trans->transaction->num_writers <= 1) |
| 358 | break; | 382 | break; |
| 383 | mutex_unlock(&root->fs_info->fs_mutex); | ||
| 359 | mutex_unlock(&root->fs_info->trans_mutex); | 384 | mutex_unlock(&root->fs_info->trans_mutex); |
| 360 | schedule(); | 385 | schedule(); |
| 386 | mutex_lock(&root->fs_info->fs_mutex); | ||
| 361 | mutex_lock(&root->fs_info->trans_mutex); | 387 | mutex_lock(&root->fs_info->trans_mutex); |
| 362 | finish_wait(&trans->transaction->writer_wait, &wait); | 388 | finish_wait(&trans->transaction->writer_wait, &wait); |
| 363 | } | 389 | } |
| @@ -372,34 +398,22 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 372 | 398 | ||
| 373 | cur_trans = root->fs_info->running_transaction; | 399 | cur_trans = root->fs_info->running_transaction; |
| 374 | root->fs_info->running_transaction = NULL; | 400 | root->fs_info->running_transaction = NULL; |
| 375 | if (cur_trans->list.prev != &root->fs_info->trans_list) { | ||
| 376 | prev_trans = list_entry(cur_trans->list.prev, | ||
| 377 | struct btrfs_transaction, list); | ||
| 378 | if (prev_trans->commit_done) | ||
| 379 | prev_trans = NULL; | ||
| 380 | else | ||
| 381 | prev_trans->use_count++; | ||
| 382 | } | ||
| 383 | btrfs_set_super_generation(&root->fs_info->super_copy, | 401 | btrfs_set_super_generation(&root->fs_info->super_copy, |
| 384 | cur_trans->transid); | 402 | cur_trans->transid); |
| 385 | btrfs_set_super_root(&root->fs_info->super_copy, | 403 | btrfs_set_super_root(&root->fs_info->super_copy, |
| 386 | bh_blocknr(root->fs_info->tree_root->node)); | 404 | bh_blocknr(root->fs_info->tree_root->node)); |
| 387 | memcpy(root->fs_info->disk_super, &root->fs_info->super_copy, | 405 | memcpy(root->fs_info->disk_super, &root->fs_info->super_copy, |
| 388 | sizeof(root->fs_info->super_copy)); | 406 | sizeof(root->fs_info->super_copy)); |
| 407 | |||
| 408 | btrfs_copy_pinned(root, &pinned_copy); | ||
| 409 | |||
| 389 | mutex_unlock(&root->fs_info->trans_mutex); | 410 | mutex_unlock(&root->fs_info->trans_mutex); |
| 390 | mutex_unlock(&root->fs_info->fs_mutex); | 411 | mutex_unlock(&root->fs_info->fs_mutex); |
| 391 | ret = btrfs_write_and_wait_transaction(trans, root); | 412 | ret = btrfs_write_and_wait_transaction(trans, root); |
| 392 | if (prev_trans) { | ||
| 393 | mutex_lock(&root->fs_info->trans_mutex); | ||
| 394 | wait_for_commit(root, prev_trans); | ||
| 395 | put_transaction(prev_trans); | ||
| 396 | mutex_unlock(&root->fs_info->trans_mutex); | ||
| 397 | } | ||
| 398 | BUG_ON(ret); | 413 | BUG_ON(ret); |
| 399 | write_ctree_super(trans, root); | 414 | write_ctree_super(trans, root); |
| 400 | |||
| 401 | mutex_lock(&root->fs_info->fs_mutex); | 415 | mutex_lock(&root->fs_info->fs_mutex); |
| 402 | btrfs_finish_extent_commit(trans, root); | 416 | btrfs_finish_extent_commit(trans, root, &pinned_copy); |
| 403 | mutex_lock(&root->fs_info->trans_mutex); | 417 | mutex_lock(&root->fs_info->trans_mutex); |
| 404 | cur_trans->commit_done = 1; | 418 | cur_trans->commit_done = 1; |
| 405 | wake_up(&cur_trans->commit_wait); | 419 | wake_up(&cur_trans->commit_wait); |
