diff options
Diffstat (limited to 'fs/btrfs/extent_map.c')
-rw-r--r-- | fs/btrfs/extent_map.c | 147 |
1 files changed, 112 insertions, 35 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index d378edf0964e..a9c7419615b9 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -30,9 +30,6 @@ struct tree_entry { | |||
30 | 30 | ||
31 | #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) | 31 | #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) |
32 | 32 | ||
33 | static LIST_HEAD(all_states); | ||
34 | spinlock_t state_lock = SPIN_LOCK_UNLOCKED; | ||
35 | |||
36 | void __init extent_map_init(void) | 33 | void __init extent_map_init(void) |
37 | { | 34 | { |
38 | extent_map_cache = kmem_cache_create("extent_map", | 35 | extent_map_cache = kmem_cache_create("extent_map", |
@@ -49,15 +46,6 @@ void __init extent_map_init(void) | |||
49 | 46 | ||
50 | void __exit extent_map_exit(void) | 47 | void __exit extent_map_exit(void) |
51 | { | 48 | { |
52 | while(!list_empty(&all_states)) { | ||
53 | struct extent_state *state; | ||
54 | struct list_head *cur = all_states.next; | ||
55 | state = list_entry(cur, struct extent_state, list); | ||
56 | printk("found leaked state %Lu %Lu state %d in_tree %d\n", | ||
57 | state->start, state->end, state->state, state->in_tree); | ||
58 | list_del(&state->list); | ||
59 | kfree(state); | ||
60 | } | ||
61 | if (extent_map_cache) | 49 | if (extent_map_cache) |
62 | kmem_cache_destroy(extent_map_cache); | 50 | kmem_cache_destroy(extent_map_cache); |
63 | if (extent_state_cache) | 51 | if (extent_state_cache) |
@@ -69,6 +57,7 @@ void extent_map_tree_init(struct extent_map_tree *tree, | |||
69 | { | 57 | { |
70 | tree->map.rb_node = NULL; | 58 | tree->map.rb_node = NULL; |
71 | tree->state.rb_node = NULL; | 59 | tree->state.rb_node = NULL; |
60 | tree->fill_delalloc = NULL; | ||
72 | rwlock_init(&tree->lock); | 61 | rwlock_init(&tree->lock); |
73 | tree->mapping = mapping; | 62 | tree->mapping = mapping; |
74 | } | 63 | } |
@@ -106,9 +95,6 @@ struct extent_state *alloc_extent_state(gfp_t mask) | |||
106 | state->in_tree = 0; | 95 | state->in_tree = 0; |
107 | atomic_set(&state->refs, 1); | 96 | atomic_set(&state->refs, 1); |
108 | init_waitqueue_head(&state->wq); | 97 | init_waitqueue_head(&state->wq); |
109 | spin_lock_irq(&state_lock); | ||
110 | list_add(&state->list, &all_states); | ||
111 | spin_unlock_irq(&state_lock); | ||
112 | return state; | 98 | return state; |
113 | } | 99 | } |
114 | EXPORT_SYMBOL(alloc_extent_state); | 100 | EXPORT_SYMBOL(alloc_extent_state); |
@@ -117,9 +103,6 @@ void free_extent_state(struct extent_state *state) | |||
117 | { | 103 | { |
118 | if (atomic_dec_and_test(&state->refs)) { | 104 | if (atomic_dec_and_test(&state->refs)) { |
119 | WARN_ON(state->in_tree); | 105 | WARN_ON(state->in_tree); |
120 | spin_lock_irq(&state_lock); | ||
121 | list_del_init(&state->list); | ||
122 | spin_unlock_irq(&state_lock); | ||
123 | kmem_cache_free(extent_state_cache, state); | 106 | kmem_cache_free(extent_state_cache, state); |
124 | } | 107 | } |
125 | } | 108 | } |
@@ -369,7 +352,7 @@ static int insert_state(struct extent_map_tree *tree, | |||
369 | if (node) { | 352 | if (node) { |
370 | struct extent_state *found; | 353 | struct extent_state *found; |
371 | found = rb_entry(node, struct extent_state, rb_node); | 354 | found = rb_entry(node, struct extent_state, rb_node); |
372 | printk("found node %Lu %Lu on insert of %Lu %Lu\n", found->start, found->end, start, end); | 355 | printk("found node %Lu %Lu on insert of %Lu %Lu\n", found->start, found->end, start, end); |
373 | free_extent_state(state); | 356 | free_extent_state(state); |
374 | return -EEXIST; | 357 | return -EEXIST; |
375 | } | 358 | } |
@@ -408,7 +391,7 @@ static int split_state(struct extent_map_tree *tree, struct extent_state *orig, | |||
408 | if (node) { | 391 | if (node) { |
409 | struct extent_state *found; | 392 | struct extent_state *found; |
410 | found = rb_entry(node, struct extent_state, rb_node); | 393 | found = rb_entry(node, struct extent_state, rb_node); |
411 | printk("found node %Lu %Lu on insert of %Lu %Lu\n", found->start, found->end, prealloc->start, prealloc->end); | 394 | printk("found node %Lu %Lu on insert of %Lu %Lu\n", found->start, found->end, prealloc->start, prealloc->end); |
412 | free_extent_state(prealloc); | 395 | free_extent_state(prealloc); |
413 | return -EEXIST; | 396 | return -EEXIST; |
414 | } | 397 | } |
@@ -792,10 +775,20 @@ int set_extent_dirty(struct extent_map_tree *tree, u64 start, u64 end, | |||
792 | } | 775 | } |
793 | EXPORT_SYMBOL(set_extent_dirty); | 776 | EXPORT_SYMBOL(set_extent_dirty); |
794 | 777 | ||
778 | int set_extent_delalloc(struct extent_map_tree *tree, u64 start, u64 end, | ||
779 | gfp_t mask) | ||
780 | { | ||
781 | return set_extent_bit(tree, start, end, | ||
782 | EXTENT_DELALLOC | EXTENT_DIRTY, 0, NULL, | ||
783 | mask); | ||
784 | } | ||
785 | EXPORT_SYMBOL(set_extent_delalloc); | ||
786 | |||
795 | int clear_extent_dirty(struct extent_map_tree *tree, u64 start, u64 end, | 787 | int clear_extent_dirty(struct extent_map_tree *tree, u64 start, u64 end, |
796 | gfp_t mask) | 788 | gfp_t mask) |
797 | { | 789 | { |
798 | return clear_extent_bit(tree, start, end, EXTENT_DIRTY, 0, 0, mask); | 790 | return clear_extent_bit(tree, start, end, |
791 | EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, mask); | ||
799 | } | 792 | } |
800 | EXPORT_SYMBOL(clear_extent_dirty); | 793 | EXPORT_SYMBOL(clear_extent_dirty); |
801 | 794 | ||
@@ -922,6 +915,62 @@ int set_range_writeback(struct extent_map_tree *tree, u64 start, u64 end) | |||
922 | } | 915 | } |
923 | EXPORT_SYMBOL(set_range_writeback); | 916 | EXPORT_SYMBOL(set_range_writeback); |
924 | 917 | ||
918 | u64 find_lock_delalloc_range(struct extent_map_tree *tree, | ||
919 | u64 start, u64 lock_start, u64 *end, u64 max_bytes) | ||
920 | { | ||
921 | struct rb_node *node; | ||
922 | struct extent_state *state; | ||
923 | u64 cur_start = start; | ||
924 | u64 found = 0; | ||
925 | u64 total_bytes = 0; | ||
926 | |||
927 | write_lock_irq(&tree->lock); | ||
928 | /* | ||
929 | * this search will find all the extents that end after | ||
930 | * our range starts. | ||
931 | */ | ||
932 | search_again: | ||
933 | node = tree_search(&tree->state, cur_start); | ||
934 | if (!node || IS_ERR(node)) { | ||
935 | goto out; | ||
936 | } | ||
937 | |||
938 | while(1) { | ||
939 | state = rb_entry(node, struct extent_state, rb_node); | ||
940 | if (state->start != cur_start) { | ||
941 | goto out; | ||
942 | } | ||
943 | if (!(state->state & EXTENT_DELALLOC)) { | ||
944 | goto out; | ||
945 | } | ||
946 | if (state->start >= lock_start) { | ||
947 | if (state->state & EXTENT_LOCKED) { | ||
948 | DEFINE_WAIT(wait); | ||
949 | atomic_inc(&state->refs); | ||
950 | write_unlock_irq(&tree->lock); | ||
951 | schedule(); | ||
952 | write_lock_irq(&tree->lock); | ||
953 | finish_wait(&state->wq, &wait); | ||
954 | free_extent_state(state); | ||
955 | goto search_again; | ||
956 | } | ||
957 | state->state |= EXTENT_LOCKED; | ||
958 | } | ||
959 | found++; | ||
960 | *end = state->end; | ||
961 | cur_start = state->end + 1; | ||
962 | node = rb_next(node); | ||
963 | if (!node) | ||
964 | break; | ||
965 | total_bytes = state->end - state->start + 1; | ||
966 | if (total_bytes >= max_bytes) | ||
967 | break; | ||
968 | } | ||
969 | out: | ||
970 | write_unlock_irq(&tree->lock); | ||
971 | return found; | ||
972 | } | ||
973 | |||
925 | /* | 974 | /* |
926 | * helper function to lock both pages and extents in the tree. | 975 | * helper function to lock both pages and extents in the tree. |
927 | * pages must be locked first. | 976 | * pages must be locked first. |
@@ -1285,6 +1334,7 @@ int extent_read_full_page(struct extent_map_tree *tree, struct page *page, | |||
1285 | if (!PagePrivate(page)) { | 1334 | if (!PagePrivate(page)) { |
1286 | SetPagePrivate(page); | 1335 | SetPagePrivate(page); |
1287 | set_page_private(page, 1); | 1336 | set_page_private(page, 1); |
1337 | WARN_ON(!page->mapping->a_ops->invalidatepage); | ||
1288 | page_cache_get(page); | 1338 | page_cache_get(page); |
1289 | } | 1339 | } |
1290 | 1340 | ||
@@ -1384,7 +1434,10 @@ int extent_write_full_page(struct extent_map_tree *tree, struct page *page, | |||
1384 | size_t blocksize; | 1434 | size_t blocksize; |
1385 | loff_t i_size = i_size_read(inode); | 1435 | loff_t i_size = i_size_read(inode); |
1386 | unsigned long end_index = i_size >> PAGE_CACHE_SHIFT; | 1436 | unsigned long end_index = i_size >> PAGE_CACHE_SHIFT; |
1437 | u64 nr_delalloc; | ||
1438 | u64 delalloc_end; | ||
1387 | 1439 | ||
1440 | WARN_ON(!PageLocked(page)); | ||
1388 | if (page->index > end_index) { | 1441 | if (page->index > end_index) { |
1389 | clear_extent_dirty(tree, start, page_end, GFP_NOFS); | 1442 | clear_extent_dirty(tree, start, page_end, GFP_NOFS); |
1390 | unlock_page(page); | 1443 | unlock_page(page); |
@@ -1400,11 +1453,34 @@ int extent_write_full_page(struct extent_map_tree *tree, struct page *page, | |||
1400 | if (!PagePrivate(page)) { | 1453 | if (!PagePrivate(page)) { |
1401 | SetPagePrivate(page); | 1454 | SetPagePrivate(page); |
1402 | set_page_private(page, 1); | 1455 | set_page_private(page, 1); |
1456 | WARN_ON(!page->mapping->a_ops->invalidatepage); | ||
1403 | page_cache_get(page); | 1457 | page_cache_get(page); |
1404 | } | 1458 | } |
1405 | 1459 | ||
1406 | end = page_end; | ||
1407 | lock_extent(tree, start, page_end, GFP_NOFS); | 1460 | lock_extent(tree, start, page_end, GFP_NOFS); |
1461 | nr_delalloc = find_lock_delalloc_range(tree, start, page_end + 1, | ||
1462 | &delalloc_end, | ||
1463 | 128 * 1024 * 1024); | ||
1464 | if (nr_delalloc) { | ||
1465 | tree->fill_delalloc(inode, start, delalloc_end); | ||
1466 | if (delalloc_end >= page_end + 1) { | ||
1467 | clear_extent_bit(tree, page_end + 1, delalloc_end, | ||
1468 | EXTENT_LOCKED | EXTENT_DELALLOC, | ||
1469 | 1, 0, GFP_NOFS); | ||
1470 | } | ||
1471 | clear_extent_bit(tree, start, page_end, EXTENT_DELALLOC, | ||
1472 | 0, 0, GFP_NOFS); | ||
1473 | if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0)) { | ||
1474 | printk("found delalloc bits after clear extent_bit\n"); | ||
1475 | } | ||
1476 | } else if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0)) { | ||
1477 | printk("found delalloc bits after find_delalloc_range returns 0\n"); | ||
1478 | } | ||
1479 | |||
1480 | end = page_end; | ||
1481 | if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0)) { | ||
1482 | printk("found delalloc bits after lock_extent\n"); | ||
1483 | } | ||
1408 | 1484 | ||
1409 | if (last_byte <= start) { | 1485 | if (last_byte <= start) { |
1410 | clear_extent_dirty(tree, start, page_end, GFP_NOFS); | 1486 | clear_extent_dirty(tree, start, page_end, GFP_NOFS); |
@@ -1419,7 +1495,7 @@ int extent_write_full_page(struct extent_map_tree *tree, struct page *page, | |||
1419 | clear_extent_dirty(tree, cur, page_end, GFP_NOFS); | 1495 | clear_extent_dirty(tree, cur, page_end, GFP_NOFS); |
1420 | break; | 1496 | break; |
1421 | } | 1497 | } |
1422 | em = get_extent(inode, page, page_offset, cur, end, 1); | 1498 | em = get_extent(inode, page, page_offset, cur, end, 0); |
1423 | if (IS_ERR(em) || !em) { | 1499 | if (IS_ERR(em) || !em) { |
1424 | SetPageError(page); | 1500 | SetPageError(page); |
1425 | break; | 1501 | break; |
@@ -1507,6 +1583,7 @@ int extent_commit_write(struct extent_map_tree *tree, | |||
1507 | if (!PagePrivate(page)) { | 1583 | if (!PagePrivate(page)) { |
1508 | SetPagePrivate(page); | 1584 | SetPagePrivate(page); |
1509 | set_page_private(page, 1); | 1585 | set_page_private(page, 1); |
1586 | WARN_ON(!page->mapping->a_ops->invalidatepage); | ||
1510 | page_cache_get(page); | 1587 | page_cache_get(page); |
1511 | } | 1588 | } |
1512 | 1589 | ||
@@ -1543,6 +1620,7 @@ int extent_prepare_write(struct extent_map_tree *tree, | |||
1543 | if (!PagePrivate(page)) { | 1620 | if (!PagePrivate(page)) { |
1544 | SetPagePrivate(page); | 1621 | SetPagePrivate(page); |
1545 | set_page_private(page, 1); | 1622 | set_page_private(page, 1); |
1623 | WARN_ON(!page->mapping->a_ops->invalidatepage); | ||
1546 | page_cache_get(page); | 1624 | page_cache_get(page); |
1547 | } | 1625 | } |
1548 | block_start = (page_start + from) & ~((u64)blocksize - 1); | 1626 | block_start = (page_start + from) & ~((u64)blocksize - 1); |
@@ -1628,29 +1706,28 @@ int try_release_extent_mapping(struct extent_map_tree *tree, struct page *page) | |||
1628 | u64 start = page->index << PAGE_CACHE_SHIFT; | 1706 | u64 start = page->index << PAGE_CACHE_SHIFT; |
1629 | u64 end = start + PAGE_CACHE_SIZE - 1; | 1707 | u64 end = start + PAGE_CACHE_SIZE - 1; |
1630 | u64 orig_start = start; | 1708 | u64 orig_start = start; |
1709 | int ret = 1; | ||
1631 | 1710 | ||
1632 | while (start <= end) { | 1711 | while (start <= end) { |
1633 | em = lookup_extent_mapping(tree, start, end); | 1712 | em = lookup_extent_mapping(tree, start, end); |
1634 | if (!em || IS_ERR(em)) | 1713 | if (!em || IS_ERR(em)) |
1635 | break; | 1714 | break; |
1636 | if (test_range_bit(tree, em->start, em->end, | 1715 | if (!test_range_bit(tree, em->start, em->end, |
1637 | EXTENT_LOCKED, 0)) { | 1716 | EXTENT_LOCKED, 0)) { |
1717 | remove_extent_mapping(tree, em); | ||
1718 | /* once for the rb tree */ | ||
1638 | free_extent_map(em); | 1719 | free_extent_map(em); |
1639 | start = em->end + 1; | ||
1640 | printk("range still locked %Lu %Lu\n", em->start, em->end); | ||
1641 | break; | ||
1642 | } | 1720 | } |
1643 | remove_extent_mapping(tree, em); | ||
1644 | start = em->end + 1; | 1721 | start = em->end + 1; |
1645 | /* once for the rb tree */ | ||
1646 | free_extent_map(em); | ||
1647 | /* once for us */ | 1722 | /* once for us */ |
1648 | free_extent_map(em); | 1723 | free_extent_map(em); |
1649 | } | 1724 | } |
1650 | WARN_ON(test_range_bit(tree, orig_start, end, EXTENT_WRITEBACK, 0)); | 1725 | if (test_range_bit(tree, orig_start, end, EXTENT_LOCKED, 0)) |
1651 | clear_extent_bit(tree, orig_start, end, EXTENT_UPTODATE, | 1726 | ret = 0; |
1652 | 1, 1, GFP_NOFS); | 1727 | else |
1653 | return 1; | 1728 | clear_extent_bit(tree, orig_start, end, EXTENT_UPTODATE, |
1729 | 1, 1, GFP_NOFS); | ||
1730 | return ret; | ||
1654 | } | 1731 | } |
1655 | EXPORT_SYMBOL(try_release_extent_mapping); | 1732 | EXPORT_SYMBOL(try_release_extent_mapping); |
1656 | 1733 | ||