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/kexec.c | |
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/kexec.c')
-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 | } |