diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index b6dc020bdde9..85616b458e18 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -5,8 +5,9 @@ #include "transaction.h" static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root - *orig_root, u64 num_blocks, u64 search_start, u64 - search_end, struct btrfs_key *ins, int data); + *orig_root, u64 num_blocks, u64 search_start, + u64 search_end, u64 hint_block, + struct btrfs_key *ins, int data); static int finish_current_insert(struct btrfs_trans_handle *trans, struct btrfs_root *extent_root); static int del_pending_extents(struct btrfs_trans_handle *trans, struct @@ -157,12 +158,6 @@ static struct btrfs_block_group_cache *lookup_block_group(struct block_group->key.objectid + block_group->key.offset) return block_group; } - WARN_ON(1); - printk("lookup_block_group fails for blocknr %Lu\n", blocknr); - printk("last ret was %d\n", ret); - if (ret) { - printk("last block group was %Lu %Lu\n", block_group->key.objectid, block_group->key.offset); - } return NULL; } @@ -378,7 +373,7 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, struct btrfs_key ins; u32 refs; - find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1, + find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1, 0, &ins, 0); path = btrfs_alloc_path(); BUG_ON(!path); @@ -495,7 +490,7 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans, struct btrfs_block_group_item *bi; struct btrfs_key ins; - find_free_extent(trans, extent_root, 0, 0, (u64)-1, &ins, 0); + find_free_extent(trans, extent_root, 0, 0, (u64)-1, 0, &ins, 0); ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1); BUG_ON(ret); bi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], @@ -788,7 +783,7 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); key.offset = num_blocks; - find_free_extent(trans, root, 0, 0, (u64)-1, &ins, 0); + find_free_extent(trans, root, 0, 0, (u64)-1, 0, &ins, 0); path = btrfs_alloc_path(); BUG_ON(!path); btrfs_init_path(path); @@ -906,7 +901,8 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root */ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *orig_root, u64 num_blocks, u64 search_start, u64 - search_end, struct btrfs_key *ins, int data) + search_end, u64 hint_block, + struct btrfs_key *ins, int data) { struct btrfs_path *path; struct btrfs_key key; @@ -926,6 +922,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root int level; struct btrfs_block_group_cache *block_group; int full_scan = 0; + int wrapped = 0; u64 limit; path = btrfs_alloc_path(); @@ -940,10 +937,10 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root } if (search_end == (u64)-1) search_end = btrfs_super_total_blocks(info->disk_super); - if (search_start) { - block_group = lookup_block_group(info, search_start); + if (hint_block) { + block_group = lookup_block_group(info, hint_block); block_group = btrfs_find_block_group(root, block_group, - search_start, data, 1); + hint_block, data, 1); } else { block_group = btrfs_find_block_group(root, trans->block_group, 0, @@ -954,7 +951,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root if (!block_group->data) search_start = find_search_start(root, &block_group, search_start, total_needed); - else + else if (!full_scan) search_start = max(block_group->last_alloc, search_start); btrfs_init_path(path); @@ -1039,7 +1036,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root start_found = 1; last_block = key.objectid + key.offset; - if (last_block >= block_group->key.objectid + + if (!full_scan && last_block >= block_group->key.objectid + block_group->key.offset) { btrfs_release_path(root, path); search_start = block_group->key.objectid + @@ -1059,10 +1056,15 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root BUG_ON(ins->objectid < search_start); if (ins->objectid + num_blocks >= search_end) { - if (full_scan) - return -ENOSPC; + if (full_scan) { + ret = -ENOSPC; + goto error; + } search_start = orig_search_start; - full_scan = 1; + if (wrapped) + full_scan = 1; + else + wrapped = 1; goto new_group; } for (test_block = ins->objectid; @@ -1132,14 +1134,20 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root new_group: if (search_start + num_blocks >= search_end) { search_start = orig_search_start; -printk("doing full scan!\n"); - full_scan = 1; + if (full_scan) { + ret = -ENOSPC; + goto error; + } + if (wrapped) + full_scan = 1; + else + wrapped = 1; } block_group = lookup_block_group(info, search_start); + cond_resched(); if (!full_scan) block_group = btrfs_find_block_group(root, block_group, search_start, data, 0); - cond_resched(); goto check_failed; error: @@ -1156,12 +1164,13 @@ printk("doing full scan!\n"); */ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 owner, - u64 num_blocks, u64 search_start, + u64 num_blocks, u64 hint_block, u64 search_end, struct btrfs_key *ins, int data) { int ret; int pending_ret; u64 super_blocks_used; + u64 search_start = 0; struct btrfs_fs_info *info = root->fs_info; struct btrfs_root *extent_root = info->extent_root; struct btrfs_extent_item extent_item; @@ -1193,7 +1202,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, */ if (data) { ret = find_free_extent(trans, root, 0, 0, - search_end, &prealloc_key, 0); + search_end, 0, &prealloc_key, 0); if (ret) { return ret; } @@ -1204,9 +1213,11 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, search_start = info->extent_tree_prealloc[0] + 1; } } + if (hint_block < search_start) + hint_block = search_start; /* do the real allocation */ ret = find_free_extent(trans, root, num_blocks, search_start, - search_end, ins, data); + search_end, hint_block, ins, data); if (ret) { return ret; } @@ -1226,8 +1237,12 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, else search_start = ins->objectid + ins->offset; + if (hint_block < search_start) + hint_block = search_start; + ret = find_free_extent(trans, root, 0, search_start, - search_end, &prealloc_key, 0); + search_end, hint_block, + &prealloc_key, 0); if (ret) { return ret; }