aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-04-25 16:53:30 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:02 -0400
commit8f18cf13396caae5a3d7ae91201cfb15181a9642 (patch)
treeff4bfc2e7f45f10d176b969408cdb469ae3f7194
parent5e478dc9828ad33d7b08dcdf277e13f14a7c1be7 (diff)
Btrfs: Make the resizer work based on shrinking and growing devices
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/disk-io.c4
-rw-r--r--fs/btrfs/extent-tree.c145
-rw-r--r--fs/btrfs/inode.c36
-rw-r--r--fs/btrfs/volumes.c324
-rw-r--r--fs/btrfs/volumes.h5
6 files changed, 407 insertions, 108 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index f00c4be59ad6..ac7106ec5357 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -474,6 +474,7 @@ struct btrfs_block_group_cache {
474 u64 pinned; 474 u64 pinned;
475 u64 flags; 475 u64 flags;
476 int cached; 476 int cached;
477 int ro;
477}; 478};
478 479
479struct btrfs_device; 480struct btrfs_device;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 71838264ca6b..a9ce491d279b 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -818,6 +818,10 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
818 return fs_info->tree_root; 818 return fs_info->tree_root;
819 if (location->objectid == BTRFS_EXTENT_TREE_OBJECTID) 819 if (location->objectid == BTRFS_EXTENT_TREE_OBJECTID)
820 return fs_info->extent_root; 820 return fs_info->extent_root;
821 if (location->objectid == BTRFS_CHUNK_TREE_OBJECTID)
822 return fs_info->chunk_root;
823 if (location->objectid == BTRFS_DEV_TREE_OBJECTID)
824 return fs_info->dev_root;
821 825
822 root = radix_tree_lookup(&fs_info->fs_roots_radix, 826 root = radix_tree_lookup(&fs_info->fs_roots_radix,
823 (unsigned long)location->objectid); 827 (unsigned long)location->objectid);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index c49592c5127a..6540095544e8 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -187,6 +187,7 @@ static int noinline find_search_start(struct btrfs_root *root,
187 187
188 if (!cache) 188 if (!cache)
189 goto out; 189 goto out;
190
190 total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); 191 total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
191 free_space_cache = &root->fs_info->free_space_cache; 192 free_space_cache = &root->fs_info->free_space_cache;
192 193
@@ -196,7 +197,7 @@ again:
196 goto out; 197 goto out;
197 198
198 last = max(search_start, cache->key.objectid); 199 last = max(search_start, cache->key.objectid);
199 if (!block_group_bits(cache, data)) { 200 if (!block_group_bits(cache, data) || cache->ro) {
200 goto new_group; 201 goto new_group;
201 } 202 }
202 203
@@ -221,6 +222,8 @@ again:
221 continue; 222 continue;
222 } 223 }
223 spin_unlock_irq(&free_space_cache->lock); 224 spin_unlock_irq(&free_space_cache->lock);
225 if (cache->ro)
226 goto new_group;
224 if (start + num > cache->key.objectid + cache->key.offset) 227 if (start + num > cache->key.objectid + cache->key.offset)
225 goto new_group; 228 goto new_group;
226 if (start + num > total_fs_bytes) 229 if (start + num > total_fs_bytes)
@@ -319,7 +322,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
319 if (search_start && search_start < total_fs_bytes) { 322 if (search_start && search_start < total_fs_bytes) {
320 struct btrfs_block_group_cache *shint; 323 struct btrfs_block_group_cache *shint;
321 shint = btrfs_lookup_block_group(info, search_start); 324 shint = btrfs_lookup_block_group(info, search_start);
322 if (shint && block_group_bits(shint, data)) { 325 if (shint && block_group_bits(shint, data) && !shint->ro) {
323 used = btrfs_block_group_used(&shint->item); 326 used = btrfs_block_group_used(&shint->item);
324 if (used + shint->pinned < 327 if (used + shint->pinned <
325 div_factor(shint->key.offset, factor)) { 328 div_factor(shint->key.offset, factor)) {
@@ -327,7 +330,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
327 } 330 }
328 } 331 }
329 } 332 }
330 if (hint && block_group_bits(hint, data) && 333 if (hint && !hint->ro && block_group_bits(hint, data) &&
331 hint->key.objectid < total_fs_bytes) { 334 hint->key.objectid < total_fs_bytes) {
332 used = btrfs_block_group_used(&hint->item); 335 used = btrfs_block_group_used(&hint->item);
333 if (used + hint->pinned < 336 if (used + hint->pinned <
@@ -364,7 +367,7 @@ again:
364 if (cache->key.objectid > total_fs_bytes) 367 if (cache->key.objectid > total_fs_bytes)
365 break; 368 break;
366 369
367 if (block_group_bits(cache, data)) { 370 if (!cache->ro && block_group_bits(cache, data)) {
368 if (full_search) 371 if (full_search)
369 free_check = cache->key.offset; 372 free_check = cache->key.offset;
370 else 373 else
@@ -1020,6 +1023,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
1020 if (found) { 1023 if (found) {
1021 found->total_bytes += total_bytes; 1024 found->total_bytes += total_bytes;
1022 found->bytes_used += bytes_used; 1025 found->bytes_used += bytes_used;
1026 found->full = 0;
1023 WARN_ON(found->total_bytes < found->bytes_used); 1027 WARN_ON(found->total_bytes < found->bytes_used);
1024 *space_info = found; 1028 *space_info = found;
1025 return 0; 1029 return 0;
@@ -1700,7 +1704,6 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
1700 u64 super_used; 1704 u64 super_used;
1701 u64 root_used; 1705 u64 root_used;
1702 u64 search_start = 0; 1706 u64 search_start = 0;
1703 u64 new_hint;
1704 u64 alloc_profile; 1707 u64 alloc_profile;
1705 u32 sizes[2]; 1708 u32 sizes[2];
1706 struct btrfs_fs_info *info = root->fs_info; 1709 struct btrfs_fs_info *info = root->fs_info;
@@ -1724,7 +1727,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
1724 data = BTRFS_BLOCK_GROUP_METADATA | alloc_profile; 1727 data = BTRFS_BLOCK_GROUP_METADATA | alloc_profile;
1725 } 1728 }
1726again: 1729again:
1727 if (root->ref_cows) { 1730 if (root != root->fs_info->extent_root) {
1728 if (!(data & BTRFS_BLOCK_GROUP_METADATA)) { 1731 if (!(data & BTRFS_BLOCK_GROUP_METADATA)) {
1729 ret = do_chunk_alloc(trans, root->fs_info->extent_root, 1732 ret = do_chunk_alloc(trans, root->fs_info->extent_root,
1730 2 * 1024 * 1024, 1733 2 * 1024 * 1024,
@@ -1738,10 +1741,6 @@ again:
1738 BUG_ON(ret); 1741 BUG_ON(ret);
1739 } 1742 }
1740 1743
1741 new_hint = max(hint_byte, root->fs_info->alloc_start);
1742 if (new_hint < btrfs_super_total_bytes(&info->super_copy))
1743 hint_byte = new_hint;
1744
1745 WARN_ON(num_bytes < root->sectorsize); 1744 WARN_ON(num_bytes < root->sectorsize);
1746 ret = find_free_extent(trans, root, num_bytes, empty_size, 1745 ret = find_free_extent(trans, root, num_bytes, empty_size,
1747 search_start, search_end, hint_byte, ins, 1746 search_start, search_end, hint_byte, ins,
@@ -2473,15 +2472,16 @@ out:
2473 return ret; 2472 return ret;
2474} 2473}
2475 2474
2476int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size) 2475int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start)
2477{ 2476{
2478 struct btrfs_trans_handle *trans; 2477 struct btrfs_trans_handle *trans;
2479 struct btrfs_root *tree_root = root->fs_info->tree_root; 2478 struct btrfs_root *tree_root = root->fs_info->tree_root;
2480 struct btrfs_path *path; 2479 struct btrfs_path *path;
2481 u64 cur_byte; 2480 u64 cur_byte;
2482 u64 total_found; 2481 u64 total_found;
2482 u64 shrink_last_byte;
2483 struct btrfs_block_group_cache *shrink_block_group;
2483 struct btrfs_fs_info *info = root->fs_info; 2484 struct btrfs_fs_info *info = root->fs_info;
2484 struct extent_io_tree *block_group_cache;
2485 struct btrfs_key key; 2485 struct btrfs_key key;
2486 struct btrfs_key found_key; 2486 struct btrfs_key found_key;
2487 struct extent_buffer *leaf; 2487 struct extent_buffer *leaf;
@@ -2489,17 +2489,29 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size)
2489 int ret; 2489 int ret;
2490 int progress = 0; 2490 int progress = 0;
2491 2491
2492 btrfs_set_super_total_bytes(&info->super_copy, new_size); 2492 shrink_block_group = btrfs_lookup_block_group(root->fs_info,
2493 clear_extent_dirty(&info->free_space_cache, new_size, (u64)-1, 2493 shrink_start);
2494 GFP_NOFS); 2494 BUG_ON(!shrink_block_group);
2495 block_group_cache = &info->block_group_cache; 2495
2496 shrink_last_byte = shrink_start + shrink_block_group->key.offset;
2497
2498 shrink_block_group->space_info->total_bytes -=
2499 shrink_block_group->key.offset;
2500printk("shrink_extent_tree %Lu -> %Lu type %Lu\n", shrink_start, shrink_last_byte, shrink_block_group->flags);
2496 path = btrfs_alloc_path(); 2501 path = btrfs_alloc_path();
2497 root = root->fs_info->extent_root; 2502 root = root->fs_info->extent_root;
2498 path->reada = 2; 2503 path->reada = 2;
2499 2504
2500again: 2505again:
2506 trans = btrfs_start_transaction(root, 1);
2507 do_chunk_alloc(trans, root->fs_info->extent_root,
2508 btrfs_block_group_used(&shrink_block_group->item) +
2509 2 * 1024 * 1024, shrink_block_group->flags);
2510 btrfs_end_transaction(trans, root);
2511 shrink_block_group->ro = 1;
2512
2501 total_found = 0; 2513 total_found = 0;
2502 key.objectid = new_size; 2514 key.objectid = shrink_start;
2503 key.offset = 0; 2515 key.offset = 0;
2504 key.type = 0; 2516 key.type = 0;
2505 cur_byte = key.objectid; 2517 cur_byte = key.objectid;
@@ -2511,10 +2523,12 @@ again:
2511 ret = btrfs_previous_item(root, path, 0, BTRFS_EXTENT_ITEM_KEY); 2523 ret = btrfs_previous_item(root, path, 0, BTRFS_EXTENT_ITEM_KEY);
2512 if (ret < 0) 2524 if (ret < 0)
2513 goto out; 2525 goto out;
2526
2514 if (ret == 0) { 2527 if (ret == 0) {
2515 leaf = path->nodes[0]; 2528 leaf = path->nodes[0];
2516 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 2529 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
2517 if (found_key.objectid + found_key.offset > new_size) { 2530 if (found_key.objectid + found_key.offset > shrink_start &&
2531 found_key.objectid < shrink_last_byte) {
2518 cur_byte = found_key.objectid; 2532 cur_byte = found_key.objectid;
2519 key.objectid = cur_byte; 2533 key.objectid = cur_byte;
2520 } 2534 }
@@ -2543,6 +2557,9 @@ next:
2543 2557
2544 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 2558 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
2545 2559
2560 if (found_key.objectid >= shrink_last_byte)
2561 break;
2562
2546 if (progress && need_resched()) { 2563 if (progress && need_resched()) {
2547 memcpy(&key, &found_key, sizeof(key)); 2564 memcpy(&key, &found_key, sizeof(key));
2548 mutex_unlock(&root->fs_info->fs_mutex); 2565 mutex_unlock(&root->fs_info->fs_mutex);
@@ -2583,68 +2600,31 @@ next:
2583 goto again; 2600 goto again;
2584 } 2601 }
2585 2602
2603 /*
2604 * we've freed all the extents, now remove the block
2605 * group item from the tree
2606 */
2586 trans = btrfs_start_transaction(root, 1); 2607 trans = btrfs_start_transaction(root, 1);
2587 key.objectid = new_size; 2608 memcpy(&key, &shrink_block_group->key, sizeof(key));
2588 key.offset = 0;
2589 key.type = 0;
2590 while(1) {
2591 u64 ptr;
2592
2593 ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
2594 if (ret < 0)
2595 goto out;
2596
2597 leaf = path->nodes[0];
2598 nritems = btrfs_header_nritems(leaf);
2599bg_next:
2600 if (path->slots[0] >= nritems) {
2601 ret = btrfs_next_leaf(root, path);
2602 if (ret < 0)
2603 break;
2604 if (ret == 1) {
2605 ret = 0;
2606 break;
2607 }
2608 leaf = path->nodes[0];
2609 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
2610 2609
2611 /* 2610 ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
2612 * btrfs_next_leaf doesn't cow buffers, we have to 2611 if (ret > 0)
2613 * do the search again 2612 ret = -EIO;
2614 */ 2613 if (ret < 0)
2615 memcpy(&key, &found_key, sizeof(key)); 2614 goto out;
2616 btrfs_release_path(root, path);
2617 goto resched_check;
2618 }
2619 2615
2620 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 2616 leaf = path->nodes[0];
2621 if (btrfs_key_type(&found_key) != BTRFS_BLOCK_GROUP_ITEM_KEY) { 2617 nritems = btrfs_header_nritems(leaf);
2622 printk("shrinker found key %Lu %u %Lu\n", 2618 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
2623 found_key.objectid, found_key.type, 2619 kfree(shrink_block_group);
2624 found_key.offset);
2625 path->slots[0]++;
2626 goto bg_next;
2627 }
2628 ret = get_state_private(&info->block_group_cache,
2629 found_key.objectid, &ptr);
2630 if (!ret)
2631 kfree((void *)(unsigned long)ptr);
2632 2620
2633 clear_extent_bits(&info->block_group_cache, found_key.objectid, 2621 clear_extent_bits(&info->block_group_cache, found_key.objectid,
2634 found_key.objectid + found_key.offset - 1, 2622 found_key.objectid + found_key.offset - 1,
2635 (unsigned int)-1, GFP_NOFS); 2623 (unsigned int)-1, GFP_NOFS);
2636 2624
2637 key.objectid = found_key.objectid + 1; 2625 btrfs_del_item(trans, root, path);
2638 btrfs_del_item(trans, root, path); 2626 clear_extent_dirty(&info->free_space_cache,
2639 btrfs_release_path(root, path); 2627 shrink_start, shrink_last_byte - 1,
2640resched_check:
2641 if (need_resched()) {
2642 mutex_unlock(&root->fs_info->fs_mutex);
2643 cond_resched();
2644 mutex_lock(&root->fs_info->fs_mutex);
2645 }
2646 }
2647 clear_extent_dirty(&info->free_space_cache, new_size, (u64)-1,
2648 GFP_NOFS); 2628 GFP_NOFS);
2649 btrfs_commit_transaction(trans, root); 2629 btrfs_commit_transaction(trans, root);
2650out: 2630out:
@@ -2652,13 +2632,6 @@ out:
2652 return ret; 2632 return ret;
2653} 2633}
2654 2634
2655int btrfs_grow_extent_tree(struct btrfs_trans_handle *trans,
2656 struct btrfs_root *root, u64 new_size)
2657{
2658 btrfs_set_super_total_bytes(&root->fs_info->super_copy, new_size);
2659 return 0;
2660}
2661
2662int find_first_block_group(struct btrfs_root *root, struct btrfs_path *path, 2635int find_first_block_group(struct btrfs_root *root, struct btrfs_path *path,
2663 struct btrfs_key *key) 2636 struct btrfs_key *key)
2664{ 2637{
@@ -2726,7 +2699,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
2726 2699
2727 leaf = path->nodes[0]; 2700 leaf = path->nodes[0];
2728 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 2701 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
2729 cache = kmalloc(sizeof(*cache), GFP_NOFS); 2702 cache = kzalloc(sizeof(*cache), GFP_NOFS);
2730 if (!cache) { 2703 if (!cache) {
2731 ret = -ENOMEM; 2704 ret = -ENOMEM;
2732 break; 2705 break;
@@ -2736,8 +2709,6 @@ int btrfs_read_block_groups(struct btrfs_root *root)
2736 btrfs_item_ptr_offset(leaf, path->slots[0]), 2709 btrfs_item_ptr_offset(leaf, path->slots[0]),
2737 sizeof(cache->item)); 2710 sizeof(cache->item));
2738 memcpy(&cache->key, &found_key, sizeof(found_key)); 2711 memcpy(&cache->key, &found_key, sizeof(found_key));
2739 cache->cached = 0;
2740 cache->pinned = 0;
2741 2712
2742 key.objectid = found_key.objectid + found_key.offset; 2713 key.objectid = found_key.objectid + found_key.offset;
2743 btrfs_release_path(root, path); 2714 btrfs_release_path(root, path);
@@ -2789,12 +2760,10 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
2789 extent_root = root->fs_info->extent_root; 2760 extent_root = root->fs_info->extent_root;
2790 block_group_cache = &root->fs_info->block_group_cache; 2761 block_group_cache = &root->fs_info->block_group_cache;
2791 2762
2792 cache = kmalloc(sizeof(*cache), GFP_NOFS); 2763 cache = kzalloc(sizeof(*cache), GFP_NOFS);
2793 BUG_ON(!cache); 2764 BUG_ON(!cache);
2794 cache->key.objectid = chunk_offset; 2765 cache->key.objectid = chunk_offset;
2795 cache->key.offset = size; 2766 cache->key.offset = size;
2796 cache->cached = 0;
2797 cache->pinned = 0;
2798 2767
2799 btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY); 2768 btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY);
2800 memset(&cache->item, 0, sizeof(cache->item)); 2769 memset(&cache->item, 0, sizeof(cache->item));
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index b31f52d4f2ca..4d12aa532c5b 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -16,6 +16,7 @@
16 * Boston, MA 021110-1307, USA. 16 * Boston, MA 021110-1307, USA.
17 */ 17 */
18 18
19#include <linux/kernel.h>
19#include <linux/bio.h> 20#include <linux/bio.h>
20#include <linux/buffer_head.h> 21#include <linux/buffer_head.h>
21#include <linux/fs.h> 22#include <linux/fs.h>
@@ -2887,9 +2888,12 @@ static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg)
2887{ 2888{
2888 u64 new_size; 2889 u64 new_size;
2889 u64 old_size; 2890 u64 old_size;
2891 u64 devid = 1;
2890 struct btrfs_ioctl_vol_args *vol_args; 2892 struct btrfs_ioctl_vol_args *vol_args;
2891 struct btrfs_trans_handle *trans; 2893 struct btrfs_trans_handle *trans;
2894 struct btrfs_device *device = NULL;
2892 char *sizestr; 2895 char *sizestr;
2896 char *devstr = NULL;
2893 int ret = 0; 2897 int ret = 0;
2894 int namelen; 2898 int namelen;
2895 int mod = 0; 2899 int mod = 0;
@@ -2909,9 +2913,25 @@ static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg)
2909 goto out; 2913 goto out;
2910 } 2914 }
2911 2915
2916 mutex_lock(&root->fs_info->fs_mutex);
2912 sizestr = vol_args->name; 2917 sizestr = vol_args->name;
2918 devstr = strchr(sizestr, ':');
2919 if (devstr) {
2920 char *end;
2921 sizestr = devstr + 1;
2922 *devstr = '\0';
2923 devstr = vol_args->name;
2924 devid = simple_strtoull(devstr, &end, 10);
2925printk("resizing devid %Lu\n", devid);
2926 }
2927 device = btrfs_find_device(root, devid, NULL);
2928 if (!device) {
2929 printk("resizer unable to find device %Lu\n", devid);
2930 ret = -EINVAL;
2931 goto out_unlock;
2932 }
2913 if (!strcmp(sizestr, "max")) 2933 if (!strcmp(sizestr, "max"))
2914 new_size = root->fs_info->sb->s_bdev->bd_inode->i_size; 2934 new_size = device->bdev->bd_inode->i_size;
2915 else { 2935 else {
2916 if (sizestr[0] == '-') { 2936 if (sizestr[0] == '-') {
2917 mod = -1; 2937 mod = -1;
@@ -2923,12 +2943,11 @@ static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg)
2923 new_size = btrfs_parse_size(sizestr); 2943 new_size = btrfs_parse_size(sizestr);
2924 if (new_size == 0) { 2944 if (new_size == 0) {
2925 ret = -EINVAL; 2945 ret = -EINVAL;
2926 goto out; 2946 goto out_unlock;
2927 } 2947 }
2928 } 2948 }
2929 2949
2930 mutex_lock(&root->fs_info->fs_mutex); 2950 old_size = device->total_bytes;
2931 old_size = btrfs_super_total_bytes(&root->fs_info->super_copy);
2932 2951
2933 if (mod < 0) { 2952 if (mod < 0) {
2934 if (new_size > old_size) { 2953 if (new_size > old_size) {
@@ -2944,7 +2963,7 @@ static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg)
2944 ret = -EINVAL; 2963 ret = -EINVAL;
2945 goto out_unlock; 2964 goto out_unlock;
2946 } 2965 }
2947 if (new_size > root->fs_info->sb->s_bdev->bd_inode->i_size) { 2966 if (new_size > device->bdev->bd_inode->i_size) {
2948 ret = -EFBIG; 2967 ret = -EFBIG;
2949 goto out_unlock; 2968 goto out_unlock;
2950 } 2969 }
@@ -2952,13 +2971,14 @@ static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg)
2952 do_div(new_size, root->sectorsize); 2971 do_div(new_size, root->sectorsize);
2953 new_size *= root->sectorsize; 2972 new_size *= root->sectorsize;
2954 2973
2955printk("new size is %Lu\n", new_size); 2974printk("new size for %s is %llu\n", device->name, (unsigned long long)new_size);
2975
2956 if (new_size > old_size) { 2976 if (new_size > old_size) {
2957 trans = btrfs_start_transaction(root, 1); 2977 trans = btrfs_start_transaction(root, 1);
2958 ret = btrfs_grow_extent_tree(trans, root, new_size); 2978 ret = btrfs_grow_device(trans, device, new_size);
2959 btrfs_commit_transaction(trans, root); 2979 btrfs_commit_transaction(trans, root);
2960 } else { 2980 } else {
2961 ret = btrfs_shrink_extent_tree(root, new_size); 2981 ret = btrfs_shrink_device(device, new_size);
2962 } 2982 }
2963 2983
2964out_unlock: 2984out_unlock:
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index c63a982e31d0..a2c56de1548a 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -77,7 +77,7 @@ static struct btrfs_device *__find_device(struct list_head *head, u64 devid,
77 list_for_each(cur, head) { 77 list_for_each(cur, head) {
78 dev = list_entry(cur, struct btrfs_device, dev_list); 78 dev = list_entry(cur, struct btrfs_device, dev_list);
79 if (dev->devid == devid && 79 if (dev->devid == devid &&
80 !memcmp(dev->uuid, uuid, BTRFS_UUID_SIZE)) { 80 (!uuid || !memcmp(dev->uuid, uuid, BTRFS_UUID_SIZE))) {
81 return dev; 81 return dev;
82 } 82 }
83 } 83 }
@@ -293,6 +293,10 @@ static int find_free_dev_extent(struct btrfs_trans_handle *trans,
293 * so we make sure to start at an offset of at least 1MB 293 * so we make sure to start at an offset of at least 1MB
294 */ 294 */
295 search_start = max((u64)1024 * 1024, search_start); 295 search_start = max((u64)1024 * 1024, search_start);
296
297 if (root->fs_info->alloc_start + num_bytes <= device->total_bytes)
298 search_start = max(root->fs_info->alloc_start, search_start);
299
296 key.objectid = device->devid; 300 key.objectid = device->devid;
297 key.offset = search_start; 301 key.offset = search_start;
298 key.type = BTRFS_DEV_EXTENT_KEY; 302 key.type = BTRFS_DEV_EXTENT_KEY;
@@ -380,6 +384,33 @@ error:
380 return ret; 384 return ret;
381} 385}
382 386
387int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
388 struct btrfs_device *device,
389 u64 start)
390{
391 int ret;
392 struct btrfs_path *path;
393 struct btrfs_root *root = device->dev_root;
394 struct btrfs_key key;
395
396 path = btrfs_alloc_path();
397 if (!path)
398 return -ENOMEM;
399
400 key.objectid = device->devid;
401 key.offset = start;
402 key.type = BTRFS_DEV_EXTENT_KEY;
403
404 ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
405 BUG_ON(ret);
406
407 ret = btrfs_del_item(trans, root, path);
408 BUG_ON(ret);
409
410 btrfs_free_path(path);
411 return ret;
412}
413
383int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, 414int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
384 struct btrfs_device *device, 415 struct btrfs_device *device,
385 u64 chunk_tree, u64 chunk_objectid, 416 u64 chunk_tree, u64 chunk_objectid,
@@ -560,6 +591,7 @@ out:
560 btrfs_free_path(path); 591 btrfs_free_path(path);
561 return ret; 592 return ret;
562} 593}
594
563int btrfs_update_device(struct btrfs_trans_handle *trans, 595int btrfs_update_device(struct btrfs_trans_handle *trans,
564 struct btrfs_device *device) 596 struct btrfs_device *device)
565{ 597{
@@ -606,6 +638,254 @@ out:
606 return ret; 638 return ret;
607} 639}
608 640
641int btrfs_grow_device(struct btrfs_trans_handle *trans,
642 struct btrfs_device *device, u64 new_size)
643{
644 struct btrfs_super_block *super_copy =
645 &device->dev_root->fs_info->super_copy;
646 u64 old_total = btrfs_super_total_bytes(super_copy);
647 u64 diff = new_size - device->total_bytes;
648
649 btrfs_set_super_total_bytes(super_copy, old_total + diff);
650 return btrfs_update_device(trans, device);
651}
652
653static int btrfs_free_chunk(struct btrfs_trans_handle *trans,
654 struct btrfs_root *root,
655 u64 chunk_tree, u64 chunk_objectid,
656 u64 chunk_offset)
657{
658 int ret;
659 struct btrfs_path *path;
660 struct btrfs_key key;
661
662 root = root->fs_info->chunk_root;
663 path = btrfs_alloc_path();
664 if (!path)
665 return -ENOMEM;
666
667 key.objectid = chunk_objectid;
668 key.offset = chunk_offset;
669 key.type = BTRFS_CHUNK_ITEM_KEY;
670
671 ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
672 BUG_ON(ret);
673
674 ret = btrfs_del_item(trans, root, path);
675 BUG_ON(ret);
676
677 btrfs_free_path(path);
678 return 0;
679}
680
681int btrfs_del_sys_chunk(struct btrfs_root *root, u64 chunk_objectid, u64
682 chunk_offset)
683{
684 struct btrfs_super_block *super_copy = &root->fs_info->super_copy;
685 struct btrfs_disk_key *disk_key;
686 struct btrfs_chunk *chunk;
687 u8 *ptr;
688 int ret = 0;
689 u32 num_stripes;
690 u32 array_size;
691 u32 len = 0;
692 u32 cur;
693 struct btrfs_key key;
694
695 array_size = btrfs_super_sys_array_size(super_copy);
696
697 ptr = super_copy->sys_chunk_array;
698 cur = 0;
699
700 while (cur < array_size) {
701 disk_key = (struct btrfs_disk_key *)ptr;
702 btrfs_disk_key_to_cpu(&key, disk_key);
703
704 len = sizeof(*disk_key);
705
706 if (key.type == BTRFS_CHUNK_ITEM_KEY) {
707 chunk = (struct btrfs_chunk *)(ptr + len);
708 num_stripes = btrfs_stack_chunk_num_stripes(chunk);
709 len += btrfs_chunk_item_size(num_stripes);
710 } else {
711 ret = -EIO;
712 break;
713 }
714 if (key.objectid == chunk_objectid &&
715 key.offset == chunk_offset) {
716 memmove(ptr, ptr + len, array_size - (cur + len));
717 array_size -= len;
718 btrfs_set_super_sys_array_size(super_copy, array_size);
719 } else {
720 ptr += len;
721 cur += len;
722 }
723 }
724 return ret;
725}
726
727
728int btrfs_relocate_chunk(struct btrfs_root *root,
729 u64 chunk_tree, u64 chunk_objectid,
730 u64 chunk_offset)
731{
732 struct extent_map_tree *em_tree;
733 struct btrfs_root *extent_root;
734 struct btrfs_trans_handle *trans;
735 struct extent_map *em;
736 struct map_lookup *map;
737 int ret;
738 int i;
739
740 root = root->fs_info->chunk_root;
741 extent_root = root->fs_info->extent_root;
742 em_tree = &root->fs_info->mapping_tree.map_tree;
743
744 /* step one, relocate all the extents inside this chunk */
745 ret = btrfs_shrink_extent_tree(extent_root, chunk_offset);
746 BUG_ON(ret);
747
748 trans = btrfs_start_transaction(root, 1);
749 BUG_ON(!trans);
750
751 /*
752 * step two, delete the device extents and the
753 * chunk tree entries
754 */
755 spin_lock(&em_tree->lock);
756 em = lookup_extent_mapping(em_tree, chunk_offset, 1);
757 spin_unlock(&em_tree->lock);
758
759 BUG_ON(em->start > chunk_offset || em->start + em->len < chunk_offset);
760 map = (struct map_lookup *)em->bdev;
761
762 for (i = 0; i < map->num_stripes; i++) {
763 ret = btrfs_free_dev_extent(trans, map->stripes[i].dev,
764 map->stripes[i].physical);
765 BUG_ON(ret);
766 }
767 ret = btrfs_free_chunk(trans, root, chunk_tree, chunk_objectid,
768 chunk_offset);
769
770 BUG_ON(ret);
771
772 if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) {
773 ret = btrfs_del_sys_chunk(root, chunk_objectid, chunk_offset);
774 BUG_ON(ret);
775 goto out;
776 }
777
778
779
780 spin_lock(&em_tree->lock);
781 remove_extent_mapping(em_tree, em);
782 kfree(map);
783 em->bdev = NULL;
784
785 /* once for the tree */
786 free_extent_map(em);
787 spin_unlock(&em_tree->lock);
788
789out:
790 /* once for us */
791 free_extent_map(em);
792
793 btrfs_end_transaction(trans, root);
794 return 0;
795}
796
797/*
798 * shrinking a device means finding all of the device extents past
799 * the new size, and then following the back refs to the chunks.
800 * The chunk relocation code actually frees the device extent
801 */
802int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
803{
804 struct btrfs_trans_handle *trans;
805 struct btrfs_root *root = device->dev_root;
806 struct btrfs_dev_extent *dev_extent = NULL;
807 struct btrfs_path *path;
808 u64 length;
809 u64 chunk_tree;
810 u64 chunk_objectid;
811 u64 chunk_offset;
812 int ret;
813 int slot;
814 struct extent_buffer *l;
815 struct btrfs_key key;
816 struct btrfs_super_block *super_copy = &root->fs_info->super_copy;
817 u64 old_total = btrfs_super_total_bytes(super_copy);
818 u64 diff = device->total_bytes - new_size;
819
820
821 path = btrfs_alloc_path();
822 if (!path)
823 return -ENOMEM;
824
825 trans = btrfs_start_transaction(root, 1);
826 if (!trans) {
827 ret = -ENOMEM;
828 goto done;
829 }
830
831 path->reada = 2;
832
833 device->total_bytes = new_size;
834 ret = btrfs_update_device(trans, device);
835 if (ret) {
836 btrfs_end_transaction(trans, root);
837 goto done;
838 }
839 WARN_ON(diff > old_total);
840 btrfs_set_super_total_bytes(super_copy, old_total - diff);
841 btrfs_end_transaction(trans, root);
842
843 key.objectid = device->devid;
844 key.offset = (u64)-1;
845 key.type = BTRFS_DEV_EXTENT_KEY;
846
847 while (1) {
848 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
849 if (ret < 0)
850 goto done;
851
852 ret = btrfs_previous_item(root, path, 0, key.type);
853 if (ret < 0)
854 goto done;
855 if (ret) {
856 ret = 0;
857 goto done;
858 }
859
860 l = path->nodes[0];
861 slot = path->slots[0];
862 btrfs_item_key_to_cpu(l, &key, path->slots[0]);
863
864 if (key.objectid != device->devid)
865 goto done;
866
867 dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
868 length = btrfs_dev_extent_length(l, dev_extent);
869
870 if (key.offset + length <= new_size)
871 goto done;
872
873 chunk_tree = btrfs_dev_extent_chunk_tree(l, dev_extent);
874 chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent);
875 chunk_offset = btrfs_dev_extent_chunk_offset(l, dev_extent);
876 btrfs_release_path(root, path);
877
878 ret = btrfs_relocate_chunk(root, chunk_tree, chunk_objectid,
879 chunk_offset);
880 if (ret)
881 goto done;
882 }
883
884done:
885 btrfs_free_path(path);
886 return ret;
887}
888
609int btrfs_add_system_chunk(struct btrfs_trans_handle *trans, 889int btrfs_add_system_chunk(struct btrfs_trans_handle *trans,
610 struct btrfs_root *root, 890 struct btrfs_root *root,
611 struct btrfs_key *key, 891 struct btrfs_key *key,
@@ -658,6 +938,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
658 u64 dev_offset; 938 u64 dev_offset;
659 struct btrfs_fs_info *info = extent_root->fs_info; 939 struct btrfs_fs_info *info = extent_root->fs_info;
660 struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root; 940 struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root;
941 struct btrfs_path *path;
661 struct btrfs_stripe *stripes; 942 struct btrfs_stripe *stripes;
662 struct btrfs_device *device = NULL; 943 struct btrfs_device *device = NULL;
663 struct btrfs_chunk *chunk; 944 struct btrfs_chunk *chunk;
@@ -724,6 +1005,10 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
724 min_stripe_size = 1 * 1024 * 1024; 1005 min_stripe_size = 1 * 1024 * 1024;
725 } 1006 }
726 1007
1008 path = btrfs_alloc_path();
1009 if (!path)
1010 return -ENOMEM;
1011
727 /* we don't want a chunk larger than 10% of the FS */ 1012 /* we don't want a chunk larger than 10% of the FS */
728 percent_max = div_factor(btrfs_super_total_bytes(&info->super_copy), 1); 1013 percent_max = div_factor(btrfs_super_total_bytes(&info->super_copy), 1);
729 max_chunk_size = min(percent_max, max_chunk_size); 1014 max_chunk_size = min(percent_max, max_chunk_size);
@@ -759,11 +1044,19 @@ again:
759 1044
760 avail = device->total_bytes - device->bytes_used; 1045 avail = device->total_bytes - device->bytes_used;
761 cur = cur->next; 1046 cur = cur->next;
1047
762 if (avail >= min_free) { 1048 if (avail >= min_free) {
763 list_move_tail(&device->dev_alloc_list, &private_devs); 1049 u64 ignored_start = 0;
764 index++; 1050 ret = find_free_dev_extent(trans, device, path,
765 if (type & BTRFS_BLOCK_GROUP_DUP) 1051 min_free,
1052 &ignored_start);
1053 if (ret == 0) {
1054 list_move_tail(&device->dev_alloc_list,
1055 &private_devs);
766 index++; 1056 index++;
1057 if (type & BTRFS_BLOCK_GROUP_DUP)
1058 index++;
1059 }
767 } else if (avail > max_avail) 1060 } else if (avail > max_avail)
768 max_avail = avail; 1061 max_avail = avail;
769 if (cur == dev_list) 1062 if (cur == dev_list)
@@ -785,30 +1078,37 @@ again:
785 calc_size = max_avail; 1078 calc_size = max_avail;
786 goto again; 1079 goto again;
787 } 1080 }
1081 btrfs_free_path(path);
788 return -ENOSPC; 1082 return -ENOSPC;
789 } 1083 }
790 key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; 1084 key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
791 key.type = BTRFS_CHUNK_ITEM_KEY; 1085 key.type = BTRFS_CHUNK_ITEM_KEY;
792 ret = find_next_chunk(chunk_root, BTRFS_FIRST_CHUNK_TREE_OBJECTID, 1086 ret = find_next_chunk(chunk_root, BTRFS_FIRST_CHUNK_TREE_OBJECTID,
793 &key.offset); 1087 &key.offset);
794 if (ret) 1088 if (ret) {
1089 btrfs_free_path(path);
795 return ret; 1090 return ret;
1091 }
796 1092
797 chunk = kmalloc(btrfs_chunk_item_size(num_stripes), GFP_NOFS); 1093 chunk = kmalloc(btrfs_chunk_item_size(num_stripes), GFP_NOFS);
798 if (!chunk) 1094 if (!chunk) {
1095 btrfs_free_path(path);
799 return -ENOMEM; 1096 return -ENOMEM;
1097 }
800 1098
801 map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS); 1099 map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
802 if (!map) { 1100 if (!map) {
803 kfree(chunk); 1101 kfree(chunk);
1102 btrfs_free_path(path);
804 return -ENOMEM; 1103 return -ENOMEM;
805 } 1104 }
1105 btrfs_free_path(path);
1106 path = NULL;
806 1107
807 stripes = &chunk->stripe; 1108 stripes = &chunk->stripe;
808 *num_bytes = chunk_bytes_by_type(type, calc_size, 1109 *num_bytes = chunk_bytes_by_type(type, calc_size,
809 num_stripes, sub_stripes); 1110 num_stripes, sub_stripes);
810 1111
811
812 index = 0; 1112 index = 0;
813printk("new chunk type %Lu start %Lu size %Lu\n", type, key.offset, *num_bytes); 1113printk("new chunk type %Lu start %Lu size %Lu\n", type, key.offset, *num_bytes);
814 while(index < num_stripes) { 1114 while(index < num_stripes) {
@@ -874,6 +1174,11 @@ printk("alloc chunk start %Lu size %Lu from dev %Lu type %Lu\n", key.offset, cal
874 em->len = *num_bytes; 1174 em->len = *num_bytes;
875 em->block_start = 0; 1175 em->block_start = 0;
876 1176
1177 if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
1178 ret = btrfs_add_system_chunk(trans, chunk_root, &key,
1179 chunk, btrfs_chunk_item_size(num_stripes));
1180 BUG_ON(ret);
1181 }
877 kfree(chunk); 1182 kfree(chunk);
878 1183
879 em_tree = &extent_root->fs_info->mapping_tree.map_tree; 1184 em_tree = &extent_root->fs_info->mapping_tree.map_tree;
@@ -1376,11 +1681,6 @@ int btrfs_read_sys_array(struct btrfs_root *root)
1376 1681
1377 array_size = btrfs_super_sys_array_size(super_copy); 1682 array_size = btrfs_super_sys_array_size(super_copy);
1378 1683
1379 /*
1380 * we do this loop twice, once for the device items and
1381 * once for all of the chunks. This way there are device
1382 * structs filled in for every chunk
1383 */
1384 ptr = super_copy->sys_chunk_array; 1684 ptr = super_copy->sys_chunk_array;
1385 sb_ptr = offsetof(struct btrfs_super_block, sys_chunk_array); 1685 sb_ptr = offsetof(struct btrfs_super_block, sys_chunk_array);
1386 cur = 0; 1686 cur = 0;
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index a2660d2b6b34..6fe8440b37a7 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -128,4 +128,9 @@ int btrfs_cleanup_fs_uuids(void);
128int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len); 128int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len);
129int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree, 129int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree,
130 u64 logical, struct page *page); 130 u64 logical, struct page *page);
131int btrfs_grow_device(struct btrfs_trans_handle *trans,
132 struct btrfs_device *device, u64 new_size);
133struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid,
134 u8 *uuid);
135int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
131#endif 136#endif