Skip to content

Commit

Permalink
kexec: do a cleanup for function kexec_load
Browse files Browse the repository at this point in the history
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: Minfei Huang <[email protected]>
Cc: Vivek Goyal <[email protected]>
Cc: "Eric W. Biederman" <[email protected]>
Cc: Xunlei Pang <[email protected]>
Cc: Baoquan He <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Minfei Huang authored and torvalds committed May 24, 2016
1 parent 917a356 commit 0eea086
Showing 1 changed file with 69 additions and 56 deletions.
125 changes: 69 additions & 56 deletions kernel/kexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,74 @@ static int kimage_alloc_init(struct kimage **rimage, unsigned long entry,
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.
*
Expand All @@ -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,
struct kexec_segment __user *, segments, unsigned long, flags)
{
struct kimage **dest_image, *image;
int result;

/* We only trust the superuser with rebooting the system. */
Expand All @@ -152,9 +219,6 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
if (nr_segments > KEXEC_SEGMENT_MAX)
return -EINVAL;

image = NULL;
result = 0;

/* Because we write directly to the reserved memory
* region when loading crash kernels we need a mutex here to
* prevent multiple crash kernels from attempting to load
Expand All @@ -166,63 +230,12 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
if (!mutex_trylock(&kexec_mutex))
return -EBUSY;

dest_image = &kexec_image;
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);
result = do_kexec_load(entry, nr_segments, segments, flags);

out:
if ((flags & KEXEC_ON_CRASH) && kexec_crash_image)
arch_kexec_protect_crashkres();

mutex_unlock(&kexec_mutex);
kimage_free(image);

return result;
}
Expand Down

0 comments on commit 0eea086

Please sign in to comment.