Btrfs: free space cache cleanups

This patch cleans up the free space cache code a bit.  It better documents the
idiosyncrasies of tree_search_offset and makes the code make a bit more sense.
I took out the info allocation at the start of __btrfs_add_free_space and put it
where it makes more sense.  This was left over cruft from when alloc_mutex
existed.  Also all of the re-searches we do to make sure we inserted properly.

Signed-off-by: Josef Bacik <jbacik@redhat.com>
This commit is contained in:
Josef Bacik 2009-04-03 10:14:19 -04:00 committed by Chris Mason
parent bedf762ba3
commit 70cb074345
2 changed files with 44 additions and 51 deletions

View File

@ -291,8 +291,8 @@ next:
block_group->key.objectid + block_group->key.objectid +
block_group->key.offset); block_group->key.offset);
remove_sb_from_cache(root, block_group);
block_group->cached = 1; block_group->cached = 1;
remove_sb_from_cache(root, block_group);
ret = 0; ret = 0;
err: err:
btrfs_free_path(path); btrfs_free_path(path);

View File

@ -68,14 +68,24 @@ static int tree_insert_bytes(struct rb_root *root, u64 bytes,
} }
/* /*
* searches the tree for the given offset. If contains is set we will return * searches the tree for the given offset.
* the free space that contains the given offset. If contains is not set we *
* will return the free space that starts at or after the given offset and is * fuzzy == 1: this is used for allocations where we are given a hint of where
* at least bytes long. * to look for free space. Because the hint may not be completely on an offset
* mark, or the hint may no longer point to free space we need to fudge our
* results a bit. So we look for free space starting at or after offset with at
* least bytes size. We prefer to find as close to the given offset as we can.
* Also if the offset is within a free space range, then we will return the free
* space that contains the given offset, which means we can return a free space
* chunk with an offset before the provided offset.
*
* fuzzy == 0: this is just a normal tree search. Give us the free space that
* starts at the given offset which is at least bytes size, and if its not there
* return NULL.
*/ */
static struct btrfs_free_space *tree_search_offset(struct rb_root *root, static struct btrfs_free_space *tree_search_offset(struct rb_root *root,
u64 offset, u64 bytes, u64 offset, u64 bytes,
int contains) int fuzzy)
{ {
struct rb_node *n = root->rb_node; struct rb_node *n = root->rb_node;
struct btrfs_free_space *entry, *ret = NULL; struct btrfs_free_space *entry, *ret = NULL;
@ -84,13 +94,14 @@ static struct btrfs_free_space *tree_search_offset(struct rb_root *root,
entry = rb_entry(n, struct btrfs_free_space, offset_index); entry = rb_entry(n, struct btrfs_free_space, offset_index);
if (offset < entry->offset) { if (offset < entry->offset) {
if (!contains && if (fuzzy &&
(!ret || entry->offset < ret->offset) && (!ret || entry->offset < ret->offset) &&
(bytes <= entry->bytes)) (bytes <= entry->bytes))
ret = entry; ret = entry;
n = n->rb_left; n = n->rb_left;
} else if (offset > entry->offset) { } else if (offset > entry->offset) {
if ((entry->offset + entry->bytes - 1) >= offset && if (fuzzy &&
(entry->offset + entry->bytes - 1) >= offset &&
bytes <= entry->bytes) { bytes <= entry->bytes) {
ret = entry; ret = entry;
break; break;
@ -190,55 +201,28 @@ static int __btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
struct btrfs_free_space *right_info; struct btrfs_free_space *right_info;
struct btrfs_free_space *left_info; struct btrfs_free_space *left_info;
struct btrfs_free_space *info = NULL; struct btrfs_free_space *info = NULL;
struct btrfs_free_space *alloc_info;
int ret = 0; int ret = 0;
alloc_info = kzalloc(sizeof(struct btrfs_free_space), GFP_NOFS);
if (!alloc_info)
return -ENOMEM;
/* /*
* first we want to see if there is free space adjacent to the range we * first we want to see if there is free space adjacent to the range we
* are adding, if there is remove that struct and add a new one to * are adding, if there is remove that struct and add a new one to
* cover the entire range * cover the entire range
*/ */
right_info = tree_search_offset(&block_group->free_space_offset, right_info = tree_search_offset(&block_group->free_space_offset,
offset+bytes, 0, 1); offset+bytes, 0, 0);
left_info = tree_search_offset(&block_group->free_space_offset, left_info = tree_search_offset(&block_group->free_space_offset,
offset-1, 0, 1); offset-1, 0, 1);
if (right_info && right_info->offset == offset+bytes) { if (right_info) {
unlink_free_space(block_group, right_info); unlink_free_space(block_group, right_info);
info = right_info; info = right_info;
info->offset = offset; info->offset = offset;
info->bytes += bytes; info->bytes += bytes;
} else if (right_info && right_info->offset != offset+bytes) {
printk(KERN_ERR "btrfs adding space in the middle of an "
"existing free space area. existing: "
"offset=%llu, bytes=%llu. new: offset=%llu, "
"bytes=%llu\n", (unsigned long long)right_info->offset,
(unsigned long long)right_info->bytes,
(unsigned long long)offset,
(unsigned long long)bytes);
BUG();
} }
if (left_info) { if (left_info && left_info->offset + left_info->bytes == offset) {
unlink_free_space(block_group, left_info); unlink_free_space(block_group, left_info);
if (unlikely((left_info->offset + left_info->bytes) !=
offset)) {
printk(KERN_ERR "btrfs free space to the left "
"of new free space isn't "
"quite right. existing: offset=%llu, "
"bytes=%llu. new: offset=%llu, bytes=%llu\n",
(unsigned long long)left_info->offset,
(unsigned long long)left_info->bytes,
(unsigned long long)offset,
(unsigned long long)bytes);
BUG();
}
if (info) { if (info) {
info->offset = left_info->offset; info->offset = left_info->offset;
info->bytes += left_info->bytes; info->bytes += left_info->bytes;
@ -251,13 +235,15 @@ static int __btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
if (info) { if (info) {
ret = link_free_space(block_group, info); ret = link_free_space(block_group, info);
if (!ret) if (ret)
info = NULL; kfree(info);
goto out; goto out;
} }
info = alloc_info; info = kzalloc(sizeof(struct btrfs_free_space), GFP_NOFS);
alloc_info = NULL; if (!info)
return -ENOMEM;
info->offset = offset; info->offset = offset;
info->bytes = bytes; info->bytes = bytes;
@ -271,8 +257,6 @@ out:
BUG(); BUG();
} }
kfree(alloc_info);
return ret; return ret;
} }
@ -283,6 +267,7 @@ __btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
struct btrfs_free_space *info; struct btrfs_free_space *info;
int ret = 0; int ret = 0;
BUG_ON(!block_group->cached);
info = tree_search_offset(&block_group->free_space_offset, offset, 0, info = tree_search_offset(&block_group->free_space_offset, offset, 0,
1); 1);
@ -341,6 +326,18 @@ __btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
offset - old_start); offset - old_start);
BUG_ON(ret); BUG_ON(ret);
} else { } else {
if (!info) {
printk(KERN_ERR "couldn't find space %llu to free\n",
(unsigned long long)offset);
printk(KERN_ERR "cached is %d, offset %llu bytes %llu\n",
block_group->cached, block_group->key.objectid,
block_group->key.offset);
btrfs_dump_free_space(block_group, bytes);
} else if (info) {
printk(KERN_ERR "hmm, found offset=%llu bytes=%llu, "
"but wanted offset=%llu bytes=%llu\n",
info->offset, info->bytes, offset, bytes);
}
WARN_ON(1); WARN_ON(1);
} }
out: out:
@ -351,12 +348,9 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
u64 offset, u64 bytes) u64 offset, u64 bytes)
{ {
int ret; int ret;
struct btrfs_free_space *sp;
mutex_lock(&block_group->alloc_mutex); mutex_lock(&block_group->alloc_mutex);
ret = __btrfs_add_free_space(block_group, offset, bytes); ret = __btrfs_add_free_space(block_group, offset, bytes);
sp = tree_search_offset(&block_group->free_space_offset, offset, 0, 1);
BUG_ON(!sp);
mutex_unlock(&block_group->alloc_mutex); mutex_unlock(&block_group->alloc_mutex);
return ret; return ret;
@ -366,11 +360,8 @@ int btrfs_add_free_space_lock(struct btrfs_block_group_cache *block_group,
u64 offset, u64 bytes) u64 offset, u64 bytes)
{ {
int ret; int ret;
struct btrfs_free_space *sp;
ret = __btrfs_add_free_space(block_group, offset, bytes); ret = __btrfs_add_free_space(block_group, offset, bytes);
sp = tree_search_offset(&block_group->free_space_offset, offset, 0, 1);
BUG_ON(!sp);
return ret; return ret;
} }
@ -408,6 +399,8 @@ void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
info = rb_entry(n, struct btrfs_free_space, offset_index); info = rb_entry(n, struct btrfs_free_space, offset_index);
if (info->bytes >= bytes) if (info->bytes >= bytes)
count++; count++;
printk(KERN_ERR "entry offset %llu, bytes %llu\n", info->offset,
info->bytes);
} }
printk(KERN_INFO "%d blocks of free space at or bigger than bytes is" printk(KERN_INFO "%d blocks of free space at or bigger than bytes is"
"\n", count); "\n", count);
@ -486,7 +479,7 @@ struct btrfs_free_space *btrfs_find_free_space(struct btrfs_block_group_cache
struct btrfs_free_space *ret = NULL; struct btrfs_free_space *ret = NULL;
ret = tree_search_offset(&block_group->free_space_offset, offset, ret = tree_search_offset(&block_group->free_space_offset, offset,
bytes, 0); bytes, 1);
if (!ret) if (!ret)
ret = tree_search_bytes(&block_group->free_space_bytes, ret = tree_search_bytes(&block_group->free_space_bytes,
offset, bytes); offset, bytes);