Skip to content

Commit

Permalink
Btrfs: switch extent_map to a rw lock
Browse files Browse the repository at this point in the history
There are two main users of the extent_map tree.  The
first is regular file inodes, where it is evenly spread
between readers and writers.

The second is the chunk allocation tree, which maps blocks from
logical addresses to phyiscal ones, and it is 99.99% reads.

The mapping tree is a point of lock contention during heavy IO
workloads, so this commit switches things to a rw lock.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
  • Loading branch information
Chris Mason committed Sep 11, 2009
1 parent 57fd5a5 commit 890871b
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 60 deletions.
8 changes: 4 additions & 4 deletions fs/btrfs/compression.c
Original file line number Diff line number Diff line change
Expand Up @@ -507,10 +507,10 @@ static noinline int add_ra_bio_pages(struct inode *inode,
*/
set_page_extent_mapped(page);
lock_extent(tree, last_offset, end, GFP_NOFS);
spin_lock(&em_tree->lock);
read_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, last_offset,
PAGE_CACHE_SIZE);
spin_unlock(&em_tree->lock);
read_unlock(&em_tree->lock);

if (!em || last_offset < em->start ||
(last_offset + PAGE_CACHE_SIZE > extent_map_end(em)) ||
Expand Down Expand Up @@ -594,11 +594,11 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
em_tree = &BTRFS_I(inode)->extent_tree;

/* we need the actual starting offset of this extent in the file */
spin_lock(&em_tree->lock);
read_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree,
page_offset(bio->bi_io_vec->bv_page),
PAGE_CACHE_SIZE);
spin_unlock(&em_tree->lock);
read_unlock(&em_tree->lock);

compressed_len = em->block_len;
cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS);
Expand Down
14 changes: 7 additions & 7 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,15 @@ static struct extent_map *btree_get_extent(struct inode *inode,
struct extent_map *em;
int ret;

spin_lock(&em_tree->lock);
read_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, start, len);
if (em) {
em->bdev =
BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
spin_unlock(&em_tree->lock);
read_unlock(&em_tree->lock);
goto out;
}
spin_unlock(&em_tree->lock);
read_unlock(&em_tree->lock);

em = alloc_extent_map(GFP_NOFS);
if (!em) {
Expand All @@ -142,7 +142,7 @@ static struct extent_map *btree_get_extent(struct inode *inode,
em->block_start = 0;
em->bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;

spin_lock(&em_tree->lock);
write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em);
if (ret == -EEXIST) {
u64 failed_start = em->start;
Expand All @@ -161,7 +161,7 @@ static struct extent_map *btree_get_extent(struct inode *inode,
free_extent_map(em);
em = NULL;
}
spin_unlock(&em_tree->lock);
write_unlock(&em_tree->lock);

if (ret)
em = ERR_PTR(ret);
Expand Down Expand Up @@ -1323,9 +1323,9 @@ static void btrfs_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
offset = page_offset(page);

em_tree = &BTRFS_I(inode)->extent_tree;
spin_lock(&em_tree->lock);
read_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, offset, PAGE_CACHE_SIZE);
spin_unlock(&em_tree->lock);
read_unlock(&em_tree->lock);
if (!em) {
__unplug_io_fn(bdi, page);
return;
Expand Down
4 changes: 2 additions & 2 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -5396,9 +5396,9 @@ static noinline int relocate_data_extent(struct inode *reloc_inode,
lock_extent(&BTRFS_I(reloc_inode)->io_tree, start, end, GFP_NOFS);
while (1) {
int ret;
spin_lock(&em_tree->lock);
write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em);
spin_unlock(&em_tree->lock);
write_unlock(&em_tree->lock);
if (ret != -EEXIST) {
free_extent_map(em);
break;
Expand Down
8 changes: 4 additions & 4 deletions fs/btrfs/extent_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -2786,15 +2786,15 @@ int try_release_extent_mapping(struct extent_map_tree *map,
u64 len;
while (start <= end) {
len = end - start + 1;
spin_lock(&map->lock);
write_lock(&map->lock);
em = lookup_extent_mapping(map, start, len);
if (!em || IS_ERR(em)) {
spin_unlock(&map->lock);
write_unlock(&map->lock);
break;
}
if (test_bit(EXTENT_FLAG_PINNED, &em->flags) ||
em->start != start) {
spin_unlock(&map->lock);
write_unlock(&map->lock);
free_extent_map(em);
break;
}
Expand All @@ -2808,7 +2808,7 @@ int try_release_extent_mapping(struct extent_map_tree *map,
free_extent_map(em);
}
start = extent_map_end(em);
spin_unlock(&map->lock);
write_unlock(&map->lock);

/* once for us */
free_extent_map(em);
Expand Down
5 changes: 1 addition & 4 deletions fs/btrfs/extent_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void extent_map_exit(void)
void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask)
{
tree->map.rb_node = NULL;
spin_lock_init(&tree->lock);
rwlock_init(&tree->lock);
}

/**
Expand Down Expand Up @@ -222,7 +222,6 @@ int add_extent_mapping(struct extent_map_tree *tree,
ret = -EEXIST;
goto out;
}
assert_spin_locked(&tree->lock);
rb = tree_insert(&tree->map, em->start, &em->rb_node);
if (rb) {
ret = -EEXIST;
Expand Down Expand Up @@ -285,7 +284,6 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
struct rb_node *next = NULL;
u64 end = range_end(start, len);

assert_spin_locked(&tree->lock);
rb_node = __tree_search(&tree->map, start, &prev, &next);
if (!rb_node && prev) {
em = rb_entry(prev, struct extent_map, rb_node);
Expand Down Expand Up @@ -331,7 +329,6 @@ int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em)
int ret = 0;

WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags));
assert_spin_locked(&tree->lock);
rb_erase(&em->rb_node, &tree->map);
em->in_tree = 0;
return ret;
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/extent_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct extent_map {

struct extent_map_tree {
struct rb_root map;
spinlock_t lock;
rwlock_t lock;
};

static inline u64 extent_map_end(struct extent_map *em)
Expand Down
8 changes: 4 additions & 4 deletions fs/btrfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,15 +188,15 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
if (!split2)
split2 = alloc_extent_map(GFP_NOFS);

spin_lock(&em_tree->lock);
write_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, start, len);
if (!em) {
spin_unlock(&em_tree->lock);
write_unlock(&em_tree->lock);
break;
}
flags = em->flags;
if (skip_pinned && test_bit(EXTENT_FLAG_PINNED, &em->flags)) {
spin_unlock(&em_tree->lock);
write_unlock(&em_tree->lock);
if (em->start <= start &&
(!testend || em->start + em->len >= start + len)) {
free_extent_map(em);
Expand Down Expand Up @@ -259,7 +259,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
free_extent_map(split);
split = NULL;
}
spin_unlock(&em_tree->lock);
write_unlock(&em_tree->lock);

/* once for us */
free_extent_map(em);
Expand Down
24 changes: 12 additions & 12 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -612,9 +612,9 @@ static noinline int submit_compressed_extents(struct inode *inode,
set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);

while (1) {
spin_lock(&em_tree->lock);
write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em);
spin_unlock(&em_tree->lock);
write_unlock(&em_tree->lock);
if (ret != -EEXIST) {
free_extent_map(em);
break;
Expand Down Expand Up @@ -748,9 +748,9 @@ static noinline int cow_file_range(struct inode *inode,
set_bit(EXTENT_FLAG_PINNED, &em->flags);

while (1) {
spin_lock(&em_tree->lock);
write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em);
spin_unlock(&em_tree->lock);
write_unlock(&em_tree->lock);
if (ret != -EEXIST) {
free_extent_map(em);
break;
Expand Down Expand Up @@ -1081,9 +1081,9 @@ static noinline int run_delalloc_nocow(struct inode *inode,
em->bdev = root->fs_info->fs_devices->latest_bdev;
set_bit(EXTENT_FLAG_PINNED, &em->flags);
while (1) {
spin_lock(&em_tree->lock);
write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em);
spin_unlock(&em_tree->lock);
write_unlock(&em_tree->lock);
if (ret != -EEXIST) {
free_extent_map(em);
break;
Expand Down Expand Up @@ -1670,13 +1670,13 @@ static int btrfs_io_failed_hook(struct bio *failed_bio,
failrec->last_mirror = 0;
failrec->bio_flags = 0;

spin_lock(&em_tree->lock);
read_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, start, failrec->len);
if (em->start > start || em->start + em->len < start) {
free_extent_map(em);
em = NULL;
}
spin_unlock(&em_tree->lock);
read_unlock(&em_tree->lock);

if (!em || IS_ERR(em)) {
kfree(failrec);
Expand Down Expand Up @@ -4069,11 +4069,11 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
int compressed;

again:
spin_lock(&em_tree->lock);
read_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, start, len);
if (em)
em->bdev = root->fs_info->fs_devices->latest_bdev;
spin_unlock(&em_tree->lock);
read_unlock(&em_tree->lock);

if (em) {
if (em->start > start || em->start + em->len <= start)
Expand Down Expand Up @@ -4264,7 +4264,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
}

err = 0;
spin_lock(&em_tree->lock);
write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em);
/* it is possible that someone inserted the extent into the tree
* while we had the lock dropped. It is also possible that
Expand Down Expand Up @@ -4304,7 +4304,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
err = 0;
}
}
spin_unlock(&em_tree->lock);
write_unlock(&em_tree->lock);
out:
if (path)
btrfs_free_path(path);
Expand Down
4 changes: 2 additions & 2 deletions fs/btrfs/relocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -2646,9 +2646,9 @@ int relocate_data_extent(struct inode *inode, struct btrfs_key *extent_key)
lock_extent(&BTRFS_I(inode)->io_tree, start, end, GFP_NOFS);
while (1) {
int ret;
spin_lock(&em_tree->lock);
write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em);
spin_unlock(&em_tree->lock);
write_unlock(&em_tree->lock);
if (ret != -EEXIST) {
free_extent_map(em);
break;
Expand Down
Loading

0 comments on commit 890871b

Please sign in to comment.