diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index d763457b3cce..15411aefbfa0 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -10135,10 +10135,99 @@ int btrfs_error_unpin_extent_range(struct btrfs_root *root, u64 start, u64 end) | |||
10135 | return unpin_extent_range(root, start, end, false); | 10135 | return unpin_extent_range(root, start, end, false); |
10136 | } | 10136 | } |
10137 | 10137 | ||
10138 | /* | ||
10139 | * It used to be that old block groups would be left around forever. | ||
10140 | * Iterating over them would be enough to trim unused space. Since we | ||
10141 | * now automatically remove them, we also need to iterate over unallocated | ||
10142 | * space. | ||
10143 | * | ||
10144 | * We don't want a transaction for this since the discard may take a | ||
10145 | * substantial amount of time. We don't require that a transaction be | ||
10146 | * running, but we do need to take a running transaction into account | ||
10147 | * to ensure that we're not discarding chunks that were released in | ||
10148 | * the current transaction. | ||
10149 | * | ||
10150 | * Holding the chunks lock will prevent other threads from allocating | ||
10151 | * or releasing chunks, but it won't prevent a running transaction | ||
10152 | * from committing and releasing the memory that the pending chunks | ||
10153 | * list head uses. For that, we need to take a reference to the | ||
10154 | * transaction. | ||
10155 | */ | ||
10156 | static int btrfs_trim_free_extents(struct btrfs_device *device, | ||
10157 | u64 minlen, u64 *trimmed) | ||
10158 | { | ||
10159 | u64 start = 0, len = 0; | ||
10160 | int ret; | ||
10161 | |||
10162 | *trimmed = 0; | ||
10163 | |||
10164 | /* Not writeable = nothing to do. */ | ||
10165 | if (!device->writeable) | ||
10166 | return 0; | ||
10167 | |||
10168 | /* No free space = nothing to do. */ | ||
10169 | if (device->total_bytes <= device->bytes_used) | ||
10170 | return 0; | ||
10171 | |||
10172 | ret = 0; | ||
10173 | |||
10174 | while (1) { | ||
10175 | struct btrfs_fs_info *fs_info = device->dev_root->fs_info; | ||
10176 | struct btrfs_transaction *trans; | ||
10177 | u64 bytes; | ||
10178 | |||
10179 | ret = mutex_lock_interruptible(&fs_info->chunk_mutex); | ||
10180 | if (ret) | ||
10181 | return ret; | ||
10182 | |||
10183 | down_read(&fs_info->commit_root_sem); | ||
10184 | |||
10185 | spin_lock(&fs_info->trans_lock); | ||
10186 | trans = fs_info->running_transaction; | ||
10187 | if (trans) | ||
10188 | atomic_inc(&trans->use_count); | ||
10189 | spin_unlock(&fs_info->trans_lock); | ||
10190 | |||
10191 | ret = find_free_dev_extent_start(trans, device, minlen, start, | ||
10192 | &start, &len); | ||
10193 | if (trans) | ||
10194 | btrfs_put_transaction(trans); | ||
10195 | |||
10196 | if (ret) { | ||
10197 | up_read(&fs_info->commit_root_sem); | ||
10198 | mutex_unlock(&fs_info->chunk_mutex); | ||
10199 | if (ret == -ENOSPC) | ||
10200 | ret = 0; | ||
10201 | break; | ||
10202 | } | ||
10203 | |||
10204 | ret = btrfs_issue_discard(device->bdev, start, len, &bytes); | ||
10205 | up_read(&fs_info->commit_root_sem); | ||
10206 | mutex_unlock(&fs_info->chunk_mutex); | ||
10207 | |||
10208 | if (ret) | ||
10209 | break; | ||
10210 | |||
10211 | start += len; | ||
10212 | *trimmed += bytes; | ||
10213 | |||
10214 | if (fatal_signal_pending(current)) { | ||
10215 | ret = -ERESTARTSYS; | ||
10216 | break; | ||
10217 | } | ||
10218 | |||
10219 | cond_resched(); | ||
10220 | } | ||
10221 | |||
10222 | return ret; | ||
10223 | } | ||
10224 | |||
10138 | int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range) | 10225 | int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range) |
10139 | { | 10226 | { |
10140 | struct btrfs_fs_info *fs_info = root->fs_info; | 10227 | struct btrfs_fs_info *fs_info = root->fs_info; |
10141 | struct btrfs_block_group_cache *cache = NULL; | 10228 | struct btrfs_block_group_cache *cache = NULL; |
10229 | struct btrfs_device *device; | ||
10230 | struct list_head *devices; | ||
10142 | u64 group_trimmed; | 10231 | u64 group_trimmed; |
10143 | u64 start; | 10232 | u64 start; |
10144 | u64 end; | 10233 | u64 end; |
@@ -10193,6 +10282,18 @@ int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range) | |||
10193 | cache = next_block_group(fs_info->tree_root, cache); | 10282 | cache = next_block_group(fs_info->tree_root, cache); |
10194 | } | 10283 | } |
10195 | 10284 | ||
10285 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); | ||
10286 | devices = &root->fs_info->fs_devices->alloc_list; | ||
10287 | list_for_each_entry(device, devices, dev_alloc_list) { | ||
10288 | ret = btrfs_trim_free_extents(device, range->minlen, | ||
10289 | &group_trimmed); | ||
10290 | if (ret) | ||
10291 | break; | ||
10292 | |||
10293 | trimmed += group_trimmed; | ||
10294 | } | ||
10295 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | ||
10296 | |||
10196 | range->len = trimmed; | 10297 | range->len = trimmed; |
10197 | return ret; | 10298 | return ret; |
10198 | } | 10299 | } |