qlist_init(from);
 }
 
-static void qlist_move(struct qlist_head *from, struct qlist_node *last,
-               struct qlist_head *to, size_t size)
-{
-       if (unlikely(last == from->tail)) {
-               qlist_move_all(from, to);
-               return;
-       }
-       if (qlist_empty(to))
-               to->head = from->head;
-       else
-               to->tail->next = from->head;
-       to->tail = last;
-       from->head = last->next;
-       last->next = NULL;
-       from->bytes -= size;
-       to->bytes += size;
-}
-
+#define QUARANTINE_PERCPU_SIZE (1 << 20)
+#define QUARANTINE_BATCHES \
+       (1024 > 4 * CONFIG_NR_CPUS ? 1024 : 4 * CONFIG_NR_CPUS)
 
 /*
  * The object quarantine consists of per-cpu queues and a global queue,
  */
 static DEFINE_PER_CPU(struct qlist_head, cpu_quarantine);
 
-static struct qlist_head global_quarantine;
+/* Round-robin FIFO array of batches. */
+static struct qlist_head global_quarantine[QUARANTINE_BATCHES];
+static int quarantine_head;
+static int quarantine_tail;
+/* Total size of all objects in global_quarantine across all batches. */
+static unsigned long quarantine_size;
 static DEFINE_SPINLOCK(quarantine_lock);
 
 /* Maximum size of the global queue. */
-static unsigned long quarantine_size;
+static unsigned long quarantine_max_size;
+
+/*
+ * Target size of a batch in global_quarantine.
+ * Usually equal to QUARANTINE_PERCPU_SIZE unless we have too much RAM.
+ */
+static unsigned long quarantine_batch_size;
 
 /*
  * The fraction of physical memory the quarantine is allowed to occupy.
  */
 #define QUARANTINE_FRACTION 32
 
-#define QUARANTINE_LOW_SIZE (READ_ONCE(quarantine_size) * 3 / 4)
-#define QUARANTINE_PERCPU_SIZE (1 << 20)
-
 static struct kmem_cache *qlink_to_cache(struct qlist_node *qlink)
 {
        return virt_to_head_page(qlink)->slab_cache;
 
        if (unlikely(!qlist_empty(&temp))) {
                spin_lock_irqsave(&quarantine_lock, flags);
-               qlist_move_all(&temp, &global_quarantine);
+               WRITE_ONCE(quarantine_size, quarantine_size + temp.bytes);
+               qlist_move_all(&temp, &global_quarantine[quarantine_tail]);
+               if (global_quarantine[quarantine_tail].bytes >=
+                               READ_ONCE(quarantine_batch_size)) {
+                       int new_tail;
+
+                       new_tail = quarantine_tail + 1;
+                       if (new_tail == QUARANTINE_BATCHES)
+                               new_tail = 0;
+                       if (new_tail != quarantine_head)
+                               quarantine_tail = new_tail;
+               }
                spin_unlock_irqrestore(&quarantine_lock, flags);
        }
 }
 
 void quarantine_reduce(void)
 {
-       size_t new_quarantine_size, percpu_quarantines;
+       size_t total_size, new_quarantine_size, percpu_quarantines;
        unsigned long flags;
        struct qlist_head to_free = QLIST_INIT;
-       size_t size_to_free = 0;
-       struct qlist_node *last;
 
-       if (likely(READ_ONCE(global_quarantine.bytes) <=
-                  READ_ONCE(quarantine_size)))
+       if (likely(READ_ONCE(quarantine_size) <=
+                  READ_ONCE(quarantine_max_size)))
                return;
 
        spin_lock_irqsave(&quarantine_lock, flags);
         * Update quarantine size in case of hotplug. Allocate a fraction of
         * the installed memory to quarantine minus per-cpu queue limits.
         */
-       new_quarantine_size = (READ_ONCE(totalram_pages) << PAGE_SHIFT) /
+       total_size = (READ_ONCE(totalram_pages) << PAGE_SHIFT) /
                QUARANTINE_FRACTION;
        percpu_quarantines = QUARANTINE_PERCPU_SIZE * num_online_cpus();
-       new_quarantine_size = (new_quarantine_size < percpu_quarantines) ?
-               0 : new_quarantine_size - percpu_quarantines;
-       WRITE_ONCE(quarantine_size, new_quarantine_size);
-
-       last = global_quarantine.head;
-       while (last) {
-               struct kmem_cache *cache = qlink_to_cache(last);
-
-               size_to_free += cache->size;
-               if (!last->next || size_to_free >
-                   global_quarantine.bytes - QUARANTINE_LOW_SIZE)
-                       break;
-               last = last->next;
+       new_quarantine_size = (total_size < percpu_quarantines) ?
+               0 : total_size - percpu_quarantines;
+       WRITE_ONCE(quarantine_max_size, new_quarantine_size);
+       /* Aim at consuming at most 1/2 of slots in quarantine. */
+       WRITE_ONCE(quarantine_batch_size, max((size_t)QUARANTINE_PERCPU_SIZE,
+               2 * total_size / QUARANTINE_BATCHES));
+
+       if (likely(quarantine_size > quarantine_max_size)) {
+               qlist_move_all(&global_quarantine[quarantine_head], &to_free);
+               WRITE_ONCE(quarantine_size, quarantine_size - to_free.bytes);
+               quarantine_head++;
+               if (quarantine_head == QUARANTINE_BATCHES)
+                       quarantine_head = 0;
        }
-       qlist_move(&global_quarantine, last, &to_free, size_to_free);
 
        spin_unlock_irqrestore(&quarantine_lock, flags);
 
 
 void quarantine_remove_cache(struct kmem_cache *cache)
 {
-       unsigned long flags;
+       unsigned long flags, i;
        struct qlist_head to_free = QLIST_INIT;
 
        on_each_cpu(per_cpu_remove_cache, cache, 1);
 
        spin_lock_irqsave(&quarantine_lock, flags);
-       qlist_move_cache(&global_quarantine, &to_free, cache);
+       for (i = 0; i < QUARANTINE_BATCHES; i++)
+               qlist_move_cache(&global_quarantine[i], &to_free, cache);
        spin_unlock_irqrestore(&quarantine_lock, flags);
 
        qlist_free_all(&to_free, cache);