aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent_map.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-11-20 10:47:25 -0500
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:58 -0400
commit3e9fd94ff0028a044d55690eb0a801fd1472e3c6 (patch)
treedb90bb2cb783763b144d2b4ff87ad3c41113495f /fs/btrfs/extent_map.c
parent2f4cbe6442d3be7b5e4cf1607a5ab33995fe2d25 (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.c83
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:
1033EXPORT_SYMBOL(find_first_extent_bit); 1033EXPORT_SYMBOL(find_first_extent_bit);
1034 1034
1035u64 find_lock_delalloc_range(struct extent_map_tree *tree, 1035u64 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)) {