diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-04-30 15:25:45 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-04-30 15:25:45 -0400 |
commit | 31f3c99b73483f7b738a886c552050cbd6128ff3 (patch) | |
tree | 35c961e01b8fe25525b9ac4a691fd931ac1dbe59 /fs/btrfs/extent-tree.c | |
parent | 308535a05e4c39d2be26e0aeee722682deeb6f77 (diff) |
Btrfs: allocator improvements, inode block groups
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 | 138 |
1 files changed, 98 insertions, 40 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 62051a36664a..8b8cbe25fffb 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -12,42 +12,57 @@ 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) | 15 | struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, |
16 | struct btrfs_block_group_cache | ||
17 | *hint, int data) | ||
16 | { | 18 | { |
17 | struct btrfs_block_group_cache *cache[8]; | 19 | struct btrfs_block_group_cache *cache[8]; |
20 | struct btrfs_block_group_cache *found_group = NULL; | ||
18 | struct btrfs_fs_info *info = root->fs_info; | 21 | struct btrfs_fs_info *info = root->fs_info; |
19 | u64 used; | 22 | u64 used; |
20 | u64 last; | 23 | u64 last = 0; |
24 | u64 hint_last; | ||
21 | int i; | 25 | int i; |
22 | int ret; | 26 | int ret; |
23 | 27 | int full_search = 0; | |
24 | cache[0] = info->block_group_cache; | 28 | if (hint) { |
25 | if (!cache[0]) | 29 | used = btrfs_block_group_used(&hint->item); |
26 | goto find_new; | 30 | if (used < (hint->key.offset * 2) / 3) { |
27 | used = btrfs_block_group_used(&cache[0]->item); | 31 | return hint; |
28 | if (used < (cache[0]->key.offset * 3 / 2)) | 32 | } |
29 | return 0; | 33 | radix_tree_tag_clear(&info->block_group_radix, |
30 | find_new: | 34 | hint->key.objectid + hint->key.offset - 1, |
31 | last = 0; | 35 | BTRFS_BLOCK_GROUP_AVAIL); |
36 | last = hint->key.objectid + hint->key.offset; | ||
37 | hint_last = last; | ||
38 | } else { | ||
39 | hint_last = 0; | ||
40 | last = 0; | ||
41 | } | ||
32 | while(1) { | 42 | while(1) { |
33 | ret = radix_tree_gang_lookup_tag(&info->block_group_radix, | 43 | ret = radix_tree_gang_lookup_tag(&info->block_group_radix, |
34 | (void **)cache, | 44 | (void **)cache, |
35 | last, ARRAY_SIZE(cache), | 45 | last, ARRAY_SIZE(cache), |
36 | BTRFS_BLOCK_GROUP_DIRTY); | 46 | BTRFS_BLOCK_GROUP_AVAIL); |
37 | if (!ret) | 47 | if (!ret) |
38 | break; | 48 | break; |
39 | for (i = 0; i < ret; i++) { | 49 | for (i = 0; i < ret; i++) { |
40 | used = btrfs_block_group_used(&cache[i]->item); | 50 | used = btrfs_block_group_used(&cache[i]->item); |
41 | if (used < (cache[i]->key.offset * 3 / 2)) { | 51 | if (used < (cache[i]->key.offset * 2) / 3) { |
42 | info->block_group_cache = cache[i]; | 52 | info->block_group_cache = cache[i]; |
43 | cache[i]->last_alloc = cache[i]->first_free; | 53 | found_group = cache[i]; |
44 | return 0; | 54 | goto found; |
45 | } | 55 | } |
56 | radix_tree_tag_clear(&info->block_group_radix, | ||
57 | cache[i]->key.objectid + | ||
58 | cache[i]->key.offset - 1, | ||
59 | BTRFS_BLOCK_GROUP_AVAIL); | ||
46 | last = cache[i]->key.objectid + | 60 | last = cache[i]->key.objectid + |
47 | cache[i]->key.offset - 1; | 61 | cache[i]->key.offset; |
48 | } | 62 | } |
49 | } | 63 | } |
50 | last = 0; | 64 | last = hint_last; |
65 | again: | ||
51 | while(1) { | 66 | while(1) { |
52 | ret = radix_tree_gang_lookup(&info->block_group_radix, | 67 | ret = radix_tree_gang_lookup(&info->block_group_radix, |
53 | (void **)cache, | 68 | (void **)cache, |
@@ -56,17 +71,32 @@ find_new: | |||
56 | break; | 71 | break; |
57 | for (i = 0; i < ret; i++) { | 72 | for (i = 0; i < ret; i++) { |
58 | used = btrfs_block_group_used(&cache[i]->item); | 73 | used = btrfs_block_group_used(&cache[i]->item); |
59 | if (used < (cache[i]->key.offset * 3 / 2)) { | 74 | if (used < cache[i]->key.offset) { |
60 | info->block_group_cache = cache[i]; | 75 | info->block_group_cache = cache[i]; |
61 | cache[i]->last_alloc = cache[i]->first_free; | 76 | found_group = cache[i]; |
62 | return 0; | 77 | goto found; |
63 | } | 78 | } |
79 | radix_tree_tag_clear(&info->block_group_radix, | ||
80 | cache[i]->key.objectid + | ||
81 | cache[i]->key.offset - 1, | ||
82 | BTRFS_BLOCK_GROUP_AVAIL); | ||
64 | last = cache[i]->key.objectid + | 83 | last = cache[i]->key.objectid + |
65 | cache[i]->key.offset - 1; | 84 | cache[i]->key.offset; |
66 | } | 85 | } |
67 | } | 86 | } |
68 | info->block_group_cache = NULL; | 87 | info->block_group_cache = NULL; |
69 | return 0; | 88 | if (!full_search) { |
89 | last = 0; | ||
90 | full_search = 1; | ||
91 | goto again; | ||
92 | } | ||
93 | found: | ||
94 | if (!found_group) { | ||
95 | ret = radix_tree_gang_lookup(&info->block_group_radix, | ||
96 | (void **)&found_group, 0, 1); | ||
97 | BUG_ON(ret != 1); | ||
98 | } | ||
99 | return found_group; | ||
70 | } | 100 | } |
71 | 101 | ||
72 | int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, | 102 | int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, |
@@ -243,6 +273,7 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | |||
243 | path, cache[i]); | 273 | path, cache[i]); |
244 | if (err) | 274 | if (err) |
245 | werr = err; | 275 | werr = err; |
276 | cache[i]->last_alloc = cache[i]->first_free; | ||
246 | } | 277 | } |
247 | } | 278 | } |
248 | btrfs_free_path(path); | 279 | btrfs_free_path(path); |
@@ -322,10 +353,6 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | |||
322 | btree_inode->i_blkbits)); | 353 | btree_inode->i_blkbits)); |
323 | } | 354 | } |
324 | } | 355 | } |
325 | if (root->fs_info->block_group_cache) { | ||
326 | root->fs_info->block_group_cache->last_alloc = | ||
327 | root->fs_info->block_group_cache->first_free; | ||
328 | } | ||
329 | return 0; | 356 | return 0; |
330 | } | 357 | } |
331 | 358 | ||
@@ -532,22 +559,43 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
532 | int total_found = 0; | 559 | int total_found = 0; |
533 | int fill_prealloc = 0; | 560 | int fill_prealloc = 0; |
534 | int level; | 561 | int level; |
562 | int update_block_group = 0; | ||
563 | struct btrfs_block_group_cache *hint_block_group; | ||
535 | 564 | ||
536 | path = btrfs_alloc_path(); | 565 | path = btrfs_alloc_path(); |
537 | ins->flags = 0; | 566 | ins->flags = 0; |
538 | btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); | 567 | btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); |
539 | 568 | ||
540 | level = btrfs_header_level(btrfs_buffer_header(root->node)); | 569 | level = btrfs_header_level(btrfs_buffer_header(root->node)); |
570 | /* find search start here */ | ||
571 | if (0 && search_start && num_blocks) { | ||
572 | u64 used; | ||
573 | ret = radix_tree_gang_lookup(&info->block_group_radix, | ||
574 | (void **)&hint_block_group, | ||
575 | search_start, 1); | ||
576 | if (ret) { | ||
577 | used = btrfs_block_group_used(&hint_block_group->item); | ||
578 | if (used > (hint_block_group->key.offset * 9) / 10) | ||
579 | search_start = 0; | ||
580 | else if (search_start < hint_block_group->last_alloc) | ||
581 | search_start = hint_block_group->last_alloc; | ||
582 | } else { | ||
583 | search_start = 0; | ||
584 | } | ||
585 | } | ||
541 | if (num_blocks == 0) { | 586 | if (num_blocks == 0) { |
542 | fill_prealloc = 1; | 587 | fill_prealloc = 1; |
543 | num_blocks = 1; | 588 | num_blocks = 1; |
544 | total_needed = (min(level + 1, BTRFS_MAX_LEVEL) + 2) * 3; | 589 | total_needed = (min(level + 1, BTRFS_MAX_LEVEL) + 2) * 3; |
545 | } | 590 | } |
546 | find_search_start(root, 0); | 591 | if (1 || !search_start) { |
547 | if (info->block_group_cache && | 592 | trans->block_group = btrfs_find_block_group(root, |
548 | info->block_group_cache->last_alloc > search_start) | 593 | trans->block_group, |
549 | search_start = info->block_group_cache->last_alloc; | 594 | 0); |
550 | 595 | if (trans->block_group->last_alloc > search_start) | |
596 | search_start = trans->block_group->last_alloc; | ||
597 | update_block_group = 1; | ||
598 | } | ||
551 | check_failed: | 599 | check_failed: |
552 | btrfs_init_path(path); | 600 | btrfs_init_path(path); |
553 | ins->objectid = search_start; | 601 | ins->objectid = search_start; |
@@ -662,11 +710,13 @@ check_pending: | |||
662 | } | 710 | } |
663 | info->extent_tree_prealloc_nr = total_found; | 711 | info->extent_tree_prealloc_nr = total_found; |
664 | } | 712 | } |
665 | ret = radix_tree_gang_lookup(&info->block_group_radix, | 713 | if (update_block_group) { |
666 | (void **)&info->block_group_cache, | 714 | ret = radix_tree_gang_lookup(&info->block_group_radix, |
667 | ins->objectid, 1); | 715 | (void **)&trans->block_group, |
668 | if (ret) { | 716 | ins->objectid, 1); |
669 | info->block_group_cache->last_alloc = ins->objectid; | 717 | if (ret) { |
718 | trans->block_group->last_alloc = ins->objectid; | ||
719 | } | ||
670 | } | 720 | } |
671 | ins->offset = num_blocks; | 721 | ins->offset = num_blocks; |
672 | btrfs_free_path(path); | 722 | btrfs_free_path(path); |
@@ -747,14 +797,14 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
747 | * returns the tree buffer or NULL. | 797 | * returns the tree buffer or NULL. |
748 | */ | 798 | */ |
749 | struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | 799 | struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, |
750 | struct btrfs_root *root) | 800 | struct btrfs_root *root, u64 hint) |
751 | { | 801 | { |
752 | struct btrfs_key ins; | 802 | struct btrfs_key ins; |
753 | int ret; | 803 | int ret; |
754 | struct buffer_head *buf; | 804 | struct buffer_head *buf; |
755 | 805 | ||
756 | ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, | 806 | ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, |
757 | 1, 0, (unsigned long)-1, &ins); | 807 | 1, hint, (unsigned long)-1, &ins); |
758 | if (ret) { | 808 | if (ret) { |
759 | BUG(); | 809 | BUG(); |
760 | return NULL; | 810 | return NULL; |
@@ -975,6 +1025,7 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
975 | struct btrfs_key found_key; | 1025 | struct btrfs_key found_key; |
976 | struct btrfs_leaf *leaf; | 1026 | struct btrfs_leaf *leaf; |
977 | u64 group_size_blocks = BTRFS_BLOCK_GROUP_SIZE / root->blocksize; | 1027 | u64 group_size_blocks = BTRFS_BLOCK_GROUP_SIZE / root->blocksize; |
1028 | u64 used; | ||
978 | 1029 | ||
979 | root = root->fs_info->extent_root; | 1030 | root = root->fs_info->extent_root; |
980 | key.objectid = 0; | 1031 | key.objectid = 0; |
@@ -1005,8 +1056,8 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
1005 | struct btrfs_block_group_item); | 1056 | struct btrfs_block_group_item); |
1006 | memcpy(&cache->item, bi, sizeof(*bi)); | 1057 | memcpy(&cache->item, bi, sizeof(*bi)); |
1007 | memcpy(&cache->key, &found_key, sizeof(found_key)); | 1058 | memcpy(&cache->key, &found_key, sizeof(found_key)); |
1008 | cache->last_alloc = 0; | 1059 | cache->last_alloc = cache->key.objectid; |
1009 | cache->first_free = 0; | 1060 | cache->first_free = cache->key.objectid; |
1010 | key.objectid = found_key.objectid + found_key.offset; | 1061 | key.objectid = found_key.objectid + found_key.offset; |
1011 | btrfs_release_path(root, path); | 1062 | btrfs_release_path(root, path); |
1012 | ret = radix_tree_insert(&root->fs_info->block_group_radix, | 1063 | ret = radix_tree_insert(&root->fs_info->block_group_radix, |
@@ -1014,6 +1065,13 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
1014 | found_key.offset - 1, | 1065 | found_key.offset - 1, |
1015 | (void *)cache); | 1066 | (void *)cache); |
1016 | BUG_ON(ret); | 1067 | BUG_ON(ret); |
1068 | used = btrfs_block_group_used(bi); | ||
1069 | if (used < (key.offset * 2) / 3) { | ||
1070 | radix_tree_tag_set(&root->fs_info->block_group_radix, | ||
1071 | found_key.objectid + | ||
1072 | found_key.offset - 1, | ||
1073 | BTRFS_BLOCK_GROUP_AVAIL); | ||
1074 | } | ||
1017 | if (key.objectid >= | 1075 | if (key.objectid >= |
1018 | btrfs_super_total_blocks(root->fs_info->disk_super)) | 1076 | btrfs_super_total_blocks(root->fs_info->disk_super)) |
1019 | break; | 1077 | break; |