return 0;
 }
 
+/*
+ * Unplug the given plugged subblocks of an online memory block.
+ *
+ * Will modify the state of the memory block.
+ */
+static int virtio_mem_mb_unplug_sb_online(struct virtio_mem *vm,
+                                         unsigned long mb_id, int sb_id,
+                                         int count)
+{
+       const unsigned long nr_pages = PFN_DOWN(vm->subblock_size) * count;
+       unsigned long start_pfn;
+       int rc;
+
+       start_pfn = PFN_DOWN(virtio_mem_mb_id_to_phys(mb_id) +
+                            sb_id * vm->subblock_size);
+       rc = alloc_contig_range(start_pfn, start_pfn + nr_pages,
+                               MIGRATE_MOVABLE, GFP_KERNEL);
+       if (rc == -ENOMEM)
+               /* whoops, out of memory */
+               return rc;
+       if (rc)
+               return -EBUSY;
+
+       /* Mark it as fake-offline before unplugging it */
+       virtio_mem_set_fake_offline(start_pfn, nr_pages, true);
+       adjust_managed_page_count(pfn_to_page(start_pfn), -nr_pages);
+
+       /* Try to unplug the allocated memory */
+       rc = virtio_mem_mb_unplug_sb(vm, mb_id, sb_id, count);
+       if (rc) {
+               /* Return the memory to the buddy. */
+               virtio_mem_fake_online(start_pfn, nr_pages);
+               return rc;
+       }
+
+       virtio_mem_mb_set_state(vm, mb_id,
+                               VIRTIO_MEM_MB_STATE_ONLINE_PARTIAL);
+       return 0;
+}
+
 /*
  * Unplug the desired number of plugged subblocks of an online memory block.
  * Will skip subblock that are busy.
                                              unsigned long mb_id,
                                              uint64_t *nb_sb)
 {
-       const unsigned long nr_pages = PFN_DOWN(vm->subblock_size);
-       unsigned long start_pfn;
        int rc, sb_id;
 
-       /*
-        * TODO: To increase the performance we want to try bigger, consecutive
-        * subblocks first before falling back to single subblocks. Also,
-        * we should sense via something like is_mem_section_removable()
-        * first if it makes sense to go ahead any try to allocate.
-        */
+       /* If possible, try to unplug the complete block in one shot. */
+       if (*nb_sb >= vm->nb_sb_per_mb &&
+           virtio_mem_mb_test_sb_plugged(vm, mb_id, 0, vm->nb_sb_per_mb)) {
+               rc = virtio_mem_mb_unplug_sb_online(vm, mb_id, 0,
+                                                   vm->nb_sb_per_mb);
+               if (!rc) {
+                       *nb_sb -= vm->nb_sb_per_mb;
+                       goto unplugged;
+               } else if (rc != -EBUSY)
+                       return rc;
+       }
+
+       /* Fallback to single subblocks. */
        for (sb_id = vm->nb_sb_per_mb - 1; sb_id >= 0 && *nb_sb; sb_id--) {
                /* Find the next candidate subblock */
                while (sb_id >= 0 &&
                if (sb_id < 0)
                        break;
 
-               start_pfn = PFN_DOWN(virtio_mem_mb_id_to_phys(mb_id) +
-                                    sb_id * vm->subblock_size);
-               rc = alloc_contig_range(start_pfn, start_pfn + nr_pages,
-                                       MIGRATE_MOVABLE, GFP_KERNEL);
-               if (rc == -ENOMEM)
-                       /* whoops, out of memory */
-                       return rc;
-               if (rc)
-                       /* memory busy, we can't unplug this chunk */
+               rc = virtio_mem_mb_unplug_sb_online(vm, mb_id, sb_id, 1);
+               if (rc == -EBUSY)
                        continue;
-
-               /* Mark it as fake-offline before unplugging it */
-               virtio_mem_set_fake_offline(start_pfn, nr_pages, true);
-               adjust_managed_page_count(pfn_to_page(start_pfn), -nr_pages);
-
-               /* Try to unplug the allocated memory */
-               rc = virtio_mem_mb_unplug_sb(vm, mb_id, sb_id, 1);
-               if (rc) {
-                       /* Return the memory to the buddy. */
-                       virtio_mem_fake_online(start_pfn, nr_pages);
+               else if (rc)
                        return rc;
-               }
-
-               virtio_mem_mb_set_state(vm, mb_id,
-                                       VIRTIO_MEM_MB_STATE_ONLINE_PARTIAL);
                *nb_sb -= 1;
        }
 
+unplugged:
        /*
         * Once all subblocks of a memory block were unplugged, offline and
         * remove it. This will usually not fail, as no memory is in use