Commit ca664626 authored by Chris Mason's avatar Chris Mason

Btrfs: Add efficient dirty accounting to the extent_map tree

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 448d640b
...@@ -210,7 +210,7 @@ static int btree_writepages(struct address_space *mapping, ...@@ -210,7 +210,7 @@ static int btree_writepages(struct address_space *mapping,
{ {
struct extent_map_tree *tree; struct extent_map_tree *tree;
tree = &BTRFS_I(mapping->host)->extent_tree; tree = &BTRFS_I(mapping->host)->extent_tree;
if (wbc->sync_mode == WB_SYNC_NONE && current_is_pdflush()) { if (wbc->sync_mode == WB_SYNC_NONE) {
u64 num_dirty; u64 num_dirty;
u64 start = 0; u64 start = 0;
unsigned long thresh = 96 * 1024 * 1024; unsigned long thresh = 96 * 1024 * 1024;
...@@ -218,6 +218,11 @@ static int btree_writepages(struct address_space *mapping, ...@@ -218,6 +218,11 @@ static int btree_writepages(struct address_space *mapping,
if (wbc->for_kupdate) if (wbc->for_kupdate)
return 0; return 0;
if (current_is_pdflush()) {
thresh = 96 * 1024 * 1024;
} else {
thresh = 8 * 1024 * 1024;
}
num_dirty = count_range_bits(tree, &start, thresh, EXTENT_DIRTY); num_dirty = count_range_bits(tree, &start, thresh, EXTENT_DIRTY);
if (num_dirty < thresh) { if (num_dirty < thresh) {
return 0; return 0;
......
...@@ -42,6 +42,7 @@ struct extent_page_data { ...@@ -42,6 +42,7 @@ struct extent_page_data {
struct extent_map_tree *tree; struct extent_map_tree *tree;
get_extent_t *get_extent; get_extent_t *get_extent;
}; };
int __init extent_map_init(void) int __init extent_map_init(void)
{ {
extent_map_cache = btrfs_cache_create("extent_map", extent_map_cache = btrfs_cache_create("extent_map",
...@@ -94,6 +95,7 @@ void extent_map_tree_init(struct extent_map_tree *tree, ...@@ -94,6 +95,7 @@ void extent_map_tree_init(struct extent_map_tree *tree,
tree->map.rb_node = NULL; tree->map.rb_node = NULL;
tree->state.rb_node = NULL; tree->state.rb_node = NULL;
tree->ops = NULL; tree->ops = NULL;
tree->dirty_bytes = 0;
rwlock_init(&tree->lock); rwlock_init(&tree->lock);
spin_lock_init(&tree->lru_lock); spin_lock_init(&tree->lru_lock);
tree->mapping = mapping; tree->mapping = mapping;
...@@ -414,6 +416,8 @@ static int insert_state(struct extent_map_tree *tree, ...@@ -414,6 +416,8 @@ static int insert_state(struct extent_map_tree *tree,
printk("end < start %Lu %Lu\n", end, start); printk("end < start %Lu %Lu\n", end, start);
WARN_ON(1); WARN_ON(1);
} }
if (bits & EXTENT_DIRTY)
tree->dirty_bytes += end - start + 1;
state->state |= bits; state->state |= bits;
state->start = start; state->start = start;
state->end = end; state->end = end;
...@@ -476,6 +480,12 @@ static int clear_state_bit(struct extent_map_tree *tree, ...@@ -476,6 +480,12 @@ static int clear_state_bit(struct extent_map_tree *tree,
int delete) int delete)
{ {
int ret = state->state & bits; int ret = state->state & bits;
if ((bits & EXTENT_DIRTY) && (state->state & EXTENT_DIRTY)) {
u64 range = state->end - state->start + 1;
WARN_ON(range > tree->dirty_bytes);
tree->dirty_bytes -= range;
}
state->state &= ~bits; state->state &= ~bits;
if (wake) if (wake)
wake_up(&state->wq); wake_up(&state->wq);
...@@ -668,6 +678,17 @@ int wait_extent_bit(struct extent_map_tree *tree, u64 start, u64 end, int bits) ...@@ -668,6 +678,17 @@ int wait_extent_bit(struct extent_map_tree *tree, u64 start, u64 end, int bits)
} }
EXPORT_SYMBOL(wait_extent_bit); EXPORT_SYMBOL(wait_extent_bit);
static void set_state_bits(struct extent_map_tree *tree,
struct extent_state *state,
int bits)
{
if ((bits & EXTENT_DIRTY) && !(state->state & EXTENT_DIRTY)) {
u64 range = state->end - state->start + 1;
tree->dirty_bytes += range;
}
state->state |= bits;
}
/* /*
* set some bits on a range in the tree. This may require allocations * set some bits on a range in the tree. This may require allocations
* or sleeping, so the gfp mask is used to indicate what is allowed. * or sleeping, so the gfp mask is used to indicate what is allowed.
...@@ -727,7 +748,7 @@ int set_extent_bit(struct extent_map_tree *tree, u64 start, u64 end, int bits, ...@@ -727,7 +748,7 @@ int set_extent_bit(struct extent_map_tree *tree, u64 start, u64 end, int bits,
err = -EEXIST; err = -EEXIST;
goto out; goto out;
} }
state->state |= bits; set_state_bits(tree, state, bits);
start = state->end + 1; start = state->end + 1;
merge_state(tree, state); merge_state(tree, state);
goto search_again; goto search_again;
...@@ -762,7 +783,7 @@ int set_extent_bit(struct extent_map_tree *tree, u64 start, u64 end, int bits, ...@@ -762,7 +783,7 @@ int set_extent_bit(struct extent_map_tree *tree, u64 start, u64 end, int bits,
if (err) if (err)
goto out; goto out;
if (state->end <= end) { if (state->end <= end) {
state->state |= bits; set_state_bits(tree, state, bits);
start = state->end + 1; start = state->end + 1;
merge_state(tree, state); merge_state(tree, state);
} else { } else {
...@@ -808,7 +829,7 @@ int set_extent_bit(struct extent_map_tree *tree, u64 start, u64 end, int bits, ...@@ -808,7 +829,7 @@ int set_extent_bit(struct extent_map_tree *tree, u64 start, u64 end, int bits,
err = split_state(tree, state, prealloc, end + 1); err = split_state(tree, state, prealloc, end + 1);
BUG_ON(err == -EEXIST); BUG_ON(err == -EEXIST);
prealloc->state |= bits; set_state_bits(tree, prealloc, bits);
merge_state(tree, prealloc); merge_state(tree, prealloc);
prealloc = NULL; prealloc = NULL;
goto out; goto out;
...@@ -1116,6 +1137,11 @@ u64 count_range_bits(struct extent_map_tree *tree, ...@@ -1116,6 +1137,11 @@ u64 count_range_bits(struct extent_map_tree *tree,
int found = 0; int found = 0;
write_lock_irq(&tree->lock); write_lock_irq(&tree->lock);
if (bits == EXTENT_DIRTY) {
*start = 0;
total_bytes = tree->dirty_bytes;
goto out;
}
/* /*
* this search will find all the extents that end after * this search will find all the extents that end after
* our range starts. * our range starts.
......
...@@ -40,6 +40,7 @@ struct extent_map_tree { ...@@ -40,6 +40,7 @@ struct extent_map_tree {
struct rb_root map; struct rb_root map;
struct rb_root state; struct rb_root state;
struct address_space *mapping; struct address_space *mapping;
u64 dirty_bytes;
rwlock_t lock; rwlock_t lock;
struct extent_map_ops *ops; struct extent_map_ops *ops;
spinlock_t lru_lock; spinlock_t lru_lock;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment