Commit 0eea0867 authored by Minfei Huang's avatar Minfei Huang Committed by Linus Torvalds

kexec: do a cleanup for function kexec_load

There are a lof of work to be done in function kexec_load, not only for
allocating structs and loading initram, but also for some misc.

To make it more clear, wrap a new function do_kexec_load which is used
to allocate structs and load initram.  And the pre-work will be done in
kexec_load.
Signed-off-by: default avatarMinfei Huang <mnfhuang@gmail.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Xunlei Pang <xlpang@redhat.com>
Cc: Baoquan He <bhe@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 917a3560
...@@ -103,6 +103,74 @@ static int kimage_alloc_init(struct kimage **rimage, unsigned long entry, ...@@ -103,6 +103,74 @@ static int kimage_alloc_init(struct kimage **rimage, unsigned long entry,
return ret; return ret;
} }
static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
struct kexec_segment __user *segments, unsigned long flags)
{
struct kimage **dest_image, *image;
unsigned long i;
int ret;
if (flags & KEXEC_ON_CRASH) {
dest_image = &kexec_crash_image;
if (kexec_crash_image)
arch_kexec_unprotect_crashkres();
} else {
dest_image = &kexec_image;
}
if (nr_segments == 0) {
/* Uninstall image */
kimage_free(xchg(dest_image, NULL));
return 0;
}
if (flags & KEXEC_ON_CRASH) {
/*
* Loading another kernel to switch to if this one
* crashes. Free any current crash dump kernel before
* we corrupt it.
*/
kimage_free(xchg(&kexec_crash_image, NULL));
}
ret = kimage_alloc_init(&image, entry, nr_segments, segments, flags);
if (ret)
return ret;
if (flags & KEXEC_ON_CRASH)
crash_map_reserved_pages();
if (flags & KEXEC_PRESERVE_CONTEXT)
image->preserve_context = 1;
ret = machine_kexec_prepare(image);
if (ret)
goto out;
for (i = 0; i < nr_segments; i++) {
ret = kimage_load_segment(image, &image->segment[i]);
if (ret)
goto out;
}
kimage_terminate(image);
/* Install the new kernel and uninstall the old */
image = xchg(dest_image, image);
out:
if ((flags & KEXEC_ON_CRASH) && kexec_crash_image)
arch_kexec_protect_crashkres();
/*
* Once the reserved memory is mapped, we should unmap this memory
* before returning
*/
if (flags & KEXEC_ON_CRASH)
crash_unmap_reserved_pages();
kimage_free(image);
return ret;
}
/* /*
* Exec Kernel system call: for obvious reasons only root may call it. * Exec Kernel system call: for obvious reasons only root may call it.
* *
...@@ -127,7 +195,6 @@ static int kimage_alloc_init(struct kimage **rimage, unsigned long entry, ...@@ -127,7 +195,6 @@ static int kimage_alloc_init(struct kimage **rimage, unsigned long entry,
SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
struct kexec_segment __user *, segments, unsigned long, flags) struct kexec_segment __user *, segments, unsigned long, flags)
{ {
struct kimage **dest_image, *image;
int result; int result;
/* We only trust the superuser with rebooting the system. */ /* We only trust the superuser with rebooting the system. */
...@@ -152,9 +219,6 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, ...@@ -152,9 +219,6 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
if (nr_segments > KEXEC_SEGMENT_MAX) if (nr_segments > KEXEC_SEGMENT_MAX)
return -EINVAL; return -EINVAL;
image = NULL;
result = 0;
/* Because we write directly to the reserved memory /* Because we write directly to the reserved memory
* region when loading crash kernels we need a mutex here to * region when loading crash kernels we need a mutex here to
* prevent multiple crash kernels from attempting to load * prevent multiple crash kernels from attempting to load
...@@ -166,63 +230,12 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, ...@@ -166,63 +230,12 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
if (!mutex_trylock(&kexec_mutex)) if (!mutex_trylock(&kexec_mutex))
return -EBUSY; return -EBUSY;
dest_image = &kexec_image; result = do_kexec_load(entry, nr_segments, segments, flags);
if (flags & KEXEC_ON_CRASH) {
dest_image = &kexec_crash_image;
if (kexec_crash_image)
arch_kexec_unprotect_crashkres();
}
if (nr_segments > 0) {
unsigned long i;
if (flags & KEXEC_ON_CRASH) {
/*
* Loading another kernel to switch to if this one
* crashes. Free any current crash dump kernel before
* we corrupt it.
*/
kimage_free(xchg(&kexec_crash_image, NULL));
result = kimage_alloc_init(&image, entry, nr_segments,
segments, flags);
crash_map_reserved_pages();
} else {
/* Loading another kernel to reboot into. */
result = kimage_alloc_init(&image, entry, nr_segments,
segments, flags);
}
if (result)
goto unmap_page;
if (flags & KEXEC_PRESERVE_CONTEXT)
image->preserve_context = 1;
result = machine_kexec_prepare(image);
if (result)
goto unmap_page;
for (i = 0; i < nr_segments; i++) {
result = kimage_load_segment(image, &image->segment[i]);
if (result)
goto unmap_page;
}
kimage_terminate(image);
unmap_page:
if (flags & KEXEC_ON_CRASH)
crash_unmap_reserved_pages();
if (result)
goto out;
}
/* Install the new kernel, and Uninstall the old */
image = xchg(dest_image, image);
out:
if ((flags & KEXEC_ON_CRASH) && kexec_crash_image) if ((flags & KEXEC_ON_CRASH) && kexec_crash_image)
arch_kexec_protect_crashkres(); arch_kexec_protect_crashkres();
mutex_unlock(&kexec_mutex); mutex_unlock(&kexec_mutex);
kimage_free(image);
return result; return result;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment