diff options
| author | Minfei Huang <mnfhuang@gmail.com> | 2016-05-23 19:24:19 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-23 20:04:14 -0400 |
| commit | 0eea08678ebe9f7d8ef98fed974a5bf1a0dd2dd2 (patch) | |
| tree | 24894ffc23a22f6f40a1f418811c17f73a15df10 /kernel | |
| parent | 917a35605f09c0d16aeb2e92c7fbff562e19a116 (diff) | |
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: Minfei 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: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/kexec.c | 125 |
1 files changed, 69 insertions, 56 deletions
diff --git a/kernel/kexec.c b/kernel/kexec.c index 4b49aa71304f..b73dc211fcfd 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
| @@ -103,6 +103,74 @@ out_free_image: | |||
| 103 | return ret; | 103 | return ret; |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | static int do_kexec_load(unsigned long entry, unsigned long nr_segments, | ||
| 107 | struct kexec_segment __user *segments, unsigned long flags) | ||
| 108 | { | ||
| 109 | struct kimage **dest_image, *image; | ||
| 110 | unsigned long i; | ||
| 111 | int ret; | ||
| 112 | |||
| 113 | if (flags & KEXEC_ON_CRASH) { | ||
| 114 | dest_image = &kexec_crash_image; | ||
| 115 | if (kexec_crash_image) | ||
| 116 | arch_kexec_unprotect_crashkres(); | ||
| 117 | } else { | ||
| 118 | dest_image = &kexec_image; | ||
| 119 | } | ||
| 120 | |||
| 121 | if (nr_segments == 0) { | ||
| 122 | /* Uninstall image */ | ||
| 123 | kimage_free(xchg(dest_image, NULL)); | ||
| 124 | return 0; | ||
| 125 | } | ||
| 126 | if (flags & KEXEC_ON_CRASH) { | ||
| 127 | /* | ||
| 128 | * Loading another kernel to switch to if this one | ||
| 129 | * crashes. Free any current crash dump kernel before | ||
| 130 | * we corrupt it. | ||
| 131 | */ | ||
| 132 | kimage_free(xchg(&kexec_crash_image, NULL)); | ||
| 133 | } | ||
| 134 | |||
| 135 | ret = kimage_alloc_init(&image, entry, nr_segments, segments, flags); | ||
| 136 | if (ret) | ||
| 137 | return ret; | ||
| 138 | |||
| 139 | if (flags & KEXEC_ON_CRASH) | ||
| 140 | crash_map_reserved_pages(); | ||
| 141 | |||
| 142 | if (flags & KEXEC_PRESERVE_CONTEXT) | ||
| 143 | image->preserve_context = 1; | ||
| 144 | |||
| 145 | ret = machine_kexec_prepare(image); | ||
| 146 | if (ret) | ||
| 147 | goto out; | ||
| 148 | |||
| 149 | for (i = 0; i < nr_segments; i++) { | ||
| 150 | ret = kimage_load_segment(image, &image->segment[i]); | ||
| 151 | if (ret) | ||
| 152 | goto out; | ||
| 153 | } | ||
| 154 | |||
| 155 | kimage_terminate(image); | ||
| 156 | |||
| 157 | /* Install the new kernel and uninstall the old */ | ||
| 158 | image = xchg(dest_image, image); | ||
| 159 | |||
| 160 | out: | ||
| 161 | if ((flags & KEXEC_ON_CRASH) && kexec_crash_image) | ||
| 162 | arch_kexec_protect_crashkres(); | ||
| 163 | |||
| 164 | /* | ||
| 165 | * Once the reserved memory is mapped, we should unmap this memory | ||
| 166 | * before returning | ||
| 167 | */ | ||
| 168 | if (flags & KEXEC_ON_CRASH) | ||
| 169 | crash_unmap_reserved_pages(); | ||
| 170 | kimage_free(image); | ||
| 171 | return ret; | ||
| 172 | } | ||
| 173 | |||
| 106 | /* | 174 | /* |
| 107 | * Exec Kernel system call: for obvious reasons only root may call it. | 175 | * Exec Kernel system call: for obvious reasons only root may call it. |
| 108 | * | 176 | * |
| @@ -127,7 +195,6 @@ out_free_image: | |||
| 127 | SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, | 195 | SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, |
| 128 | struct kexec_segment __user *, segments, unsigned long, flags) | 196 | struct kexec_segment __user *, segments, unsigned long, flags) |
| 129 | { | 197 | { |
| 130 | struct kimage **dest_image, *image; | ||
| 131 | int result; | 198 | int result; |
| 132 | 199 | ||
| 133 | /* We only trust the superuser with rebooting the system. */ | 200 | /* 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 | if (nr_segments > KEXEC_SEGMENT_MAX) | 219 | if (nr_segments > KEXEC_SEGMENT_MAX) |
| 153 | return -EINVAL; | 220 | return -EINVAL; |
| 154 | 221 | ||
| 155 | image = NULL; | ||
| 156 | result = 0; | ||
| 157 | |||
| 158 | /* Because we write directly to the reserved memory | 222 | /* Because we write directly to the reserved memory |
| 159 | * region when loading crash kernels we need a mutex here to | 223 | * region when loading crash kernels we need a mutex here to |
| 160 | * prevent multiple crash kernels from attempting to load | 224 | * prevent multiple crash kernels from attempting to load |
| @@ -166,63 +230,12 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, | |||
| 166 | if (!mutex_trylock(&kexec_mutex)) | 230 | if (!mutex_trylock(&kexec_mutex)) |
| 167 | return -EBUSY; | 231 | return -EBUSY; |
| 168 | 232 | ||
| 169 | dest_image = &kexec_image; | 233 | result = do_kexec_load(entry, nr_segments, segments, flags); |
| 170 | if (flags & KEXEC_ON_CRASH) { | ||
| 171 | dest_image = &kexec_crash_image; | ||
| 172 | if (kexec_crash_image) | ||
| 173 | arch_kexec_unprotect_crashkres(); | ||
| 174 | } | ||
| 175 | |||
| 176 | if (nr_segments > 0) { | ||
| 177 | unsigned long i; | ||
| 178 | |||
| 179 | if (flags & KEXEC_ON_CRASH) { | ||
| 180 | /* | ||
| 181 | * Loading another kernel to switch to if this one | ||
| 182 | * crashes. Free any current crash dump kernel before | ||
| 183 | * we corrupt it. | ||
| 184 | */ | ||
| 185 | |||
| 186 | kimage_free(xchg(&kexec_crash_image, NULL)); | ||
| 187 | result = kimage_alloc_init(&image, entry, nr_segments, | ||
| 188 | segments, flags); | ||
| 189 | crash_map_reserved_pages(); | ||
| 190 | } else { | ||
| 191 | /* Loading another kernel to reboot into. */ | ||
| 192 | |||
| 193 | result = kimage_alloc_init(&image, entry, nr_segments, | ||
| 194 | segments, flags); | ||
| 195 | } | ||
| 196 | if (result) | ||
| 197 | goto unmap_page; | ||
| 198 | |||
| 199 | if (flags & KEXEC_PRESERVE_CONTEXT) | ||
| 200 | image->preserve_context = 1; | ||
| 201 | result = machine_kexec_prepare(image); | ||
| 202 | if (result) | ||
| 203 | goto unmap_page; | ||
| 204 | |||
| 205 | for (i = 0; i < nr_segments; i++) { | ||
| 206 | result = kimage_load_segment(image, &image->segment[i]); | ||
| 207 | if (result) | ||
| 208 | goto unmap_page; | ||
| 209 | } | ||
| 210 | kimage_terminate(image); | ||
| 211 | unmap_page: | ||
| 212 | if (flags & KEXEC_ON_CRASH) | ||
| 213 | crash_unmap_reserved_pages(); | ||
| 214 | if (result) | ||
| 215 | goto out; | ||
| 216 | } | ||
| 217 | /* Install the new kernel, and Uninstall the old */ | ||
| 218 | image = xchg(dest_image, image); | ||
| 219 | 234 | ||
| 220 | out: | ||
| 221 | if ((flags & KEXEC_ON_CRASH) && kexec_crash_image) | 235 | if ((flags & KEXEC_ON_CRASH) && kexec_crash_image) |
| 222 | arch_kexec_protect_crashkres(); | 236 | arch_kexec_protect_crashkres(); |
| 223 | 237 | ||
| 224 | mutex_unlock(&kexec_mutex); | 238 | mutex_unlock(&kexec_mutex); |
| 225 | kimage_free(image); | ||
| 226 | 239 | ||
| 227 | return result; | 240 | return result; |
| 228 | } | 241 | } |
