diff options
Diffstat (limited to 'fs/btrfs/discard.c')
| -rw-r--r-- | fs/btrfs/discard.c | 52 |
1 files changed, 45 insertions, 7 deletions
diff --git a/fs/btrfs/discard.c b/fs/btrfs/discard.c index ee5f5b2788e1..1c304bf473e5 100644 --- a/fs/btrfs/discard.c +++ b/fs/btrfs/discard.c @@ -216,6 +216,25 @@ static struct btrfs_block_group *find_next_block_group( } /* + * Check whether a block group is empty. + * + * "Empty" here means that there are no extents physically located within the + * device extents corresponding to this block group. + * + * For a remapped block group, this means that all of its identity remaps have + * been removed. For a non-remapped block group, this means that no extents + * have an address within its range, and that nothing has been remapped to be + * within it. + */ +static bool block_group_is_empty(const struct btrfs_block_group *bg) +{ + if (bg->flags & BTRFS_BLOCK_GROUP_REMAPPED) + return bg->identity_remap_count == 0; + + return bg->used == 0 && bg->remap_bytes == 0; +} + +/* * Look up next block group and set it for use. * * @discard_ctl: discard control @@ -241,8 +260,10 @@ again: block_group = find_next_block_group(discard_ctl, now); if (block_group && now >= block_group->discard_eligible_time) { + const bool empty = block_group_is_empty(block_group); + if (block_group->discard_index == BTRFS_DISCARD_INDEX_UNUSED && - block_group->used != 0) { + !empty) { if (btrfs_is_block_group_data_only(block_group)) { __add_to_discard_list(discard_ctl, block_group); /* @@ -267,7 +288,12 @@ again: } if (block_group->discard_state == BTRFS_DISCARD_RESET_CURSOR) { block_group->discard_cursor = block_group->start; - block_group->discard_state = BTRFS_DISCARD_EXTENTS; + + if (block_group->flags & BTRFS_BLOCK_GROUP_REMAPPED && empty) { + block_group->discard_state = BTRFS_DISCARD_FULLY_REMAPPED; + } else { + block_group->discard_state = BTRFS_DISCARD_EXTENTS; + } } } if (block_group) { @@ -373,7 +399,7 @@ void btrfs_discard_queue_work(struct btrfs_discard_ctl *discard_ctl, if (!block_group || !btrfs_test_opt(block_group->fs_info, DISCARD_ASYNC)) return; - if (block_group->used == 0 && block_group->remap_bytes == 0) + if (block_group_is_empty(block_group)) add_to_discard_unused_list(discard_ctl, block_group); else add_to_discard_list(discard_ctl, block_group); @@ -470,7 +496,7 @@ static void btrfs_finish_discard_pass(struct btrfs_discard_ctl *discard_ctl, { remove_from_discard_list(discard_ctl, block_group); - if (block_group->used == 0) { + if (block_group_is_empty(block_group)) { if (btrfs_is_free_space_trimmed(block_group)) btrfs_mark_bg_unused(block_group); else @@ -524,7 +550,8 @@ static void btrfs_discard_workfn(struct work_struct *work) /* Perform discarding */ minlen = discard_minlen[discard_index]; - if (discard_state == BTRFS_DISCARD_BITMAPS) { + switch (discard_state) { + case BTRFS_DISCARD_BITMAPS: { u64 maxlen = 0; /* @@ -541,17 +568,28 @@ static void btrfs_discard_workfn(struct work_struct *work) btrfs_block_group_end(block_group), minlen, maxlen, true); discard_ctl->discard_bitmap_bytes += trimmed; - } else { + + break; + } + + case BTRFS_DISCARD_FULLY_REMAPPED: + btrfs_trim_fully_remapped_block_group(block_group); + break; + + default: btrfs_trim_block_group_extents(block_group, &trimmed, block_group->discard_cursor, btrfs_block_group_end(block_group), minlen, true); discard_ctl->discard_extent_bytes += trimmed; + + break; } /* Determine next steps for a block_group */ if (block_group->discard_cursor >= btrfs_block_group_end(block_group)) { - if (discard_state == BTRFS_DISCARD_BITMAPS) { + if (discard_state == BTRFS_DISCARD_BITMAPS || + discard_state == BTRFS_DISCARD_FULLY_REMAPPED) { btrfs_finish_discard_pass(discard_ctl, block_group); } else { block_group->discard_cursor = block_group->start; |
