diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-01-09 15:55:33 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:59 -0400 |
commit | 55c69072d6bd5be170a85467f64a20963cddf490 (patch) | |
tree | 92f9f34c5d3a19df2bbfc662386ccd690a5f39fb /fs/btrfs | |
parent | 21ad10cf3e9c1ef42e725e5c3a593c49f779a16b (diff) |
Btrfs: Fix extent_buffer usage when nodesize != leafsize
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/disk-io.c | 26 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 13 | ||||
-rw-r--r-- | fs/btrfs/extent_map.c | 30 |
3 files changed, 54 insertions, 15 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index a481b970608c..0338f8fd382d 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -197,9 +197,23 @@ int csum_dirty_buffer(struct btrfs_root *root, struct page *page) | |||
197 | if (found_start != start) { | 197 | if (found_start != start) { |
198 | printk("warning: eb start incorrect %Lu buffer %Lu len %lu\n", | 198 | printk("warning: eb start incorrect %Lu buffer %Lu len %lu\n", |
199 | start, found_start, len); | 199 | start, found_start, len); |
200 | WARN_ON(1); | ||
201 | goto err; | ||
202 | } | ||
203 | if (eb->first_page != page) { | ||
204 | printk("bad first page %lu %lu\n", eb->first_page->index, | ||
205 | page->index); | ||
206 | WARN_ON(1); | ||
207 | goto err; | ||
208 | } | ||
209 | if (!PageUptodate(page)) { | ||
210 | printk("csum not up to date page %lu\n", page->index); | ||
211 | WARN_ON(1); | ||
212 | goto err; | ||
200 | } | 213 | } |
201 | found_level = btrfs_header_level(eb); | 214 | found_level = btrfs_header_level(eb); |
202 | csum_tree_block(root, eb, 0); | 215 | csum_tree_block(root, eb, 0); |
216 | err: | ||
203 | free_extent_buffer(eb); | 217 | free_extent_buffer(eb); |
204 | out: | 218 | out: |
205 | return 0; | 219 | return 0; |
@@ -368,7 +382,10 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
368 | struct extent_buffer *buf) | 382 | struct extent_buffer *buf) |
369 | { | 383 | { |
370 | struct inode *btree_inode = root->fs_info->btree_inode; | 384 | struct inode *btree_inode = root->fs_info->btree_inode; |
371 | clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf); | 385 | if (btrfs_header_generation(buf) == |
386 | root->fs_info->running_transaction->transid) | ||
387 | clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, | ||
388 | buf); | ||
372 | return 0; | 389 | return 0; |
373 | } | 390 | } |
374 | 391 | ||
@@ -897,8 +914,11 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf) | |||
897 | 914 | ||
898 | void btrfs_throttle(struct btrfs_root *root) | 915 | void btrfs_throttle(struct btrfs_root *root) |
899 | { | 916 | { |
900 | if (root->fs_info->throttles) | 917 | struct backing_dev_info *bdi; |
901 | congestion_wait(WRITE, HZ/10); | 918 | |
919 | bdi = root->fs_info->sb->s_bdev->bd_inode->i_mapping->backing_dev_info; | ||
920 | if (root->fs_info->throttles && bdi_write_congested(bdi)) | ||
921 | congestion_wait(WRITE, HZ/20); | ||
902 | } | 922 | } |
903 | 923 | ||
904 | void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) | 924 | void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 99a8b0f0d318..2c569b4d59d4 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -1212,6 +1212,7 @@ static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes, | |||
1212 | u64 header_transid = | 1212 | u64 header_transid = |
1213 | btrfs_header_generation(buf); | 1213 | btrfs_header_generation(buf); |
1214 | if (header_transid == transid) { | 1214 | if (header_transid == transid) { |
1215 | clean_tree_block(NULL, root, buf); | ||
1215 | free_extent_buffer(buf); | 1216 | free_extent_buffer(buf); |
1216 | return 1; | 1217 | return 1; |
1217 | } | 1218 | } |
@@ -1249,7 +1250,6 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1249 | key.objectid = bytenr; | 1250 | key.objectid = bytenr; |
1250 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); | 1251 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); |
1251 | key.offset = num_bytes; | 1252 | key.offset = num_bytes; |
1252 | |||
1253 | path = btrfs_alloc_path(); | 1253 | path = btrfs_alloc_path(); |
1254 | if (!path) | 1254 | if (!path) |
1255 | return -ENOMEM; | 1255 | return -ENOMEM; |
@@ -1648,8 +1648,6 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1648 | search_start, search_end, hint_byte, ins, | 1648 | search_start, search_end, hint_byte, ins, |
1649 | trans->alloc_exclude_start, | 1649 | trans->alloc_exclude_start, |
1650 | trans->alloc_exclude_nr, data); | 1650 | trans->alloc_exclude_nr, data); |
1651 | if (ret) | ||
1652 | printk("find free extent returns %d\n", ret); | ||
1653 | BUG_ON(ret); | 1651 | BUG_ON(ret); |
1654 | if (ret) | 1652 | if (ret) |
1655 | return ret; | 1653 | return ret; |
@@ -1764,7 +1762,16 @@ struct extent_buffer *__btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
1764 | 0, 0, 0); | 1762 | 0, 0, 0); |
1765 | return ERR_PTR(-ENOMEM); | 1763 | return ERR_PTR(-ENOMEM); |
1766 | } | 1764 | } |
1765 | btrfs_set_header_generation(buf, trans->transid); | ||
1766 | clean_tree_block(trans, root, buf); | ||
1767 | wait_on_tree_block_writeback(root, buf); | ||
1767 | btrfs_set_buffer_uptodate(buf); | 1768 | btrfs_set_buffer_uptodate(buf); |
1769 | |||
1770 | if (PageDirty(buf->first_page)) { | ||
1771 | printk("page %lu dirty\n", buf->first_page->index); | ||
1772 | WARN_ON(1); | ||
1773 | } | ||
1774 | |||
1768 | set_extent_dirty(&trans->transaction->dirty_pages, buf->start, | 1775 | set_extent_dirty(&trans->transaction->dirty_pages, buf->start, |
1769 | buf->start + buf->len - 1, GFP_NOFS); | 1776 | buf->start + buf->len - 1, GFP_NOFS); |
1770 | set_extent_bits(&BTRFS_I(root->fs_info->btree_inode)->extent_tree, | 1777 | set_extent_bits(&BTRFS_I(root->fs_info->btree_inode)->extent_tree, |
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 9d6aefa937c4..f3a384ed700c 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -1663,6 +1663,13 @@ void set_page_extent_mapped(struct page *page) | |||
1663 | } | 1663 | } |
1664 | } | 1664 | } |
1665 | 1665 | ||
1666 | void set_page_extent_head(struct page *page, unsigned long len) | ||
1667 | { | ||
1668 | WARN_ON(page->private && page->private == EXTENT_PAGE_PRIVATE && | ||
1669 | PageDirty(page)); | ||
1670 | set_page_private(page, EXTENT_PAGE_PRIVATE_FIRST_PAGE | len << 2); | ||
1671 | } | ||
1672 | |||
1666 | /* | 1673 | /* |
1667 | * basic readpage implementation. Locked extent state structs are inserted | 1674 | * basic readpage implementation. Locked extent state structs are inserted |
1668 | * into the tree that are removed when the IO is done (by the end_io | 1675 | * into the tree that are removed when the IO is done (by the end_io |
@@ -2490,8 +2497,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, | |||
2490 | mark_page_accessed(page0); | 2497 | mark_page_accessed(page0); |
2491 | set_page_extent_mapped(page0); | 2498 | set_page_extent_mapped(page0); |
2492 | WARN_ON(!PageUptodate(page0)); | 2499 | WARN_ON(!PageUptodate(page0)); |
2493 | set_page_private(page0, EXTENT_PAGE_PRIVATE_FIRST_PAGE | | 2500 | set_page_extent_head(page0, len); |
2494 | len << 2); | ||
2495 | } else { | 2501 | } else { |
2496 | i = 0; | 2502 | i = 0; |
2497 | } | 2503 | } |
@@ -2505,8 +2511,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, | |||
2505 | mark_page_accessed(p); | 2511 | mark_page_accessed(p); |
2506 | if (i == 0) { | 2512 | if (i == 0) { |
2507 | eb->first_page = p; | 2513 | eb->first_page = p; |
2508 | set_page_private(p, EXTENT_PAGE_PRIVATE_FIRST_PAGE | | 2514 | set_page_extent_head(p, len); |
2509 | len << 2); | ||
2510 | } else { | 2515 | } else { |
2511 | set_page_private(p, EXTENT_PAGE_PRIVATE); | 2516 | set_page_private(p, EXTENT_PAGE_PRIVATE); |
2512 | } | 2517 | } |
@@ -2569,8 +2574,7 @@ struct extent_buffer *find_extent_buffer(struct extent_map_tree *tree, | |||
2569 | 2574 | ||
2570 | if (i == 0) { | 2575 | if (i == 0) { |
2571 | eb->first_page = p; | 2576 | eb->first_page = p; |
2572 | set_page_private(p, EXTENT_PAGE_PRIVATE_FIRST_PAGE | | 2577 | set_page_extent_head(p, len); |
2573 | len << 2); | ||
2574 | } else { | 2578 | } else { |
2575 | set_page_private(p, EXTENT_PAGE_PRIVATE); | 2579 | set_page_private(p, EXTENT_PAGE_PRIVATE); |
2576 | } | 2580 | } |
@@ -2643,6 +2647,11 @@ int clear_extent_buffer_dirty(struct extent_map_tree *tree, | |||
2643 | for (i = 0; i < num_pages; i++) { | 2647 | for (i = 0; i < num_pages; i++) { |
2644 | page = extent_buffer_page(eb, i); | 2648 | page = extent_buffer_page(eb, i); |
2645 | lock_page(page); | 2649 | lock_page(page); |
2650 | if (i == 0) | ||
2651 | set_page_extent_head(page, eb->len); | ||
2652 | else | ||
2653 | set_page_private(page, EXTENT_PAGE_PRIVATE); | ||
2654 | |||
2646 | /* | 2655 | /* |
2647 | * if we're on the last page or the first page and the | 2656 | * if we're on the last page or the first page and the |
2648 | * block isn't aligned on a page boundary, do extra checks | 2657 | * block isn't aligned on a page boundary, do extra checks |
@@ -2697,9 +2706,12 @@ int set_extent_buffer_dirty(struct extent_map_tree *tree, | |||
2697 | */ | 2706 | */ |
2698 | if (i == 0) { | 2707 | if (i == 0) { |
2699 | lock_page(page); | 2708 | lock_page(page); |
2700 | set_page_private(page, | 2709 | set_page_extent_head(page, eb->len); |
2701 | EXTENT_PAGE_PRIVATE_FIRST_PAGE | | 2710 | } else if (PagePrivate(page) && |
2702 | eb->len << 2); | 2711 | page->private != EXTENT_PAGE_PRIVATE) { |
2712 | lock_page(page); | ||
2713 | set_page_extent_mapped(page); | ||
2714 | unlock_page(page); | ||
2703 | } | 2715 | } |
2704 | __set_page_dirty_nobuffers(extent_buffer_page(eb, i)); | 2716 | __set_page_dirty_nobuffers(extent_buffer_page(eb, i)); |
2705 | if (i == 0) | 2717 | if (i == 0) |