On Fri, Oct 17, 2008 at 09:48:58AM +0800, Yan Zheng wrote:
> 2008/10/17 Josef Bacik <[EMAIL PROTECTED]>:
> > 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 [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to