@@ -1307,6 +1307,46 @@ static int virtio_mem_mb_unplug_any_sb_offline(struct virtio_mem *vm,
1307
1307
return 0 ;
1308
1308
}
1309
1309
1310
+ /*
1311
+ * Unplug the given plugged subblocks of an online memory block.
1312
+ *
1313
+ * Will modify the state of the memory block.
1314
+ */
1315
+ static int virtio_mem_mb_unplug_sb_online (struct virtio_mem * vm ,
1316
+ unsigned long mb_id , int sb_id ,
1317
+ int count )
1318
+ {
1319
+ const unsigned long nr_pages = PFN_DOWN (vm -> subblock_size ) * count ;
1320
+ unsigned long start_pfn ;
1321
+ int rc ;
1322
+
1323
+ start_pfn = PFN_DOWN (virtio_mem_mb_id_to_phys (mb_id ) +
1324
+ sb_id * vm -> subblock_size );
1325
+ rc = alloc_contig_range (start_pfn , start_pfn + nr_pages ,
1326
+ MIGRATE_MOVABLE , GFP_KERNEL );
1327
+ if (rc == - ENOMEM )
1328
+ /* whoops, out of memory */
1329
+ return rc ;
1330
+ if (rc )
1331
+ return - EBUSY ;
1332
+
1333
+ /* Mark it as fake-offline before unplugging it */
1334
+ virtio_mem_set_fake_offline (start_pfn , nr_pages , true);
1335
+ adjust_managed_page_count (pfn_to_page (start_pfn ), - nr_pages );
1336
+
1337
+ /* Try to unplug the allocated memory */
1338
+ rc = virtio_mem_mb_unplug_sb (vm , mb_id , sb_id , count );
1339
+ if (rc ) {
1340
+ /* Return the memory to the buddy. */
1341
+ virtio_mem_fake_online (start_pfn , nr_pages );
1342
+ return rc ;
1343
+ }
1344
+
1345
+ virtio_mem_mb_set_state (vm , mb_id ,
1346
+ VIRTIO_MEM_MB_STATE_ONLINE_PARTIAL );
1347
+ return 0 ;
1348
+ }
1349
+
1310
1350
/*
1311
1351
* Unplug the desired number of plugged subblocks of an online memory block.
1312
1352
* Will skip subblock that are busy.
@@ -1321,16 +1361,21 @@ static int virtio_mem_mb_unplug_any_sb_online(struct virtio_mem *vm,
1321
1361
unsigned long mb_id ,
1322
1362
uint64_t * nb_sb )
1323
1363
{
1324
- const unsigned long nr_pages = PFN_DOWN (vm -> subblock_size );
1325
- unsigned long start_pfn ;
1326
1364
int rc , sb_id ;
1327
1365
1328
- /*
1329
- * TODO: To increase the performance we want to try bigger, consecutive
1330
- * subblocks first before falling back to single subblocks. Also,
1331
- * we should sense via something like is_mem_section_removable()
1332
- * first if it makes sense to go ahead any try to allocate.
1333
- */
1366
+ /* If possible, try to unplug the complete block in one shot. */
1367
+ if (* nb_sb >= vm -> nb_sb_per_mb &&
1368
+ virtio_mem_mb_test_sb_plugged (vm , mb_id , 0 , vm -> nb_sb_per_mb )) {
1369
+ rc = virtio_mem_mb_unplug_sb_online (vm , mb_id , 0 ,
1370
+ vm -> nb_sb_per_mb );
1371
+ if (!rc ) {
1372
+ * nb_sb -= vm -> nb_sb_per_mb ;
1373
+ goto unplugged ;
1374
+ } else if (rc != - EBUSY )
1375
+ return rc ;
1376
+ }
1377
+
1378
+ /* Fallback to single subblocks. */
1334
1379
for (sb_id = vm -> nb_sb_per_mb - 1 ; sb_id >= 0 && * nb_sb ; sb_id -- ) {
1335
1380
/* Find the next candidate subblock */
1336
1381
while (sb_id >= 0 &&
@@ -1339,34 +1384,15 @@ static int virtio_mem_mb_unplug_any_sb_online(struct virtio_mem *vm,
1339
1384
if (sb_id < 0 )
1340
1385
break ;
1341
1386
1342
- start_pfn = PFN_DOWN (virtio_mem_mb_id_to_phys (mb_id ) +
1343
- sb_id * vm -> subblock_size );
1344
- rc = alloc_contig_range (start_pfn , start_pfn + nr_pages ,
1345
- MIGRATE_MOVABLE , GFP_KERNEL );
1346
- if (rc == - ENOMEM )
1347
- /* whoops, out of memory */
1348
- return rc ;
1349
- if (rc )
1350
- /* memory busy, we can't unplug this chunk */
1387
+ rc = virtio_mem_mb_unplug_sb_online (vm , mb_id , sb_id , 1 );
1388
+ if (rc == - EBUSY )
1351
1389
continue ;
1352
-
1353
- /* Mark it as fake-offline before unplugging it */
1354
- virtio_mem_set_fake_offline (start_pfn , nr_pages , true);
1355
- adjust_managed_page_count (pfn_to_page (start_pfn ), - nr_pages );
1356
-
1357
- /* Try to unplug the allocated memory */
1358
- rc = virtio_mem_mb_unplug_sb (vm , mb_id , sb_id , 1 );
1359
- if (rc ) {
1360
- /* Return the memory to the buddy. */
1361
- virtio_mem_fake_online (start_pfn , nr_pages );
1390
+ else if (rc )
1362
1391
return rc ;
1363
- }
1364
-
1365
- virtio_mem_mb_set_state (vm , mb_id ,
1366
- VIRTIO_MEM_MB_STATE_ONLINE_PARTIAL );
1367
1392
* nb_sb -= 1 ;
1368
1393
}
1369
1394
1395
+ unplugged :
1370
1396
/*
1371
1397
* Once all subblocks of a memory block were unplugged, offline and
1372
1398
* remove it. This will usually not fail, as no memory is in use
0 commit comments