Mailing List Archive

[PATCH] linux-2.6.18: 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 <jbeulich@suse.com>

--- a/drivers/xen/core/machine_kexec.c
+++ b/drivers/xen/core/machine_kexec.c
@@ -5,6 +5,7 @@

#include <linux/kexec.h>
#include <xen/interface/kexec.h>
+#include <xen/interface/platform.h>
#include <linux/mm.h>
#include <linux/bootmem.h>

@@ -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)