From: Josef Bacik Subject: Re: Need some help with a backref problem Date: Fri, 17 Oct 2008 07:06:48 -0400 Message-ID: <20081017110646.GH2864@unused.rdu.redhat.com> References: <20081016205412.GE2864@unused.rdu.redhat.com> <20081017004323.GF2864@unused.rdu.redhat.com> <3d0408630810161848w294373a7ud0297274c9cde5c7@mail.gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Cc: Josef Bacik , linux-btrfs@vger.kernel.org To: Yan Zheng Return-path: In-Reply-To: <3d0408630810161848w294373a7ud0297274c9cde5c7@mail.gmail.com> List-ID: On Fri, Oct 17, 2008 at 09:48:58AM +0800, Yan Zheng wrote: > 2008/10/17 Josef Bacik : > > 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) > > >> [] ? btrfs_update_ref+0x2ce/0x322 [btrfs] > >> [] ? insert_ptr+0x176/0x184 [btrfs] > >> [] ? split_node+0x54a/0x5b3 [btrfs] > >> [] ? btrfs_search_slot+0x4ef/0x7aa [btrfs] > >> [] ? check_bytes_and_report+0x37/0xc9 > >> [] ? check_bytes_and_report+0x37/0xc9 > >> [] ? btrfs_insert_empty_items+0x7d/0x43b [btrfs] > >> [] ? btrfs_insert_item+0x4f/0xa4 [btrfs] > >> [] ? finish_current_insert+0xfc/0x2b5 [btrfs] > >> [] ? init_object+0x27/0x6e > >> [] ? __btrfs_alloc_reserved_extent+0x37d/0x3dc [btrfs] > >> [] ? btrfs_alloc_reserved_extent+0x2b/0x5b [btrfs] > >> [] ? btrfs_finish_ordered_io+0x21b/0x344 [btrfs] > >> [] ? end_bio_extent_writepage+0x9b/0x172 [btrfs] > >> [] ? worker_loop+0x42/0x125 [btrfs] > >> [] ? worker_loop+0x0/0x125 [btrfs] > >> [] ? kthread+0x47/0x76 > >> [] ? child_rip+0xa/0x11 > >> [] ? kthread+0x0/0x76 > >> [] ? 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); }