xen/balloon: Mark unallocated host memory as UNUSABLE

Commit f5775e0b6116 ("x86/xen: discard RAM regions above the maximum
reservation") left host memory not assigned to dom0 as available for
memory hotplug.

Unfortunately this also meant that those regions could be used by
others. Specifically, commit fa564ad96366 ("x86/PCI: Enable a 64bit BAR
on AMD Family 15h (Models 00-1f, 30-3f, 60-7f)") may try to map those
addresses as MMIO.

To prevent this mark unallocated host memory as E820_TYPE_UNUSABLE (thus
effectively reverting f5775e0b6116) and keep track of that region as
a hostmem resource that can be used for the hotplug.

Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: Juergen Gross <jgross@suse.com>

+144 -13
+81
arch/x86/xen/enlighten.c
··· 1 #include <linux/cpu.h> 2 #include <linux/kexec.h> 3 4 #include <xen/features.h> 5 #include <xen/page.h> 6 7 #include <asm/xen/hypercall.h> 8 #include <asm/xen/hypervisor.h> ··· 335 } 336 EXPORT_SYMBOL(xen_arch_unregister_cpu); 337 #endif
··· 1 + #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG 2 + #include <linux/bootmem.h> 3 + #endif 4 #include <linux/cpu.h> 5 #include <linux/kexec.h> 6 7 #include <xen/features.h> 8 #include <xen/page.h> 9 + #include <xen/interface/memory.h> 10 11 #include <asm/xen/hypercall.h> 12 #include <asm/xen/hypervisor.h> ··· 331 } 332 EXPORT_SYMBOL(xen_arch_unregister_cpu); 333 #endif 334 + 335 + #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG 336 + void __init arch_xen_balloon_init(struct resource *hostmem_resource) 337 + { 338 + struct xen_memory_map memmap; 339 + int rc; 340 + unsigned int i, last_guest_ram; 341 + phys_addr_t max_addr = PFN_PHYS(max_pfn); 342 + struct e820_table *xen_e820_table; 343 + const struct e820_entry *entry; 344 + struct resource *res; 345 + 346 + if (!xen_initial_domain()) 347 + return; 348 + 349 + xen_e820_table = kmalloc(sizeof(*xen_e820_table), GFP_KERNEL); 350 + if (!xen_e820_table) 351 + return; 352 + 353 + memmap.nr_entries = ARRAY_SIZE(xen_e820_table->entries); 354 + set_xen_guest_handle(memmap.buffer, xen_e820_table->entries); 355 + rc = HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap); 356 + if (rc) { 357 + pr_warn("%s: Can't read host e820 (%d)\n", __func__, rc); 358 + goto out; 359 + } 360 + 361 + last_guest_ram = 0; 362 + for (i = 0; i < memmap.nr_entries; i++) { 363 + if (xen_e820_table->entries[i].addr >= max_addr) 364 + break; 365 + if (xen_e820_table->entries[i].type == E820_TYPE_RAM) 366 + last_guest_ram = i; 367 + } 368 + 369 + entry = &xen_e820_table->entries[last_guest_ram]; 370 + if (max_addr >= entry->addr + entry->size) 371 + goto out; /* No unallocated host RAM. */ 372 + 373 + hostmem_resource->start = max_addr; 374 + hostmem_resource->end = entry->addr + entry->size; 375 + 376 + /* 377 + * Mark non-RAM regions between the end of dom0 RAM and end of host RAM 378 + * as unavailable. The rest of that region can be used for hotplug-based 379 + * ballooning. 380 + */ 381 + for (; i < memmap.nr_entries; i++) { 382 + entry = &xen_e820_table->entries[i]; 383 + 384 + if (entry->type == E820_TYPE_RAM) 385 + continue; 386 + 387 + if (entry->addr >= hostmem_resource->end) 388 + break; 389 + 390 + res = kzalloc(sizeof(*res), GFP_KERNEL); 391 + if (!res) 392 + goto out; 393 + 394 + res->name = "Unavailable host RAM"; 395 + res->start = entry->addr; 396 + res->end = (entry->addr + entry->size < hostmem_resource->end) ? 397 + entry->addr + entry->size : hostmem_resource->end; 398 + rc = insert_resource(hostmem_resource, res); 399 + if (rc) { 400 + pr_warn("%s: Can't insert [%llx - %llx) (%d)\n", 401 + __func__, res->start, res->end, rc); 402 + kfree(res); 403 + goto out; 404 + } 405 + } 406 + 407 + out: 408 + kfree(xen_e820_table); 409 + } 410 + #endif /* CONFIG_XEN_BALLOON_MEMORY_HOTPLUG */
+2 -4
arch/x86/xen/setup.c
··· 807 addr = xen_e820_table.entries[0].addr; 808 size = xen_e820_table.entries[0].size; 809 while (i < xen_e820_table.nr_entries) { 810 - bool discard = false; 811 812 chunk_size = size; 813 type = xen_e820_table.entries[i].type; ··· 822 xen_add_extra_mem(pfn_s, n_pfns); 823 xen_max_p2m_pfn = pfn_s + n_pfns; 824 } else 825 - discard = true; 826 } 827 828 - if (!discard) 829 - xen_align_and_add_e820_region(addr, chunk_size, type); 830 831 addr += chunk_size; 832 size -= chunk_size;
··· 807 addr = xen_e820_table.entries[0].addr; 808 size = xen_e820_table.entries[0].size; 809 while (i < xen_e820_table.nr_entries) { 810 811 chunk_size = size; 812 type = xen_e820_table.entries[i].type; ··· 823 xen_add_extra_mem(pfn_s, n_pfns); 824 xen_max_p2m_pfn = pfn_s + n_pfns; 825 } else 826 + type = E820_TYPE_UNUSABLE; 827 } 828 829 + xen_align_and_add_e820_region(addr, chunk_size, type); 830 831 addr += chunk_size; 832 size -= chunk_size;
+56 -9
drivers/xen/balloon.c
··· 257 kfree(resource); 258 } 259 260 static struct resource *additional_memory_resource(phys_addr_t size) 261 { 262 - struct resource *res; 263 - int ret; 264 265 res = kzalloc(sizeof(*res), GFP_KERNEL); 266 if (!res) ··· 284 res->name = "System RAM"; 285 res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; 286 287 - ret = allocate_resource(&iomem_resource, res, 288 - size, 0, -1, 289 - PAGES_PER_SECTION * PAGE_SIZE, NULL, NULL); 290 - if (ret < 0) { 291 - pr_err("Cannot allocate new System RAM resource\n"); 292 - kfree(res); 293 - return NULL; 294 } 295 296 #ifdef CONFIG_SPARSEMEM ··· 331 pr_err("New System RAM resource outside addressable RAM (%lu > %lu)\n", 332 pfn, limit); 333 release_memory_resource(res); 334 return NULL; 335 } 336 } ··· 810 set_online_page_callback(&xen_online_page); 811 register_memory_notifier(&xen_memory_nb); 812 register_sysctl_table(xen_root); 813 #endif 814 815 #ifdef CONFIG_XEN_PV
··· 257 kfree(resource); 258 } 259 260 + /* 261 + * Host memory not allocated to dom0. We can use this range for hotplug-based 262 + * ballooning. 263 + * 264 + * It's a type-less resource. Setting IORESOURCE_MEM will make resource 265 + * management algorithms (arch_remove_reservations()) look into guest e820, 266 + * which we don't want. 267 + */ 268 + static struct resource hostmem_resource = { 269 + .name = "Host RAM", 270 + }; 271 + 272 + void __attribute__((weak)) __init arch_xen_balloon_init(struct resource *res) 273 + {} 274 + 275 static struct resource *additional_memory_resource(phys_addr_t size) 276 { 277 + struct resource *res, *res_hostmem; 278 + int ret = -ENOMEM; 279 280 res = kzalloc(sizeof(*res), GFP_KERNEL); 281 if (!res) ··· 269 res->name = "System RAM"; 270 res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; 271 272 + res_hostmem = kzalloc(sizeof(*res), GFP_KERNEL); 273 + if (res_hostmem) { 274 + /* Try to grab a range from hostmem */ 275 + res_hostmem->name = "Host memory"; 276 + ret = allocate_resource(&hostmem_resource, res_hostmem, 277 + size, 0, -1, 278 + PAGES_PER_SECTION * PAGE_SIZE, NULL, NULL); 279 + } 280 + 281 + if (!ret) { 282 + /* 283 + * Insert this resource into iomem. Because hostmem_resource 284 + * tracks portion of guest e820 marked as UNUSABLE noone else 285 + * should try to use it. 286 + */ 287 + res->start = res_hostmem->start; 288 + res->end = res_hostmem->end; 289 + ret = insert_resource(&iomem_resource, res); 290 + if (ret < 0) { 291 + pr_err("Can't insert iomem_resource [%llx - %llx]\n", 292 + res->start, res->end); 293 + release_memory_resource(res_hostmem); 294 + res_hostmem = NULL; 295 + res->start = res->end = 0; 296 + } 297 + } 298 + 299 + if (ret) { 300 + ret = allocate_resource(&iomem_resource, res, 301 + size, 0, -1, 302 + PAGES_PER_SECTION * PAGE_SIZE, NULL, NULL); 303 + if (ret < 0) { 304 + pr_err("Cannot allocate new System RAM resource\n"); 305 + kfree(res); 306 + return NULL; 307 + } 308 } 309 310 #ifdef CONFIG_SPARSEMEM ··· 287 pr_err("New System RAM resource outside addressable RAM (%lu > %lu)\n", 288 pfn, limit); 289 release_memory_resource(res); 290 + release_memory_resource(res_hostmem); 291 return NULL; 292 } 293 } ··· 765 set_online_page_callback(&xen_online_page); 766 register_memory_notifier(&xen_memory_nb); 767 register_sysctl_table(xen_root); 768 + 769 + arch_xen_balloon_init(&hostmem_resource); 770 #endif 771 772 #ifdef CONFIG_XEN_PV
+5
include/xen/balloon.h
··· 43 { 44 } 45 #endif
··· 43 { 44 } 45 #endif 46 + 47 + #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG 48 + struct resource; 49 + void arch_xen_balloon_init(struct resource *hostmem_resource); 50 + #endif