Newer
Older
#include "ctree.h"
#include "disk-io.h"
#include "print-tree.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);
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
btrfs_root *extent_root);
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
static int cache_block_group(struct btrfs_root *root,
struct btrfs_block_group_cache *block_group)
{
struct btrfs_path *path;
int ret;
struct btrfs_key key;
struct btrfs_leaf *leaf;
struct radix_tree_root *extent_radix;
int slot;
u64 i;
u64 last = 0;
u64 hole_size;
int found = 0;
root = root->fs_info->extent_root;
extent_radix = &root->fs_info->extent_map_radix;
if (block_group->cached)
return 0;
if (block_group->data)
return 0;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
printk("cache block group %Lu\n", block_group->key.objectid);
key.objectid = block_group->key.objectid;
key.flags = 0;
key.offset = 0;
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0)
return ret;
if (ret && path->slots[0] > 0)
path->slots[0]--;
while(1) {
leaf = btrfs_buffer_leaf(path->nodes[0]);
slot = path->slots[0];
if (slot >= btrfs_header_nritems(&leaf->header)) {
ret = btrfs_next_leaf(root, path);
if (ret == 0)
continue;
else {
if (found) {
hole_size = block_group->key.objectid +
block_group->key.offset - last;
} else {
last = block_group->key.objectid;
hole_size = block_group->key.offset;
}
for (i = 0; i < hole_size; i++) {
set_radix_bit(extent_radix,
last + i);
}
break;
}
}
btrfs_disk_key_to_cpu(&key, &leaf->items[slot].key);
if (key.objectid >= block_group->key.objectid +
block_group->key.offset) {
if (found) {
hole_size = block_group->key.objectid +
block_group->key.offset - last;
} else {
last = block_group->key.objectid;
hole_size = block_group->key.offset;
}
for (i = 0; i < hole_size; i++) {
set_radix_bit(extent_radix, last + i);
}
break;
}
if (btrfs_key_type(&key) == BTRFS_EXTENT_ITEM_KEY) {
if (!found) {
last = key.objectid + key.offset;
found = 1;
} else {
hole_size = key.objectid - last;
for (i = 0; i < hole_size; i++) {
set_radix_bit(extent_radix, last + i);
}
last = key.objectid + key.offset;
}
}
path->slots[0]++;
}
block_group->cached = 1;
btrfs_free_path(path);
return 0;
}
static struct btrfs_block_group_cache *lookup_block_group(struct
btrfs_fs_info *info,
u64 blocknr)
{
struct btrfs_block_group_cache *block_group;
int ret;
ret = radix_tree_gang_lookup(&info->block_group_radix,
(void **)&block_group,
blocknr, 1);
if (ret) {
if (block_group->key.objectid <= blocknr && blocknr <=
block_group->key.objectid + block_group->key.offset)
return block_group;
}
ret = radix_tree_gang_lookup(&info->block_group_data_radix,
(void **)&block_group,
blocknr, 1);
if (ret) {
if (block_group->key.objectid <= blocknr && blocknr <=
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);
}
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
static u64 leaf_range(struct btrfs_root *root)
{
u64 size = BTRFS_LEAF_DATA_SIZE(root);
size = size / (sizeof(struct btrfs_extent_item) +
sizeof(struct btrfs_item));
return size;
}
static u64 find_search_start(struct btrfs_root *root,
struct btrfs_block_group_cache **cache_ret,
u64 search_start, int num)
{
unsigned long gang[8];
int ret;
struct btrfs_block_group_cache *cache = *cache_ret;
u64 last = max(search_start, cache->key.objectid);
if (cache->data)
goto out;
if (num > 1) {
last = max(last, cache->last_prealloc);
}
again:
cache_block_group(root, cache);
while(1) {
ret = find_first_radix_bit(&root->fs_info->extent_map_radix,
gang, last, ARRAY_SIZE(gang));
if (!ret)
goto out;
last = gang[ret-1] + 1;
if (num > 1) {
if (ret != ARRAY_SIZE(gang)) {
goto new_group;
}
if (gang[ret-1] - gang[0] > leaf_range(root)) {
continue;
}
}
if (gang[0] >= cache->key.objectid + cache->key.offset) {
goto new_group;
}
return gang[0];
}
out:
return max(cache->last_alloc, search_start);
new_group:
cache = lookup_block_group(root->fs_info, last + cache->key.offset - 1);
if (!cache) {
return max((*cache_ret)->last_alloc, search_start);
}
cache = btrfs_find_block_group(root, cache,
last + cache->key.offset - 1, 0);
*cache_ret = cache;
goto again;
}
struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
struct btrfs_block_group_cache
{
struct btrfs_block_group_cache *cache[8];
struct btrfs_block_group_cache *found_group = NULL;
struct btrfs_fs_info *info = root->fs_info;
u64 last = 0;
u64 hint_last;
if (data)
radix = &info->block_group_data_radix;
else
radix = &info->block_group_radix;
if (search_start) {
struct btrfs_block_group_cache *shint;
shint = lookup_block_group(info, search_start);
if (shint->data == data) {
used = btrfs_block_group_used(&shint->item);
if (used + shint->pinned <
(shint->key.offset * 8) / 10) {
return shint;
}
}
}
if (hint && hint->data == data) {
used = btrfs_block_group_used(&hint->item);
if (used + hint->pinned < (hint->key.offset * 8) / 10) {
if (used >= (hint->key.offset * 8) / 10) {
radix_tree_tag_clear(radix,
hint->key.objectid +
hint->key.offset - 1,
BTRFS_BLOCK_GROUP_AVAIL);
}
last = hint->key.offset * 3;
last = max(search_start + hint->key.offset - 1,
hint->key.objectid - last);
else
last = hint->key.objectid + hint->key.offset;
hint_last = last;
} else {
if (hint)
hint_last = max(hint->key.objectid, search_start);
else
hint_last = search_start;
last = hint_last;
ret = radix_tree_gang_lookup_tag(radix, (void **)cache,
BTRFS_BLOCK_GROUP_AVAIL);
if (!ret)
break;
for (i = 0; i < ret; i++) {
last = cache[i]->key.objectid +
cache[i]->key.offset;
used = btrfs_block_group_used(&cache[i]->item);
if (used + cache[i]->pinned <
(cache[i]->key.offset * 8) / 10) {
found_group = cache[i];
goto found;
if (used >= (cache[i]->key.offset * 8) / 10) {
radix_tree_tag_clear(radix,
cache[i]->key.objectid +
cache[i]->key.offset - 1,
BTRFS_BLOCK_GROUP_AVAIL);
}
last = hint_last;
again:
ret = radix_tree_gang_lookup(radix, (void **)cache,
last, ARRAY_SIZE(cache));
if (!ret)
break;
for (i = 0; i < ret; i++) {
last = cache[i]->key.objectid +
cache[i]->key.offset;
used = btrfs_block_group_used(&cache[i]->item);
if (used + cache[i]->pinned < cache[i]->key.offset) {
found_group = cache[i];
goto found;
if (used >= cache[i]->key.offset) {
radix_tree_tag_clear(radix,
cache[i]->key.objectid +
cache[i]->key.offset - 1,
BTRFS_BLOCK_GROUP_AVAIL);
}
full_search = 1;
goto again;
}
if (!found_group) {
(void **)&found_group, 0, 1);
BUG_ON(ret != 1);
}
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 blocknr, u64 num_blocks)
struct btrfs_leaf *l;
struct btrfs_extent_item *item;
find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1,
path = btrfs_alloc_path();
BUG_ON(!path);
btrfs_init_path(path);
key.objectid = blocknr;
key.flags = 0;
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
if (ret != 0) {
printk("can't find block %Lu %Lu\n", blocknr, num_blocks);
l = btrfs_buffer_leaf(path->nodes[0]);
item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
refs = btrfs_extent_refs(item);
btrfs_set_extent_refs(item, refs + 1);
btrfs_mark_buffer_dirty(path->nodes[0]);
btrfs_release_path(root->fs_info->extent_root, path);
btrfs_free_path(path);
finish_current_insert(trans, root->fs_info->extent_root);
del_pending_extents(trans, root->fs_info->extent_root);
static int lookup_extent_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 blocknr,
u64 num_blocks, u32 *refs)
struct btrfs_leaf *l;
struct btrfs_extent_item *item;
path = btrfs_alloc_path();
btrfs_init_path(path);
key.flags = 0;
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
l = btrfs_buffer_leaf(path->nodes[0]);
item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
btrfs_release_path(root->fs_info->extent_root, path);
btrfs_free_path(path);
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
return btrfs_inc_extent_ref(trans, root, bh_blocknr(root->node), 1);
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_leaf *buf_leaf;
struct btrfs_disk_key *key;
struct btrfs_file_extent_item *fi;

Chris Mason
committed
if (!root->ref_cows)
leaf = btrfs_is_leaf(buf_node);
buf_leaf = btrfs_buffer_leaf(buf);
for (i = 0; i < btrfs_header_nritems(&buf_node->header); i++) {
if (leaf) {
key = &buf_leaf->items[i].key;
if (btrfs_disk_key_type(key) != BTRFS_EXTENT_DATA_KEY)
continue;
fi = btrfs_item_ptr(buf_leaf, i,
struct btrfs_file_extent_item);
if (btrfs_file_extent_type(fi) ==
BTRFS_FILE_EXTENT_INLINE)
continue;
btrfs_file_extent_disk_blocknr(fi),
btrfs_file_extent_disk_num_blocks(fi));
BUG_ON(ret);
} else {
blocknr = btrfs_node_blockptr(buf_node, i);
ret = btrfs_inc_extent_ref(trans, root, blocknr, 1);
static int write_one_cache_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
struct btrfs_block_group_cache *cache)
{
int ret;
int pending_ret;
struct btrfs_root *extent_root = root->fs_info->extent_root;
struct btrfs_block_group_item *bi;
struct btrfs_key ins;
find_free_extent(trans, extent_root, 0, 0, (u64)-1, &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],
struct btrfs_block_group_item);
memcpy(bi, &cache->item, sizeof(*bi));
mark_buffer_dirty(path->nodes[0]);
btrfs_release_path(extent_root, path);
finish_current_insert(trans, extent_root);
pending_ret = del_pending_extents(trans, extent_root);
if (ret)
return ret;
if (pending_ret)
return pending_ret;
if (cache->data)
cache->last_alloc = cache->first_free;
static int write_dirty_block_radix(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct radix_tree_root *radix)
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
{
struct btrfs_block_group_cache *cache[8];
int ret;
int err = 0;
int werr = 0;
int i;
struct btrfs_path *path;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
while(1) {
ret = radix_tree_gang_lookup_tag(radix, (void **)cache,
0, ARRAY_SIZE(cache),
BTRFS_BLOCK_GROUP_DIRTY);
if (!ret)
break;
for (i = 0; i < ret; i++) {
radix_tree_tag_clear(radix, cache[i]->key.objectid +
cache[i]->key.offset - 1,
BTRFS_BLOCK_GROUP_DIRTY);
err = write_one_cache_group(trans, root,
path, cache[i]);
if (err)
werr = err;
}
}
btrfs_free_path(path);
return werr;
}
int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
int ret;
int ret2;
ret = write_dirty_block_radix(trans, root,
&root->fs_info->block_group_radix);
ret2 = write_dirty_block_radix(trans, root,
&root->fs_info->block_group_data_radix);
if (ret)
return ret;
if (ret2)
return ret2;
return 0;
}
static int update_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 blocknr, u64 num, int alloc, int mark_free)
{
struct btrfs_block_group_cache *cache;
struct btrfs_fs_info *info = root->fs_info;
u64 total = num;
u64 old_val;
u64 block_in_group;
cache = lookup_block_group(info, blocknr);
if (!cache) {
printk(KERN_CRIT "blocknr %Lu lookup failed\n",
blocknr);
block_in_group = blocknr - cache->key.objectid;
WARN_ON(block_in_group > cache->key.offset);
radix_tree_tag_set(cache->radix, cache->key.objectid +
BTRFS_BLOCK_GROUP_DIRTY);
old_val = btrfs_block_group_used(&cache->item);
num = min(total, cache->key.offset - block_in_group);
if (blocknr > cache->last_alloc)
cache->last_alloc = blocknr;
if (!cache->data) {
for (i = 0; i < num; i++) {
clear_radix_bit(&info->extent_map_radix,
blocknr + i);
}
}
if (blocknr < cache->first_free)
cache->first_free = blocknr;
if (!cache->data && mark_free) {
for (i = 0; i < num; i++) {
set_radix_bit(&info->extent_map_radix,
blocknr + i);
}
}
if (old_val < (cache->key.offset * 6) / 10 &&
old_val + num >= (cache->key.offset * 6) / 10) {
printk("group %Lu now available\n", cache->key.objectid);
radix_tree_tag_set(cache->radix,
cache->key.objectid +
cache->key.offset - 1,
BTRFS_BLOCK_GROUP_AVAIL);
}
btrfs_set_block_group_used(&cache->item, old_val);
total -= num;
blocknr += num;
static int try_remove_page(struct address_space *mapping, unsigned long index)
{
int ret;
ret = invalidate_mapping_pages(mapping, index, index);
return ret;
}
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
btrfs_root *root)
struct inode *btree_inode = root->fs_info->btree_inode;
struct btrfs_block_group_cache *block_group;
struct radix_tree_root *pinned_radix = &root->fs_info->pinned_radix;
struct radix_tree_root *extent_radix = &root->fs_info->extent_map_radix;
ret = find_first_radix_bit(pinned_radix, gang, 0,
block_group = lookup_block_group(root->fs_info,
gang[i]);
if (block_group) {
WARN_ON(block_group->pinned == 0);
block_group->pinned--;
if (gang[i] < block_group->last_alloc)
block_group->last_alloc = gang[i];
if (gang[i] < block_group->last_prealloc)
block_group->last_prealloc = gang[i];
if (!block_group->data)
set_radix_bit(extent_radix, gang[i]);
try_remove_page(btree_inode->i_mapping,
gang[i] << (PAGE_CACHE_SHIFT -
btree_inode->i_blkbits));
static int finish_current_insert(struct btrfs_trans_handle *trans, struct
btrfs_root *extent_root)
u64 super_blocks_used;
struct btrfs_fs_info *info = extent_root->fs_info;
btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY);
btrfs_set_extent_owner(&extent_item, extent_root->root_key.objectid);
for (i = 0; i < extent_root->fs_info->extent_tree_insert_nr; i++) {
ins.objectid = extent_root->fs_info->extent_tree_insert[i];
super_blocks_used = btrfs_super_blocks_used(info->disk_super);
btrfs_set_super_blocks_used(info->disk_super,
super_blocks_used + 1);
ret = btrfs_insert_item(trans, extent_root, &ins, &extent_item,
sizeof(extent_item));
extent_root->fs_info->extent_tree_insert_nr = 0;
extent_root->fs_info->extent_tree_prealloc_nr = 0;
static int pin_down_block(struct btrfs_root *root, u64 blocknr, int pending)
bh = btrfs_find_tree_block(root, blocknr);
if (bh) {
if (buffer_uptodate(bh)) {
u64 transid =
root->fs_info->running_transaction->transid;
header = btrfs_buffer_header(bh);
if (btrfs_header_generation(header) ==
transid) {
btrfs_block_release(root, bh);
return 0;
}
}
err = set_radix_bit(&root->fs_info->pinned_radix, blocknr);
if (!err) {
struct btrfs_block_group_cache *cache;
cache = lookup_block_group(root->fs_info, blocknr);
if (cache)
cache->pinned++;
}
} else {
err = set_radix_bit(&root->fs_info->pending_del_radix, blocknr);
}
* remove an extent from the root, returns 0 on success
static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
*root, u64 blocknr, u64 num_blocks, int pin,
int mark_free)
struct btrfs_fs_info *info = root->fs_info;
struct btrfs_root *extent_root = info->extent_root;
key.objectid = blocknr;
key.flags = 0;
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
find_free_extent(trans, root, 0, 0, (u64)-1, &ins, 0);
path = btrfs_alloc_path();
BUG_ON(!path);
btrfs_init_path(path);
ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1);
printk("failed to find %Lu\n", key.objectid);
btrfs_print_tree(extent_root, extent_root->node);
printk("failed to find %Lu\n", key.objectid);
ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
refs = btrfs_extent_refs(ei) - 1;
btrfs_set_extent_refs(ei, refs);
btrfs_mark_buffer_dirty(path->nodes[0]);
super_blocks_used = btrfs_super_blocks_used(info->disk_super);
btrfs_set_super_blocks_used(info->disk_super,
super_blocks_used - num_blocks);
ret = btrfs_del_item(trans, extent_root, path);
ret = update_block_group(trans, root, blocknr, num_blocks, 0,
mark_free);
finish_current_insert(trans, extent_root);
return ret;
}
/*
* find all the blocks marked as pending in the radix tree and remove
* them from the extent map
*/
static int del_pending_extents(struct btrfs_trans_handle *trans, struct
btrfs_root *extent_root)
struct radix_tree_root *pending_radix;
struct radix_tree_root *pinned_radix;
pending_radix = &extent_root->fs_info->pending_del_radix;
pinned_radix = &extent_root->fs_info->pinned_radix;
ret = find_first_radix_bit(pending_radix, gang, 0,
if (!ret)
break;
for (i = 0; i < ret; i++) {
wret = set_radix_bit(pinned_radix, gang[i]);
if (wret == 0) {
cache = lookup_block_group(extent_root->fs_info,
gang[i]);
if (cache)
cache->pinned++;
}
if (wret < 0) {
printk(KERN_CRIT "set_radix_bit, err %d\n",
wret);
BUG_ON(wret < 0);
}
wret = clear_radix_bit(pending_radix, gang[i]);
BUG_ON(wret);
wret = __free_extent(trans, extent_root,
}
/*
* remove an extent from the root, returns 0 on success
*/
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
*root, u64 blocknr, u64 num_blocks, int pin)
struct btrfs_root *extent_root = root->fs_info->extent_root;
ret = __free_extent(trans, root, blocknr, num_blocks, pin, pin == 0);
pending_ret = del_pending_extents(trans, root->fs_info->extent_root);
return ret ? ret : pending_ret;
}
/*
* walks the btree of allocated extents and find a hole of a given size.
* The key ins is changed to record the hole:
* ins->objectid == block start
* ins->flags = BTRFS_EXTENT_ITEM_KEY
* ins->offset == number of blocks
* Any available blocks before search_start are skipped.
*/
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)
int ret;
u64 hole_size = 0;
int slot = 0;
struct btrfs_root * root = orig_root->fs_info->extent_root;
struct btrfs_fs_info *info = root->fs_info;
int total_found = 0;
int fill_prealloc = 0;
struct btrfs_block_group_cache *block_group;
path = btrfs_alloc_path();
ins->flags = 0;
btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
level = btrfs_header_level(btrfs_buffer_header(root->node));
if (num_blocks == 0) {
fill_prealloc = 1;
num_blocks = 1;
total_needed = (min(level + 1, BTRFS_MAX_LEVEL) + 2) * 3;
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);
block_group = btrfs_find_block_group(root, block_group,
search_start, data);
} else {
block_group = btrfs_find_block_group(root,
trans->block_group, 0,
data);
}
check_failed:
if (!data)
search_start = find_search_start(root, &block_group,
search_start, total_needed);
else
search_start = max(block_group->last_alloc, search_start);
ins->objectid = search_start;
ins->offset = 0;
start_found = 0;
ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
}
l = btrfs_buffer_leaf(path->nodes[0]);
btrfs_disk_key_to_cpu(&key, &l->items[path->slots[0]].key);
/*
* a rare case, go back one key if we hit a block group item
* instead of an extent item
*/
if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY &&
key.objectid + key.offset >= search_start) {
ins->objectid = key.objectid;
ins->offset = key.offset - 1;
btrfs_release_path(root, path);
ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
if (ret < 0)
goto error;
if (path->slots[0] > 0) {
path->slots[0]--;
}
}
l = btrfs_buffer_leaf(path->nodes[0]);
slot = path->slots[0];
if (slot >= btrfs_header_nritems(&l->header)) {
if (fill_prealloc) {
info->extent_tree_prealloc_nr = 0;
total_found = 0;
}
ret = btrfs_next_leaf(root, path);
if (!start_found) {
ins->objectid = search_start;
start_found = 1;
goto check_pending;
}
ins->objectid = last_block > search_start ?
last_block : search_start;
btrfs_disk_key_to_cpu(&key, &l->items[slot].key);
if (key.objectid >= search_start && key.objectid > last_block &&
start_found) {
if (last_block < search_start)
last_block = search_start;
hole_size = key.objectid - last_block;
if (hole_size >= num_blocks) {
ins->objectid = last_block;
ins->offset = hole_size;
goto check_pending;
if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY)
goto next;
if (last_block >= block_group->key.objectid +
block_group->key.offset) {
btrfs_release_path(root, path);
search_start = block_group->key.objectid +
block_group->key.offset * 2;
goto new_group;
}
}
// FIXME -ENOSPC
check_pending:
/* we have to make sure we didn't find an extent that has already
* been allocated by the map tree or the original allocation
*/
BUG_ON(ins->objectid < search_start);
if (ins->objectid + num_blocks >= search_end) {
search_start = orig_search_start;
full_scan = 1;
goto new_group;
test_block < ins->objectid + num_blocks; test_block++) {
if (test_radix_bit(&info->pinned_radix, test_block)) {
if (!fill_prealloc && info->extent_tree_insert_nr) {
u64 last =
info->extent_tree_insert[info->extent_tree_insert_nr - 1];
if (ins->objectid + num_blocks >
info->extent_tree_insert[0] &&
ins->objectid <= last) {
search_start = last + 1;
}
}
if (!fill_prealloc && info->extent_tree_prealloc_nr) {
u64 first =
info->extent_tree_prealloc[info->extent_tree_prealloc_nr - 1];
if (ins->objectid + num_blocks > first &&