On Fri, Oct 17, 2008 at 09:48:58AM +0800, Yan Zheng
wrote:> 2008/10/17 Josef Bacik <jbacik@redhat.com>:
> > On Thu, Oct 16, 2008 at 04:54:12PM -0400, Josef Bacik wrote:
> >> Hello,
> >>
> >> Its the end of the day here and I haven''t figured this
out, so hopefully Yan you
> >> can figure this out and I can come in tomorrow and keep working on
taking
> >> alloc_mutex out :). What is happening is I''m getting
-ENOENT from
> >> lookup_extent_backref in finish_current_insert() when
extent_op->type => >> PENDING_BACKREF_UPDATE. The way I have
locking is that the only way this can
> >> happen is if we delete the extent backref completely, and then do
> >> btrfs_update_ref. I put a lookup_extent_backref in
__btrfs_update_extent_ref
> >> and did a BUG_ON(ret), and it gave me this backtrace
> >>
>
> I guess there are two or more threads running finish_current_insert at the
same
> time. (find_first_extent_bit vs clear_extent_bits race)
>
> >> [<ffffffffa035ecac>] ? btrfs_update_ref+0x2ce/0x322 [btrfs]
> >> [<ffffffffa034f859>] ? insert_ptr+0x176/0x184 [btrfs]
> >> [<ffffffffa0354615>] ? split_node+0x54a/0x5b3 [btrfs]
> >> [<ffffffffa03555af>] ? btrfs_search_slot+0x4ef/0x7aa
[btrfs]
> >> [<ffffffff8109a1ad>] ? check_bytes_and_report+0x37/0xc9
> >> [<ffffffff8109a1ad>] ? check_bytes_and_report+0x37/0xc9
> >> [<ffffffffa0355da7>] ? btrfs_insert_empty_items+0x7d/0x43b
[btrfs]
> >> [<ffffffffa03561b4>] ? btrfs_insert_item+0x4f/0xa4 [btrfs]
> >> [<ffffffffa0358ef6>] ? finish_current_insert+0xfc/0x2b5
[btrfs]
> >> [<ffffffff8109a832>] ? init_object+0x27/0x6e
> >> [<ffffffffa035a77b>] ?
__btrfs_alloc_reserved_extent+0x37d/0x3dc [btrfs]
> >> [<ffffffffa035aa26>] ?
btrfs_alloc_reserved_extent+0x2b/0x5b [btrfs]
> >> [<ffffffffa036accf>] ? btrfs_finish_ordered_io+0x21b/0x344
[btrfs]
> >> [<ffffffffa037a782>] ? end_bio_extent_writepage+0x9b/0x172
[btrfs]
> >> [<ffffffffa037fe51>] ? worker_loop+0x42/0x125 [btrfs]
> >> [<ffffffffa037fe0f>] ? worker_loop+0x0/0x125 [btrfs]
> >> [<ffffffff81046721>] ? kthread+0x47/0x76
> >> [<ffffffff8100cd59>] ? child_rip+0xa/0x11
> >> [<ffffffff810466da>] ? kthread+0x0/0x76
> >> [<ffffffff8100cd4f>] ? child_rip+0x0/0x11
> >>
> >> And I also put in some printk''s to figure out when
exactly this was happening,
> >> and it happens in split_node() when c == root->node, so we do
an
> >> insert_new_root. My first reaction was to put a c =
path->nodes[level] after
> >> the insert_new_root, but looking at it thats just going to give me
the same
> >> thing back. I can''t figure out if I''m doing
something wrong or if there is
> >> something wonky with the backref stuff, and what is even more
worriesome is that
> >> I can''t figure out why having alloc_mutex in there kept
this problem from
> >> happenign before, since the way this happens doesn''t have
anything to do with
> >> alloc_mutex. All help is appreciated, even random thinking
outloud, hopefully
> >> we can figure out what is going on and I can finish ripping
alloc_mutex out.
> >> Thanks,
> >>
> >
> > Ok I think I figured it out, we need to have a
> >
> > c = root->node;
> >
> > after the insert_new_root, since we will have free''d the old
extent buffer and
> > replaced it with a new one. Does that sound right? Thanks,
> >
>
> I don''t think so. If we do this, we will end up spliting the new
root.
>
here is my patch, its a bit of a mess right now, thanks,
Josef
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 9caeb37..4f55552 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1390,8 +1390,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans,
struct btrfs_root
lowest_level = p->lowest_level;
WARN_ON(lowest_level && ins_len > 0);
WARN_ON(p->nodes[0] != NULL);
- WARN_ON(cow && root == root->fs_info->extent_root &&
- !mutex_is_locked(&root->fs_info->alloc_mutex));
+
if (ins_len < 0)
lowest_unlock = 2;
@@ -2051,6 +2050,7 @@ static noinline int split_node(struct btrfs_trans_handle
*trans,
if (c == root->node) {
/* trying to split the root, lets make a new one */
ret = insert_new_root(trans, root, path, level + 1);
+ printk(KERN_ERR "splitting the root, %llu\n", c->start);
if (ret)
return ret;
} else {
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index fad58b9..d1e304f 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -516,12 +516,14 @@ struct btrfs_free_space {
struct rb_node offset_index;
u64 offset;
u64 bytes;
+ unsigned long ip;
};
struct btrfs_block_group_cache {
struct btrfs_key key;
struct btrfs_block_group_item item;
spinlock_t lock;
+ struct mutex alloc_mutex;
u64 pinned;
u64 reserved;
u64 flags;
@@ -600,6 +602,7 @@ struct btrfs_fs_info {
struct mutex transaction_kthread_mutex;
struct mutex cleaner_mutex;
struct mutex alloc_mutex;
+ struct mutex extent_io_mutex;
struct mutex chunk_mutex;
struct mutex drop_mutex;
struct mutex volume_mutex;
@@ -1879,8 +1882,12 @@ int btrfs_acl_chmod(struct inode *inode);
/* free-space-cache.c */
int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
u64 bytenr, u64 size);
+int btrfs_add_free_space_lock(struct btrfs_block_group_cache *block_group,
+ u64 offset, u64 bytes);
int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
u64 bytenr, u64 size);
+int btrfs_remove_free_space_lock(struct btrfs_block_group_cache *block_group,
+ u64 offset, u64 bytes);
void btrfs_remove_free_space_cache(struct btrfs_block_group_cache
*block_group);
struct btrfs_free_space *btrfs_find_free_space(struct btrfs_block_group_cache
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 0be044b..6da2345 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1458,6 +1458,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
mutex_init(&fs_info->tree_log_mutex);
mutex_init(&fs_info->drop_mutex);
mutex_init(&fs_info->alloc_mutex);
+ mutex_init(&fs_info->extent_io_mutex);
mutex_init(&fs_info->chunk_mutex);
mutex_init(&fs_info->transaction_kthread_mutex);
mutex_init(&fs_info->cleaner_mutex);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 5f235fc..c27c71b 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -164,6 +164,7 @@ static int add_new_free_space(struct btrfs_block_group_cache
*block_group,
u64 extent_start, extent_end, size;
int ret;
+ mutex_lock(&info->extent_io_mutex);
while (start < end) {
ret = find_first_extent_bit(&info->pinned_extents, start,
&extent_start, &extent_end,
@@ -175,7 +176,8 @@ static int add_new_free_space(struct btrfs_block_group_cache
*block_group,
start = extent_end + 1;
} else if (extent_start > start && extent_start < end) {
size = extent_start - start;
- ret = btrfs_add_free_space(block_group, start, size);
+ ret = btrfs_add_free_space_lock(block_group, start,
+ size);
BUG_ON(ret);
start = extent_end + 1;
} else {
@@ -185,9 +187,10 @@ static int add_new_free_space(struct
btrfs_block_group_cache *block_group,
if (start < end) {
size = end - start;
- ret = btrfs_add_free_space(block_group, start, size);
+ ret = btrfs_add_free_space_lock(block_group, start, size);
BUG_ON(ret);
}
+ mutex_unlock(&info->extent_io_mutex);
return 0;
}
@@ -231,6 +234,7 @@ static int cache_block_group(struct btrfs_root *root,
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0)
goto err;
+
ret = btrfs_previous_item(root, path, 0, BTRFS_EXTENT_ITEM_KEY);
if (ret < 0)
goto err;
@@ -676,6 +680,7 @@ static int __btrfs_update_extent_ref(struct
btrfs_trans_handle *trans,
BUG_ON(owner_objectid >= BTRFS_MAX_LEVEL);
num_bytes = btrfs_level_size(root, (int)owner_objectid);
+ mutex_lock(&root->fs_info->extent_io_mutex);
if (test_range_bit(&root->fs_info->extent_ins, bytenr,
bytenr + num_bytes - 1, EXTENT_LOCKED, 0)) {
u64 priv;
@@ -707,6 +712,21 @@ static int __btrfs_update_extent_ref(struct
btrfs_trans_handle *trans,
set_state_private(&root->fs_info->extent_ins,
bytenr, (unsigned long)extent_op);
}
+
+ if (extent_op->type == PENDING_BACKREF_UPDATE) {
+ path = btrfs_alloc_path();
+ BUG_ON(!path);
+ path->skip_locking = 1;
+ ret = lookup_extent_backref(trans, extent_root,
+ path, bytenr, orig_parent,
+ orig_root, orig_generation,
+ owner_objectid, 0);
+ if (ret)
+ printk(KERN_ERR "Oops, %llu\n", orig_parent);
+ BUG_ON(ret);
+ btrfs_free_path(path);
+ }
+ mutex_unlock(&root->fs_info->extent_io_mutex);
return 0;
}
@@ -1390,9 +1410,11 @@ static int update_space_info(struct btrfs_fs_info *info,
u64 flags,
found = __find_space_info(info, flags);
if (found) {
+ spin_lock(&found->lock);
found->total_bytes += total_bytes;
found->bytes_used += bytes_used;
found->full = 0;
+ spin_unlock(&found->lock);
*space_info = found;
return 0;
}
@@ -1479,18 +1501,25 @@ static int do_chunk_alloc(struct btrfs_trans_handle
*trans,
}
BUG_ON(!space_info);
+ spin_lock(&space_info->lock);
if (space_info->force_alloc) {
force = 1;
space_info->force_alloc = 0;
}
- if (space_info->full)
+ if (space_info->full) {
+ spin_unlock(&space_info->lock);
goto out;
+ }
thresh = div_factor(space_info->total_bytes, 6);
if (!force &&
(space_info->bytes_used + space_info->bytes_pinned +
- space_info->bytes_reserved + alloc_bytes) < thresh)
+ space_info->bytes_reserved + alloc_bytes) < thresh) {
+ spin_unlock(&space_info->lock);
goto out;
+ }
+
+ spin_unlock(&space_info->lock);
while (!mutex_trylock(&extent_root->fs_info->chunk_mutex)) {
if (!force)
@@ -1501,13 +1530,20 @@ static int do_chunk_alloc(struct btrfs_trans_handle
*trans,
waited = 1;
}
- if (waited && space_info->full)
- goto out_unlock;
+ if (waited) {
+ spin_lock(&space_info->lock);
+ if (space_info->full) {
+ spin_unlock(&space_info->lock);
+ goto out_unlock;
+ }
+ spin_unlock(&space_info->lock);
+ }
ret = btrfs_alloc_chunk(trans, extent_root, &start, &num_bytes,
flags);
+ if (ret)
+ goto out_unlock;
if (ret == -ENOSPC) {
printk("space info full %Lu\n", flags);
- space_info->full = 1;
goto out_unlock;
}
BUG_ON(ret);
@@ -1518,6 +1554,12 @@ printk("space info full %Lu\n", flags);
out_unlock:
mutex_unlock(&extent_root->fs_info->chunk_mutex);
+ if (ret == -ENOSPC) {
+printk("space info full %Lu\n", flags);
+ spin_lock(&space_info->lock);
+ space_info->full = 1;
+ spin_unlock(&space_info->lock);
+ }
out:
return ret;
}
@@ -1533,7 +1575,6 @@ static int update_block_group(struct btrfs_trans_handle
*trans,
u64 old_val;
u64 byte_in_group;
- WARN_ON(!mutex_is_locked(&root->fs_info->alloc_mutex));
while(total) {
cache = btrfs_lookup_block_group(info, bytenr);
if (!cache) {
@@ -1542,6 +1583,7 @@ static int update_block_group(struct btrfs_trans_handle
*trans,
byte_in_group = bytenr - cache->key.objectid;
WARN_ON(byte_in_group > cache->key.offset);
+ spin_lock(&cache->space_info->lock);
spin_lock(&cache->lock);
cache->dirty = 1;
old_val = btrfs_block_group_used(&cache->item);
@@ -1551,11 +1593,13 @@ static int update_block_group(struct btrfs_trans_handle
*trans,
cache->space_info->bytes_used += num_bytes;
btrfs_set_block_group_used(&cache->item, old_val);
spin_unlock(&cache->lock);
+ spin_unlock(&cache->space_info->lock);
} else {
old_val -= num_bytes;
cache->space_info->bytes_used -= num_bytes;
btrfs_set_block_group_used(&cache->item, old_val);
spin_unlock(&cache->lock);
+ spin_unlock(&cache->space_info->lock);
if (mark_free) {
int ret;
ret = btrfs_add_free_space(cache, bytenr,
@@ -1588,7 +1632,7 @@ int btrfs_update_pinned_extents(struct btrfs_root *root,
struct btrfs_block_group_cache *cache;
struct btrfs_fs_info *fs_info = root->fs_info;
- WARN_ON(!mutex_is_locked(&root->fs_info->alloc_mutex));
+ WARN_ON(!mutex_is_locked(&root->fs_info->extent_io_mutex));
if (pin) {
set_extent_dirty(&fs_info->pinned_extents,
bytenr, bytenr + num - 1, GFP_NOFS);
@@ -1602,16 +1646,20 @@ int btrfs_update_pinned_extents(struct btrfs_root *root,
len = min(num, cache->key.offset -
(bytenr - cache->key.objectid));
if (pin) {
+ spin_lock(&cache->space_info->lock);
spin_lock(&cache->lock);
cache->pinned += len;
cache->space_info->bytes_pinned += len;
spin_unlock(&cache->lock);
+ spin_unlock(&cache->space_info->lock);
fs_info->total_pinned += len;
} else {
+ spin_lock(&cache->space_info->lock);
spin_lock(&cache->lock);
cache->pinned -= len;
cache->space_info->bytes_pinned -= len;
spin_unlock(&cache->lock);
+ spin_unlock(&cache->space_info->lock);
fs_info->total_pinned -= len;
}
bytenr += len;
@@ -1627,23 +1675,23 @@ static int update_reserved_extents(struct btrfs_root
*root,
struct btrfs_block_group_cache *cache;
struct btrfs_fs_info *fs_info = root->fs_info;
- WARN_ON(!mutex_is_locked(&root->fs_info->alloc_mutex));
while (num > 0) {
cache = btrfs_lookup_block_group(fs_info, bytenr);
BUG_ON(!cache);
len = min(num, cache->key.offset -
(bytenr - cache->key.objectid));
+
+ spin_lock(&cache->space_info->lock);
+ spin_lock(&cache->lock);
if (reserve) {
- spin_lock(&cache->lock);
cache->reserved += len;
cache->space_info->bytes_reserved += len;
- spin_unlock(&cache->lock);
} else {
- spin_lock(&cache->lock);
cache->reserved -= len;
cache->space_info->bytes_reserved -= len;
- spin_unlock(&cache->lock);
}
+ spin_unlock(&cache->lock);
+ spin_unlock(&cache->space_info->lock);
bytenr += len;
num -= len;
}
@@ -1658,6 +1706,7 @@ int btrfs_copy_pinned(struct btrfs_root *root, struct
extent_io_tree *copy)
struct extent_io_tree *pinned_extents =
&root->fs_info->pinned_extents;
int ret;
+ mutex_lock(&root->fs_info->extent_io_mutex);
while(1) {
ret = find_first_extent_bit(pinned_extents, last,
&start, &end, EXTENT_DIRTY);
@@ -1666,6 +1715,7 @@ int btrfs_copy_pinned(struct btrfs_root *root, struct
extent_io_tree *copy)
set_extent_dirty(copy, start, end, GFP_NOFS);
last = end + 1;
}
+ mutex_unlock(&root->fs_info->extent_io_mutex);
return 0;
}
@@ -1679,6 +1729,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle
*trans,
struct btrfs_block_group_cache *cache;
mutex_lock(&root->fs_info->alloc_mutex);
+ mutex_lock(&root->fs_info->extent_io_mutex);
while(1) {
ret = find_first_extent_bit(unpin, 0, &start, &end,
EXTENT_DIRTY);
@@ -1690,11 +1741,14 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle
*trans,
if (cache->cached)
btrfs_add_free_space(cache, start, end - start + 1);
if (need_resched()) {
+ mutex_unlock(&root->fs_info->extent_io_mutex);
mutex_unlock(&root->fs_info->alloc_mutex);
cond_resched();
mutex_lock(&root->fs_info->alloc_mutex);
+ mutex_lock(&root->fs_info->extent_io_mutex);
}
}
+ mutex_unlock(&root->fs_info->extent_io_mutex);
mutex_unlock(&root->fs_info->alloc_mutex);
return 0;
}
@@ -1714,11 +1768,11 @@ static int finish_current_insert(struct
btrfs_trans_handle *trans,
int ret;
int err = 0;
- WARN_ON(!mutex_is_locked(&extent_root->fs_info->alloc_mutex));
btrfs_set_stack_extent_refs(&extent_item, 1);
path = btrfs_alloc_path();
while(1) {
+ mutex_lock(&extent_root->fs_info->extent_io_mutex);
ret = find_first_extent_bit(&info->extent_ins, 0, &start,
&end, EXTENT_LOCKED);
if (ret)
@@ -1729,16 +1783,24 @@ static int finish_current_insert(struct
btrfs_trans_handle *trans,
extent_op = (struct pending_extent_op *)(unsigned long)priv;
if (extent_op->type == PENDING_EXTENT_INSERT) {
+ clear_extent_bits(&info->extent_ins, start, end,
+ EXTENT_LOCKED, GFP_NOFS);
+ mutex_unlock(&extent_root->fs_info->extent_io_mutex);
+
+ /*
+ * FIXME: when we decide to cull all of these BUG''s
+ * we need to re set those bits on the extent_ins
+ * map if anything under here fails so we can recover
+ * later
+ */
key.objectid = start;
key.offset = end + 1 - start;
key.type = BTRFS_EXTENT_ITEM_KEY;
+
err = btrfs_insert_item(trans, extent_root, &key,
&extent_item, sizeof(extent_item));
BUG_ON(err);
- clear_extent_bits(&info->extent_ins, start, end,
- EXTENT_LOCKED, GFP_NOFS);
-
err = insert_extent_backref(trans, extent_root, path,
start, extent_op->parent,
extent_root->root_key.objectid,
@@ -1746,16 +1808,24 @@ static int finish_current_insert(struct
btrfs_trans_handle *trans,
extent_op->level);
BUG_ON(err);
} else if (extent_op->type == PENDING_BACKREF_UPDATE) {
+ clear_extent_bits(&info->extent_ins, start, end,
+ EXTENT_LOCKED, GFP_NOFS);
+ if (test_range_bit(&info->pinned_extents, start,
+ end, EXTENT_DIRTY, 0))
+ printk(KERN_ERR "%llu may not be found\n",
+ start);
+ mutex_unlock(&extent_root->fs_info->extent_io_mutex);
+
+ /* FIXME: same note as above */
err = lookup_extent_backref(trans, extent_root, path,
start, extent_op->orig_parent,
extent_root->root_key.objectid,
extent_op->orig_generation,
extent_op->level, 0);
+ if (err == -ENOENT)
+ printk(KERN_ERR "couldn''t find %llu\n", start);
BUG_ON(err);
- clear_extent_bits(&info->extent_ins, start, end,
- EXTENT_LOCKED, GFP_NOFS);
-
key.objectid = start;
key.offset = extent_op->parent;
key.type = BTRFS_EXTENT_REF_KEY;
@@ -1772,13 +1842,8 @@ static int finish_current_insert(struct
btrfs_trans_handle *trans,
BUG_ON(1);
}
kfree(extent_op);
-
- if (need_resched()) {
- mutex_unlock(&extent_root->fs_info->alloc_mutex);
- cond_resched();
- mutex_lock(&extent_root->fs_info->alloc_mutex);
- }
}
+ mutex_unlock(&extent_root->fs_info->extent_io_mutex);
btrfs_free_path(path);
return 0;
}
@@ -1790,7 +1855,6 @@ static int pin_down_bytes(struct btrfs_trans_handle
*trans,
int err = 0;
struct extent_buffer *buf;
- WARN_ON(!mutex_is_locked(&root->fs_info->alloc_mutex));
if (is_data)
goto pinit;
@@ -1847,7 +1911,6 @@ static int __free_extent(struct btrfs_trans_handle *trans,
struct btrfs_extent_item *ei;
u32 refs;
- WARN_ON(!mutex_is_locked(&root->fs_info->alloc_mutex));
key.objectid = bytenr;
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
key.offset = num_bytes;
@@ -1935,8 +1998,10 @@ static int __free_extent(struct btrfs_trans_handle
*trans,
#endif
if (pin) {
+ mutex_lock(&root->fs_info->extent_io_mutex);
ret = pin_down_bytes(trans, root, bytenr, num_bytes,
owner_objectid >= BTRFS_FIRST_FREE_OBJECTID);
+ mutex_unlock(&root->fs_info->extent_io_mutex);
if (ret > 0)
mark_free = 1;
BUG_ON(ret < 0);
@@ -1956,6 +2021,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
ret = btrfs_del_items(trans, extent_root, path, path->slots[0],
num_to_del);
BUG_ON(ret);
+ btrfs_release_path(extent_root, path);
ret = update_block_group(trans, root, bytenr, num_bytes, 0,
mark_free);
BUG_ON(ret);
@@ -1980,6 +2046,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
}
#endif
}
+
btrfs_free_path(path);
finish_current_insert(trans, extent_root);
return ret;
@@ -1994,7 +2061,6 @@ static int del_pending_extents(struct btrfs_trans_handle
*trans, struct
{
int ret;
int err = 0;
- int mark_free = 0;
u64 start;
u64 end;
u64 priv;
@@ -2002,11 +2068,11 @@ static int del_pending_extents(struct btrfs_trans_handle
*trans, struct
struct extent_io_tree *extent_ins;
struct pending_extent_op *extent_op;
- WARN_ON(!mutex_is_locked(&extent_root->fs_info->alloc_mutex));
extent_ins = &extent_root->fs_info->extent_ins;
pending_del = &extent_root->fs_info->pending_del;
while(1) {
+ mutex_lock(&extent_root->fs_info->extent_io_mutex);
ret = find_first_extent_bit(pending_del, 0, &start, &end,
EXTENT_LOCKED);
if (ret)
@@ -2019,21 +2085,20 @@ static int del_pending_extents(struct btrfs_trans_handle
*trans, struct
clear_extent_bits(pending_del, start, end, EXTENT_LOCKED,
GFP_NOFS);
- ret = pin_down_bytes(trans, extent_root, start,
- end + 1 - start, 0);
- mark_free = ret > 0;
if (!test_range_bit(extent_ins, start, end,
EXTENT_LOCKED, 0)) {
+ mutex_unlock(&extent_root->fs_info->extent_io_mutex);
free_extent:
ret = __free_extent(trans, extent_root,
start, end + 1 - start,
extent_op->orig_parent,
extent_root->root_key.objectid,
extent_op->orig_generation,
- extent_op->level, 0, mark_free);
+ extent_op->level, 1, 0);
kfree(extent_op);
} else {
kfree(extent_op);
+
ret = get_state_private(extent_ins, start, &priv);
BUG_ON(ret);
extent_op = (struct pending_extent_op *)
@@ -2042,23 +2107,25 @@ free_extent:
clear_extent_bits(extent_ins, start, end,
EXTENT_LOCKED, GFP_NOFS);
- if (extent_op->type == PENDING_BACKREF_UPDATE)
+ if (extent_op->type == PENDING_BACKREF_UPDATE) {
+ mutex_unlock(&extent_root->fs_info->extent_io_mutex);
goto free_extent;
+ }
+
+ ret = pin_down_bytes(trans, extent_root, start,
+ end + 1 - start, 0);
+ mutex_unlock(&extent_root->fs_info->extent_io_mutex);
ret = update_block_group(trans, extent_root, start,
- end + 1 - start, 0, mark_free);
+ end + 1 - start, 0, ret > 0);
BUG_ON(ret);
kfree(extent_op);
}
if (ret)
err = ret;
-
- if (need_resched()) {
- mutex_unlock(&extent_root->fs_info->alloc_mutex);
- cond_resched();
- mutex_lock(&extent_root->fs_info->alloc_mutex);
- }
}
+ mutex_unlock(&extent_root->fs_info->extent_io_mutex);
+
return err;
}
@@ -2091,11 +2158,13 @@ static int __btrfs_free_extent(struct btrfs_trans_handle
*trans,
extent_op->orig_generation = ref_generation;
extent_op->level = (int)owner_objectid;
+ mutex_lock(&root->fs_info->extent_io_mutex);
set_extent_bits(&root->fs_info->pending_del,
bytenr, bytenr + num_bytes - 1,
EXTENT_LOCKED, GFP_NOFS);
set_state_private(&root->fs_info->pending_del,
bytenr, (unsigned long)extent_op);
+ mutex_unlock(&root->fs_info->extent_io_mutex);
return 0;
}
/* if metadata always pin */
@@ -2163,7 +2232,7 @@ static int noinline find_free_extent(struct
btrfs_trans_handle *trans,
u64 search_start, u64 search_end,
u64 hint_byte, struct btrfs_key *ins,
u64 exclude_start, u64 exclude_nr,
- int data)
+ int data, unsigned long *ip)
{
int ret = 0;
struct btrfs_root * root = orig_root->fs_info->extent_root;
@@ -2214,12 +2283,16 @@ static int noinline find_free_extent(struct
btrfs_trans_handle *trans,
* group thats not of the proper type, while looping this
* should never happen
*/
+ WARN_ON(!block_group);
+ mutex_lock(&block_group->alloc_mutex);
if (unlikely(!block_group_bits(block_group, data)))
goto new_group;
ret = cache_block_group(root, block_group);
- if (ret)
+ if (ret) {
+ mutex_unlock(&block_group->alloc_mutex);
break;
+ }
if (block_group->ro)
goto new_group;
@@ -2250,8 +2323,10 @@ static int noinline find_free_extent(struct
btrfs_trans_handle *trans,
* then we just re-search this block group
*/
if (search_start >= start &&
- search_start < end)
+ search_start < end) {
+ mutex_unlock(&block_group->alloc_mutex);
continue;
+ }
/* else we go to the next block group */
goto new_group;
@@ -2259,10 +2334,18 @@ static int noinline find_free_extent(struct
btrfs_trans_handle *trans,
ins->objectid = search_start;
ins->offset = num_bytes;
+
+ if (ip)
+ *ip = free_space->ip;
+
+ btrfs_remove_free_space_lock(block_group, search_start,
+ num_bytes);
/* we are all good, lets return */
+ mutex_unlock(&block_group->alloc_mutex);
break;
}
new_group:
+ mutex_unlock(&block_group->alloc_mutex);
/*
* Here''s how this works.
* loop == 0: we were searching a block group via a hint
@@ -2357,13 +2440,12 @@ static int __btrfs_reserve_extent(struct
btrfs_trans_handle *trans,
u64 num_bytes, u64 min_alloc_size,
u64 empty_size, u64 hint_byte,
u64 search_end, struct btrfs_key *ins,
- u64 data)
+ u64 data, unsigned long *ip)
{
int ret;
u64 search_start = 0;
u64 alloc_profile;
struct btrfs_fs_info *info = root->fs_info;
- struct btrfs_block_group_cache *cache;
if (data) {
alloc_profile = info->avail_data_alloc_bits &
@@ -2400,7 +2482,7 @@ again:
ret = find_free_extent(trans, root, num_bytes, empty_size,
search_start, search_end, hint_byte, ins,
trans->alloc_exclude_start,
- trans->alloc_exclude_nr, data);
+ trans->alloc_exclude_nr, data, ip);
if (ret == -ENOSPC && num_bytes > min_alloc_size) {
num_bytes = num_bytes >> 1;
@@ -2419,13 +2501,6 @@ again:
dump_space_info(sinfo, num_bytes);
BUG();
}
- cache = btrfs_lookup_block_group(root->fs_info, ins->objectid);
- if (!cache) {
- printk(KERN_ERR "Unable to find block group for %Lu\n",
ins->objectid);
- return -ENOSPC;
- }
-
- ret = btrfs_remove_free_space(cache, ins->objectid, ins->offset);
return ret;
}
@@ -2434,16 +2509,13 @@ int btrfs_free_reserved_extent(struct btrfs_root *root,
u64 start, u64 len)
{
struct btrfs_block_group_cache *cache;
- maybe_lock_mutex(root);
cache = btrfs_lookup_block_group(root->fs_info, start);
if (!cache) {
printk(KERN_ERR "Unable to find block group for %Lu\n", start);
- maybe_unlock_mutex(root);
return -ENOSPC;
}
btrfs_add_free_space(cache, start, len);
update_reserved_extents(root, start, len, 0);
- maybe_unlock_mutex(root);
return 0;
}
@@ -2455,19 +2527,18 @@ int btrfs_reserve_extent(struct btrfs_trans_handle
*trans,
u64 data)
{
int ret;
- maybe_lock_mutex(root);
ret = __btrfs_reserve_extent(trans, root, num_bytes, min_alloc_size,
empty_size, hint_byte, search_end, ins,
- data);
+ data, NULL);
update_reserved_extents(root, ins->objectid, ins->offset, 1);
- maybe_unlock_mutex(root);
return ret;
}
static int __btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 parent,
u64 root_objectid, u64 ref_generation,
- u64 owner, struct btrfs_key *ins)
+ u64 owner, struct btrfs_key *ins,
+ unsigned long ip)
{
int ret;
int pending_ret;
@@ -2510,11 +2581,13 @@ static int __btrfs_alloc_reserved_extent(struct
btrfs_trans_handle *trans,
extent_op->orig_generation = 0;
extent_op->level = (int)owner;
+ mutex_lock(&root->fs_info->extent_io_mutex);
set_extent_bits(&root->fs_info->extent_ins, ins->objectid,
ins->objectid + ins->offset - 1,
EXTENT_LOCKED, GFP_NOFS);
set_state_private(&root->fs_info->extent_ins,
ins->objectid, (unsigned long)extent_op);
+ mutex_unlock(&root->fs_info->extent_io_mutex);
goto update_block;
}
@@ -2530,6 +2603,36 @@ static int __btrfs_alloc_reserved_extent(struct
btrfs_trans_handle *trans,
ret = btrfs_insert_empty_items(trans, extent_root, path, keys,
sizes, 2);
+ if (ret == -EEXIST) {
+ u64 start, end;
+ struct btrfs_block_group_cache *cache +
btrfs_lookup_block_group(root->fs_info,
+ keys[0].objectid);
+ printk(KERN_ERR "extent %Lu already exists, type %Ld, id %Ld, "
+ "ip is %lu\n",
+ keys[0].objectid, cache->flags,
+ root->root_key.objectid, ip);
+ mutex_lock(&root->fs_info->extent_io_mutex);
+ ret = find_first_extent_bit(&extent_root->fs_info->pending_del,
+ keys[0].objectid, &start, &end,
+ EXTENT_LOCKED);
+ if (ret) {
+ printk(KERN_ERR "Ok its not on pending_del\n");
+ } else if (start == keys[0].objectid) {
+ printk(KERN_ERR "It was on the pending del list, why "
+ "the fuck was the space available\n");
+ }
+ ret = find_first_extent_bit(&extent_root->fs_info->pinned_extents,
+ keys[0].objectid, &start, &end,
+ EXTENT_DIRTY);
+ if (ret || start != keys[0].objectid) {
+ printk(KERN_ERR "ok its not on pinned either\n");
+ } else if (start == keys[0].objectid) {
+ printk(KERN_ERR "it was on pinned\n");
+ }
+ ret = -EEXIST;
+ mutex_unlock(&root->fs_info->extent_io_mutex);
+ }
BUG_ON(ret);
extent_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
@@ -2578,9 +2681,9 @@ int btrfs_alloc_reserved_extent(struct btrfs_trans_handle
*trans,
if (root_objectid == BTRFS_TREE_LOG_OBJECTID)
return 0;
- maybe_lock_mutex(root);
ret = __btrfs_alloc_reserved_extent(trans, root, parent, root_objectid,
- ref_generation, owner, ins);
+ ref_generation, owner, ins, 0);
+ maybe_lock_mutex(root);
update_reserved_extents(root, ins->objectid, ins->offset, 0);
maybe_unlock_mutex(root);
return ret;
@@ -2599,15 +2702,15 @@ int btrfs_alloc_logged_extent(struct btrfs_trans_handle
*trans,
int ret;
struct btrfs_block_group_cache *block_group;
- maybe_lock_mutex(root);
block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid);
+ mutex_lock(&block_group->alloc_mutex);
cache_block_group(root, block_group);
+ mutex_unlock(&block_group->alloc_mutex);
ret = btrfs_remove_free_space(block_group, ins->objectid, ins->offset);
BUG_ON(ret);
ret = __btrfs_alloc_reserved_extent(trans, root, parent, root_objectid,
- ref_generation, owner, ins);
- maybe_unlock_mutex(root);
+ ref_generation, owner, ins, 0);
return ret;
}
@@ -2626,23 +2729,23 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
u64 search_end, struct btrfs_key *ins, u64 data)
{
int ret;
-
- maybe_lock_mutex(root);
+ unsigned long ip = 0;
ret = __btrfs_reserve_extent(trans, root, num_bytes,
min_alloc_size, empty_size, hint_byte,
- search_end, ins, data);
+ search_end, ins, data, &ip);
BUG_ON(ret);
if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
ret = __btrfs_alloc_reserved_extent(trans, root, parent,
root_objectid, ref_generation,
- owner_objectid, ins);
+ owner_objectid, ins, ip);
BUG_ON(ret);
} else {
+ maybe_lock_mutex(root);
update_reserved_extents(root, ins->objectid, ins->offset, 1);
+ maybe_unlock_mutex(root);
}
- maybe_unlock_mutex(root);
return ret;
}
@@ -5067,6 +5170,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
}
spin_lock_init(&cache->lock);
+ mutex_init(&cache->alloc_mutex);
INIT_LIST_HEAD(&cache->list);
read_extent_buffer(leaf, &cache->item,
btrfs_item_ptr_offset(leaf, path->slots[0]),
@@ -5107,7 +5211,6 @@ int btrfs_make_block_group(struct btrfs_trans_handle
*trans,
struct btrfs_root *extent_root;
struct btrfs_block_group_cache *cache;
- WARN_ON(!mutex_is_locked(&root->fs_info->alloc_mutex));
extent_root = root->fs_info->extent_root;
root->fs_info->last_trans_new_blockgroup = trans->transid;
@@ -5119,6 +5222,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle
*trans,
cache->key.objectid = chunk_offset;
cache->key.offset = size;
spin_lock_init(&cache->lock);
+ mutex_init(&cache->alloc_mutex);
INIT_LIST_HEAD(&cache->list);
btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY);
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 96241f0..25a3110 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -184,8 +184,8 @@ static int link_free_space(struct btrfs_block_group_cache
*block_group,
return ret;
}
-int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
- u64 offset, u64 bytes)
+static int __btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
+ u64 offset, u64 bytes)
{
struct btrfs_free_space *right_info;
struct btrfs_free_space *left_info;
@@ -202,8 +202,6 @@ int btrfs_add_free_space(struct btrfs_block_group_cache
*block_group,
* are adding, if there is remove that struct and add a new one to
* cover the entire range
*/
- spin_lock(&block_group->lock);
-
right_info = tree_search_offset(&block_group->free_space_offset,
offset+bytes, 0, 1);
left_info = tree_search_offset(&block_group->free_space_offset,
@@ -261,7 +259,6 @@ int btrfs_add_free_space(struct btrfs_block_group_cache
*block_group,
if (ret)
kfree(info);
out:
- spin_unlock(&block_group->lock);
if (ret) {
printk(KERN_ERR "btrfs: unable to add free space :%d\n", ret);
if (ret == -EEXIST)
@@ -274,13 +271,13 @@ out:
return ret;
}
-int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
- u64 offset, u64 bytes)
+static int
+__btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
+ u64 offset, u64 bytes)
{
struct btrfs_free_space *info;
int ret = 0;
- spin_lock(&block_group->lock);
info = tree_search_offset(&block_group->free_space_offset, offset, 0,
1);
@@ -334,17 +331,65 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache
*block_group,
/* step two, insert a new info struct to cover anything
* before the hole
*/
- spin_unlock(&block_group->lock);
- ret = btrfs_add_free_space(block_group, old_start,
- offset - old_start);
+ ret = __btrfs_add_free_space(block_group, old_start,
+ offset - old_start);
BUG_ON(ret);
- goto out_nolock;
} else {
WARN_ON(1);
}
out:
- spin_unlock(&block_group->lock);
-out_nolock:
+ return ret;
+}
+
+int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
+ u64 offset, u64 bytes)
+{
+ int ret;
+ struct btrfs_free_space *sp;
+
+ mutex_lock(&block_group->alloc_mutex);
+ ret = __btrfs_add_free_space(block_group, offset, bytes);
+ sp = tree_search_offset(&block_group->free_space_offset, offset, 0, 1);
+ BUG_ON(!sp);
+ sp->ip = (unsigned long)__builtin_return_address(0);
+ mutex_unlock(&block_group->alloc_mutex);
+
+ return ret;
+}
+
+int btrfs_add_free_space_lock(struct btrfs_block_group_cache *block_group,
+ u64 offset, u64 bytes)
+{
+ int ret;
+ struct btrfs_free_space *sp;
+
+ ret = __btrfs_add_free_space(block_group, offset, bytes);
+ sp = tree_search_offset(&block_group->free_space_offset, offset, 0, 1);
+ BUG_ON(!sp);
+ sp->ip = (unsigned long)__builtin_return_address(0);
+
+ return ret;
+}
+
+int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
+ u64 offset, u64 bytes)
+{
+ int ret = 0;
+
+ mutex_lock(&block_group->alloc_mutex);
+ ret = __btrfs_remove_free_space(block_group, offset, bytes);
+ mutex_unlock(&block_group->alloc_mutex);
+
+ return ret;
+}
+
+int btrfs_remove_free_space_lock(struct btrfs_block_group_cache *block_group,
+ u64 offset, u64 bytes)
+{
+ int ret;
+
+ ret = __btrfs_remove_free_space(block_group, offset, bytes);
+
return ret;
}
@@ -386,18 +431,18 @@ void btrfs_remove_free_space_cache(struct
btrfs_block_group_cache *block_group)
struct btrfs_free_space *info;
struct rb_node *node;
- spin_lock(&block_group->lock);
+ mutex_lock(&block_group->alloc_mutex);
while ((node = rb_last(&block_group->free_space_bytes)) != NULL) {
info = rb_entry(node, struct btrfs_free_space, bytes_index);
unlink_free_space(block_group, info);
kfree(info);
if (need_resched()) {
- spin_unlock(&block_group->lock);
+ mutex_unlock(&block_group->alloc_mutex);
cond_resched();
- spin_lock(&block_group->lock);
+ mutex_lock(&block_group->alloc_mutex);
}
}
- spin_unlock(&block_group->lock);
+ mutex_unlock(&block_group->alloc_mutex);
}
struct btrfs_free_space *btrfs_find_free_space_offset(struct
@@ -407,10 +452,10 @@ struct btrfs_free_space
*btrfs_find_free_space_offset(struct
{
struct btrfs_free_space *ret;
- spin_lock(&block_group->lock);
+ mutex_lock(&block_group->alloc_mutex);
ret = tree_search_offset(&block_group->free_space_offset, offset,
bytes, 0);
- spin_unlock(&block_group->lock);
+ mutex_unlock(&block_group->alloc_mutex);
return ret;
}
@@ -422,10 +467,10 @@ struct btrfs_free_space
*btrfs_find_free_space_bytes(struct
{
struct btrfs_free_space *ret;
- spin_lock(&block_group->lock);
+ mutex_lock(&block_group->alloc_mutex);
ret = tree_search_bytes(&block_group->free_space_bytes, offset, bytes);
- spin_unlock(&block_group->lock);
+ mutex_unlock(&block_group->alloc_mutex);
return ret;
}
@@ -434,16 +479,13 @@ struct btrfs_free_space *btrfs_find_free_space(struct
btrfs_block_group_cache
*block_group, u64 offset,
u64 bytes)
{
- struct btrfs_free_space *ret;
+ struct btrfs_free_space *ret = NULL;
- spin_lock(&block_group->lock);
ret = tree_search_offset(&block_group->free_space_offset, offset,
bytes, 0);
if (!ret)
ret = tree_search_bytes(&block_group->free_space_bytes,
offset, bytes);
- spin_unlock(&block_group->lock);
-
return ret;
}
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index cf618cc..fc3a8d8 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -272,8 +272,10 @@ static int process_one_buffer(struct btrfs_root *log,
{
if (wc->pin) {
mutex_lock(&log->fs_info->alloc_mutex);
+ mutex_lock(&log->fs_info->extent_io_mutex);
btrfs_update_pinned_extents(log->fs_info->extent_root,
eb->start, eb->len, 1);
+ mutex_unlock(&log->fs_info->extent_io_mutex);
mutex_unlock(&log->fs_info->alloc_mutex);
}
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs"
in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html