aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-03-24 15:01:59 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:01 -0400
commit6324fbf334f4586325057197da7752f4ffa409d3 (patch)
treeaf67d90c3a58f48b91f73ac23f753f4f3907a453 /fs/btrfs/extent-tree.c
parent0b86a832a1f38abec695864ec2eaedc9d2383f1b (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.c208
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);
37static int del_pending_extents(struct btrfs_trans_handle *trans, struct 37static int del_pending_extents(struct btrfs_trans_handle *trans, struct
38 btrfs_root *extent_root); 38 btrfs_root *extent_root);
39int 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
41static int cache_block_group(struct btrfs_root *root, 45static int cache_block_group(struct btrfs_root *root,
@@ -168,16 +172,7 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(struct
168 172
169static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits) 173static 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
183static int noinline find_search_start(struct btrfs_root *root, 178static 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
274static 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
279struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, 286struct 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
998static 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
1013static 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) {
1036printk("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
986static int update_block_group(struct btrfs_trans_handle *trans, 1050static 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
1029static int update_pinned_extents(struct btrfs_root *root, 1096static 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
2575static 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
2493int btrfs_read_block_groups(struct btrfs_root *root) 2603int 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
2684int 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}