aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2007-10-18 06:04:52 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-18 17:37:19 -0400
commitd307c4a8e826c44f9633bd3f7e60d0491e7d885a (patch)
tree1e381840363594557c5e31b1bcdc3f491d474039
parent50a1efe14fd56a273cdbe53bf1c7fc12099d2e1a (diff)
Hibernation: Arbitrary boot kernel support - generic code
Add the bits needed for supporting arbitrary boot kernels to the common hibernation code. To support arbitrary boot kernels, make it possible to replace the 'struct new_utsname' and the kernel version in the hibernation image header by some architecture specific data that will be used to verify if the image is valid and to restore the image. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@ucw.cz> Cc: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--kernel/power/power.h20
-rw-r--r--kernel/power/snapshot.c53
2 files changed, 54 insertions, 19 deletions
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 95fbf2dd3fe3..a0204dfc6c4c 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -11,14 +11,32 @@ struct swsusp_info {
11 unsigned long size; 11 unsigned long size;
12} __attribute__((aligned(PAGE_SIZE))); 12} __attribute__((aligned(PAGE_SIZE)));
13 13
14#ifdef CONFIG_HIBERNATION
15#ifdef CONFIG_ARCH_HIBERNATION_HEADER
16/* Maximum size of architecture specific data in a hibernation header */
17#define MAX_ARCH_HEADER_SIZE (sizeof(struct new_utsname) + 4)
14 18
19extern int arch_hibernation_header_save(void *addr, unsigned int max_size);
20extern int arch_hibernation_header_restore(void *addr);
21
22static inline int init_header_complete(struct swsusp_info *info)
23{
24 return arch_hibernation_header_save(info, MAX_ARCH_HEADER_SIZE);
25}
26
27static inline char *check_image_kernel(struct swsusp_info *info)
28{
29 return arch_hibernation_header_restore(info) ?
30 "architecture specific data" : NULL;
31}
32#endif /* CONFIG_ARCH_HIBERNATION_HEADER */
15 33
16#ifdef CONFIG_HIBERNATION
17/* 34/*
18 * Keep some memory free so that I/O operations can succeed without paging 35 * Keep some memory free so that I/O operations can succeed without paging
19 * [Might this be more than 4 MB?] 36 * [Might this be more than 4 MB?]
20 */ 37 */
21#define PAGES_FOR_IO ((4096 * 1024) >> PAGE_SHIFT) 38#define PAGES_FOR_IO ((4096 * 1024) >> PAGE_SHIFT)
39
22/* 40/*
23 * Keep 1 MB of memory free so that device drivers can allocate some pages in 41 * Keep 1 MB of memory free so that device drivers can allocate some pages in
24 * their .suspend() routines without breaking the suspend to disk. 42 * their .suspend() routines without breaking the suspend to disk.
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index a686590d88c1..ccc95ac07bed 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -1239,17 +1239,39 @@ asmlinkage int swsusp_save(void)
1239 return 0; 1239 return 0;
1240} 1240}
1241 1241
1242static void init_header(struct swsusp_info *info) 1242#ifndef CONFIG_ARCH_HIBERNATION_HEADER
1243static int init_header_complete(struct swsusp_info *info)
1243{ 1244{
1244 memset(info, 0, sizeof(struct swsusp_info)); 1245 memcpy(&info->uts, init_utsname(), sizeof(struct new_utsname));
1245 info->version_code = LINUX_VERSION_CODE; 1246 info->version_code = LINUX_VERSION_CODE;
1247 return 0;
1248}
1249
1250static char *check_image_kernel(struct swsusp_info *info)
1251{
1252 if (info->version_code != LINUX_VERSION_CODE)
1253 return "kernel version";
1254 if (strcmp(info->uts.sysname,init_utsname()->sysname))
1255 return "system type";
1256 if (strcmp(info->uts.release,init_utsname()->release))
1257 return "kernel release";
1258 if (strcmp(info->uts.version,init_utsname()->version))
1259 return "version";
1260 if (strcmp(info->uts.machine,init_utsname()->machine))
1261 return "machine";
1262 return NULL;
1263}
1264#endif /* CONFIG_ARCH_HIBERNATION_HEADER */
1265
1266static int init_header(struct swsusp_info *info)
1267{
1268 memset(info, 0, sizeof(struct swsusp_info));
1246 info->num_physpages = num_physpages; 1269 info->num_physpages = num_physpages;
1247 memcpy(&info->uts, init_utsname(), sizeof(struct new_utsname));
1248 info->cpus = num_online_cpus();
1249 info->image_pages = nr_copy_pages; 1270 info->image_pages = nr_copy_pages;
1250 info->pages = nr_copy_pages + nr_meta_pages + 1; 1271 info->pages = nr_copy_pages + nr_meta_pages + 1;
1251 info->size = info->pages; 1272 info->size = info->pages;
1252 info->size <<= PAGE_SHIFT; 1273 info->size <<= PAGE_SHIFT;
1274 return init_header_complete(info);
1253} 1275}
1254 1276
1255/** 1277/**
@@ -1303,7 +1325,11 @@ int snapshot_read_next(struct snapshot_handle *handle, size_t count)
1303 return -ENOMEM; 1325 return -ENOMEM;
1304 } 1326 }
1305 if (!handle->offset) { 1327 if (!handle->offset) {
1306 init_header((struct swsusp_info *)buffer); 1328 int error;
1329
1330 error = init_header((struct swsusp_info *)buffer);
1331 if (error)
1332 return error;
1307 handle->buffer = buffer; 1333 handle->buffer = buffer;
1308 memory_bm_position_reset(&orig_bm); 1334 memory_bm_position_reset(&orig_bm);
1309 memory_bm_position_reset(&copy_bm); 1335 memory_bm_position_reset(&copy_bm);
@@ -1394,22 +1420,13 @@ duplicate_memory_bitmap(struct memory_bitmap *dst, struct memory_bitmap *src)
1394 } 1420 }
1395} 1421}
1396 1422
1397static inline int check_header(struct swsusp_info *info) 1423static int check_header(struct swsusp_info *info)
1398{ 1424{
1399 char *reason = NULL; 1425 char *reason;
1400 1426
1401 if (info->version_code != LINUX_VERSION_CODE) 1427 reason = check_image_kernel(info);
1402 reason = "kernel version"; 1428 if (!reason && info->num_physpages != num_physpages)
1403 if (info->num_physpages != num_physpages)
1404 reason = "memory size"; 1429 reason = "memory size";
1405 if (strcmp(info->uts.sysname,init_utsname()->sysname))
1406 reason = "system type";
1407 if (strcmp(info->uts.release,init_utsname()->release))
1408 reason = "kernel release";
1409 if (strcmp(info->uts.version,init_utsname()->version))
1410 reason = "version";
1411 if (strcmp(info->uts.machine,init_utsname()->machine))
1412 reason = "machine";
1413 if (reason) { 1430 if (reason) {
1414 printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason); 1431 printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason);
1415 return -EPERM; 1432 return -EPERM;