aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fb.com>2014-09-18 11:20:02 -0400
committerChris Mason <clm@fb.com>2014-09-22 20:13:21 -0400
commit47ab2a6c689913db23ccae38349714edf8365e0a (patch)
tree5d1001d192e6ccd0159d59e31d705b38e17c09ef /fs/btrfs/volumes.c
parent8407f553268a4611f2542ed90677f0edfaa2c9c4 (diff)
Btrfs: remove empty block groups automatically
One problem that has plagued us is that a user will use up all of his space with data, remove a bunch of that data, and then try to create a bunch of small files and run out of space. This happens because all the chunks were allocated for data since the metadata requirements were so low. But now there's a bunch of empty data block groups and not enough metadata space to do anything. This patch solves this problem by automatically deleting empty block groups. If we notice the used count go down to 0 when deleting or on mount notice that a block group has a used count of 0 then we will queue it to be deleted. When the cleaner thread runs we will double check to make sure the block group is still empty and then we will delete it. This patch has the side effect of no longer having a bunch of BUG_ON()'s in the chunk delete code, which will be helpful for both this and relocate. Thanks, Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r--fs/btrfs/volumes.c115
1 files changed, 76 insertions, 39 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 63e632746d8a..f27c0f7c387e 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2568,58 +2568,49 @@ static int btrfs_del_sys_chunk(struct btrfs_root *root, u64 chunk_objectid, u64
2568 return ret; 2568 return ret;
2569} 2569}
2570 2570
2571static int btrfs_relocate_chunk(struct btrfs_root *root, 2571int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
2572 u64 chunk_tree, u64 chunk_objectid, 2572 struct btrfs_root *root, u64 chunk_offset)
2573 u64 chunk_offset)
2574{ 2573{
2575 struct extent_map_tree *em_tree; 2574 struct extent_map_tree *em_tree;
2576 struct btrfs_root *extent_root;
2577 struct btrfs_trans_handle *trans;
2578 struct btrfs_device *device;
2579 struct extent_map *em; 2575 struct extent_map *em;
2576 struct btrfs_root *extent_root = root->fs_info->extent_root;
2580 struct map_lookup *map; 2577 struct map_lookup *map;
2581 u64 dev_extent_len = 0; 2578 u64 dev_extent_len = 0;
2582 int ret; 2579 u64 chunk_objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
2583 int i; 2580 u64 chunk_tree = root->fs_info->chunk_root->objectid;
2581 int i, ret = 0;
2584 2582
2583 /* Just in case */
2585 root = root->fs_info->chunk_root; 2584 root = root->fs_info->chunk_root;
2586 extent_root = root->fs_info->extent_root;
2587 em_tree = &root->fs_info->mapping_tree.map_tree; 2585 em_tree = &root->fs_info->mapping_tree.map_tree;
2588 2586
2589 ret = btrfs_can_relocate(extent_root, chunk_offset);
2590 if (ret)
2591 return -ENOSPC;
2592
2593 /* step one, relocate all the extents inside this chunk */
2594 ret = btrfs_relocate_block_group(extent_root, chunk_offset);
2595 if (ret)
2596 return ret;
2597
2598 trans = btrfs_start_transaction(root, 0);
2599 if (IS_ERR(trans)) {
2600 ret = PTR_ERR(trans);
2601 btrfs_std_error(root->fs_info, ret);
2602 return ret;
2603 }
2604
2605 /*
2606 * step two, delete the device extents and the
2607 * chunk tree entries
2608 */
2609 read_lock(&em_tree->lock); 2587 read_lock(&em_tree->lock);
2610 em = lookup_extent_mapping(em_tree, chunk_offset, 1); 2588 em = lookup_extent_mapping(em_tree, chunk_offset, 1);
2611 read_unlock(&em_tree->lock); 2589 read_unlock(&em_tree->lock);
2612 2590
2613 BUG_ON(!em || em->start > chunk_offset || 2591 if (!em || em->start > chunk_offset ||
2614 em->start + em->len < chunk_offset); 2592 em->start + em->len < chunk_offset) {
2593 /*
2594 * This is a logic error, but we don't want to just rely on the
2595 * user having built with ASSERT enabled, so if ASSERT doens't
2596 * do anything we still error out.
2597 */
2598 ASSERT(0);
2599 if (em)
2600 free_extent_map(em);
2601 return -EINVAL;
2602 }
2615 map = (struct map_lookup *)em->bdev; 2603 map = (struct map_lookup *)em->bdev;
2616 2604
2617 for (i = 0; i < map->num_stripes; i++) { 2605 for (i = 0; i < map->num_stripes; i++) {
2618 device = map->stripes[i].dev; 2606 struct btrfs_device *device = map->stripes[i].dev;
2619 ret = btrfs_free_dev_extent(trans, device, 2607 ret = btrfs_free_dev_extent(trans, device,
2620 map->stripes[i].physical, 2608 map->stripes[i].physical,
2621 &dev_extent_len); 2609 &dev_extent_len);
2622 BUG_ON(ret); 2610 if (ret) {
2611 btrfs_abort_transaction(trans, root, ret);
2612 goto out;
2613 }
2623 2614
2624 if (device->bytes_used > 0) { 2615 if (device->bytes_used > 0) {
2625 lock_chunks(root); 2616 lock_chunks(root);
@@ -2634,23 +2625,34 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
2634 2625
2635 if (map->stripes[i].dev) { 2626 if (map->stripes[i].dev) {
2636 ret = btrfs_update_device(trans, map->stripes[i].dev); 2627 ret = btrfs_update_device(trans, map->stripes[i].dev);
2637 BUG_ON(ret); 2628 if (ret) {
2629 btrfs_abort_transaction(trans, root, ret);
2630 goto out;
2631 }
2638 } 2632 }
2639 } 2633 }
2640 ret = btrfs_free_chunk(trans, root, chunk_tree, chunk_objectid, 2634 ret = btrfs_free_chunk(trans, root, chunk_tree, chunk_objectid,
2641 chunk_offset); 2635 chunk_offset);
2642 2636 if (ret) {
2643 BUG_ON(ret); 2637 btrfs_abort_transaction(trans, root, ret);
2638 goto out;
2639 }
2644 2640
2645 trace_btrfs_chunk_free(root, map, chunk_offset, em->len); 2641 trace_btrfs_chunk_free(root, map, chunk_offset, em->len);
2646 2642
2647 if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) { 2643 if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) {
2648 ret = btrfs_del_sys_chunk(root, chunk_objectid, chunk_offset); 2644 ret = btrfs_del_sys_chunk(root, chunk_objectid, chunk_offset);
2649 BUG_ON(ret); 2645 if (ret) {
2646 btrfs_abort_transaction(trans, root, ret);
2647 goto out;
2648 }
2650 } 2649 }
2651 2650
2652 ret = btrfs_remove_block_group(trans, extent_root, chunk_offset); 2651 ret = btrfs_remove_block_group(trans, extent_root, chunk_offset);
2653 BUG_ON(ret); 2652 if (ret) {
2653 btrfs_abort_transaction(trans, extent_root, ret);
2654 goto out;
2655 }
2654 2656
2655 write_lock(&em_tree->lock); 2657 write_lock(&em_tree->lock);
2656 remove_extent_mapping(em_tree, em); 2658 remove_extent_mapping(em_tree, em);
@@ -2658,11 +2660,46 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
2658 2660
2659 /* once for the tree */ 2661 /* once for the tree */
2660 free_extent_map(em); 2662 free_extent_map(em);
2663out:
2661 /* once for us */ 2664 /* once for us */
2662 free_extent_map(em); 2665 free_extent_map(em);
2666 return ret;
2667}
2668
2669static int btrfs_relocate_chunk(struct btrfs_root *root,
2670 u64 chunk_tree, u64 chunk_objectid,
2671 u64 chunk_offset)
2672{
2673 struct btrfs_root *extent_root;
2674 struct btrfs_trans_handle *trans;
2675 int ret;
2676
2677 root = root->fs_info->chunk_root;
2678 extent_root = root->fs_info->extent_root;
2679
2680 ret = btrfs_can_relocate(extent_root, chunk_offset);
2681 if (ret)
2682 return -ENOSPC;
2683
2684 /* step one, relocate all the extents inside this chunk */
2685 ret = btrfs_relocate_block_group(extent_root, chunk_offset);
2686 if (ret)
2687 return ret;
2663 2688
2689 trans = btrfs_start_transaction(root, 0);
2690 if (IS_ERR(trans)) {
2691 ret = PTR_ERR(trans);
2692 btrfs_std_error(root->fs_info, ret);
2693 return ret;
2694 }
2695
2696 /*
2697 * step two, delete the device extents and the
2698 * chunk tree entries
2699 */
2700 ret = btrfs_remove_chunk(trans, root, chunk_offset);
2664 btrfs_end_transaction(trans, root); 2701 btrfs_end_transaction(trans, root);
2665 return 0; 2702 return ret;
2666} 2703}
2667 2704
2668static int btrfs_relocate_sys_chunks(struct btrfs_root *root) 2705static int btrfs_relocate_sys_chunks(struct btrfs_root *root)