Message ID | 20231114091658.228030-2-bhe@redhat.com (mailing list archive) |
---|---|
State | Handled Elsewhere |
Headers | show |
Series | kexec_file: Load kernel at top of system RAM if required | expand |
On Tue, 14 Nov 2023 17:16:57 +0800 Baoquan He <bhe@redhat.com> wrote: > This function, being a variant of walk_system_ram_res() introduced in > commit 8c86e70acead ("resource: provide new functions to walk through > resources"), walks through a list of all the resources of System RAM > in reversed order, i.e., from higher to lower. > > It will be used in kexec_file code to load kernel, initrd etc when > preparing kexec reboot. > > ... > > +/* > + * This function, being a variant of walk_system_ram_res(), calls the @func > + * callback against all memory ranges of type System RAM which are marked as > + * IORESOURCE_SYSTEM_RAM and IORESOUCE_BUSY in reversed order, i.e., from > + * higher to lower. > + */ > +int walk_system_ram_res_rev(u64 start, u64 end, void *arg, > + int (*func)(struct resource *, void *)) > +{ > + struct resource res, *rams; > + int rams_size = 16, i; > + unsigned long flags; > + int ret = -1; > + > + /* create a list */ > + rams = kvcalloc(rams_size, sizeof(struct resource), GFP_KERNEL); > + if (!rams) > + return ret; > + > + flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; > + i = 0; > + while ((start < end) && > + (!find_next_iomem_res(start, end, flags, IORES_DESC_NONE, &res))) { > + if (i >= rams_size) { > + /* re-alloc */ > + struct resource *rams_new; > + int rams_new_size; > + > + rams_new_size = rams_size + 16; > + rams_new = kvcalloc(rams_new_size, sizeof(struct resource), > + GFP_KERNEL); kvrealloc()? > + if (!rams_new) > + goto out; > + > + memcpy(rams_new, rams, > + sizeof(struct resource) * rams_size); > + kvfree(rams); > + rams = rams_new; > + rams_size = rams_new_size; > + } > + > + rams[i].start = res.start; > + rams[i++].end = res.end; > + > + start = res.end + 1; > + } > + > + /* go reverse */ > + for (i--; i >= 0; i--) { > + ret = (*func)(&rams[i], arg); > + if (ret) > + break; > + } > + > +out: > + kvfree(rams); > + return ret; > +} > + > /* > * This function calls the @func callback against all memory ranges, which > * are ranges marked as IORESOURCE_MEM and IORESOUCE_BUSY. > -- > 2.41.0
On 11/14/23 at 03:17pm, Andrew Morton wrote: > On Tue, 14 Nov 2023 17:16:57 +0800 Baoquan He <bhe@redhat.com> wrote: > > > This function, being a variant of walk_system_ram_res() introduced in > > commit 8c86e70acead ("resource: provide new functions to walk through > > resources"), walks through a list of all the resources of System RAM > > in reversed order, i.e., from higher to lower. > > > > It will be used in kexec_file code to load kernel, initrd etc when > > preparing kexec reboot. > > > > ... > > > > +/* > > + * This function, being a variant of walk_system_ram_res(), calls the @func > > + * callback against all memory ranges of type System RAM which are marked as > > + * IORESOURCE_SYSTEM_RAM and IORESOUCE_BUSY in reversed order, i.e., from > > + * higher to lower. > > + */ > > +int walk_system_ram_res_rev(u64 start, u64 end, void *arg, > > + int (*func)(struct resource *, void *)) > > +{ > > + struct resource res, *rams; > > + int rams_size = 16, i; > > + unsigned long flags; > > + int ret = -1; > > + > > + /* create a list */ > > + rams = kvcalloc(rams_size, sizeof(struct resource), GFP_KERNEL); > > + if (!rams) > > + return ret; > > + > > + flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; > > + i = 0; > > + while ((start < end) && > > + (!find_next_iomem_res(start, end, flags, IORES_DESC_NONE, &res))) { > > + if (i >= rams_size) { > > + /* re-alloc */ > > + struct resource *rams_new; > > + int rams_new_size; > > + > > + rams_new_size = rams_size + 16; > > + rams_new = kvcalloc(rams_new_size, sizeof(struct resource), > > + GFP_KERNEL); > > kvrealloc()? Exactly. Will udpate. Thanks for the great suggestion. > > > + if (!rams_new) > > + goto out; > > + > > + memcpy(rams_new, rams, > > + sizeof(struct resource) * rams_size); > > + kvfree(rams); > > + rams = rams_new; > > + rams_size = rams_new_size; > > + } > > + > > + rams[i].start = res.start; > > + rams[i++].end = res.end; > > + > > + start = res.end + 1; > > + } > > + > > + /* go reverse */ > > + for (i--; i >= 0; i--) { > > + ret = (*func)(&rams[i], arg); > > + if (ret) > > + break; > > + } > > + > > +out: > > + kvfree(rams); > > + return ret; > > +} > > + > > /* > > * This function calls the @func callback against all memory ranges, which > > * are ranges marked as IORESOURCE_MEM and IORESOUCE_BUSY. > > -- > > 2.41.0 >
diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 14f5cfabbbc8..db7fe25f3370 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -331,6 +331,9 @@ extern int walk_system_ram_res(u64 start, u64 end, void *arg, int (*func)(struct resource *, void *)); extern int +walk_system_ram_res_rev(u64 start, u64 end, void *arg, + int (*func)(struct resource *, void *)); +extern int walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start, u64 end, void *arg, int (*func)(struct resource *, void *)); diff --git a/kernel/resource.c b/kernel/resource.c index 866ef3663a0b..12bce44a2c08 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -27,6 +27,8 @@ #include <linux/mount.h> #include <linux/resource_ext.h> #include <uapi/linux/magic.h> +#include <linux/string.h> +#include <linux/vmalloc.h> #include <asm/io.h> @@ -429,6 +431,65 @@ int walk_system_ram_res(u64 start, u64 end, void *arg, func); } +/* + * This function, being a variant of walk_system_ram_res(), calls the @func + * callback against all memory ranges of type System RAM which are marked as + * IORESOURCE_SYSTEM_RAM and IORESOUCE_BUSY in reversed order, i.e., from + * higher to lower. + */ +int walk_system_ram_res_rev(u64 start, u64 end, void *arg, + int (*func)(struct resource *, void *)) +{ + struct resource res, *rams; + int rams_size = 16, i; + unsigned long flags; + int ret = -1; + + /* create a list */ + rams = kvcalloc(rams_size, sizeof(struct resource), GFP_KERNEL); + if (!rams) + return ret; + + flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; + i = 0; + while ((start < end) && + (!find_next_iomem_res(start, end, flags, IORES_DESC_NONE, &res))) { + if (i >= rams_size) { + /* re-alloc */ + struct resource *rams_new; + int rams_new_size; + + rams_new_size = rams_size + 16; + rams_new = kvcalloc(rams_new_size, sizeof(struct resource), + GFP_KERNEL); + if (!rams_new) + goto out; + + memcpy(rams_new, rams, + sizeof(struct resource) * rams_size); + kvfree(rams); + rams = rams_new; + rams_size = rams_new_size; + } + + rams[i].start = res.start; + rams[i++].end = res.end; + + start = res.end + 1; + } + + /* go reverse */ + for (i--; i >= 0; i--) { + ret = (*func)(&rams[i], arg); + if (ret) + break; + } + +out: + kvfree(rams); + return ret; +} + /* * This function calls the @func callback against all memory ranges, which * are ranges marked as IORESOURCE_MEM and IORESOUCE_BUSY.