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 /fs/btrfs/extent-tree.c | |
parent | 5e478dc9828ad33d7b08dcdf277e13f14a7c1be7 (diff) |
Btrfs: Make the resizer work based on shrinking and growing devices
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 145 |
1 files changed, 57 insertions, 88 deletions
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)); |