Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

virtio-mem: check if the config changed before fake offlining memory

If we repeatedly fail to fake offline memory to unplug it, we won't be
sending any unplug requests to the device. However, we only check if the
config changed when sending such (un)plug requests.

We could end up trying for a long time to unplug memory, even though
the config changed already and we're not supposed to unplug memory
anymore. For example, the hypervisor might detect a low-memory situation
while unplugging memory and decide to replug some memory. Continuing
trying to unplug memory in that case can be problematic.

So let's check on a more regular basis.

Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20230713145551.2824980-5-david@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

authored by

David Hildenbrand and committed by
Michael S. Tsirkin
f55484fd a31648fd

+12 -3
+12 -3
drivers/virtio/virtio_mem.c
··· 1189 1189 * Try to allocate a range, marking pages fake-offline, effectively 1190 1190 * fake-offlining them. 1191 1191 */ 1192 - static int virtio_mem_fake_offline(unsigned long pfn, unsigned long nr_pages) 1192 + static int virtio_mem_fake_offline(struct virtio_mem *vm, unsigned long pfn, 1193 + unsigned long nr_pages) 1193 1194 { 1194 1195 const bool is_movable = is_zone_movable_page(pfn_to_page(pfn)); 1195 1196 int rc, retry_count; ··· 1203 1202 * some guarantees. 1204 1203 */ 1205 1204 for (retry_count = 0; retry_count < 5; retry_count++) { 1205 + /* 1206 + * If the config changed, stop immediately and go back to the 1207 + * main loop: avoid trying to keep unplugging if the device 1208 + * might have decided to not remove any more memory. 1209 + */ 1210 + if (atomic_read(&vm->config_changed)) 1211 + return -EAGAIN; 1212 + 1206 1213 rc = alloc_contig_range(pfn, pfn + nr_pages, MIGRATE_MOVABLE, 1207 1214 GFP_KERNEL); 1208 1215 if (rc == -ENOMEM) ··· 1960 1951 start_pfn = PFN_DOWN(virtio_mem_mb_id_to_phys(mb_id) + 1961 1952 sb_id * vm->sbm.sb_size); 1962 1953 1963 - rc = virtio_mem_fake_offline(start_pfn, nr_pages); 1954 + rc = virtio_mem_fake_offline(vm, start_pfn, nr_pages); 1964 1955 if (rc) 1965 1956 return rc; 1966 1957 ··· 2158 2149 if (!page) 2159 2150 continue; 2160 2151 2161 - rc = virtio_mem_fake_offline(pfn, PAGES_PER_SECTION); 2152 + rc = virtio_mem_fake_offline(vm, pfn, PAGES_PER_SECTION); 2162 2153 if (rc) { 2163 2154 end_pfn = pfn; 2164 2155 goto rollback;