diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-03-24 15:01:59 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:01 -0400 |
commit | 6324fbf334f4586325057197da7752f4ffa409d3 (patch) | |
tree | af67d90c3a58f48b91f73ac23f753f4f3907a453 /fs/btrfs/extent-tree.c | |
parent | 0b86a832a1f38abec695864ec2eaedc9d2383f1b (diff) |
Btrfs: Dynamic chunk and block group allocation
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 | 208 |
1 files changed, 190 insertions, 18 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 2cd957d6e8d8..15082b1087be 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -36,6 +36,10 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct | |||
36 | btrfs_root *extent_root); | 36 | btrfs_root *extent_root); |
37 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct | 37 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct |
38 | btrfs_root *extent_root); | 38 | btrfs_root *extent_root); |
39 | int btrfs_make_block_group(struct btrfs_trans_handle *trans, | ||
40 | struct btrfs_root *root, u64 bytes_used, | ||
41 | u64 type, u64 chunk_tree, u64 chunk_objectid, | ||
42 | u64 size); | ||
39 | 43 | ||
40 | 44 | ||
41 | static int cache_block_group(struct btrfs_root *root, | 45 | static int cache_block_group(struct btrfs_root *root, |
@@ -168,16 +172,7 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(struct | |||
168 | 172 | ||
169 | static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits) | 173 | static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits) |
170 | { | 174 | { |
171 | if ((bits & BLOCK_GROUP_DATA) && | 175 | return (cache->flags & bits); |
172 | (cache->flags & BTRFS_BLOCK_GROUP_DATA)) | ||
173 | return 1; | ||
174 | if ((bits & BLOCK_GROUP_METADATA) && | ||
175 | (cache->flags & BTRFS_BLOCK_GROUP_METADATA)) | ||
176 | return 1; | ||
177 | if ((bits & BLOCK_GROUP_SYSTEM) && | ||
178 | (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM)) | ||
179 | return 1; | ||
180 | return 0; | ||
181 | } | 176 | } |
182 | 177 | ||
183 | static int noinline find_search_start(struct btrfs_root *root, | 178 | static int noinline find_search_start(struct btrfs_root *root, |
@@ -276,6 +271,18 @@ static u64 div_factor(u64 num, int factor) | |||
276 | return num; | 271 | return num; |
277 | } | 272 | } |
278 | 273 | ||
274 | static int block_group_state_bits(u64 flags) | ||
275 | { | ||
276 | int bits = 0; | ||
277 | if (flags & BTRFS_BLOCK_GROUP_DATA) | ||
278 | bits |= BLOCK_GROUP_DATA; | ||
279 | if (flags & BTRFS_BLOCK_GROUP_METADATA) | ||
280 | bits |= BLOCK_GROUP_METADATA; | ||
281 | if (flags & BTRFS_BLOCK_GROUP_SYSTEM) | ||
282 | bits |= BLOCK_GROUP_SYSTEM; | ||
283 | return bits; | ||
284 | } | ||
285 | |||
279 | struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | 286 | struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, |
280 | struct btrfs_block_group_cache | 287 | struct btrfs_block_group_cache |
281 | *hint, u64 search_start, | 288 | *hint, u64 search_start, |
@@ -304,7 +311,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
304 | if (!owner) | 311 | if (!owner) |
305 | factor = 8; | 312 | factor = 8; |
306 | 313 | ||
307 | bit = data; | 314 | bit = block_group_state_bits(data); |
308 | 315 | ||
309 | if (search_start && search_start < total_fs_bytes) { | 316 | if (search_start && search_start < total_fs_bytes) { |
310 | struct btrfs_block_group_cache *shint; | 317 | struct btrfs_block_group_cache *shint; |
@@ -358,10 +365,15 @@ again: | |||
358 | free_check = cache->key.offset; | 365 | free_check = cache->key.offset; |
359 | else | 366 | else |
360 | free_check = div_factor(cache->key.offset, factor); | 367 | free_check = div_factor(cache->key.offset, factor); |
368 | |||
361 | if (used + cache->pinned < free_check) { | 369 | if (used + cache->pinned < free_check) { |
362 | found_group = cache; | 370 | found_group = cache; |
363 | goto found; | 371 | goto found; |
364 | } | 372 | } |
373 | if (full_search) { | ||
374 | printk("failed on cache %Lu used %Lu total %Lu\n", | ||
375 | cache->key.objectid, used, cache->key.offset); | ||
376 | } | ||
365 | cond_resched(); | 377 | cond_resched(); |
366 | } | 378 | } |
367 | if (!full_search) { | 379 | if (!full_search) { |
@@ -983,6 +995,58 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | |||
983 | return werr; | 995 | return werr; |
984 | } | 996 | } |
985 | 997 | ||
998 | static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info, | ||
999 | u64 flags) | ||
1000 | { | ||
1001 | struct list_head *head = &info->space_info; | ||
1002 | struct list_head *cur; | ||
1003 | struct btrfs_space_info *found; | ||
1004 | list_for_each(cur, head) { | ||
1005 | found = list_entry(cur, struct btrfs_space_info, list); | ||
1006 | if (found->flags == flags) | ||
1007 | return found; | ||
1008 | } | ||
1009 | return NULL; | ||
1010 | |||
1011 | } | ||
1012 | |||
1013 | static int do_chunk_alloc(struct btrfs_trans_handle *trans, | ||
1014 | struct btrfs_root *extent_root, u64 alloc_bytes, | ||
1015 | u64 flags) | ||
1016 | { | ||
1017 | struct btrfs_space_info *space_info; | ||
1018 | u64 thresh; | ||
1019 | u64 start; | ||
1020 | u64 num_bytes; | ||
1021 | int ret; | ||
1022 | |||
1023 | space_info = __find_space_info(extent_root->fs_info, flags); | ||
1024 | BUG_ON(!space_info); | ||
1025 | |||
1026 | if (space_info->full) | ||
1027 | return 0; | ||
1028 | |||
1029 | thresh = div_factor(space_info->total_bytes, 7); | ||
1030 | if ((space_info->bytes_used + space_info->bytes_pinned + alloc_bytes) < | ||
1031 | thresh) | ||
1032 | return 0; | ||
1033 | |||
1034 | ret = btrfs_alloc_chunk(trans, extent_root, &start, &num_bytes, flags); | ||
1035 | if (ret == -ENOSPC) { | ||
1036 | printk("space info full %Lu\n", flags); | ||
1037 | space_info->full = 1; | ||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | BUG_ON(ret); | ||
1042 | |||
1043 | ret = btrfs_make_block_group(trans, extent_root, 0, flags, | ||
1044 | extent_root->fs_info->chunk_root->root_key.objectid, | ||
1045 | start, num_bytes); | ||
1046 | BUG_ON(ret); | ||
1047 | return 0; | ||
1048 | } | ||
1049 | |||
986 | static int update_block_group(struct btrfs_trans_handle *trans, | 1050 | static int update_block_group(struct btrfs_trans_handle *trans, |
987 | struct btrfs_root *root, | 1051 | struct btrfs_root *root, |
988 | u64 bytenr, u64 num_bytes, int alloc, | 1052 | u64 bytenr, u64 num_bytes, int alloc, |
@@ -1012,8 +1076,10 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
1012 | num_bytes = min(total, cache->key.offset - byte_in_group); | 1076 | num_bytes = min(total, cache->key.offset - byte_in_group); |
1013 | if (alloc) { | 1077 | if (alloc) { |
1014 | old_val += num_bytes; | 1078 | old_val += num_bytes; |
1079 | cache->space_info->bytes_used += num_bytes; | ||
1015 | } else { | 1080 | } else { |
1016 | old_val -= num_bytes; | 1081 | old_val -= num_bytes; |
1082 | cache->space_info->bytes_used -= num_bytes; | ||
1017 | if (mark_free) { | 1083 | if (mark_free) { |
1018 | set_extent_dirty(&info->free_space_cache, | 1084 | set_extent_dirty(&info->free_space_cache, |
1019 | bytenr, bytenr + num_bytes - 1, | 1085 | bytenr, bytenr + num_bytes - 1, |
@@ -1026,6 +1092,7 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
1026 | } | 1092 | } |
1027 | return 0; | 1093 | return 0; |
1028 | } | 1094 | } |
1095 | |||
1029 | static int update_pinned_extents(struct btrfs_root *root, | 1096 | static int update_pinned_extents(struct btrfs_root *root, |
1030 | u64 bytenr, u64 num, int pin) | 1097 | u64 bytenr, u64 num, int pin) |
1031 | { | 1098 | { |
@@ -1047,9 +1114,11 @@ static int update_pinned_extents(struct btrfs_root *root, | |||
1047 | (bytenr - cache->key.objectid)); | 1114 | (bytenr - cache->key.objectid)); |
1048 | if (pin) { | 1115 | if (pin) { |
1049 | cache->pinned += len; | 1116 | cache->pinned += len; |
1117 | cache->space_info->bytes_pinned += len; | ||
1050 | fs_info->total_pinned += len; | 1118 | fs_info->total_pinned += len; |
1051 | } else { | 1119 | } else { |
1052 | cache->pinned -= len; | 1120 | cache->pinned -= len; |
1121 | cache->space_info->bytes_pinned -= len; | ||
1053 | fs_info->total_pinned -= len; | 1122 | fs_info->total_pinned -= len; |
1054 | } | 1123 | } |
1055 | bytenr += len; | 1124 | bytenr += len; |
@@ -1472,7 +1541,7 @@ check_failed: | |||
1472 | goto new_group; | 1541 | goto new_group; |
1473 | } | 1542 | } |
1474 | 1543 | ||
1475 | if (!(data & BLOCK_GROUP_DATA)) { | 1544 | if (!(data & BTRFS_BLOCK_GROUP_DATA)) { |
1476 | block_group = btrfs_lookup_block_group(info, ins->objectid); | 1545 | block_group = btrfs_lookup_block_group(info, ins->objectid); |
1477 | if (block_group) | 1546 | if (block_group) |
1478 | trans->block_group = block_group; | 1547 | trans->block_group = block_group; |
@@ -1532,12 +1601,25 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1532 | struct btrfs_path *path; | 1601 | struct btrfs_path *path; |
1533 | struct btrfs_key keys[2]; | 1602 | struct btrfs_key keys[2]; |
1534 | 1603 | ||
1535 | if (data) | 1604 | if (data) { |
1536 | data = BLOCK_GROUP_DATA; | 1605 | data = BTRFS_BLOCK_GROUP_DATA; |
1537 | else if (root == root->fs_info->chunk_root) | 1606 | } else if (root == root->fs_info->chunk_root) { |
1538 | data = BLOCK_GROUP_SYSTEM; | 1607 | data = BTRFS_BLOCK_GROUP_SYSTEM; |
1539 | else | 1608 | } else { |
1540 | data = BLOCK_GROUP_METADATA; | 1609 | data = BTRFS_BLOCK_GROUP_METADATA; |
1610 | } | ||
1611 | |||
1612 | if (root->ref_cows) { | ||
1613 | if (data != BTRFS_BLOCK_GROUP_METADATA) { | ||
1614 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, | ||
1615 | num_bytes, | ||
1616 | BTRFS_BLOCK_GROUP_METADATA); | ||
1617 | BUG_ON(ret); | ||
1618 | } | ||
1619 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, | ||
1620 | num_bytes, data); | ||
1621 | BUG_ON(ret); | ||
1622 | } | ||
1541 | 1623 | ||
1542 | new_hint = max(hint_byte, root->fs_info->alloc_start); | 1624 | new_hint = max(hint_byte, root->fs_info->alloc_start); |
1543 | if (new_hint < btrfs_super_total_bytes(&info->super_copy)) | 1625 | if (new_hint < btrfs_super_total_bytes(&info->super_copy)) |
@@ -2490,6 +2572,34 @@ error: | |||
2490 | return ret; | 2572 | return ret; |
2491 | } | 2573 | } |
2492 | 2574 | ||
2575 | static int update_space_info(struct btrfs_fs_info *info, u64 flags, | ||
2576 | u64 total_bytes, u64 bytes_used, | ||
2577 | struct btrfs_space_info **space_info) | ||
2578 | { | ||
2579 | struct btrfs_space_info *found; | ||
2580 | |||
2581 | found = __find_space_info(info, flags); | ||
2582 | if (found) { | ||
2583 | found->total_bytes += total_bytes; | ||
2584 | found->bytes_used += bytes_used; | ||
2585 | WARN_ON(found->total_bytes < found->bytes_used); | ||
2586 | *space_info = found; | ||
2587 | return 0; | ||
2588 | } | ||
2589 | found = kmalloc(sizeof(*found), GFP_NOFS); | ||
2590 | if (!found) | ||
2591 | return -ENOMEM; | ||
2592 | |||
2593 | list_add(&found->list, &info->space_info); | ||
2594 | found->flags = flags; | ||
2595 | found->total_bytes = total_bytes; | ||
2596 | found->bytes_used = bytes_used; | ||
2597 | found->bytes_pinned = 0; | ||
2598 | found->full = 0; | ||
2599 | *space_info = found; | ||
2600 | return 0; | ||
2601 | } | ||
2602 | |||
2493 | int btrfs_read_block_groups(struct btrfs_root *root) | 2603 | int btrfs_read_block_groups(struct btrfs_root *root) |
2494 | { | 2604 | { |
2495 | struct btrfs_path *path; | 2605 | struct btrfs_path *path; |
@@ -2497,6 +2607,7 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
2497 | int bit; | 2607 | int bit; |
2498 | struct btrfs_block_group_cache *cache; | 2608 | struct btrfs_block_group_cache *cache; |
2499 | struct btrfs_fs_info *info = root->fs_info; | 2609 | struct btrfs_fs_info *info = root->fs_info; |
2610 | struct btrfs_space_info *space_info; | ||
2500 | struct extent_io_tree *block_group_cache; | 2611 | struct extent_io_tree *block_group_cache; |
2501 | struct btrfs_key key; | 2612 | struct btrfs_key key; |
2502 | struct btrfs_key found_key; | 2613 | struct btrfs_key found_key; |
@@ -2547,6 +2658,12 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
2547 | bit = BLOCK_GROUP_METADATA; | 2658 | bit = BLOCK_GROUP_METADATA; |
2548 | } | 2659 | } |
2549 | 2660 | ||
2661 | ret = update_space_info(info, cache->flags, found_key.offset, | ||
2662 | btrfs_block_group_used(&cache->item), | ||
2663 | &space_info); | ||
2664 | BUG_ON(ret); | ||
2665 | cache->space_info = space_info; | ||
2666 | |||
2550 | /* use EXTENT_LOCKED to prevent merging */ | 2667 | /* use EXTENT_LOCKED to prevent merging */ |
2551 | set_extent_bits(block_group_cache, found_key.objectid, | 2668 | set_extent_bits(block_group_cache, found_key.objectid, |
2552 | found_key.objectid + found_key.offset - 1, | 2669 | found_key.objectid + found_key.offset - 1, |
@@ -2563,3 +2680,58 @@ error: | |||
2563 | btrfs_free_path(path); | 2680 | btrfs_free_path(path); |
2564 | return ret; | 2681 | return ret; |
2565 | } | 2682 | } |
2683 | |||
2684 | int btrfs_make_block_group(struct btrfs_trans_handle *trans, | ||
2685 | struct btrfs_root *root, u64 bytes_used, | ||
2686 | u64 type, u64 chunk_tree, u64 chunk_objectid, | ||
2687 | u64 size) | ||
2688 | { | ||
2689 | int ret; | ||
2690 | int bit = 0; | ||
2691 | struct btrfs_root *extent_root; | ||
2692 | struct btrfs_block_group_cache *cache; | ||
2693 | struct extent_io_tree *block_group_cache; | ||
2694 | |||
2695 | extent_root = root->fs_info->extent_root; | ||
2696 | block_group_cache = &root->fs_info->block_group_cache; | ||
2697 | |||
2698 | cache = kmalloc(sizeof(*cache), GFP_NOFS); | ||
2699 | BUG_ON(!cache); | ||
2700 | cache->key.objectid = chunk_objectid; | ||
2701 | cache->key.offset = size; | ||
2702 | cache->cached = 0; | ||
2703 | cache->pinned = 0; | ||
2704 | btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY); | ||
2705 | memset(&cache->item, 0, sizeof(cache->item)); | ||
2706 | btrfs_set_block_group_used(&cache->item, bytes_used); | ||
2707 | btrfs_set_block_group_chunk_tree(&cache->item, chunk_tree); | ||
2708 | btrfs_set_block_group_chunk_objectid(&cache->item, chunk_objectid); | ||
2709 | cache->flags = type; | ||
2710 | btrfs_set_block_group_flags(&cache->item, type); | ||
2711 | |||
2712 | ret = update_space_info(root->fs_info, cache->flags, size, bytes_used, | ||
2713 | &cache->space_info); | ||
2714 | BUG_ON(ret); | ||
2715 | |||
2716 | if (type & BTRFS_BLOCK_GROUP_DATA) { | ||
2717 | bit = BLOCK_GROUP_DATA; | ||
2718 | } else if (type & BTRFS_BLOCK_GROUP_SYSTEM) { | ||
2719 | bit = BLOCK_GROUP_SYSTEM; | ||
2720 | } else if (type & BTRFS_BLOCK_GROUP_METADATA) { | ||
2721 | bit = BLOCK_GROUP_METADATA; | ||
2722 | } | ||
2723 | set_extent_bits(block_group_cache, chunk_objectid, | ||
2724 | chunk_objectid + size - 1, | ||
2725 | bit | EXTENT_LOCKED, GFP_NOFS); | ||
2726 | set_state_private(block_group_cache, chunk_objectid, | ||
2727 | (unsigned long)cache); | ||
2728 | |||
2729 | ret = btrfs_insert_item(trans, extent_root, &cache->key, &cache->item, | ||
2730 | sizeof(cache->item)); | ||
2731 | BUG_ON(ret); | ||
2732 | |||
2733 | finish_current_insert(trans, extent_root); | ||
2734 | ret = del_pending_extents(trans, extent_root); | ||
2735 | BUG_ON(ret); | ||
2736 | return 0; | ||
2737 | } | ||