kexec adjustments - fix error path after retrieving vmcoreinfo (must no directly return, special casing -EINVAL should only happen if absolutely needed) - improve detection of number of CPUs (utilize platform hypercall) - clean up in error path as far as possible (only after possibly having inserted some or all resources it would be problematic to free the allocated space) - leverage the fact that alloc_bootmem() already clears the memory Signed-off-by: Jan Beulich --- a/drivers/xen/core/machine_kexec.c +++ b/drivers/xen/core/machine_kexec.c @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -17,7 +18,7 @@ extern void machine_kexec_register_resou static int __initdata xen_max_nr_phys_cpus; static struct resource xen_hypervisor_res; -static struct resource *xen_phys_cpus; +static struct resource *__initdata xen_phys_cpus; size_t vmcoreinfo_size_xen; unsigned long paddr_vmcoreinfo_xen; @@ -25,16 +26,21 @@ unsigned long paddr_vmcoreinfo_xen; void __init xen_machine_kexec_setup_resources(void) { xen_kexec_range_t range; + xen_platform_op_t op; struct resource *res; - int k = 0; + unsigned int k = 0, nr = 0; int rc; if (!is_initial_xendomain()) return; /* determine maximum number of physical cpus */ - - while (1) { + op.cmd = XENPF_get_cpuinfo; + op.u.pcpu_info.xen_cpuid = 0; + if (HYPERVISOR_platform_op(&op) == 0) + k = op.u.pcpu_info.max_present + 1; +#if CONFIG_XEN_COMPAT < 0x040000 + else while (1) { memset(&range, 0, sizeof(range)); range.range = KEXEC_RANGE_MA_CPU; range.nr = k; @@ -44,6 +50,7 @@ void __init xen_machine_kexec_setup_reso k++; } +#endif if (k == 0) return; @@ -62,25 +69,27 @@ void __init xen_machine_kexec_setup_reso range.range = KEXEC_RANGE_MA_CPU; range.nr = k; - if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) - goto err; - - res = xen_phys_cpus + k; + if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range) + || range.size == 0) + continue; - memset(res, 0, sizeof(*res)); + res = xen_phys_cpus + nr++; res->name = "Crash note"; res->start = range.start; res->end = range.start + range.size - 1; res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; } + if (nr == 0) + goto free; + /* fill in xen_hypervisor_res with hypervisor machine address range */ memset(&range, 0, sizeof(range)); range.range = KEXEC_RANGE_MA_XEN; if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) - goto err; + goto free; xen_hypervisor_res.name = "Hypervisor code and data"; xen_hypervisor_res.start = range.start; @@ -93,7 +102,7 @@ void __init xen_machine_kexec_setup_reso range.range = KEXEC_RANGE_MA_CRASH; if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) - goto err; + goto free; if (range.size) { crashk_res.start = range.start; @@ -118,28 +127,35 @@ void __init xen_machine_kexec_setup_reso vmcoreinfo_size_xen = 0; paddr_vmcoreinfo_xen = 0; +#if CONFIG_XEN_COMPAT < 0x030300 /* The KEXEC_CMD_kexec_get_range hypercall did not implement * KEXEC_RANGE_MA_VMCOREINFO until Xen 3.3. * Do not bail out if it fails for this reason. */ if (rc != -EINVAL) - return; +#endif + goto free; } if (machine_kexec_setup_resources(&xen_hypervisor_res, xen_phys_cpus, - xen_max_nr_phys_cpus)) + nr)) { + /* + * It's too cumbersome to properly free xen_phys_cpus here. + * Failure at this stage is unexpected and the amount of + * memory is small therefore we tolerate the potential leak. + */ goto err; + } + + xen_max_nr_phys_cpus = nr; return; + free: + free_bootmem(__pa(xen_phys_cpus), + xen_max_nr_phys_cpus * sizeof(*xen_phys_cpus)); err: - /* - * It isn't possible to free xen_phys_cpus this early in the - * boot. Failure at this stage is unexpected and the amount of - * memory is small therefore we tolerate the potential leak. - */ xen_max_nr_phys_cpus = 0; - return; } void __init xen_machine_kexec_register_resources(struct resource *res)