aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/extent-tree.c50
-rw-r--r--fs/btrfs/free-space-cache.c92
-rw-r--r--fs/btrfs/free-space-cache.h2
-rw-r--r--fs/btrfs/ioctl.c46
5 files changed, 190 insertions, 1 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index a18b7bc2b22c..93a0191aded6 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -2232,6 +2232,7 @@ int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr,
2232 u64 num_bytes, u64 *actual_bytes); 2232 u64 num_bytes, u64 *actual_bytes);
2233int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, 2233int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
2234 struct btrfs_root *root, u64 type); 2234 struct btrfs_root *root, u64 type);
2235int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range);
2235 2236
2236/* ctree.c */ 2237/* ctree.c */
2237int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, 2238int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
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
8782int 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}
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index f03ef97c3b21..0037427d8a9d 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -2178,3 +2178,95 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster)
2178 cluster->block_group = NULL; 2178 cluster->block_group = NULL;
2179} 2179}
2180 2180
2181int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
2182 u64 *trimmed, u64 start, u64 end, u64 minlen)
2183{
2184 struct btrfs_free_space *entry = NULL;
2185 struct btrfs_fs_info *fs_info = block_group->fs_info;
2186 u64 bytes = 0;
2187 u64 actually_trimmed;
2188 int ret = 0;
2189
2190 *trimmed = 0;
2191
2192 while (start < end) {
2193 spin_lock(&block_group->tree_lock);
2194
2195 if (block_group->free_space < minlen) {
2196 spin_unlock(&block_group->tree_lock);
2197 break;
2198 }
2199
2200 entry = tree_search_offset(block_group, start, 0, 1);
2201 if (!entry)
2202 entry = tree_search_offset(block_group,
2203 offset_to_bitmap(block_group,
2204 start),
2205 1, 1);
2206
2207 if (!entry || entry->offset >= end) {
2208 spin_unlock(&block_group->tree_lock);
2209 break;
2210 }
2211
2212 if (entry->bitmap) {
2213 ret = search_bitmap(block_group, entry, &start, &bytes);
2214 if (!ret) {
2215 if (start >= end) {
2216 spin_unlock(&block_group->tree_lock);
2217 break;
2218 }
2219 bytes = min(bytes, end - start);
2220 bitmap_clear_bits(block_group, entry,
2221 start, bytes);
2222 if (entry->bytes == 0)
2223 free_bitmap(block_group, entry);
2224 } else {
2225 start = entry->offset + BITS_PER_BITMAP *
2226 block_group->sectorsize;
2227 spin_unlock(&block_group->tree_lock);
2228 ret = 0;
2229 continue;
2230 }
2231 } else {
2232 start = entry->offset;
2233 bytes = min(entry->bytes, end - start);
2234 unlink_free_space(block_group, entry);
2235 kfree(entry);
2236 }
2237
2238 spin_unlock(&block_group->tree_lock);
2239
2240 if (bytes >= minlen) {
2241 int update_ret;
2242 update_ret = btrfs_update_reserved_bytes(block_group,
2243 bytes, 1, 1);
2244
2245 ret = btrfs_error_discard_extent(fs_info->extent_root,
2246 start,
2247 bytes,
2248 &actually_trimmed);
2249
2250 btrfs_add_free_space(block_group,
2251 start, bytes);
2252 if (!update_ret)
2253 btrfs_update_reserved_bytes(block_group,
2254 bytes, 0, 1);
2255
2256 if (ret)
2257 break;
2258 *trimmed += actually_trimmed;
2259 }
2260 start += bytes;
2261 bytes = 0;
2262
2263 if (fatal_signal_pending(current)) {
2264 ret = -ERESTARTSYS;
2265 break;
2266 }
2267
2268 cond_resched();
2269 }
2270
2271 return ret;
2272}
diff --git a/fs/btrfs/free-space-cache.h b/fs/btrfs/free-space-cache.h
index e49ca5c321b5..65c3b935289f 100644
--- a/fs/btrfs/free-space-cache.h
+++ b/fs/btrfs/free-space-cache.h
@@ -68,4 +68,6 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
68int btrfs_return_cluster_to_free_space( 68int btrfs_return_cluster_to_free_space(
69 struct btrfs_block_group_cache *block_group, 69 struct btrfs_block_group_cache *block_group,
70 struct btrfs_free_cluster *cluster); 70 struct btrfs_free_cluster *cluster);
71int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
72 u64 *trimmed, u64 start, u64 end, u64 minlen);
71#endif 73#endif
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 32c980ae0f1c..649f47d2afb4 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -40,6 +40,7 @@
40#include <linux/xattr.h> 40#include <linux/xattr.h>
41#include <linux/vmalloc.h> 41#include <linux/vmalloc.h>
42#include <linux/slab.h> 42#include <linux/slab.h>
43#include <linux/blkdev.h>
43#include "compat.h" 44#include "compat.h"
44#include "ctree.h" 45#include "ctree.h"
45#include "disk-io.h" 46#include "disk-io.h"
@@ -258,6 +259,49 @@ static int btrfs_ioctl_getversion(struct file *file, int __user *arg)
258 return put_user(inode->i_generation, arg); 259 return put_user(inode->i_generation, arg);
259} 260}
260 261
262static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
263{
264 struct btrfs_root *root = fdentry(file)->d_sb->s_fs_info;
265 struct btrfs_fs_info *fs_info = root->fs_info;
266 struct btrfs_device *device;
267 struct request_queue *q;
268 struct fstrim_range range;
269 u64 minlen = ULLONG_MAX;
270 u64 num_devices = 0;
271 int ret;
272
273 if (!capable(CAP_SYS_ADMIN))
274 return -EPERM;
275
276 mutex_lock(&fs_info->fs_devices->device_list_mutex);
277 list_for_each_entry(device, &fs_info->fs_devices->devices, dev_list) {
278 if (!device->bdev)
279 continue;
280 q = bdev_get_queue(device->bdev);
281 if (blk_queue_discard(q)) {
282 num_devices++;
283 minlen = min((u64)q->limits.discard_granularity,
284 minlen);
285 }
286 }
287 mutex_unlock(&fs_info->fs_devices->device_list_mutex);
288 if (!num_devices)
289 return -EOPNOTSUPP;
290
291 if (copy_from_user(&range, arg, sizeof(range)))
292 return -EFAULT;
293
294 range.minlen = max(range.minlen, minlen);
295 ret = btrfs_trim_fs(root, &range);
296 if (ret < 0)
297 return ret;
298
299 if (copy_to_user(arg, &range, sizeof(range)))
300 return -EFAULT;
301
302 return 0;
303}
304
261static noinline int create_subvol(struct btrfs_root *root, 305static noinline int create_subvol(struct btrfs_root *root,
262 struct dentry *dentry, 306 struct dentry *dentry,
263 char *name, int namelen, 307 char *name, int namelen,
@@ -2426,6 +2470,8 @@ long btrfs_ioctl(struct file *file, unsigned int
2426 return btrfs_ioctl_setflags(file, argp); 2470 return btrfs_ioctl_setflags(file, argp);
2427 case FS_IOC_GETVERSION: 2471 case FS_IOC_GETVERSION:
2428 return btrfs_ioctl_getversion(file, argp); 2472 return btrfs_ioctl_getversion(file, argp);
2473 case FITRIM:
2474 return btrfs_ioctl_fitrim(file, argp);
2429 case BTRFS_IOC_SNAP_CREATE: 2475 case BTRFS_IOC_SNAP_CREATE:
2430 return btrfs_ioctl_snap_create(file, argp, 0); 2476 return btrfs_ioctl_snap_create(file, argp, 0);
2431 case BTRFS_IOC_SNAP_CREATE_V2: 2477 case BTRFS_IOC_SNAP_CREATE_V2: