diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-04-27 10:08:34 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-04-27 10:08:34 -0400 |
commit | cd1bc4653dc37f6390f4d6df4f987044c64f700b (patch) | |
tree | ff259c33e47159758d70a6d8bdc1ff5d47f710bb /fs/btrfs/extent-tree.c | |
parent | 9078a3e1e4e489dddc636c7bb8780349d4298743 (diff) |
Btrfs: more block allocator work
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 95 |
1 files changed, 83 insertions, 12 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 0bb4fc83cfd6..71e3b311fc42 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -12,6 +12,63 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct | |||
12 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct | 12 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct |
13 | btrfs_root *extent_root); | 13 | btrfs_root *extent_root); |
14 | 14 | ||
15 | static int find_search_start(struct btrfs_root *root, int data) | ||
16 | { | ||
17 | struct btrfs_block_group_cache *cache[8]; | ||
18 | struct btrfs_fs_info *info = root->fs_info; | ||
19 | u64 used; | ||
20 | u64 last; | ||
21 | int i; | ||
22 | int ret; | ||
23 | |||
24 | cache[0] = info->block_group_cache; | ||
25 | if (!cache[0]) | ||
26 | goto find_new; | ||
27 | used = btrfs_block_group_used(&cache[0]->item); | ||
28 | if (used < (cache[0]->key.offset * 3 / 2)) | ||
29 | return 0; | ||
30 | find_new: | ||
31 | last = 0; | ||
32 | while(1) { | ||
33 | ret = radix_tree_gang_lookup_tag(&info->block_group_radix, | ||
34 | (void **)cache, | ||
35 | last, ARRAY_SIZE(cache), | ||
36 | BTRFS_BLOCK_GROUP_DIRTY); | ||
37 | if (!ret) | ||
38 | break; | ||
39 | for (i = 0; i < ret; i++) { | ||
40 | used = btrfs_block_group_used(&cache[i]->item); | ||
41 | if (used < (cache[i]->key.offset * 3 / 2)) { | ||
42 | info->block_group_cache = cache[i]; | ||
43 | cache[i]->last_alloc = cache[i]->first_free; | ||
44 | return 0; | ||
45 | } | ||
46 | last = cache[i]->key.objectid + | ||
47 | cache[i]->key.offset - 1; | ||
48 | } | ||
49 | } | ||
50 | last = 0; | ||
51 | while(1) { | ||
52 | ret = radix_tree_gang_lookup(&info->block_group_radix, | ||
53 | (void **)cache, | ||
54 | last, ARRAY_SIZE(cache)); | ||
55 | if (!ret) | ||
56 | break; | ||
57 | for (i = 0; i < ret; i++) { | ||
58 | used = btrfs_block_group_used(&cache[i]->item); | ||
59 | if (used < (cache[i]->key.offset * 3 / 2)) { | ||
60 | info->block_group_cache = cache[i]; | ||
61 | cache[i]->last_alloc = cache[i]->first_free; | ||
62 | return 0; | ||
63 | } | ||
64 | last = cache[i]->key.objectid + | ||
65 | cache[i]->key.offset - 1; | ||
66 | } | ||
67 | } | ||
68 | info->block_group_cache = NULL; | ||
69 | return 0; | ||
70 | } | ||
71 | |||
15 | int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, | 72 | int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, |
16 | struct btrfs_root *root, | 73 | struct btrfs_root *root, |
17 | u64 blocknr, u64 num_blocks) | 74 | u64 blocknr, u64 num_blocks) |
@@ -205,8 +262,11 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
205 | while(total) { | 262 | while(total) { |
206 | ret = radix_tree_gang_lookup(&info->block_group_radix, | 263 | ret = radix_tree_gang_lookup(&info->block_group_radix, |
207 | (void **)&cache, blocknr, 1); | 264 | (void **)&cache, blocknr, 1); |
208 | if (!ret) | 265 | if (!ret) { |
266 | printk(KERN_CRIT "blocknr %Lu lookup failed\n", | ||
267 | blocknr); | ||
209 | return -1; | 268 | return -1; |
269 | } | ||
210 | block_in_group = blocknr - cache->key.objectid; | 270 | block_in_group = blocknr - cache->key.objectid; |
211 | WARN_ON(block_in_group > cache->key.offset); | 271 | WARN_ON(block_in_group > cache->key.offset); |
212 | radix_tree_tag_set(&info->block_group_radix, | 272 | radix_tree_tag_set(&info->block_group_radix, |
@@ -217,10 +277,15 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
217 | num = min(total, cache->key.offset - block_in_group); | 277 | num = min(total, cache->key.offset - block_in_group); |
218 | total -= num; | 278 | total -= num; |
219 | blocknr += num; | 279 | blocknr += num; |
220 | if (alloc) | 280 | if (alloc) { |
221 | old_val += num; | 281 | old_val += num; |
222 | else | 282 | if (blocknr > cache->last_alloc) |
283 | cache->last_alloc = blocknr; | ||
284 | } else { | ||
223 | old_val -= num; | 285 | old_val -= num; |
286 | if (blocknr < cache->first_free) | ||
287 | cache->first_free = blocknr; | ||
288 | } | ||
224 | btrfs_set_block_group_used(&cache->item, old_val); | 289 | btrfs_set_block_group_used(&cache->item, old_val); |
225 | } | 290 | } |
226 | return 0; | 291 | return 0; |
@@ -246,9 +311,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | |||
246 | clear_radix_bit(pinned_radix, gang[i]); | 311 | clear_radix_bit(pinned_radix, gang[i]); |
247 | } | 312 | } |
248 | } | 313 | } |
249 | if (root->fs_info->last_insert.objectid > first) | 314 | root->fs_info->block_group_cache = NULL; |
250 | root->fs_info->last_insert.objectid = first; | ||
251 | root->fs_info->last_insert.offset = 0; | ||
252 | return 0; | 315 | return 0; |
253 | } | 316 | } |
254 | 317 | ||
@@ -466,8 +529,10 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
466 | num_blocks = 1; | 529 | num_blocks = 1; |
467 | total_needed = min(level + 2, BTRFS_MAX_LEVEL) * 3; | 530 | total_needed = min(level + 2, BTRFS_MAX_LEVEL) * 3; |
468 | } | 531 | } |
469 | if (info->last_insert.objectid > search_start) | 532 | find_search_start(root, 0); |
470 | search_start = info->last_insert.objectid; | 533 | if (info->block_group_cache && |
534 | info->block_group_cache->last_alloc > search_start) | ||
535 | search_start = info->block_group_cache->last_alloc; | ||
471 | 536 | ||
472 | check_failed: | 537 | check_failed: |
473 | btrfs_init_path(path); | 538 | btrfs_init_path(path); |
@@ -567,8 +632,7 @@ check_pending: | |||
567 | total_found < total_needed) { | 632 | total_found < total_needed) { |
568 | nr = total_needed - total_found - 1; | 633 | nr = total_needed - total_found - 1; |
569 | BUG_ON(nr < 0); | 634 | BUG_ON(nr < 0); |
570 | root->fs_info->extent_tree_prealloc[nr] = | 635 | info->extent_tree_prealloc[nr] = test_block; |
571 | test_block; | ||
572 | total_found++; | 636 | total_found++; |
573 | test_block++; | 637 | test_block++; |
574 | } | 638 | } |
@@ -576,9 +640,14 @@ check_pending: | |||
576 | search_start = test_block; | 640 | search_start = test_block; |
577 | goto check_failed; | 641 | goto check_failed; |
578 | } | 642 | } |
579 | root->fs_info->extent_tree_prealloc_nr = total_found; | 643 | info->extent_tree_prealloc_nr = total_found; |
644 | } | ||
645 | ret = radix_tree_gang_lookup(&info->block_group_radix, | ||
646 | (void **)&info->block_group_cache, | ||
647 | ins->objectid, 1); | ||
648 | if (ret) { | ||
649 | info->block_group_cache->last_alloc = ins->objectid; | ||
580 | } | 650 | } |
581 | root->fs_info->last_insert.objectid = ins->objectid; | ||
582 | ins->offset = num_blocks; | 651 | ins->offset = num_blocks; |
583 | btrfs_free_path(path); | 652 | btrfs_free_path(path); |
584 | return 0; | 653 | return 0; |
@@ -915,6 +984,8 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
915 | struct btrfs_block_group_item); | 984 | struct btrfs_block_group_item); |
916 | memcpy(&cache->item, bi, sizeof(*bi)); | 985 | memcpy(&cache->item, bi, sizeof(*bi)); |
917 | memcpy(&cache->key, &found_key, sizeof(found_key)); | 986 | memcpy(&cache->key, &found_key, sizeof(found_key)); |
987 | cache->last_alloc = 0; | ||
988 | cache->first_free = 0; | ||
918 | key.objectid = found_key.objectid + found_key.offset; | 989 | key.objectid = found_key.objectid + found_key.offset; |
919 | btrfs_release_path(root, path); | 990 | btrfs_release_path(root, path); |
920 | ret = radix_tree_insert(&root->fs_info->block_group_radix, | 991 | ret = radix_tree_insert(&root->fs_info->block_group_radix, |