diff options
author | Jiri Slaby <jslaby@suse.cz> | 2011-01-06 19:42:31 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2011-01-07 00:26:45 -0500 |
commit | 26fcaf60fe3861409eb4c455c5c0d0f00f599b08 (patch) | |
tree | 43b0b91df3a1c8d136b63ce499001a05c9a02c93 | |
parent | 3c0eee3fe6a3a1c745379547c7e7c904aa64f6d5 (diff) |
PM: Fix oops in suspend/hibernate code related to failing ioremap()
When ioremap() fails (which might happen for some reason), we nicely
oops in suspend_nvs_save() due to NULL dereference by memcpy() in there.
Fail gracefully instead.
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | drivers/acpi/sleep.c | 5 | ||||
-rw-r--r-- | include/linux/suspend.h | 4 | ||||
-rw-r--r-- | kernel/power/nvs.c | 8 |
3 files changed, 11 insertions, 6 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index febb153b5a68..d8bca6c90719 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
@@ -124,8 +124,7 @@ static int acpi_pm_freeze(void) | |||
124 | static int acpi_pm_pre_suspend(void) | 124 | static int acpi_pm_pre_suspend(void) |
125 | { | 125 | { |
126 | acpi_pm_freeze(); | 126 | acpi_pm_freeze(); |
127 | suspend_nvs_save(); | 127 | return suspend_nvs_save(); |
128 | return 0; | ||
129 | } | 128 | } |
130 | 129 | ||
131 | /** | 130 | /** |
@@ -151,7 +150,7 @@ static int acpi_pm_prepare(void) | |||
151 | { | 150 | { |
152 | int error = __acpi_pm_prepare(); | 151 | int error = __acpi_pm_prepare(); |
153 | if (!error) | 152 | if (!error) |
154 | acpi_pm_pre_suspend(); | 153 | error = acpi_pm_pre_suspend(); |
155 | 154 | ||
156 | return error; | 155 | return error; |
157 | } | 156 | } |
diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 26697514c5ec..acb7d911bb0c 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h | |||
@@ -262,7 +262,7 @@ static inline bool system_entering_hibernation(void) { return false; } | |||
262 | extern int suspend_nvs_register(unsigned long start, unsigned long size); | 262 | extern int suspend_nvs_register(unsigned long start, unsigned long size); |
263 | extern int suspend_nvs_alloc(void); | 263 | extern int suspend_nvs_alloc(void); |
264 | extern void suspend_nvs_free(void); | 264 | extern void suspend_nvs_free(void); |
265 | extern void suspend_nvs_save(void); | 265 | extern int suspend_nvs_save(void); |
266 | extern void suspend_nvs_restore(void); | 266 | extern void suspend_nvs_restore(void); |
267 | #else /* CONFIG_SUSPEND_NVS */ | 267 | #else /* CONFIG_SUSPEND_NVS */ |
268 | static inline int suspend_nvs_register(unsigned long a, unsigned long b) | 268 | static inline int suspend_nvs_register(unsigned long a, unsigned long b) |
@@ -271,7 +271,7 @@ static inline int suspend_nvs_register(unsigned long a, unsigned long b) | |||
271 | } | 271 | } |
272 | static inline int suspend_nvs_alloc(void) { return 0; } | 272 | static inline int suspend_nvs_alloc(void) { return 0; } |
273 | static inline void suspend_nvs_free(void) {} | 273 | static inline void suspend_nvs_free(void) {} |
274 | static inline void suspend_nvs_save(void) {} | 274 | static inline int suspend_nvs_save(void) {} |
275 | static inline void suspend_nvs_restore(void) {} | 275 | static inline void suspend_nvs_restore(void) {} |
276 | #endif /* CONFIG_SUSPEND_NVS */ | 276 | #endif /* CONFIG_SUSPEND_NVS */ |
277 | 277 | ||
diff --git a/kernel/power/nvs.c b/kernel/power/nvs.c index 1836db60bbb6..57c6fabbb6b6 100644 --- a/kernel/power/nvs.c +++ b/kernel/power/nvs.c | |||
@@ -105,7 +105,7 @@ int suspend_nvs_alloc(void) | |||
105 | /** | 105 | /** |
106 | * suspend_nvs_save - save NVS memory regions | 106 | * suspend_nvs_save - save NVS memory regions |
107 | */ | 107 | */ |
108 | void suspend_nvs_save(void) | 108 | int suspend_nvs_save(void) |
109 | { | 109 | { |
110 | struct nvs_page *entry; | 110 | struct nvs_page *entry; |
111 | 111 | ||
@@ -114,8 +114,14 @@ void suspend_nvs_save(void) | |||
114 | list_for_each_entry(entry, &nvs_list, node) | 114 | list_for_each_entry(entry, &nvs_list, node) |
115 | if (entry->data) { | 115 | if (entry->data) { |
116 | entry->kaddr = ioremap(entry->phys_start, entry->size); | 116 | entry->kaddr = ioremap(entry->phys_start, entry->size); |
117 | if (!entry->kaddr) { | ||
118 | suspend_nvs_free(); | ||
119 | return -ENOMEM; | ||
120 | } | ||
117 | memcpy(entry->data, entry->kaddr, entry->size); | 121 | memcpy(entry->data, entry->kaddr, entry->size); |
118 | } | 122 | } |
123 | |||
124 | return 0; | ||
119 | } | 125 | } |
120 | 126 | ||
121 | /** | 127 | /** |