kexec: increase max of kexec segments and use dynamic allocation
Subsystems (4)
PATCH RESEND v2 1/1 kexec: increase max of kexec segments and use dynamic allocation
Currently KEXEC_SEGMENT_MAX is only 16 which is too small for machine with many memory ranges. When hibernate on a machine with disjoint memory we do need one segment for each memory region. Increase this hard limit to 16K which is reasonably large.
And change ->segment from a static array to a dynamically allocated memory.
---
arch/powerpc/kernel/machine_kexec_64.c +6 -7
@@ -134,10 +134,7 @@ static void copy_segments(unsigned long ind)void kexec_copy_flush (struct kimage *image) {long i, nr_segments = image->nr_segments; -struct kexec_segment ranges[KEXEC_SEGMENT_MAX ]; - -/* save the ranges on the stack to efficiently flush the icache */ -memcpy (ranges, image->segment,sizeof (ranges)); +struct kexec_segment range;/* * After this call we may not use anything allocated in dynamic
@@ -151,9 +148,11 @@ void kexec_copy_flush(struct kimage *image)* we need to clear the icache for all dest pages sometime, * including ones that were in place on the original copy */ -for (i =0 ; i < nr_segments; i++) -flush_icache_range ((unsigned long )__va (ranges[i].mem), - (unsigned long )__va (ranges[i].mem + ranges[i].memsz)); +for (i =0 ; i < nr_segments; i++) { +memcpy (&range, &image->segment[i],sizeof (range)); +flush_icache_range ((unsigned long )__va (range.mem), + (unsigned long )__va (range.mem + range.memsz)); + } }#ifdef CONFIG_SMP
include/linux/kexec.h +2 -2
@@ -57,7 +57,7 @@ typedef unsigned long kimage_entry_t;#define IND_DONE 0x4#define IND_SOURCE 0x8 -#define KEXEC_SEGMENT_MAX 16 +#define KEXEC_SEGMENT_MAX (1024*16)struct kexec_segment {void __user *buf;size_t bufsz;
@@ -86,7 +86,7 @@ struct kimage {struct page *swap_page;unsigned long nr_segments; -struct kexec_segment segment[KEXEC_SEGMENT_MAX ]; +struct kexec_segment *segment;struct list_head control_pages;struct list_head dest_pages;
kernel/kexec.c +15 -3
@@ -131,6 +131,11 @@ static int do_kimage_alloc(struct kimage **rimage, unsigned long entry,if (!image) goto out; + image->segment =kzalloc (nr_segments *sizeof (struct kexec_segment ), +GFP_KERNEL ); +if (!image->segment) + goto out; + image->head =0 ; image->entry = &image->head; image->last_entry = &image->head;
@@ -218,8 +223,10 @@ static int do_kimage_alloc(struct kimage **rimage, unsigned long entry, out:if (result ==0 ) *rimage = image; -else +else if (image) { +kfree (image->segment);kfree (image); + }return result;
@@ -263,8 +270,10 @@ static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry, out:if (result ==0 ) *rimage = image; -else +else if (image) { +kfree (image->segment);kfree (image); + }return result; }
@@ -332,8 +341,10 @@ static int kimage_crash_alloc(struct kimage **rimage, unsigned long entry, out:if (result ==0 ) *rimage = image; -else +else if (image) { +kfree (image->segment);kfree (image); + }return result; }
@@ -658,6 +669,7 @@ static void kimage_free(struct kimage *image)/* Free the kexec control pages... */ kimage_free_page_list (&image->control_pages); +kfree (image->segment);kfree (image); }
_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
Quoted 7 lines · Amerigo Wang
Currently
KEXEC_SEGMENT_MAXis only 16 which is too small for machine with many memory ranges. When hibernate on a machine with disjoint memory we do need one segment for each memory region. Increase this hard limit to 16K which is reasonably large.And change ->segment from a static array to a dynamically allocated memory.
FWIW, this looks good to me.
Quoted 129 lines
Cc Neil Horman <[email protected]>Cc Vivek Goyal <[email protected]>Cc huang ying <[email protected]>Cc Eric W. Biederman <[email protected]>Cc Benjamin Herrenschmidt <[email protected]>Cc Paul Mackerras <[email protected]>Signed-off-by WANG Cong <[email protected]>---
arch/powerpc/kernel/machine_kexec_64.c +6
-7@@ -134,10 +134,7 @@ static void copy_segments(unsigned long ind)void kexec_copy_flush (struct kimage *image) {long i, nr_segments = image->nr_segments; -struct kexec_segment ranges[KEXEC_SEGMENT_MAX ]; - -/* save the ranges on the stack to efficiently flush the icache */ -memcpy (ranges, image->segment,sizeof (ranges)); +struct kexec_segment range;/* * After this call we may not use anything allocated in dynamic @@ -151,9 +148,11 @@ void kexec_copy_flush(struct kimage *image)* we need to clear the icache for all dest pages sometime, * including ones that were in place on the original copy */ -for (i =0 ; i < nr_segments; i++) -flush_icache_range ((unsigned long )__va (ranges[i].mem), - (unsigned long )__va (ranges[i].mem + ranges[i].memsz)); +for (i =0 ; i < nr_segments; i++) { +memcpy (&range, &image->segment[i],sizeof (range)); +flush_icache_range ((unsigned long )__va (range.mem), + (unsigned long )__va (range.mem + range.memsz)); + } }#ifdef CONFIG_SMP include/linux/kexec.h +2
-2@@ -57,7 +57,7 @@ typedef unsigned long kimage_entry_t;#define IND_DONE 0x4#define IND_SOURCE 0x8 -#define KEXEC_SEGMENT_MAX 16 +#define KEXEC_SEGMENT_MAX (1024*16)struct kexec_segment {void __user *buf;size_t bufsz;@@ -86,7 +86,7 @@ struct kimage {struct page *swap_page;unsigned long nr_segments; -struct kexec_segment segment[KEXEC_SEGMENT_MAX ]; +struct kexec_segment *segment;struct list_head control_pages;struct list_head dest_pages;kernel/kexec.c +15
-4@@ -131,6 +131,11 @@ static int do_kimage_alloc(struct kimage **rimage, unsigned long entry,if (!image) goto out; + image->segment =kzalloc (nr_segments *sizeof (struct kexec_segment ), +GFP_KERNEL ); +if (!image->segment) + goto out; + image->head =0 ; image->entry = &image->head; image->last_entry = &image->head;@@ -218,8 +223,10 @@ static int do_kimage_alloc(struct kimage **rimage, unsigned long entry, out:if (result ==0 ) *rimage = image; -else +else if (image) { +kfree (image->segment);kfree (image); + }return result;@@ -263,8 +270,10 @@ static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry, out:if (result ==0 ) *rimage = image; -else +else if (image) { +kfree (image->segment);kfree (image); + }return result; }@@ -332,8 +341,10 @@ static int kimage_crash_alloc(struct kimage **rimage, unsigned long entry, out:if (result ==0 ) *rimage = image; -else +else if (image) { +kfree (image->segment);kfree (image); + }return result; }@@ -658,6 +669,7 @@ static void kimage_free(struct kimage *image)/* Free the kexec control pages... */ kimage_free_page_list (&image->control_pages); +kfree (image->segment);kfree (image); } --To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Quoted 8 lines · Amerigo Wang
Currently
KEXEC_SEGMENT_MAXis only 16 which is too small for machine with many memory ranges. When hibernate on a machine with disjoint memory we do need one segment for each memory region. Increase this hard limit to 16K which is reasonably large.And change ->segment from a static array to a dynamically allocated memory.
Quoted 8 lines
Cc Neil Horman <[email protected]>Cc Vivek Goyal <[email protected]>Cc huang ying <[email protected]>Cc Eric W. Biederman <[email protected]>Cc Benjamin Herrenschmidt <[email protected]>Cc Paul Mackerras <[email protected]>Signed-off-by WANG Cong <[email protected]>
Concur with Simon