@@ -168,6 +168,13 @@ struct virtio_mem {
168
168
/* The number of subblocks per Linux memory block. */
169
169
uint32_t sbs_per_mb ;
170
170
171
+ /*
172
+ * Some of the Linux memory blocks tracked as "partially
173
+ * plugged" are completely unplugged and can be offlined
174
+ * and removed -- which previously failed.
175
+ */
176
+ bool have_unplugged_mb ;
177
+
171
178
/* Summary of all memory block states. */
172
179
unsigned long mb_count [VIRTIO_MEM_SBM_MB_COUNT ];
173
180
@@ -765,6 +772,34 @@ static int virtio_mem_sbm_offline_and_remove_mb(struct virtio_mem *vm,
765
772
return virtio_mem_offline_and_remove_memory (vm , addr , size );
766
773
}
767
774
775
+ /*
776
+ * Try (offlining and) removing memory from Linux in case all subblocks are
777
+ * unplugged. Can be called on online and offline memory blocks.
778
+ *
779
+ * May modify the state of memory blocks in virtio-mem.
780
+ */
781
+ static int virtio_mem_sbm_try_remove_unplugged_mb (struct virtio_mem * vm ,
782
+ unsigned long mb_id )
783
+ {
784
+ int rc ;
785
+
786
+ /*
787
+ * Once all subblocks of a memory block were unplugged, offline and
788
+ * remove it.
789
+ */
790
+ if (!virtio_mem_sbm_test_sb_unplugged (vm , mb_id , 0 , vm -> sbm .sbs_per_mb ))
791
+ return 0 ;
792
+
793
+ /* offline_and_remove_memory() works for online and offline memory. */
794
+ mutex_unlock (& vm -> hotplug_mutex );
795
+ rc = virtio_mem_sbm_offline_and_remove_mb (vm , mb_id );
796
+ mutex_lock (& vm -> hotplug_mutex );
797
+ if (!rc )
798
+ virtio_mem_sbm_set_mb_state (vm , mb_id ,
799
+ VIRTIO_MEM_SBM_MB_UNUSED );
800
+ return rc ;
801
+ }
802
+
768
803
/*
769
804
* See virtio_mem_offline_and_remove_memory(): Try to offline and remove a
770
805
* all Linux memory blocks covered by the big block.
@@ -1988,20 +2023,10 @@ static int virtio_mem_sbm_unplug_any_sb_online(struct virtio_mem *vm,
1988
2023
}
1989
2024
1990
2025
unplugged :
1991
- /*
1992
- * Once all subblocks of a memory block were unplugged, offline and
1993
- * remove it. This will usually not fail, as no memory is in use
1994
- * anymore - however some other notifiers might NACK the request.
1995
- */
1996
- if (virtio_mem_sbm_test_sb_unplugged (vm , mb_id , 0 , vm -> sbm .sbs_per_mb )) {
1997
- mutex_unlock (& vm -> hotplug_mutex );
1998
- rc = virtio_mem_sbm_offline_and_remove_mb (vm , mb_id );
1999
- mutex_lock (& vm -> hotplug_mutex );
2000
- if (!rc )
2001
- virtio_mem_sbm_set_mb_state (vm , mb_id ,
2002
- VIRTIO_MEM_SBM_MB_UNUSED );
2003
- }
2004
-
2026
+ rc = virtio_mem_sbm_try_remove_unplugged_mb (vm , mb_id );
2027
+ if (rc )
2028
+ vm -> sbm .have_unplugged_mb = 1 ;
2029
+ /* Ignore errors, this is not critical. We'll retry later. */
2005
2030
return 0 ;
2006
2031
}
2007
2032
@@ -2253,12 +2278,13 @@ static int virtio_mem_unplug_request(struct virtio_mem *vm, uint64_t diff)
2253
2278
2254
2279
/*
2255
2280
* Try to unplug all blocks that couldn't be unplugged before, for example,
2256
- * because the hypervisor was busy.
2281
+ * because the hypervisor was busy. Further, offline and remove any memory
2282
+ * blocks where we previously failed.
2257
2283
*/
2258
- static int virtio_mem_unplug_pending_mb (struct virtio_mem * vm )
2284
+ static int virtio_mem_cleanup_pending_mb (struct virtio_mem * vm )
2259
2285
{
2260
2286
unsigned long id ;
2261
- int rc ;
2287
+ int rc = 0 ;
2262
2288
2263
2289
if (!vm -> in_sbm ) {
2264
2290
virtio_mem_bbm_for_each_bb (vm , id ,
@@ -2280,6 +2306,27 @@ static int virtio_mem_unplug_pending_mb(struct virtio_mem *vm)
2280
2306
VIRTIO_MEM_SBM_MB_UNUSED );
2281
2307
}
2282
2308
2309
+ if (!vm -> sbm .have_unplugged_mb )
2310
+ return 0 ;
2311
+
2312
+ /*
2313
+ * Let's retry (offlining and) removing completely unplugged Linux
2314
+ * memory blocks.
2315
+ */
2316
+ vm -> sbm .have_unplugged_mb = false;
2317
+
2318
+ mutex_lock (& vm -> hotplug_mutex );
2319
+ virtio_mem_sbm_for_each_mb (vm , id , VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL )
2320
+ rc |= virtio_mem_sbm_try_remove_unplugged_mb (vm , id );
2321
+ virtio_mem_sbm_for_each_mb (vm , id , VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL )
2322
+ rc |= virtio_mem_sbm_try_remove_unplugged_mb (vm , id );
2323
+ virtio_mem_sbm_for_each_mb (vm , id , VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL )
2324
+ rc |= virtio_mem_sbm_try_remove_unplugged_mb (vm , id );
2325
+ mutex_unlock (& vm -> hotplug_mutex );
2326
+
2327
+ if (rc )
2328
+ vm -> sbm .have_unplugged_mb = true;
2329
+ /* Ignore errors, this is not critical. We'll retry later. */
2283
2330
return 0 ;
2284
2331
}
2285
2332
@@ -2361,9 +2408,9 @@ static void virtio_mem_run_wq(struct work_struct *work)
2361
2408
virtio_mem_refresh_config (vm );
2362
2409
}
2363
2410
2364
- /* Unplug any leftovers from previous runs */
2411
+ /* Cleanup any leftovers from previous runs */
2365
2412
if (!rc )
2366
- rc = virtio_mem_unplug_pending_mb (vm );
2413
+ rc = virtio_mem_cleanup_pending_mb (vm );
2367
2414
2368
2415
if (!rc && vm -> requested_size != vm -> plugged_size ) {
2369
2416
if (vm -> requested_size > vm -> plugged_size ) {
@@ -2375,6 +2422,13 @@ static void virtio_mem_run_wq(struct work_struct *work)
2375
2422
}
2376
2423
}
2377
2424
2425
+ /*
2426
+ * Keep retrying to offline and remove completely unplugged Linux
2427
+ * memory blocks.
2428
+ */
2429
+ if (!rc && vm -> in_sbm && vm -> sbm .have_unplugged_mb )
2430
+ rc = - EBUSY ;
2431
+
2378
2432
switch (rc ) {
2379
2433
case 0 :
2380
2434
vm -> retry_timer_ms = VIRTIO_MEM_RETRY_TIMER_MIN_MS ;
0 commit comments