diff options
| author | Chris Mason <chris.mason@oracle.com> | 2008-04-25 16:53:30 -0400 |
|---|---|---|
| committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:02 -0400 |
| commit | 8f18cf13396caae5a3d7ae91201cfb15181a9642 (patch) | |
| tree | ff4bfc2e7f45f10d176b969408cdb469ae3f7194 | |
| parent | 5e478dc9828ad33d7b08dcdf277e13f14a7c1be7 (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.h | 1 | ||||
| -rw-r--r-- | fs/btrfs/disk-io.c | 4 | ||||
| -rw-r--r-- | fs/btrfs/extent-tree.c | 145 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 36 | ||||
| -rw-r--r-- | fs/btrfs/volumes.c | 324 | ||||
| -rw-r--r-- | fs/btrfs/volumes.h | 5 |
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 | ||
| 479 | struct btrfs_device; | 480 | struct 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 | } |
| 1726 | again: | 1729 | again: |
| 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 | ||
| 2476 | int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size) | 2475 | int 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; | ||
| 2500 | printk("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 | ||
| 2500 | again: | 2505 | again: |
| 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); | ||
| 2599 | bg_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, |
| 2640 | resched_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); |
| 2650 | out: | 2630 | out: |
| @@ -2652,13 +2632,6 @@ out: | |||
| 2652 | return ret; | 2632 | return ret; |
| 2653 | } | 2633 | } |
| 2654 | 2634 | ||
| 2655 | int 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 | |||
| 2662 | int find_first_block_group(struct btrfs_root *root, struct btrfs_path *path, | 2635 | int 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); | ||
| 2925 | printk("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 | ||
| 2955 | printk("new size is %Lu\n", new_size); | 2974 | printk("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 | ||
| 2964 | out_unlock: | 2984 | out_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 | ||
| 387 | int 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 | |||
| 383 | int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, | 414 | int 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 | |||
| 563 | int btrfs_update_device(struct btrfs_trans_handle *trans, | 595 | int 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 | ||
| 641 | int 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 | |||
| 653 | static 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 | |||
| 681 | int 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 | |||
| 728 | int 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 | |||
| 789 | out: | ||
| 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 | */ | ||
| 802 | int 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 | |||
| 884 | done: | ||
| 885 | btrfs_free_path(path); | ||
| 886 | return ret; | ||
| 887 | } | ||
| 888 | |||
| 609 | int btrfs_add_system_chunk(struct btrfs_trans_handle *trans, | 889 | int 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; |
| 813 | printk("new chunk type %Lu start %Lu size %Lu\n", type, key.offset, *num_bytes); | 1113 | printk("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); | |||
| 128 | int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len); | 128 | int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len); |
| 129 | int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree, | 129 | int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree, |
| 130 | u64 logical, struct page *page); | 130 | u64 logical, struct page *page); |
| 131 | int btrfs_grow_device(struct btrfs_trans_handle *trans, | ||
| 132 | struct btrfs_device *device, u64 new_size); | ||
| 133 | struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid, | ||
| 134 | u8 *uuid); | ||
| 135 | int btrfs_shrink_device(struct btrfs_device *device, u64 new_size); | ||
| 131 | #endif | 136 | #endif |
