diff options
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 50 | ||||
-rw-r--r-- | fs/btrfs/free-space-cache.c | 92 | ||||
-rw-r--r-- | fs/btrfs/free-space-cache.h | 2 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 46 |
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); |
2233 | int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, | 2233 | int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, |
2234 | struct btrfs_root *root, u64 type); | 2234 | struct btrfs_root *root, u64 type); |
2235 | int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range); | ||
2235 | 2236 | ||
2236 | /* ctree.c */ | 2237 | /* ctree.c */ |
2237 | int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, | 2238 | int 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 | |||
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 | } | ||
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 | ||
2181 | int 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, | |||
68 | int btrfs_return_cluster_to_free_space( | 68 | int 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); |
71 | int 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 | ||
262 | static 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 | |||
261 | static noinline int create_subvol(struct btrfs_root *root, | 305 | static 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: |