@@ -264,6 +264,24 @@ int kimage_is_destination_range(struct kimage *image,
return 0;
}
+int kimage_is_control_page(struct kimage *image,
+ unsigned long start,
+ unsigned long end)
+{
+
+ struct page *page;
+
+ list_for_each_entry(page, &image->control_pages, lru) {
+ unsigned long pstart, pend;
+ pstart = page_to_boot_pfn(page) << PAGE_SHIFT;
+ pend = pstart + PAGE_SIZE * (1 << page_private(page)) - 1;
+ if ((end >= pstart) && (start <= pend))
+ return 1;
+ }
+
+ return 0;
+}
+
static struct page *kimage_alloc_pages(gfp_t gfp_mask, unsigned int order)
{
struct page *pages;
@@ -464,7 +464,8 @@ static int locate_mem_hole_top_down(unsigned long start, unsigned long end,
* Make sure this does not conflict with any of existing
* segments
*/
- if (kimage_is_destination_range(image, temp_start, temp_end)) {
+ if (kimage_is_destination_range(image, temp_start, temp_end) ||
+ kimage_is_control_page(image, temp_start, temp_end)) {
temp_start = temp_start - PAGE_SIZE;
continue;
}
@@ -498,7 +499,8 @@ static int locate_mem_hole_bottom_up(unsigned long start, unsigned long end,
* Make sure this does not conflict with any of existing
* segments
*/
- if (kimage_is_destination_range(image, temp_start, temp_end)) {
+ if (kimage_is_destination_range(image, temp_start, temp_end) ||
+ kimage_is_control_page(image, temp_start, temp_end)) {
temp_start = temp_start + PAGE_SIZE;
continue;
}
@@ -671,18 +673,6 @@ int kexec_add_buffer(struct kexec_buf *kbuf)
if (kbuf->image->nr_segments >= KEXEC_SEGMENT_MAX)
return -EINVAL;
- /*
- * Make sure we are not trying to add buffer after allocating
- * control pages. All segments need to be placed first before
- * any control pages are allocated. As control page allocation
- * logic goes through list of segments to make sure there are
- * no destination overlaps.
- */
- if (!list_empty(&kbuf->image->control_pages)) {
- WARN_ON(1);
- return -EINVAL;
- }
-
/* Ensure minimum alignment needed for segments. */
kbuf->memsz = ALIGN(kbuf->memsz, PAGE_SIZE);
kbuf->buf_align = max(kbuf->buf_align, PAGE_SIZE);
@@ -14,6 +14,9 @@ int kimage_load_segment(struct kimage *image, struct kexec_segment *segment);
void kimage_terminate(struct kimage *image);
int kimage_is_destination_range(struct kimage *image,
unsigned long start, unsigned long end);
+int kimage_is_control_page(struct kimage *image,
+ unsigned long start,
+ unsigned long end);
/*
* Whatever is used to serialize accesses to the kexec_crash_image needs to be
Kexec relies on control pages allocated after all destination ranges have been chosen. To be able to preserve memory across kexec we need to be able to pick destination ranges after the control pages allocated. Add check for control pages to locate_mem_hole() callbacks so it excludes control pages, hence we can allocate them in any order. Signed-off-by: Andrey Ryabinin <arbn@yandex-team.com> --- kernel/kexec_core.c | 18 ++++++++++++++++++ kernel/kexec_file.c | 18 ++++-------------- kernel/kexec_internal.h | 3 +++ 3 files changed, 25 insertions(+), 14 deletions(-)