aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c101
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 */
10156static 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
10138int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range) 10225int 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}