diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-11-20 10:47:25 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:58 -0400 |
commit | 3e9fd94ff0028a044d55690eb0a801fd1472e3c6 (patch) | |
tree | db90bb2cb783763b144d2b4ff87ad3c41113495f /fs/btrfs/extent_map.c | |
parent | 2f4cbe6442d3be7b5e4cf1607a5ab33995fe2d25 (diff) |
Btrfs: Avoid fragmentation from parallel delalloc filling
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent_map.c')
-rw-r--r-- | fs/btrfs/extent_map.c | 83 |
1 files changed, 49 insertions, 34 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index f91f28efdb59..7fd4eb7a8f03 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -1033,11 +1033,11 @@ out: | |||
1033 | EXPORT_SYMBOL(find_first_extent_bit); | 1033 | EXPORT_SYMBOL(find_first_extent_bit); |
1034 | 1034 | ||
1035 | u64 find_lock_delalloc_range(struct extent_map_tree *tree, | 1035 | u64 find_lock_delalloc_range(struct extent_map_tree *tree, |
1036 | u64 start, u64 lock_start, u64 *end, u64 max_bytes) | 1036 | u64 *start, u64 *end, u64 max_bytes) |
1037 | { | 1037 | { |
1038 | struct rb_node *node; | 1038 | struct rb_node *node; |
1039 | struct extent_state *state; | 1039 | struct extent_state *state; |
1040 | u64 cur_start = start; | 1040 | u64 cur_start = *start; |
1041 | u64 found = 0; | 1041 | u64 found = 0; |
1042 | u64 total_bytes = 0; | 1042 | u64 total_bytes = 0; |
1043 | 1043 | ||
@@ -1054,27 +1054,43 @@ search_again: | |||
1054 | 1054 | ||
1055 | while(1) { | 1055 | while(1) { |
1056 | state = rb_entry(node, struct extent_state, rb_node); | 1056 | state = rb_entry(node, struct extent_state, rb_node); |
1057 | if (state->start != cur_start) { | 1057 | if (found && state->start != cur_start) { |
1058 | goto out; | 1058 | goto out; |
1059 | } | 1059 | } |
1060 | if (!(state->state & EXTENT_DELALLOC)) { | 1060 | if (!(state->state & EXTENT_DELALLOC)) { |
1061 | goto out; | 1061 | goto out; |
1062 | } | 1062 | } |
1063 | if (state->start >= lock_start) { | 1063 | if (!found) { |
1064 | if (state->state & EXTENT_LOCKED) { | 1064 | struct extent_state *prev_state; |
1065 | DEFINE_WAIT(wait); | 1065 | struct rb_node *prev_node = node; |
1066 | atomic_inc(&state->refs); | 1066 | while(1) { |
1067 | prepare_to_wait(&state->wq, &wait, | 1067 | prev_node = rb_prev(prev_node); |
1068 | TASK_UNINTERRUPTIBLE); | 1068 | if (!prev_node) |
1069 | write_unlock_irq(&tree->lock); | 1069 | break; |
1070 | schedule(); | 1070 | prev_state = rb_entry(prev_node, |
1071 | write_lock_irq(&tree->lock); | 1071 | struct extent_state, |
1072 | finish_wait(&state->wq, &wait); | 1072 | rb_node); |
1073 | free_extent_state(state); | 1073 | if (!(prev_state->state & EXTENT_DELALLOC)) |
1074 | goto search_again; | 1074 | break; |
1075 | state = prev_state; | ||
1076 | node = prev_node; | ||
1075 | } | 1077 | } |
1076 | state->state |= EXTENT_LOCKED; | ||
1077 | } | 1078 | } |
1079 | if (state->state & EXTENT_LOCKED) { | ||
1080 | DEFINE_WAIT(wait); | ||
1081 | atomic_inc(&state->refs); | ||
1082 | prepare_to_wait(&state->wq, &wait, | ||
1083 | TASK_UNINTERRUPTIBLE); | ||
1084 | write_unlock_irq(&tree->lock); | ||
1085 | schedule(); | ||
1086 | write_lock_irq(&tree->lock); | ||
1087 | finish_wait(&state->wq, &wait); | ||
1088 | free_extent_state(state); | ||
1089 | goto search_again; | ||
1090 | } | ||
1091 | state->state |= EXTENT_LOCKED; | ||
1092 | if (!found) | ||
1093 | *start = state->start; | ||
1078 | found++; | 1094 | found++; |
1079 | *end = state->end; | 1095 | *end = state->end; |
1080 | cur_start = state->end + 1; | 1096 | cur_start = state->end + 1; |
@@ -1695,6 +1711,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
1695 | struct extent_page_data *epd = data; | 1711 | struct extent_page_data *epd = data; |
1696 | struct extent_map_tree *tree = epd->tree; | 1712 | struct extent_map_tree *tree = epd->tree; |
1697 | u64 start = (u64)page->index << PAGE_CACHE_SHIFT; | 1713 | u64 start = (u64)page->index << PAGE_CACHE_SHIFT; |
1714 | u64 delalloc_start; | ||
1698 | u64 page_end = start + PAGE_CACHE_SIZE - 1; | 1715 | u64 page_end = start + PAGE_CACHE_SIZE - 1; |
1699 | u64 end; | 1716 | u64 end; |
1700 | u64 cur = start; | 1717 | u64 cur = start; |
@@ -1729,25 +1746,23 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
1729 | 1746 | ||
1730 | set_page_extent_mapped(page); | 1747 | set_page_extent_mapped(page); |
1731 | 1748 | ||
1732 | lock_extent(tree, start, page_end, GFP_NOFS); | 1749 | delalloc_start = start; |
1733 | nr_delalloc = find_lock_delalloc_range(tree, start, page_end + 1, | 1750 | delalloc_end = 0; |
1734 | &delalloc_end, | 1751 | while(delalloc_end < page_end) { |
1735 | 128 * 1024 * 1024); | 1752 | nr_delalloc = find_lock_delalloc_range(tree, &delalloc_start, |
1736 | if (nr_delalloc) { | 1753 | &delalloc_end, |
1737 | tree->ops->fill_delalloc(inode, start, delalloc_end); | 1754 | 128 * 1024 * 1024); |
1738 | if (delalloc_end >= page_end + 1) { | 1755 | if (nr_delalloc <= 0) |
1739 | clear_extent_bit(tree, page_end + 1, delalloc_end, | 1756 | break; |
1740 | EXTENT_LOCKED | EXTENT_DELALLOC, | 1757 | tree->ops->fill_delalloc(inode, delalloc_start, |
1741 | 1, 0, GFP_NOFS); | 1758 | delalloc_end); |
1742 | } | 1759 | clear_extent_bit(tree, delalloc_start, |
1743 | clear_extent_bit(tree, start, page_end, EXTENT_DELALLOC, | 1760 | delalloc_end, |
1744 | 0, 0, GFP_NOFS); | 1761 | EXTENT_LOCKED | EXTENT_DELALLOC, |
1745 | if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0)) { | 1762 | 1, 0, GFP_NOFS); |
1746 | printk("found delalloc bits after clear extent_bit\n"); | 1763 | delalloc_start = delalloc_end + 1; |
1747 | } | ||
1748 | } else if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0)) { | ||
1749 | printk("found delalloc bits after find_delalloc_range returns 0\n"); | ||
1750 | } | 1764 | } |
1765 | lock_extent(tree, start, page_end, GFP_NOFS); | ||
1751 | 1766 | ||
1752 | end = page_end; | 1767 | end = page_end; |
1753 | if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0)) { | 1768 | if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0)) { |