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 | |
parent | 0b86a832a1f38abec695864ec2eaedc9d2383f1b (diff) |
Btrfs: Dynamic chunk and block group allocation
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.h | 12 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 2 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 208 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 9 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 87 | ||||
-rw-r--r-- | fs/btrfs/volumes.h | 2 |
6 files changed, 263 insertions, 57 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 1453d995fef6..a877105f5c47 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -431,9 +431,19 @@ struct btrfs_block_group_item { | |||
431 | __le64 flags; | 431 | __le64 flags; |
432 | } __attribute__ ((__packed__)); | 432 | } __attribute__ ((__packed__)); |
433 | 433 | ||
434 | struct btrfs_space_info { | ||
435 | u64 flags; | ||
436 | u64 total_bytes; | ||
437 | u64 bytes_used; | ||
438 | u64 bytes_pinned; | ||
439 | int full; | ||
440 | struct list_head list; | ||
441 | }; | ||
442 | |||
434 | struct btrfs_block_group_cache { | 443 | struct btrfs_block_group_cache { |
435 | struct btrfs_key key; | 444 | struct btrfs_key key; |
436 | struct btrfs_block_group_item item; | 445 | struct btrfs_block_group_item item; |
446 | struct btrfs_space_info *space_info; | ||
437 | u64 pinned; | 447 | u64 pinned; |
438 | u64 flags; | 448 | u64 flags; |
439 | int cached; | 449 | int cached; |
@@ -490,7 +500,7 @@ struct btrfs_fs_info { | |||
490 | struct list_head dirty_cowonly_roots; | 500 | struct list_head dirty_cowonly_roots; |
491 | 501 | ||
492 | struct list_head devices; | 502 | struct list_head devices; |
493 | struct list_head *last_device; | 503 | struct list_head space_info; |
494 | spinlock_t delalloc_lock; | 504 | spinlock_t delalloc_lock; |
495 | spinlock_t new_trans_lock; | 505 | spinlock_t new_trans_lock; |
496 | u64 delalloc_bytes; | 506 | u64 delalloc_bytes; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 8e37fa120cc8..2a239ae49f78 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -700,8 +700,8 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
700 | fs_info->dev_root = dev_root; | 700 | fs_info->dev_root = dev_root; |
701 | INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); | 701 | INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); |
702 | INIT_LIST_HEAD(&fs_info->devices); | 702 | INIT_LIST_HEAD(&fs_info->devices); |
703 | INIT_LIST_HEAD(&fs_info->space_info); | ||
703 | btrfs_mapping_init(&fs_info->mapping_tree); | 704 | btrfs_mapping_init(&fs_info->mapping_tree); |
704 | fs_info->last_device = &fs_info->devices; | ||
705 | fs_info->sb = sb; | 705 | fs_info->sb = sb; |
706 | fs_info->throttles = 0; | 706 | fs_info->throttles = 0; |
707 | fs_info->mount_opt = 0; | 707 | fs_info->mount_opt = 0; |
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 | } | ||
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 17063cd2cb73..109576b57f69 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -1527,6 +1527,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
1527 | { | 1527 | { |
1528 | struct inode *inode; | 1528 | struct inode *inode; |
1529 | struct btrfs_inode_item *inode_item; | 1529 | struct btrfs_inode_item *inode_item; |
1530 | struct btrfs_block_group_cache *new_inode_group; | ||
1530 | struct btrfs_key *location; | 1531 | struct btrfs_key *location; |
1531 | struct btrfs_path *path; | 1532 | struct btrfs_path *path; |
1532 | struct btrfs_inode_ref *ref; | 1533 | struct btrfs_inode_ref *ref; |
@@ -1553,9 +1554,13 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
1553 | owner = 0; | 1554 | owner = 0; |
1554 | else | 1555 | else |
1555 | owner = 1; | 1556 | owner = 1; |
1556 | group = btrfs_find_block_group(root, group, 0, | 1557 | new_inode_group = btrfs_find_block_group(root, group, 0, |
1557 | BTRFS_BLOCK_GROUP_METADATA, owner); | 1558 | BTRFS_BLOCK_GROUP_METADATA, owner); |
1558 | BTRFS_I(inode)->block_group = group; | 1559 | if (!new_inode_group) { |
1560 | printk("find_block group failed\n"); | ||
1561 | new_inode_group = group; | ||
1562 | } | ||
1563 | BTRFS_I(inode)->block_group = new_inode_group; | ||
1559 | BTRFS_I(inode)->flags = 0; | 1564 | BTRFS_I(inode)->flags = 0; |
1560 | 1565 | ||
1561 | key[0].objectid = objectid; | 1566 | key[0].objectid = objectid; |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 90a8d45dc6d7..a52a13f365d6 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -131,7 +131,7 @@ check_pending: | |||
131 | btrfs_release_path(root, path); | 131 | btrfs_release_path(root, path); |
132 | BUG_ON(*start < search_start); | 132 | BUG_ON(*start < search_start); |
133 | 133 | ||
134 | if (*start + num_bytes >= search_end) { | 134 | if (*start + num_bytes > search_end) { |
135 | ret = -ENOSPC; | 135 | ret = -ENOSPC; |
136 | goto error; | 136 | goto error; |
137 | } | 137 | } |
@@ -159,8 +159,9 @@ int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, | |||
159 | return -ENOMEM; | 159 | return -ENOMEM; |
160 | 160 | ||
161 | ret = find_free_dev_extent(trans, device, path, num_bytes, start); | 161 | ret = find_free_dev_extent(trans, device, path, num_bytes, start); |
162 | if (ret) | 162 | if (ret) { |
163 | goto err; | 163 | goto err; |
164 | } | ||
164 | 165 | ||
165 | key.objectid = device->devid; | 166 | key.objectid = device->devid; |
166 | key.offset = *start; | 167 | key.offset = *start; |
@@ -214,22 +215,6 @@ error: | |||
214 | return ret; | 215 | return ret; |
215 | } | 216 | } |
216 | 217 | ||
217 | static struct btrfs_device *next_device(struct list_head *head, | ||
218 | struct list_head *last) | ||
219 | { | ||
220 | struct list_head *next = last->next; | ||
221 | struct btrfs_device *dev; | ||
222 | |||
223 | if (list_empty(head)) | ||
224 | return NULL; | ||
225 | |||
226 | if (next == head) | ||
227 | next = next->next; | ||
228 | |||
229 | dev = list_entry(next, struct btrfs_device, dev_list); | ||
230 | return dev; | ||
231 | } | ||
232 | |||
233 | static int find_next_devid(struct btrfs_root *root, struct btrfs_path *path, | 218 | static int find_next_devid(struct btrfs_root *root, struct btrfs_path *path, |
234 | u64 *objectid) | 219 | u64 *objectid) |
235 | { | 220 | { |
@@ -397,31 +382,63 @@ int btrfs_add_system_chunk(struct btrfs_trans_handle *trans, | |||
397 | 382 | ||
398 | int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | 383 | int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, |
399 | struct btrfs_root *extent_root, u64 *start, | 384 | struct btrfs_root *extent_root, u64 *start, |
400 | u64 *num_bytes, u32 type) | 385 | u64 *num_bytes, u64 type) |
401 | { | 386 | { |
402 | u64 dev_offset; | 387 | u64 dev_offset; |
403 | struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root; | 388 | struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root; |
404 | struct btrfs_stripe *stripes; | 389 | struct btrfs_stripe *stripes; |
405 | struct btrfs_device *device = NULL; | 390 | struct btrfs_device *device = NULL; |
406 | struct btrfs_chunk *chunk; | 391 | struct btrfs_chunk *chunk; |
392 | struct list_head private_devs; | ||
407 | struct list_head *dev_list = &extent_root->fs_info->devices; | 393 | struct list_head *dev_list = &extent_root->fs_info->devices; |
408 | struct list_head *last_dev = extent_root->fs_info->last_device; | 394 | struct list_head *cur; |
409 | struct extent_map_tree *em_tree; | 395 | struct extent_map_tree *em_tree; |
410 | struct map_lookup *map; | 396 | struct map_lookup *map; |
411 | struct extent_map *em; | 397 | struct extent_map *em; |
412 | u64 physical; | 398 | u64 physical; |
413 | u64 calc_size = 1024 * 1024 * 1024; | 399 | u64 calc_size = 1024 * 1024 * 1024; |
414 | int num_stripes; | 400 | u64 avail; |
401 | u64 max_avail = 0; | ||
402 | int num_stripes = 1; | ||
403 | int looped = 0; | ||
415 | int ret; | 404 | int ret; |
416 | int index = 0; | 405 | int index; |
417 | struct btrfs_key key; | 406 | struct btrfs_key key; |
418 | 407 | ||
408 | if (list_empty(dev_list)) | ||
409 | return -ENOSPC; | ||
410 | again: | ||
411 | INIT_LIST_HEAD(&private_devs); | ||
412 | cur = dev_list->next; | ||
413 | index = 0; | ||
414 | /* build a private list of devices we will allocate from */ | ||
415 | while(index < num_stripes) { | ||
416 | device = list_entry(cur, struct btrfs_device, dev_list); | ||
417 | avail = device->total_bytes - device->bytes_used; | ||
418 | cur = cur->next; | ||
419 | if (avail > max_avail) | ||
420 | max_avail = avail; | ||
421 | if (avail >= calc_size) { | ||
422 | list_move_tail(&device->dev_list, &private_devs); | ||
423 | index++; | ||
424 | } | ||
425 | if (cur == dev_list) | ||
426 | break; | ||
427 | } | ||
428 | if (index < num_stripes) { | ||
429 | list_splice(&private_devs, dev_list); | ||
430 | if (!looped && max_avail > 0) { | ||
431 | looped = 1; | ||
432 | calc_size = max_avail; | ||
433 | goto again; | ||
434 | } | ||
435 | return -ENOSPC; | ||
436 | } | ||
419 | 437 | ||
420 | ret = find_next_chunk(chunk_root, &key.objectid); | 438 | ret = find_next_chunk(chunk_root, &key.objectid); |
421 | if (ret) | 439 | if (ret) |
422 | return ret; | 440 | return ret; |
423 | 441 | ||
424 | num_stripes = 1; | ||
425 | chunk = kmalloc(btrfs_chunk_item_size(num_stripes), GFP_NOFS); | 442 | chunk = kmalloc(btrfs_chunk_item_size(num_stripes), GFP_NOFS); |
426 | if (!chunk) | 443 | if (!chunk) |
427 | return -ENOMEM; | 444 | return -ENOMEM; |
@@ -429,11 +446,12 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
429 | stripes = &chunk->stripe; | 446 | stripes = &chunk->stripe; |
430 | 447 | ||
431 | *num_bytes = calc_size; | 448 | *num_bytes = calc_size; |
449 | index = 0; | ||
432 | while(index < num_stripes) { | 450 | while(index < num_stripes) { |
433 | device = next_device(dev_list, last_dev); | 451 | BUG_ON(list_empty(&private_devs)); |
434 | BUG_ON(!device); | 452 | cur = private_devs.next; |
435 | last_dev = &device->dev_list; | 453 | device = list_entry(cur, struct btrfs_device, dev_list); |
436 | extent_root->fs_info->last_device = last_dev; | 454 | list_move_tail(&device->dev_list, dev_list); |
437 | 455 | ||
438 | ret = btrfs_alloc_dev_extent(trans, device, | 456 | ret = btrfs_alloc_dev_extent(trans, device, |
439 | key.objectid, | 457 | key.objectid, |
@@ -449,6 +467,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
449 | physical = dev_offset; | 467 | physical = dev_offset; |
450 | index++; | 468 | index++; |
451 | } | 469 | } |
470 | BUG_ON(!list_empty(&private_devs)); | ||
452 | 471 | ||
453 | /* key.objectid was set above */ | 472 | /* key.objectid was set above */ |
454 | key.offset = *num_bytes; | 473 | key.offset = *num_bytes; |
@@ -692,17 +711,17 @@ static int read_one_dev(struct btrfs_root *root, struct btrfs_key *key, | |||
692 | int ret; | 711 | int ret; |
693 | 712 | ||
694 | devid = btrfs_device_id(leaf, dev_item); | 713 | devid = btrfs_device_id(leaf, dev_item); |
695 | if (btrfs_find_device(root, devid)) | 714 | device = btrfs_find_device(root, devid); |
696 | return 0; | 715 | if (!device) { |
697 | 716 | device = kmalloc(sizeof(*device), GFP_NOFS); | |
698 | device = kmalloc(sizeof(*device), GFP_NOFS); | 717 | if (!device) |
699 | if (!device) | 718 | return -ENOMEM; |
700 | return -ENOMEM; | 719 | list_add(&device->dev_list, &root->fs_info->devices); |
720 | } | ||
701 | 721 | ||
702 | fill_device_from_item(leaf, dev_item, device); | 722 | fill_device_from_item(leaf, dev_item, device); |
703 | device->dev_root = root->fs_info->dev_root; | 723 | device->dev_root = root->fs_info->dev_root; |
704 | device->bdev = root->fs_info->sb->s_bdev; | 724 | device->bdev = root->fs_info->sb->s_bdev; |
705 | list_add(&device->dev_list, &root->fs_info->devices); | ||
706 | memcpy(&device->dev_key, key, sizeof(*key)); | 725 | memcpy(&device->dev_key, key, sizeof(*key)); |
707 | ret = 0; | 726 | ret = 0; |
708 | #if 0 | 727 | #if 0 |
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 4a47dcb00a73..4ab9891878a8 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
@@ -71,7 +71,7 @@ int btrfs_read_sys_array(struct btrfs_root *root); | |||
71 | int btrfs_read_chunk_tree(struct btrfs_root *root); | 71 | int btrfs_read_chunk_tree(struct btrfs_root *root); |
72 | int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | 72 | int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, |
73 | struct btrfs_root *extent_root, u64 *start, | 73 | struct btrfs_root *extent_root, u64 *start, |
74 | u64 *num_bytes, u32 type); | 74 | u64 *num_bytes, u64 type); |
75 | void btrfs_mapping_init(struct btrfs_mapping_tree *tree); | 75 | void btrfs_mapping_init(struct btrfs_mapping_tree *tree); |
76 | void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree); | 76 | void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree); |
77 | int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio); | 77 | int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio); |