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; |
