|
@@ -10833,6 +10833,15 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Trim the whole filesystem by:
|
|
|
+ * 1) trimming the free space in each block group
|
|
|
+ * 2) trimming the unallocated space on each device
|
|
|
+ *
|
|
|
+ * This will also continue trimming even if a block group or device encounters
|
|
|
+ * an error. The return value will be the last error, or 0 if nothing bad
|
|
|
+ * happens.
|
|
|
+ */
|
|
|
int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
|
|
|
{
|
|
|
struct btrfs_block_group_cache *cache = NULL;
|
|
@@ -10843,6 +10852,10 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
|
|
|
u64 end;
|
|
|
u64 trimmed = 0;
|
|
|
u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy);
|
|
|
+ u64 bg_failed = 0;
|
|
|
+ u64 dev_failed = 0;
|
|
|
+ int bg_ret = 0;
|
|
|
+ int dev_ret = 0;
|
|
|
int ret = 0;
|
|
|
|
|
|
/*
|
|
@@ -10853,7 +10866,7 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
|
|
|
else
|
|
|
cache = btrfs_lookup_block_group(fs_info, range->start);
|
|
|
|
|
|
- while (cache) {
|
|
|
+ for (; cache; cache = next_block_group(fs_info, cache)) {
|
|
|
if (cache->key.objectid >= (range->start + range->len)) {
|
|
|
btrfs_put_block_group(cache);
|
|
|
break;
|
|
@@ -10867,13 +10880,15 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
|
|
|
if (!block_group_cache_done(cache)) {
|
|
|
ret = cache_block_group(cache, 0);
|
|
|
if (ret) {
|
|
|
- btrfs_put_block_group(cache);
|
|
|
- break;
|
|
|
+ bg_failed++;
|
|
|
+ bg_ret = ret;
|
|
|
+ continue;
|
|
|
}
|
|
|
ret = wait_block_group_cache_done(cache);
|
|
|
if (ret) {
|
|
|
- btrfs_put_block_group(cache);
|
|
|
- break;
|
|
|
+ bg_failed++;
|
|
|
+ bg_ret = ret;
|
|
|
+ continue;
|
|
|
}
|
|
|
}
|
|
|
ret = btrfs_trim_block_group(cache,
|
|
@@ -10884,28 +10899,40 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
|
|
|
|
|
|
trimmed += group_trimmed;
|
|
|
if (ret) {
|
|
|
- btrfs_put_block_group(cache);
|
|
|
- break;
|
|
|
+ bg_failed++;
|
|
|
+ bg_ret = ret;
|
|
|
+ continue;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- cache = next_block_group(fs_info, cache);
|
|
|
}
|
|
|
|
|
|
+ if (bg_failed)
|
|
|
+ btrfs_warn(fs_info,
|
|
|
+ "failed to trim %llu block group(s), last error %d",
|
|
|
+ bg_failed, bg_ret);
|
|
|
mutex_lock(&fs_info->fs_devices->device_list_mutex);
|
|
|
devices = &fs_info->fs_devices->alloc_list;
|
|
|
list_for_each_entry(device, devices, dev_alloc_list) {
|
|
|
ret = btrfs_trim_free_extents(device, range->minlen,
|
|
|
&group_trimmed);
|
|
|
- if (ret)
|
|
|
+ if (ret) {
|
|
|
+ dev_failed++;
|
|
|
+ dev_ret = ret;
|
|
|
break;
|
|
|
+ }
|
|
|
|
|
|
trimmed += group_trimmed;
|
|
|
}
|
|
|
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
|
|
|
|
|
|
+ if (dev_failed)
|
|
|
+ btrfs_warn(fs_info,
|
|
|
+ "failed to trim %llu device(s), last error %d",
|
|
|
+ dev_failed, dev_ret);
|
|
|
range->len = trimmed;
|
|
|
- return ret;
|
|
|
+ if (bg_ret)
|
|
|
+ return bg_ret;
|
|
|
+ return dev_ret;
|
|
|
}
|
|
|
|
|
|
/*
|