With MHP_MEMMAP_ON_MEMORY, the core excludes the memmap at the start of each memory block from the range passed to memory notifiers. The virtio-mem notifier does not expect that:
* In Sub Block Mode, it rejects any range that is not exactly one aligned memory block with a WARN and NOTIFY_BAD. * It adjusts offline_size by the notified size, while adding and removing memory use the full size. Every onlined memory block would leave its memmap size behind in offline_size, until the offline threshold stops further hotplug. Track the memmap pages per memory block in vm->memmap_pages, expect the notified range to start after the memmap in Sub Block Mode, and include the memmap when adjusting offline_size. vm->memmap_pages is always 0 for now, so there is no functional change. Assisted-by: LLM Signed-off-by: Nikolaos Karaolidis <[email protected]> --- drivers/virtio/virtio_mem.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c index e18dd736f2ec..ab06adbc0342 100644 --- a/drivers/virtio/virtio_mem.c +++ b/drivers/virtio/virtio_mem.c @@ -158,6 +158,9 @@ struct virtio_mem { /* If set, the driver is in SBM, otherwise in BBM. */ bool in_sbm; + /* Pages at the start of each Linux memory block hosting its memmap. */ + unsigned long memmap_pages; + union { struct { /* Id of the first memory block of this device. */ @@ -995,21 +998,23 @@ static int virtio_mem_memory_notifier_cb(struct notifier_block *nb, struct memory_notify *mhp = arg; const unsigned long start = PFN_PHYS(mhp->start_pfn); const unsigned long size = PFN_PHYS(mhp->nr_pages); + const unsigned long memmap_size = PFN_PHYS(vm->memmap_pages); int rc = NOTIFY_OK; - unsigned long id; + unsigned long id, mb_start; if (!virtio_mem_overlaps_range(vm, start, size)) return NOTIFY_DONE; if (vm->in_sbm) { id = virtio_mem_phys_to_mb_id(start); + mb_start = virtio_mem_mb_id_to_phys(id); /* * In SBM, we add memory in separate memory blocks - we expect - * it to be onlined/offlined in the same granularity. Bail out - * if this ever changes. + * it to be onlined/offlined in the same granularity, excluding + * a self-hosted memmap. Bail out if this ever changes. */ - if (WARN_ON_ONCE(size != memory_block_size_bytes() || - !IS_ALIGNED(start, memory_block_size_bytes()))) + if (WARN_ON_ONCE(start != mb_start + memmap_size || + size != memory_block_size_bytes() - memmap_size)) return NOTIFY_BAD; } else { id = virtio_mem_phys_to_bb_id(vm, start); @@ -1062,7 +1067,8 @@ static int virtio_mem_memory_notifier_cb(struct notifier_block *nb, if (vm->in_sbm) virtio_mem_sbm_notify_offline(vm, id); - atomic64_add(size, &vm->offline_size); + /* Adding/removing memory accounts the memmap as well. */ + atomic64_add(size + memmap_size, &vm->offline_size); /* * Trigger the workqueue. Now that we have some offline memory, * maybe we can handle pending unplug requests. @@ -1077,7 +1083,7 @@ static int virtio_mem_memory_notifier_cb(struct notifier_block *nb, if (vm->in_sbm) virtio_mem_sbm_notify_online(vm, id, mhp->start_pfn); - atomic64_sub(size, &vm->offline_size); + atomic64_sub(size + memmap_size, &vm->offline_size); /* * Start adding more memory once we onlined half of our * threshold. Don't trigger if it's possibly due to our action -- 2.55.0
