#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);
 
                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;
                        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);