diff options
Diffstat (limited to 'kernel/power/user.c')
-rw-r--r-- | kernel/power/user.c | 109 |
1 files changed, 80 insertions, 29 deletions
diff --git a/kernel/power/user.c b/kernel/power/user.c index 5bd321bcbb75..f5512cb3aa86 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
@@ -28,6 +28,29 @@ | |||
28 | 28 | ||
29 | #include "power.h" | 29 | #include "power.h" |
30 | 30 | ||
31 | /* | ||
32 | * NOTE: The SNAPSHOT_SET_SWAP_FILE and SNAPSHOT_PMOPS ioctls are obsolete and | ||
33 | * will be removed in the future. They are only preserved here for | ||
34 | * compatibility with existing userland utilities. | ||
35 | */ | ||
36 | #define SNAPSHOT_SET_SWAP_FILE _IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int) | ||
37 | #define SNAPSHOT_PMOPS _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int) | ||
38 | |||
39 | #define PMOPS_PREPARE 1 | ||
40 | #define PMOPS_ENTER 2 | ||
41 | #define PMOPS_FINISH 3 | ||
42 | |||
43 | /* | ||
44 | * NOTE: The following ioctl definitions are wrong and have been replaced with | ||
45 | * correct ones. They are only preserved here for compatibility with existing | ||
46 | * userland utilities and will be removed in the future. | ||
47 | */ | ||
48 | #define SNAPSHOT_ATOMIC_SNAPSHOT _IOW(SNAPSHOT_IOC_MAGIC, 3, void *) | ||
49 | #define SNAPSHOT_SET_IMAGE_SIZE _IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long) | ||
50 | #define SNAPSHOT_AVAIL_SWAP _IOR(SNAPSHOT_IOC_MAGIC, 7, void *) | ||
51 | #define SNAPSHOT_GET_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 8, void *) | ||
52 | |||
53 | |||
31 | #define SNAPSHOT_MINOR 231 | 54 | #define SNAPSHOT_MINOR 231 |
32 | 55 | ||
33 | static struct snapshot_data { | 56 | static struct snapshot_data { |
@@ -36,7 +59,7 @@ static struct snapshot_data { | |||
36 | int mode; | 59 | int mode; |
37 | char frozen; | 60 | char frozen; |
38 | char ready; | 61 | char ready; |
39 | char platform_suspend; | 62 | char platform_support; |
40 | } snapshot_state; | 63 | } snapshot_state; |
41 | 64 | ||
42 | atomic_t snapshot_device_available = ATOMIC_INIT(1); | 65 | atomic_t snapshot_device_available = ATOMIC_INIT(1); |
@@ -44,6 +67,7 @@ atomic_t snapshot_device_available = ATOMIC_INIT(1); | |||
44 | static int snapshot_open(struct inode *inode, struct file *filp) | 67 | static int snapshot_open(struct inode *inode, struct file *filp) |
45 | { | 68 | { |
46 | struct snapshot_data *data; | 69 | struct snapshot_data *data; |
70 | int error; | ||
47 | 71 | ||
48 | if (!atomic_add_unless(&snapshot_device_available, -1, 0)) | 72 | if (!atomic_add_unless(&snapshot_device_available, -1, 0)) |
49 | return -EBUSY; | 73 | return -EBUSY; |
@@ -64,13 +88,23 @@ static int snapshot_open(struct inode *inode, struct file *filp) | |||
64 | data->swap = swsusp_resume_device ? | 88 | data->swap = swsusp_resume_device ? |
65 | swap_type_of(swsusp_resume_device, 0, NULL) : -1; | 89 | swap_type_of(swsusp_resume_device, 0, NULL) : -1; |
66 | data->mode = O_RDONLY; | 90 | data->mode = O_RDONLY; |
91 | error = pm_notifier_call_chain(PM_RESTORE_PREPARE); | ||
92 | if (error) | ||
93 | pm_notifier_call_chain(PM_POST_RESTORE); | ||
67 | } else { | 94 | } else { |
68 | data->swap = -1; | 95 | data->swap = -1; |
69 | data->mode = O_WRONLY; | 96 | data->mode = O_WRONLY; |
97 | error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE); | ||
98 | if (error) | ||
99 | pm_notifier_call_chain(PM_POST_HIBERNATION); | ||
100 | } | ||
101 | if (error) { | ||
102 | atomic_inc(&snapshot_device_available); | ||
103 | return error; | ||
70 | } | 104 | } |
71 | data->frozen = 0; | 105 | data->frozen = 0; |
72 | data->ready = 0; | 106 | data->ready = 0; |
73 | data->platform_suspend = 0; | 107 | data->platform_support = 0; |
74 | 108 | ||
75 | return 0; | 109 | return 0; |
76 | } | 110 | } |
@@ -88,6 +122,8 @@ static int snapshot_release(struct inode *inode, struct file *filp) | |||
88 | thaw_processes(); | 122 | thaw_processes(); |
89 | mutex_unlock(&pm_mutex); | 123 | mutex_unlock(&pm_mutex); |
90 | } | 124 | } |
125 | pm_notifier_call_chain(data->mode == O_WRONLY ? | ||
126 | PM_POST_HIBERNATION : PM_POST_RESTORE); | ||
91 | atomic_inc(&snapshot_device_available); | 127 | atomic_inc(&snapshot_device_available); |
92 | return 0; | 128 | return 0; |
93 | } | 129 | } |
@@ -133,7 +169,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
133 | { | 169 | { |
134 | int error = 0; | 170 | int error = 0; |
135 | struct snapshot_data *data; | 171 | struct snapshot_data *data; |
136 | loff_t avail; | 172 | loff_t size; |
137 | sector_t offset; | 173 | sector_t offset; |
138 | 174 | ||
139 | if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC) | 175 | if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC) |
@@ -151,18 +187,13 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
151 | if (data->frozen) | 187 | if (data->frozen) |
152 | break; | 188 | break; |
153 | mutex_lock(&pm_mutex); | 189 | mutex_lock(&pm_mutex); |
154 | error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE); | 190 | printk("Syncing filesystems ... "); |
155 | if (!error) { | 191 | sys_sync(); |
156 | printk("Syncing filesystems ... "); | 192 | printk("done.\n"); |
157 | sys_sync(); | 193 | |
158 | printk("done.\n"); | 194 | error = freeze_processes(); |
159 | |||
160 | error = freeze_processes(); | ||
161 | if (error) | ||
162 | thaw_processes(); | ||
163 | } | ||
164 | if (error) | 195 | if (error) |
165 | pm_notifier_call_chain(PM_POST_HIBERNATION); | 196 | thaw_processes(); |
166 | mutex_unlock(&pm_mutex); | 197 | mutex_unlock(&pm_mutex); |
167 | if (!error) | 198 | if (!error) |
168 | data->frozen = 1; | 199 | data->frozen = 1; |
@@ -173,19 +204,19 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
173 | break; | 204 | break; |
174 | mutex_lock(&pm_mutex); | 205 | mutex_lock(&pm_mutex); |
175 | thaw_processes(); | 206 | thaw_processes(); |
176 | pm_notifier_call_chain(PM_POST_HIBERNATION); | ||
177 | mutex_unlock(&pm_mutex); | 207 | mutex_unlock(&pm_mutex); |
178 | data->frozen = 0; | 208 | data->frozen = 0; |
179 | break; | 209 | break; |
180 | 210 | ||
211 | case SNAPSHOT_CREATE_IMAGE: | ||
181 | case SNAPSHOT_ATOMIC_SNAPSHOT: | 212 | case SNAPSHOT_ATOMIC_SNAPSHOT: |
182 | if (data->mode != O_RDONLY || !data->frozen || data->ready) { | 213 | if (data->mode != O_RDONLY || !data->frozen || data->ready) { |
183 | error = -EPERM; | 214 | error = -EPERM; |
184 | break; | 215 | break; |
185 | } | 216 | } |
186 | error = hibernation_snapshot(data->platform_suspend); | 217 | error = hibernation_snapshot(data->platform_support); |
187 | if (!error) | 218 | if (!error) |
188 | error = put_user(in_suspend, (unsigned int __user *)arg); | 219 | error = put_user(in_suspend, (int __user *)arg); |
189 | if (!error) | 220 | if (!error) |
190 | data->ready = 1; | 221 | data->ready = 1; |
191 | break; | 222 | break; |
@@ -197,7 +228,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
197 | error = -EPERM; | 228 | error = -EPERM; |
198 | break; | 229 | break; |
199 | } | 230 | } |
200 | error = hibernation_restore(data->platform_suspend); | 231 | error = hibernation_restore(data->platform_support); |
201 | break; | 232 | break; |
202 | 233 | ||
203 | case SNAPSHOT_FREE: | 234 | case SNAPSHOT_FREE: |
@@ -206,16 +237,29 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
206 | data->ready = 0; | 237 | data->ready = 0; |
207 | break; | 238 | break; |
208 | 239 | ||
240 | case SNAPSHOT_PREF_IMAGE_SIZE: | ||
209 | case SNAPSHOT_SET_IMAGE_SIZE: | 241 | case SNAPSHOT_SET_IMAGE_SIZE: |
210 | image_size = arg; | 242 | image_size = arg; |
211 | break; | 243 | break; |
212 | 244 | ||
245 | case SNAPSHOT_GET_IMAGE_SIZE: | ||
246 | if (!data->ready) { | ||
247 | error = -ENODATA; | ||
248 | break; | ||
249 | } | ||
250 | size = snapshot_get_image_size(); | ||
251 | size <<= PAGE_SHIFT; | ||
252 | error = put_user(size, (loff_t __user *)arg); | ||
253 | break; | ||
254 | |||
255 | case SNAPSHOT_AVAIL_SWAP_SIZE: | ||
213 | case SNAPSHOT_AVAIL_SWAP: | 256 | case SNAPSHOT_AVAIL_SWAP: |
214 | avail = count_swap_pages(data->swap, 1); | 257 | size = count_swap_pages(data->swap, 1); |
215 | avail <<= PAGE_SHIFT; | 258 | size <<= PAGE_SHIFT; |
216 | error = put_user(avail, (loff_t __user *)arg); | 259 | error = put_user(size, (loff_t __user *)arg); |
217 | break; | 260 | break; |
218 | 261 | ||
262 | case SNAPSHOT_ALLOC_SWAP_PAGE: | ||
219 | case SNAPSHOT_GET_SWAP_PAGE: | 263 | case SNAPSHOT_GET_SWAP_PAGE: |
220 | if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { | 264 | if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { |
221 | error = -ENODEV; | 265 | error = -ENODEV; |
@@ -224,7 +268,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
224 | offset = alloc_swapdev_block(data->swap); | 268 | offset = alloc_swapdev_block(data->swap); |
225 | if (offset) { | 269 | if (offset) { |
226 | offset <<= PAGE_SHIFT; | 270 | offset <<= PAGE_SHIFT; |
227 | error = put_user(offset, (sector_t __user *)arg); | 271 | error = put_user(offset, (loff_t __user *)arg); |
228 | } else { | 272 | } else { |
229 | error = -ENOSPC; | 273 | error = -ENOSPC; |
230 | } | 274 | } |
@@ -238,7 +282,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
238 | free_all_swap_pages(data->swap); | 282 | free_all_swap_pages(data->swap); |
239 | break; | 283 | break; |
240 | 284 | ||
241 | case SNAPSHOT_SET_SWAP_FILE: | 285 | case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */ |
242 | if (!swsusp_swap_in_use()) { | 286 | if (!swsusp_swap_in_use()) { |
243 | /* | 287 | /* |
244 | * User space encodes device types as two-byte values, | 288 | * User space encodes device types as two-byte values, |
@@ -275,26 +319,33 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
275 | mutex_unlock(&pm_mutex); | 319 | mutex_unlock(&pm_mutex); |
276 | break; | 320 | break; |
277 | 321 | ||
278 | case SNAPSHOT_PMOPS: | 322 | case SNAPSHOT_PLATFORM_SUPPORT: |
323 | data->platform_support = !!arg; | ||
324 | break; | ||
325 | |||
326 | case SNAPSHOT_POWER_OFF: | ||
327 | if (data->platform_support) | ||
328 | error = hibernation_platform_enter(); | ||
329 | break; | ||
330 | |||
331 | case SNAPSHOT_PMOPS: /* This ioctl is deprecated */ | ||
279 | error = -EINVAL; | 332 | error = -EINVAL; |
280 | 333 | ||
281 | switch (arg) { | 334 | switch (arg) { |
282 | 335 | ||
283 | case PMOPS_PREPARE: | 336 | case PMOPS_PREPARE: |
284 | data->platform_suspend = 1; | 337 | data->platform_support = 1; |
285 | error = 0; | 338 | error = 0; |
286 | break; | 339 | break; |
287 | 340 | ||
288 | case PMOPS_ENTER: | 341 | case PMOPS_ENTER: |
289 | if (data->platform_suspend) | 342 | if (data->platform_support) |
290 | error = hibernation_platform_enter(); | 343 | error = hibernation_platform_enter(); |
291 | |||
292 | break; | 344 | break; |
293 | 345 | ||
294 | case PMOPS_FINISH: | 346 | case PMOPS_FINISH: |
295 | if (data->platform_suspend) | 347 | if (data->platform_support) |
296 | error = 0; | 348 | error = 0; |
297 | |||
298 | break; | 349 | break; |
299 | 350 | ||
300 | default: | 351 | default: |