diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-06-28 15:57:36 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-06-28 15:57:36 -0400 |
commit | ccd467d60e81b48cdbecae93532b66bcdedca91d (patch) | |
tree | 7c8c74ca8c6c058fc2e3c90c0082e796b7c1e92e | |
parent | f2654de42a759127cb1f1e8a626ec94178732e20 (diff) |
Btrfs: crash recovery fixes
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-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); |