提交 fe30f1c1 编写于 作者: D David Hildenbrand 提交者: Caspar Zhang

virtio-mem: Try to unplug the complete online memory block first

task #29077503
commit 72f9525ad76b1ddfe663285805982e9d57c7b2c2 upstream
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" <mst@redhat.com>
Cc: Pankaj Gupta <pankaj.gupta.linux@gmail.com>
Signed-off-by: NDavid Hildenbrand <david@redhat.com>
Link: https://lore.kernel.org/r/20200507140139.17083-16-david@redhat.comSigned-off-by: NMichael S. Tsirkin <mst@redhat.com>
(cherry picked from ccommit 72f9525ad76b1ddfe663285805982e9d57c7b2c2)
Signed-off-by: NAlex Shi <alex.shi@linux.alibaba.com>
Reviewed-by: NXunlei Pang <xlpang@linux.alibaba.com>
上级 7540dce9
...@@ -1308,36 +1308,17 @@ static int virtio_mem_mb_unplug_any_sb_offline(struct virtio_mem *vm, ...@@ -1308,36 +1308,17 @@ static int virtio_mem_mb_unplug_any_sb_offline(struct virtio_mem *vm,
} }
/* /*
* Unplug the desired number of plugged subblocks of an online memory block. * Unplug the given plugged subblocks of an online memory block.
* Will skip subblock that are busy.
*
* Will modify the state of the memory block. Might temporarily drop the
* hotplug_mutex.
* *
* Note: Can fail after some subblocks were successfully unplugged. Can * Will modify the state of the memory block.
* return 0 even if subblocks were busy and could not get unplugged.
*/ */
static int virtio_mem_mb_unplug_any_sb_online(struct virtio_mem *vm, static int virtio_mem_mb_unplug_sb_online(struct virtio_mem *vm,
unsigned long mb_id, unsigned long mb_id, int sb_id,
uint64_t *nb_sb) int count)
{ {
const unsigned long nr_pages = PFN_DOWN(vm->subblock_size); const unsigned long nr_pages = PFN_DOWN(vm->subblock_size) * count;
unsigned long start_pfn; unsigned long start_pfn;
int rc, sb_id; int rc;
/*
* 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.
*/
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 &&
!virtio_mem_mb_test_sb_plugged(vm, mb_id, sb_id, 1))
sb_id--;
if (sb_id < 0)
break;
start_pfn = PFN_DOWN(virtio_mem_mb_id_to_phys(mb_id) + start_pfn = PFN_DOWN(virtio_mem_mb_id_to_phys(mb_id) +
sb_id * vm->subblock_size); sb_id * vm->subblock_size);
...@@ -1347,15 +1328,14 @@ static int virtio_mem_mb_unplug_any_sb_online(struct virtio_mem *vm, ...@@ -1347,15 +1328,14 @@ static int virtio_mem_mb_unplug_any_sb_online(struct virtio_mem *vm,
/* whoops, out of memory */ /* whoops, out of memory */
return rc; return rc;
if (rc) if (rc)
/* memory busy, we can't unplug this chunk */ return -EBUSY;
continue;
/* Mark it as fake-offline before unplugging it */ /* Mark it as fake-offline before unplugging it */
virtio_mem_set_fake_offline(start_pfn, nr_pages, true); virtio_mem_set_fake_offline(start_pfn, nr_pages, true);
adjust_managed_page_count(pfn_to_page(start_pfn), -nr_pages); adjust_managed_page_count(pfn_to_page(start_pfn), -nr_pages);
/* Try to unplug the allocated memory */ /* Try to unplug the allocated memory */
rc = virtio_mem_mb_unplug_sb(vm, mb_id, sb_id, 1); rc = virtio_mem_mb_unplug_sb(vm, mb_id, sb_id, count);
if (rc) { if (rc) {
/* Return the memory to the buddy. */ /* Return the memory to the buddy. */
virtio_mem_fake_online(start_pfn, nr_pages); virtio_mem_fake_online(start_pfn, nr_pages);
...@@ -1364,9 +1344,55 @@ static int virtio_mem_mb_unplug_any_sb_online(struct virtio_mem *vm, ...@@ -1364,9 +1344,55 @@ static int virtio_mem_mb_unplug_any_sb_online(struct virtio_mem *vm,
virtio_mem_mb_set_state(vm, mb_id, virtio_mem_mb_set_state(vm, mb_id,
VIRTIO_MEM_MB_STATE_ONLINE_PARTIAL); 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.
*
* Will modify the state of the memory block. Might temporarily drop the
* hotplug_mutex.
*
* Note: Can fail after some subblocks were successfully unplugged. Can
* return 0 even if subblocks were busy and could not get unplugged.
*/
static int virtio_mem_mb_unplug_any_sb_online(struct virtio_mem *vm,
unsigned long mb_id,
uint64_t *nb_sb)
{
int rc, sb_id;
/* 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 &&
!virtio_mem_mb_test_sb_plugged(vm, mb_id, sb_id, 1))
sb_id--;
if (sb_id < 0)
break;
rc = virtio_mem_mb_unplug_sb_online(vm, mb_id, sb_id, 1);
if (rc == -EBUSY)
continue;
else if (rc)
return rc;
*nb_sb -= 1; *nb_sb -= 1;
} }
unplugged:
/* /*
* Once all subblocks of a memory block were unplugged, offline and * Once all subblocks of a memory block were unplugged, offline and
* remove it. This will usually not fail, as no memory is in use * remove it. This will usually not fail, as no memory is in use
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册