diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index e990d2d1ba4a..1efeda3b2f6f 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -440,7 +440,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, | |||
440 | * allocate blocks for the tree root we can't do the fast caching since | 440 | * allocate blocks for the tree root we can't do the fast caching since |
441 | * we likely hold important locks. | 441 | * we likely hold important locks. |
442 | */ | 442 | */ |
443 | if (!trans->transaction->in_commit && | 443 | if (trans && (!trans->transaction->in_commit) && |
444 | (root && root != root->fs_info->tree_root)) { | 444 | (root && root != root->fs_info->tree_root)) { |
445 | spin_lock(&cache->lock); | 445 | spin_lock(&cache->lock); |
446 | if (cache->cached != BTRFS_CACHE_NO) { | 446 | if (cache->cached != BTRFS_CACHE_NO) { |
@@ -8778,3 +8778,51 @@ int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr, | |||
8778 | { | 8778 | { |
8779 | return btrfs_discard_extent(root, bytenr, num_bytes, actual_bytes); | 8779 | return btrfs_discard_extent(root, bytenr, num_bytes, actual_bytes); |
8780 | } | 8780 | } |
8781 | |||
8782 | int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range) | ||
8783 | { | ||
8784 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
8785 | struct btrfs_block_group_cache *cache = NULL; | ||
8786 | u64 group_trimmed; | ||
8787 | u64 start; | ||
8788 | u64 end; | ||
8789 | u64 trimmed = 0; | ||
8790 | int ret = 0; | ||
8791 | |||
8792 | cache = btrfs_lookup_block_group(fs_info, range->start); | ||
8793 | |||
8794 | while (cache) { | ||
8795 | if (cache->key.objectid >= (range->start + range->len)) { | ||
8796 | btrfs_put_block_group(cache); | ||
8797 | break; | ||
8798 | } | ||
8799 | |||
8800 | start = max(range->start, cache->key.objectid); | ||
8801 | end = min(range->start + range->len, | ||
8802 | cache->key.objectid + cache->key.offset); | ||
8803 | |||
8804 | if (end - start >= range->minlen) { | ||
8805 | if (!block_group_cache_done(cache)) { | ||
8806 | ret = cache_block_group(cache, NULL, root, 0); | ||
8807 | if (!ret) | ||
8808 | wait_block_group_cache_done(cache); | ||
8809 | } | ||
8810 | ret = btrfs_trim_block_group(cache, | ||
8811 | &group_trimmed, | ||
8812 | start, | ||
8813 | end, | ||
8814 | range->minlen); | ||
8815 | |||
8816 | trimmed += group_trimmed; | ||
8817 | if (ret) { | ||
8818 | btrfs_put_block_group(cache); | ||
8819 | break; | ||
8820 | } | ||
8821 | } | ||
8822 | |||
8823 | cache = next_block_group(fs_info->tree_root, cache); | ||
8824 | } | ||
8825 | |||
8826 | range->len = trimmed; | ||
8827 | return ret; | ||
8828 | } | ||