Skip to content

Commit c740bb9

Browse files
davidhildenbrandmstsirkin
authored andcommitted
virtio-mem: prioritize unplug from ZONE_MOVABLE in Sub Block Mode
Until now, memory provided by a single virtio-mem device was usually either onlined completely to ZONE_MOVABLE (online_movable) or to ZONE_NORMAL (online_kernel); however, that will change in the future. There are two reasons why we want to track to which zone a memory blocks belongs to and prioritize ZONE_MOVABLE blocks: 1) Memory managed by ZONE_MOVABLE can more likely get unplugged, therefore, resulting in a faster memory hotunplug process. Further, we can more reliably unplug and remove complete memory blocks, removing metadata allocated for the whole memory block. 2) We want to avoid corner cases where unplugging with the current scheme (highest to lowest address) could result in accidential zone imbalances, whereby we remove too much ZONE_NORMAL memory for ZONE_MOVABLE memory of the same device. Let's track the zone via memory block states and try unplug from ZONE_MOVABLE first. Rename VIRTIO_MEM_SBM_MB_ONLINE* to VIRTIO_MEM_SBM_MB_KERNEL* to avoid even longer state names. In commit 27f8527 ("virtio-mem: don't special-case ZONE_MOVABLE"), we removed slightly similar tracking for fully plugged memory blocks to support unplugging from ZONE_MOVABLE at all -- as we didn't allow partially plugged memory blocks in ZONE_MOVABLE before that. That commit already mentioned "In the future, we might want to remember the zone again and use the information when (un)plugging memory." Signed-off-by: David Hildenbrand <david@redhat.com> Link: https://lore.kernel.org/r/20210602185720.31821-6-david@redhat.com Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
1 parent 5304ca3 commit c740bb9

1 file changed

Lines changed: 52 additions & 20 deletions

File tree

drivers/virtio/virtio_mem.c

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,14 @@ enum virtio_mem_sbm_mb_state {
7575
VIRTIO_MEM_SBM_MB_OFFLINE,
7676
/* Partially plugged, fully added to Linux, offline. */
7777
VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL,
78-
/* Fully plugged, fully added to Linux, online. */
79-
VIRTIO_MEM_SBM_MB_ONLINE,
80-
/* Partially plugged, fully added to Linux, online. */
81-
VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL,
78+
/* Fully plugged, fully added to Linux, onlined to a kernel zone. */
79+
VIRTIO_MEM_SBM_MB_KERNEL,
80+
/* Partially plugged, fully added to Linux, online to a kernel zone */
81+
VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL,
82+
/* Fully plugged, fully added to Linux, onlined to ZONE_MOVABLE. */
83+
VIRTIO_MEM_SBM_MB_MOVABLE,
84+
/* Partially plugged, fully added to Linux, onlined to ZONE_MOVABLE. */
85+
VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL,
8286
VIRTIO_MEM_SBM_MB_COUNT
8387
};
8488

@@ -832,11 +836,13 @@ static void virtio_mem_sbm_notify_offline(struct virtio_mem *vm,
832836
unsigned long mb_id)
833837
{
834838
switch (virtio_mem_sbm_get_mb_state(vm, mb_id)) {
835-
case VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL:
839+
case VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL:
840+
case VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL:
836841
virtio_mem_sbm_set_mb_state(vm, mb_id,
837842
VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL);
838843
break;
839-
case VIRTIO_MEM_SBM_MB_ONLINE:
844+
case VIRTIO_MEM_SBM_MB_KERNEL:
845+
case VIRTIO_MEM_SBM_MB_MOVABLE:
840846
virtio_mem_sbm_set_mb_state(vm, mb_id,
841847
VIRTIO_MEM_SBM_MB_OFFLINE);
842848
break;
@@ -847,21 +853,29 @@ static void virtio_mem_sbm_notify_offline(struct virtio_mem *vm,
847853
}
848854

849855
static void virtio_mem_sbm_notify_online(struct virtio_mem *vm,
850-
unsigned long mb_id)
856+
unsigned long mb_id,
857+
unsigned long start_pfn)
851858
{
859+
const bool is_movable = page_zonenum(pfn_to_page(start_pfn)) ==
860+
ZONE_MOVABLE;
861+
int new_state;
862+
852863
switch (virtio_mem_sbm_get_mb_state(vm, mb_id)) {
853864
case VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL:
854-
virtio_mem_sbm_set_mb_state(vm, mb_id,
855-
VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL);
865+
new_state = VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL;
866+
if (is_movable)
867+
new_state = VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL;
856868
break;
857869
case VIRTIO_MEM_SBM_MB_OFFLINE:
858-
virtio_mem_sbm_set_mb_state(vm, mb_id,
859-
VIRTIO_MEM_SBM_MB_ONLINE);
870+
new_state = VIRTIO_MEM_SBM_MB_KERNEL;
871+
if (is_movable)
872+
new_state = VIRTIO_MEM_SBM_MB_MOVABLE;
860873
break;
861874
default:
862875
BUG();
863876
break;
864877
}
878+
virtio_mem_sbm_set_mb_state(vm, mb_id, new_state);
865879
}
866880

867881
static void virtio_mem_sbm_notify_going_offline(struct virtio_mem *vm,
@@ -1015,7 +1029,7 @@ static int virtio_mem_memory_notifier_cb(struct notifier_block *nb,
10151029
break;
10161030
case MEM_ONLINE:
10171031
if (vm->in_sbm)
1018-
virtio_mem_sbm_notify_online(vm, id);
1032+
virtio_mem_sbm_notify_online(vm, id, mhp->start_pfn);
10191033

10201034
atomic64_sub(size, &vm->offline_size);
10211035
/*
@@ -1626,7 +1640,8 @@ static int virtio_mem_sbm_plug_any_sb(struct virtio_mem *vm,
16261640
static int virtio_mem_sbm_plug_request(struct virtio_mem *vm, uint64_t diff)
16271641
{
16281642
const int mb_states[] = {
1629-
VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL,
1643+
VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL,
1644+
VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL,
16301645
VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL,
16311646
};
16321647
uint64_t nb_sb = diff / vm->sbm.sb_size;
@@ -1843,6 +1858,7 @@ static int virtio_mem_sbm_unplug_sb_online(struct virtio_mem *vm,
18431858
int count)
18441859
{
18451860
const unsigned long nr_pages = PFN_DOWN(vm->sbm.sb_size) * count;
1861+
const int old_state = virtio_mem_sbm_get_mb_state(vm, mb_id);
18461862
unsigned long start_pfn;
18471863
int rc;
18481864

@@ -1861,8 +1877,17 @@ static int virtio_mem_sbm_unplug_sb_online(struct virtio_mem *vm,
18611877
return rc;
18621878
}
18631879

1864-
virtio_mem_sbm_set_mb_state(vm, mb_id,
1865-
VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL);
1880+
switch (old_state) {
1881+
case VIRTIO_MEM_SBM_MB_KERNEL:
1882+
virtio_mem_sbm_set_mb_state(vm, mb_id,
1883+
VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL);
1884+
break;
1885+
case VIRTIO_MEM_SBM_MB_MOVABLE:
1886+
virtio_mem_sbm_set_mb_state(vm, mb_id,
1887+
VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL);
1888+
break;
1889+
}
1890+
18661891
return 0;
18671892
}
18681893

@@ -1948,8 +1973,10 @@ static int virtio_mem_sbm_unplug_any_sb(struct virtio_mem *vm,
19481973
const int old_state = virtio_mem_sbm_get_mb_state(vm, mb_id);
19491974

19501975
switch (old_state) {
1951-
case VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL:
1952-
case VIRTIO_MEM_SBM_MB_ONLINE:
1976+
case VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL:
1977+
case VIRTIO_MEM_SBM_MB_KERNEL:
1978+
case VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL:
1979+
case VIRTIO_MEM_SBM_MB_MOVABLE:
19531980
return virtio_mem_sbm_unplug_any_sb_online(vm, mb_id, nb_sb);
19541981
case VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL:
19551982
case VIRTIO_MEM_SBM_MB_OFFLINE:
@@ -1963,8 +1990,10 @@ static int virtio_mem_sbm_unplug_request(struct virtio_mem *vm, uint64_t diff)
19631990
const int mb_states[] = {
19641991
VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL,
19651992
VIRTIO_MEM_SBM_MB_OFFLINE,
1966-
VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL,
1967-
VIRTIO_MEM_SBM_MB_ONLINE,
1993+
VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL,
1994+
VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL,
1995+
VIRTIO_MEM_SBM_MB_MOVABLE,
1996+
VIRTIO_MEM_SBM_MB_KERNEL,
19681997
};
19691998
uint64_t nb_sb = diff / vm->sbm.sb_size;
19701999
unsigned long mb_id;
@@ -1982,7 +2011,10 @@ static int virtio_mem_sbm_unplug_request(struct virtio_mem *vm, uint64_t diff)
19822011

19832012
/*
19842013
* We try unplug from partially plugged blocks first, to try removing
1985-
* whole memory blocks along with metadata.
2014+
* whole memory blocks along with metadata. We prioritize ZONE_MOVABLE
2015+
* as it's more reliable to unplug memory and remove whole memory
2016+
* blocks, and we don't want to trigger a zone imbalances by
2017+
* accidentially removing too much kernel memory.
19862018
*/
19872019
for (i = 0; i < ARRAY_SIZE(mb_states); i++) {
19882020
virtio_mem_sbm_for_each_mb_rev(vm, mb_id, mb_states[i]) {

0 commit comments

Comments
 (0)