Skip to content

Commit 72f9525

Browse files
davidhildenbrandmstsirkin
authored andcommitted
virtio-mem: Try to unplug the complete online memory block first
Right now, we always try to unplug single subblocks when processing an online memory block. Let's try to unplug the complete online memory block first, in case it is fully plugged and the unplug request is large enough. Fallback to single subblocks in case the memory block cannot get unplugged as a whole. Cc: "Michael S. Tsirkin" <[email protected]> Cc: Pankaj Gupta <[email protected]> Signed-off-by: David Hildenbrand <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Michael S. Tsirkin <[email protected]>
1 parent 8d4edcf commit 72f9525

File tree

1 file changed

+57
-31
lines changed

1 file changed

+57
-31
lines changed

drivers/virtio/virtio_mem.c

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,6 +1307,46 @@ static int virtio_mem_mb_unplug_any_sb_offline(struct virtio_mem *vm,
13071307
return 0;
13081308
}
13091309

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+
13101350
/*
13111351
* Unplug the desired number of plugged subblocks of an online memory block.
13121352
* Will skip subblock that are busy.
@@ -1321,16 +1361,21 @@ static int virtio_mem_mb_unplug_any_sb_online(struct virtio_mem *vm,
13211361
unsigned long mb_id,
13221362
uint64_t *nb_sb)
13231363
{
1324-
const unsigned long nr_pages = PFN_DOWN(vm->subblock_size);
1325-
unsigned long start_pfn;
13261364
int rc, sb_id;
13271365

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. */
13341379
for (sb_id = vm->nb_sb_per_mb - 1; sb_id >= 0 && *nb_sb; sb_id--) {
13351380
/* Find the next candidate subblock */
13361381
while (sb_id >= 0 &&
@@ -1339,34 +1384,15 @@ static int virtio_mem_mb_unplug_any_sb_online(struct virtio_mem *vm,
13391384
if (sb_id < 0)
13401385
break;
13411386

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)
13511389
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)
13621391
return rc;
1363-
}
1364-
1365-
virtio_mem_mb_set_state(vm, mb_id,
1366-
VIRTIO_MEM_MB_STATE_ONLINE_PARTIAL);
13671392
*nb_sb -= 1;
13681393
}
13691394

1395+
unplugged:
13701396
/*
13711397
* Once all subblocks of a memory block were unplugged, offline and
13721398
* remove it. This will usually not fail, as no memory is in use

0 commit comments

Comments
 (0)