btrfs: limit max discard size for async discard
authorDennis Zhou <dennis@kernel.org>
Thu, 2 Jan 2020 21:26:37 +0000 (16:26 -0500)
committerDavid Sterba <dsterba@suse.com>
Mon, 20 Jan 2020 15:40:59 +0000 (16:40 +0100)
Throttle the maximum size of a discard so that we can provide an upper
bound for the rate of async discard. While the block layer is able to
split discards into the appropriate sized discards, we want to be able
to account more accurately the rate at which we are consuming NCQ slots
as well as limit the upper bound of work for a discard.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Dennis Zhou <dennis@kernel.org>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/discard.h
fs/btrfs/free-space-cache.c

index 5250fe178e49bef3f67f74592ac21b9dae1ff6a8..562c60fab77a90d6b141eaf87027a019705d48ad 100644 (file)
@@ -3,10 +3,15 @@
 #ifndef BTRFS_DISCARD_H
 #define BTRFS_DISCARD_H
 
+#include <linux/sizes.h>
+
 struct btrfs_fs_info;
 struct btrfs_discard_ctl;
 struct btrfs_block_group;
 
+/* Discard size limits */
+#define BTRFS_ASYNC_DISCARD_MAX_SIZE   (SZ_64M)
+
 /* Work operations */
 void btrfs_discard_cancel_work(struct btrfs_discard_ctl *discard_ctl,
                               struct btrfs_block_group *block_group);
index 40fb918a82f496319da7c9f888c4480ba9abf8b8..438043aab6fb7f068eb4f11fd62bdef6d8a7251c 100644 (file)
@@ -3466,16 +3466,36 @@ static int trim_no_bitmap(struct btrfs_block_group *block_group,
                extent_start = entry->offset;
                extent_bytes = entry->bytes;
                extent_trim_state = entry->trim_state;
-               start = max(start, extent_start);
-               bytes = min(extent_start + extent_bytes, end) - start;
-               if (bytes < minlen) {
-                       spin_unlock(&ctl->tree_lock);
-                       mutex_unlock(&ctl->cache_writeout_mutex);
-                       goto next;
-               }
+               if (async) {
+                       start = entry->offset;
+                       bytes = entry->bytes;
+                       if (bytes < minlen) {
+                               spin_unlock(&ctl->tree_lock);
+                               mutex_unlock(&ctl->cache_writeout_mutex);
+                               goto next;
+                       }
+                       unlink_free_space(ctl, entry);
+                       if (bytes > BTRFS_ASYNC_DISCARD_MAX_SIZE) {
+                               bytes = BTRFS_ASYNC_DISCARD_MAX_SIZE;
+                               extent_bytes = BTRFS_ASYNC_DISCARD_MAX_SIZE;
+                               entry->offset += BTRFS_ASYNC_DISCARD_MAX_SIZE;
+                               entry->bytes -= BTRFS_ASYNC_DISCARD_MAX_SIZE;
+                               link_free_space(ctl, entry);
+                       } else {
+                               kmem_cache_free(btrfs_free_space_cachep, entry);
+                       }
+               } else {
+                       start = max(start, extent_start);
+                       bytes = min(extent_start + extent_bytes, end) - start;
+                       if (bytes < minlen) {
+                               spin_unlock(&ctl->tree_lock);
+                               mutex_unlock(&ctl->cache_writeout_mutex);
+                               goto next;
+                       }
 
-               unlink_free_space(ctl, entry);
-               kmem_cache_free(btrfs_free_space_cachep, entry);
+                       unlink_free_space(ctl, entry);
+                       kmem_cache_free(btrfs_free_space_cachep, entry);
+               }
 
                spin_unlock(&ctl->tree_lock);
                trim_entry.start = extent_start;
@@ -3639,6 +3659,9 @@ static int trim_bitmaps(struct btrfs_block_group *block_group,
                        goto next;
                }
 
+               if (async && bytes > BTRFS_ASYNC_DISCARD_MAX_SIZE)
+                       bytes = BTRFS_ASYNC_DISCARD_MAX_SIZE;
+
                bitmap_clear_bits(ctl, entry, start, bytes);
                if (entry->bytes == 0)
                        free_bitmap(ctl, entry);