Skip to content

Commit

Permalink
kexec: reuse crash kernel reserved memory for normal kexec
Browse files Browse the repository at this point in the history
normally, for kexec reboot, each segment of the second os
(such as : kernel、initrd、etc.) will be copied to discontinuous
physical memory during kexec load.  and then a memory copy will
be performed when kexec -e is executed to copy each segment of
the second os to contiguous physical memory, which will Affects
the time the kexec switch to the  new os. Therefore, if we reuse
the crash kernel reserved memory for kexec. When kexec loads the
second os, each segment of the second OS is directly copied to the
contiguous physical memory, so there is no need to make a second copy
when kexec -e is executed later.

The kexec userspace tool also needs to add parameter options(-r) that
support the use of reserved memory (see another patch for kexec)

examples:
bzimage: 53M initramfs: 28M
can save aboat 40 ms, The larger the image size, the greater the time
savings

Signed-off-by: huangjie.albert <huangjie.albert@bytedance.com>
Signed-off-by: Alexandre Frade <kernel@xanmod.org>
  • Loading branch information
huangjie.albert authored and xanmod committed Aug 2, 2022
1 parent 69231fa commit e3f81f3
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 14 deletions.
9 changes: 5 additions & 4 deletions include/linux/kexec.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,9 +305,10 @@ struct kimage {
unsigned long control_page;

/* Flags to indicate special processing */
unsigned int type : 1;
unsigned int type : 2;
#define KEXEC_TYPE_DEFAULT 0
#define KEXEC_TYPE_CRASH 1
#define KEXEC_TYPE_RESERVED_MEM 2
unsigned int preserve_context : 1;
/* If set, we are using file mode kexec syscall */
unsigned int file_mode:1;
Expand Down Expand Up @@ -377,14 +378,14 @@ extern int kexec_load_disabled;

/* List of defined/legal kexec flags */
#ifndef CONFIG_KEXEC_JUMP
#define KEXEC_FLAGS KEXEC_ON_CRASH
#define KEXEC_FLAGS (KEXEC_ON_CRASH | KEXEC_RESERVED_MEM)
#else
#define KEXEC_FLAGS (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)
#define KEXEC_FLAGS (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT | KEXEC_RESERVED_MEM)
#endif

/* List of defined/legal kexec file flags */
#define KEXEC_FILE_FLAGS (KEXEC_FILE_UNLOAD | KEXEC_FILE_ON_CRASH | \
KEXEC_FILE_NO_INITRAMFS)
KEXEC_FILE_NO_INITRAMFS | KEXEC_FILE_RESERVED_MEM)

/* flag to track if kexec reboot is in progress */
extern bool kexec_in_progress;
Expand Down
2 changes: 2 additions & 0 deletions include/uapi/linux/kexec.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
/* kexec flags for different usage scenarios */
#define KEXEC_ON_CRASH 0x00000001
#define KEXEC_PRESERVE_CONTEXT 0x00000002
#define KEXEC_RESERVED_MEM 0x00000004
#define KEXEC_ARCH_MASK 0xffff0000

/*
Expand All @@ -24,6 +25,7 @@
#define KEXEC_FILE_UNLOAD 0x00000001
#define KEXEC_FILE_ON_CRASH 0x00000002
#define KEXEC_FILE_NO_INITRAMFS 0x00000004
#define KEXEC_FILE_RESERVED_MEM 0x00000008

/* These values match the ELF architecture values.
* Unless there is a good reason that should continue to be the case.
Expand Down
19 changes: 18 additions & 1 deletion kernel/kexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,14 @@ static int kimage_alloc_init(struct kimage **rimage, unsigned long entry,
int ret;
struct kimage *image;
bool kexec_on_panic = flags & KEXEC_ON_CRASH;
bool kexec_on_reserved = flags & KEXEC_RESERVED_MEM;

if (kexec_on_panic) {
if (kexec_on_panic && kexec_on_reserved) {
pr_err("both kexec_on_panic and kexec_on_reserved is true, they can not coexist");
return -EINVAL;
}

if (kexec_on_panic || kexec_on_reserved) {
/* Verify we have a valid entry point */
if ((entry < phys_to_boot_phys(crashk_res.start)) ||
(entry > phys_to_boot_phys(crashk_res.end)))
Expand All @@ -50,6 +56,12 @@ static int kimage_alloc_init(struct kimage **rimage, unsigned long entry,
image->type = KEXEC_TYPE_CRASH;
}

if (kexec_on_reserved) {
/* Enable special reserved kernel control page alloc policy. */
image->control_page = crashk_res.start;
image->type = KEXEC_TYPE_RESERVED_MEM;
}

ret = sanity_check_segment_list(image);
if (ret)
goto out_free_image;
Expand Down Expand Up @@ -110,6 +122,11 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
dest_image = &kexec_image;
}

if (flags & KEXEC_RESERVED_MEM) {
if (kexec_crash_image)
arch_kexec_unprotect_crashkres();
}

if (nr_segments == 0) {
/* Uninstall image */
kimage_free(xchg(dest_image, NULL));
Expand Down
16 changes: 9 additions & 7 deletions kernel/kexec_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,13 @@ int sanity_check_segment_list(struct kimage *image)
* Verify we have good destination addresses. Normally
* the caller is responsible for making certain we don't
* attempt to load the new image into invalid or reserved
* areas of RAM. But crash kernels are preloaded into a
* areas of RAM. But crash kernels (or we specify to load
* the new image into reserved areas) are preloaded into a
* reserved area of ram. We must ensure the addresses
* are in the reserved area otherwise preloading the
* kernel could corrupt things.
*/

if (image->type == KEXEC_TYPE_CRASH) {
if (image->type == KEXEC_TYPE_CRASH || image->type == KEXEC_TYPE_RESERVED_MEM) {
for (i = 0; i < nr_segments; i++) {
unsigned long mstart, mend;

Expand Down Expand Up @@ -414,7 +414,7 @@ static struct page *kimage_alloc_normal_control_pages(struct kimage *image,
return pages;
}

static struct page *kimage_alloc_crash_control_pages(struct kimage *image,
static struct page *kimage_alloc_reserverd_control_pages(struct kimage *image,
unsigned int order)
{
/* Control pages are special, they are the intermediaries
Expand Down Expand Up @@ -491,7 +491,8 @@ struct page *kimage_alloc_control_pages(struct kimage *image,
pages = kimage_alloc_normal_control_pages(image, order);
break;
case KEXEC_TYPE_CRASH:
pages = kimage_alloc_crash_control_pages(image, order);
case KEXEC_TYPE_RESERVED_MEM:
pages = kimage_alloc_reserverd_control_pages(image, order);
break;
}

Expand Down Expand Up @@ -846,7 +847,7 @@ static int kimage_load_normal_segment(struct kimage *image,
return result;
}

static int kimage_load_crash_segment(struct kimage *image,
static int kimage_load_reserved_segment(struct kimage *image,
struct kexec_segment *segment)
{
/* For crash dumps kernels we simply copy the data from
Expand Down Expand Up @@ -924,7 +925,8 @@ int kimage_load_segment(struct kimage *image,
result = kimage_load_normal_segment(image, segment);
break;
case KEXEC_TYPE_CRASH:
result = kimage_load_crash_segment(image, segment);
case KEXEC_TYPE_RESERVED_MEM:
result = kimage_load_reserved_segment(image, segment);
break;
}

Expand Down
20 changes: 18 additions & 2 deletions kernel/kexec_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ kimage_file_alloc_init(struct kimage **rimage, int kernel_fd,
int ret;
struct kimage *image;
bool kexec_on_panic = flags & KEXEC_FILE_ON_CRASH;

bool kexec_on_reserved = flags & KEXEC_FILE_RESERVED_MEM;
image = do_kimage_alloc_init();
if (!image)
return -ENOMEM;
Expand All @@ -290,6 +290,12 @@ kimage_file_alloc_init(struct kimage **rimage, int kernel_fd,
image->type = KEXEC_TYPE_CRASH;
}

if (kexec_on_reserved) {
/* Enable special crash kernel control page alloc policy. */
image->control_page = crashk_res.start;
image->type = KEXEC_TYPE_RESERVED_MEM;
}

ret = kimage_file_prepare_segments(image, kernel_fd, initrd_fd,
cmdline_ptr, cmdline_len, flags);
if (ret)
Expand Down Expand Up @@ -346,13 +352,23 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd,
if (!mutex_trylock(&kexec_mutex))
return -EBUSY;

if ((flags & KEXEC_FILE_ON_CRASH) && (flags & KEXEC_FILE_RESERVED_MEM)) {
pr_err("both kexec_on_panic and kexec_on_reserved is true, they can not coexist");
return -EINVAL;
}

dest_image = &kexec_image;
if (flags & KEXEC_FILE_ON_CRASH) {
dest_image = &kexec_crash_image;
if (kexec_crash_image)
arch_kexec_unprotect_crashkres();
}

if (flags & KEXEC_FILE_RESERVED_MEM) {
if (kexec_crash_image)
arch_kexec_unprotect_crashkres();
}

if (flags & KEXEC_FILE_UNLOAD)
goto exchange;

Expand Down Expand Up @@ -588,7 +604,7 @@ static int kexec_walk_memblock(struct kexec_buf *kbuf,
static int kexec_walk_resources(struct kexec_buf *kbuf,
int (*func)(struct resource *, void *))
{
if (kbuf->image->type == KEXEC_TYPE_CRASH)
if (kbuf->image->type == KEXEC_TYPE_CRASH || kbuf->image->type == KEXEC_TYPE_RESERVED_MEM)
return walk_iomem_res_desc(crashk_res.desc,
IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY,
crashk_res.start, crashk_res.end,
Expand Down

0 comments on commit e3f81f3

Please sign in to comment.