Btrfs: Fix more false enospc errors and an oops from empty clustering
[linux-2.6-block.git] / fs / btrfs / extent-tree.c
index 0d73a53c67633e38f2805c29f838e4ee40090df5..b92e92c29e3b6c66205208e5d42d54dfbc4b3324 100644 (file)
@@ -2152,11 +2152,13 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
        }
        search_start = max(search_start, first_logical_byte(root, 0));
        search_start = max(search_start, hint_byte);
-       total_needed += empty_size;
 
-       if (search_start != last_wanted)
+       if (last_wanted && search_start != last_wanted) {
                last_wanted = 0;
+               empty_size += empty_cluster;
+       }
 
+       total_needed += empty_size;
        block_group = btrfs_lookup_block_group(root->fs_info, search_start);
        if (!block_group)
                block_group = btrfs_lookup_first_block_group(root->fs_info,
@@ -2171,7 +2173,9 @@ 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);
+               if (!block_group)
+                       goto new_group_no_lock;
+
                mutex_lock(&block_group->alloc_mutex);
                if (unlikely(!block_group_bits(block_group, data)))
                        goto new_group;
@@ -2248,12 +2252,13 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
                        break;
                }
 new_group:
+               mutex_unlock(&block_group->alloc_mutex);
+new_group_no_lock:
                last_wanted = 0;
-               if (loop > 0) {
+               if (!allowed_chunk_alloc && loop > 0) {
                        total_needed -= empty_cluster;
                        empty_cluster = 0;
                }
-               mutex_unlock(&block_group->alloc_mutex);
                /*
                 * Here's how this works.
                 * loop == 0: we were searching a block group via a hint
@@ -2271,6 +2276,10 @@ new_group:
                        cur = head->next;
                        loop++;
                } else if (loop == 1 && cur == head) {
+
+                       total_needed -= empty_cluster;
+                       empty_cluster = 0;
+
                        if (allowed_chunk_alloc && !chunk_alloc_done) {
                                up_read(&space_info->groups_sem);
                                ret = do_chunk_alloc(trans, root, num_bytes +