getting memory footprint of new kernel
Subsystems (4)
I'm working on kexec support for a ballooned Xen PVonHVM guest.
One of the issues is that the new kernel must run in populated memory, otherwise it will access ballooned pages and crash.
The kexec syscall passes several physical memory ranges in kexec_segment->{mem,memsz}. Thats enough info to populate the purgatory code and early startup code of the new kernel.
But it lacks the memory range of the new kernel. From my understanding the entry point is know by kexec(1), it is kexec/arch/i386/kexec-bzImage.c:do_bzImage_load():kernel32_load_addr The memory size howver is not known, and I dont see a way to retreive this information from a bzImage. I think it should be all in the ELF data of the compressed vmlinux.bin, but this compressed content is not accessible.
So what would be a good way to know or estimate the memory size of the new kernel, and pass the start and size to the balloon driver so that it can populate the range? I see there are already a few kexec related sysfs files in kernel/ksysfs.c. What about something like kexec_newkernel_phys and kexec_newkernel_memsz?
Olaf
_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
PATCH 1/2 kexec_newkernel_phys and kexec_newkernel_memsz
This adds sysfs entries /sys/kernel/kexec_newkernel_phys and /sys/kernel/kexec_newkernel_memsz. Both are supposed to be passed to a balloon driver.
--- include/linux/kexec.h | 5 +++++ kernel/kexec.c | 24 ++++++++++++++++++++++++ kernel/ksysfs.c | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+)
include/linux/kexec.h +5 -0
@@ -203,6 +203,11 @@ int crash_shrink_memory(unsigned long new_size);size_t crash_get_memory_size (void );void crash_free_reserved_phys_range (unsigned long begin,unsigned long end); +unsigned long kexec_newkernel_get_phys (void ); +void kexec_newkernel_set_phys (unsigned long phys); +unsigned long kexec_newkernel_get_memsz (void ); +void kexec_newkernel_set_memsz (unsigned long memsz); +#else /* !CONFIG_KEXEC */ struct pt_regs ;struct task_struct ;
kernel/kexec.c +24 -0
@@ -38,6 +38,9 @@#include <asm/io.h> #include <asm/sections.h> +static unsigned long kexec_newkernel_phys; +static unsigned long kexec_newkernel_memsz; +/* Per cpu memory for storing cpu states in case of system crash. */ note_buf_t __percpu *crash_notes;
@@ -62,6 +65,27 @@ int kexec_should_crash(struct task_struct *p)return 0 ; } +unsigned long kexec_newkernel_get_phys (void ) +{ +return kexec_newkernel_phys; +} + +void kexec_newkernel_set_phys (unsigned long phys) +{ +printk ("%s: kexec_newkernel_phys %lx -> %lx\n" , __func__, kexec_newkernel_phys, phys); + kexec_newkernel_phys = phys; +} + +unsigned long kexec_newkernel_get_memsz (void ) +{ +return kexec_newkernel_memsz; +} + +void kexec_newkernel_set_memsz (unsigned long memsz) +{ +printk ("%s: kexec_newkernel_mensz %lx -> %lx\n" , __func__, kexec_newkernel_memsz, memsz); + kexec_newkernel_memsz = memsz; +}/* * When kexec transitions to the new kernel there is a one-to-one * mapping between physical and virtual addresses. On processors
kernel/ksysfs.c +40 -0
@@ -121,6 +121,44 @@ static ssize_t kexec_crash_size_store(struct kobject *kobj, }KERNEL_ATTR_RW (kexec_crash_size); +static ssize_t kexec_newkernel_phys_show (struct kobject *kobj, +struct kobj_attribute *attr,char *buf) +{ +return sprintf (buf,"%zu\n" ,kexec_newkernel_get_phys ()); +} +static ssize_t kexec_newkernel_phys_store (struct kobject *kobj, +struct kobj_attribute *attr, +const char *buf,size_t count) +{ +unsigned long phys; + +if (strict_strtoul (buf,0 , &phys)) +return -EINVAL ; + +kexec_newkernel_set_phys (phys); +return count; +} +KERNEL_ATTR_RW (kexec_newkernel_phys); + +static ssize_t kexec_newkernel_memsz_show (struct kobject *kobj, +struct kobj_attribute *attr,char *buf) +{ +return sprintf (buf,"%zu\n" ,kexec_newkernel_get_memsz ()); +} +static ssize_t kexec_newkernel_memsz_store (struct kobject *kobj, +struct kobj_attribute *attr, +const char *buf,size_t count) +{ +unsigned long memsz; + +if (strict_strtoul (buf,0 , &memsz)) +return -EINVAL ; + +kexec_newkernel_set_memsz (memsz); +return count; +} +KERNEL_ATTR_RW (kexec_newkernel_memsz); +static ssize_t vmcoreinfo_show (struct kobject *kobj,struct kobj_attribute *attr,char *buf) {
@@ -194,6 +232,8 @@ static struct attribute * kernel_attrs[] = { &kexec_loaded_attr.attr, &kexec_crash_loaded_attr.attr, &kexec_crash_size_attr.attr, + &kexec_newkernel_phys_attr.attr, + &kexec_newkernel_memsz_attr.attr, &vmcoreinfo_attr.attr, #endif &rcu_expedited_attr.attr,
Signature · 7 lines
1.8.1 _______________________________________________ kexec mailing list [email protected] http://lists.infradead.org/mailman/listinfo/kexec
PATCH 2/2 register_balloon_populate_range
In reply to Olaf HeringThis patch adds a hook for a balloon driver to populate segments before the actual kexec.
--- include/linux/kexec.h | 2 ++ kernel/kexec.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+)
include/linux/kexec.h +2 -0
@@ -207,11 +207,13 @@ unsigned long kexec_newkernel_get_phys(void);void kexec_newkernel_set_phys (unsigned long phys);unsigned long kexec_newkernel_get_memsz (void );void kexec_newkernel_set_memsz (unsigned long memsz); +void register_balloon_populate_range (void (*fn)(unsigned long pfn,unsigned long num));#else /* !CONFIG_KEXEC */ struct pt_regs ;struct task_struct ;static inline void crash_kexec (struct pt_regs *regs) { }static inline int kexec_should_crash (struct task_struct *p) {return 0 ; } +static inline void register_balloon_populate_range (void (*fn)(unsigned long pfn,unsigned long num)) { }#endif /* CONFIG_KEXEC */ #endif /* LINUX_KEXEC_H */
kernel/kexec.c +38 -0
@@ -32,6 +32,7 @@#include <linux/vmalloc.h> #include <linux/swap.h> #include <linux/syscore_ops.h> +#include <linux/export.h> #include <asm/page.h> #include <asm/uaccess.h>
@@ -86,6 +87,41 @@ void kexec_newkernel_set_memsz(unsigned long memsz)printk ("%s: kexec_newkernel_mensz %lx -> %lx\n" , __func__, kexec_newkernel_memsz, memsz); kexec_newkernel_memsz = memsz; } + +static void (*balloon_populate_range)(unsigned long pfn,unsigned long num); + +void register_balloon_populate_range (void (*fn)(unsigned long pfn,unsigned long num)) +{ +if (!balloon_populate_range) + balloon_populate_range = fn; +} +EXPORT_SYMBOL_GPL (register_balloon_populate_range); + +static void populate_range (unsigned long mem,size_t memsz) +{ +unsigned long pfn, num; + + + + pfn =PFN_DOWN (mem); + num =PFN_UP (memsz); +if (pfn && num) +balloon_populate_range (pfn, num); +} + +static void kimage_populate_ranges (struct kimage *image) +{ +unsigned long i; + +if (!balloon_populate_range) +return ; + +for (i =0 ; i < image->nr_segments; i++) +populate_range (image->segment[i].mem, image->segment[i].memsz); + +populate_range (kexec_newkernel_phys, kexec_newkernel_memsz); +} +/* * When kexec transitions to the new kernel there is a one-to-one * mapping between physical and virtual addresses. On processors
@@ -1598,6 +1634,8 @@ int kernel_kexec(void)machine_shutdown (); } +kimage_populate_ranges (kexec_image); +machine_kexec (kexec_image);#ifdef CONFIG_KEXEC_JUMP
Signature · 7 lines
1.8.1 _______________________________________________ kexec mailing list [email protected] http://lists.infradead.org/mailman/listinfo/kexec