Blame view

kernel/power/user.c 10.1 KB
55716d264   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
2
3
4
5
6
7
  /*
   * linux/kernel/power/user.c
   *
   * This file provides the user space interface for software suspend/resume.
   *
   * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
8
9
10
   */
  
  #include <linux/suspend.h>
3592695c3   Stefan Seyfried   [PATCH] uswsusp: ...
11
  #include <linux/reboot.h>
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
12
13
14
15
16
17
18
19
  #include <linux/string.h>
  #include <linux/device.h>
  #include <linux/miscdevice.h>
  #include <linux/mm.h>
  #include <linux/swap.h>
  #include <linux/swapops.h>
  #include <linux/pm.h>
  #include <linux/fs.h>
c336078bf   Ben Hutchings   PM / Hibernate: I...
20
  #include <linux/compat.h>
97c7801cd   Rafael J. Wysocki   [PATCH] swsusp: U...
21
  #include <linux/console.h>
e3920fb42   Rafael J. Wysocki   [PATCH] Disable C...
22
  #include <linux/cpu.h>
7dfb71030   Nigel Cunningham   [PATCH] Add inclu...
23
  #include <linux/freezer.h>
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
24

7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
25
  #include <linux/uaccess.h>
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
26
27
  
  #include "power.h"
eb57c1cf0   Rafael J. Wysocki   Hibernation: Rewo...
28

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
29
30
31
32
33
  #define SNAPSHOT_MINOR	231
  
  static struct snapshot_data {
  	struct snapshot_handle handle;
  	int swap;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
34
  	int mode;
7bc9b1cff   Rafael J. Wysocki   PM / Hibernate: U...
35
36
37
  	bool frozen;
  	bool ready;
  	bool platform_support;
aab172891   Rafael J. Wysocki   PM / hibernate: F...
38
  	bool free_bitmaps;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
39
  } snapshot_state;
0709db607   Rafael J. Wysocki   swsusp: use GFP_K...
40
  atomic_t snapshot_device_available = ATOMIC_INIT(1);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
41
42
43
44
  
  static int snapshot_open(struct inode *inode, struct file *filp)
  {
  	struct snapshot_data *data;
ea00f4f4f   Lianwei Wang   PM / sleep: make ...
45
  	int error, nr_calls = 0;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
46

a6e15a390   Kees Cook   PM / hibernate: i...
47
48
  	if (!hibernation_available())
  		return -EPERM;
bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
49
  	lock_system_sleep();
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
50
51
52
53
54
  
  	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
  		error = -EBUSY;
  		goto Unlock;
  	}
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
55

1525a2ad7   Rafael J. Wysocki   swsusp: fix error...
56
  	if ((filp->f_flags & O_ACCMODE) == O_RDWR) {
0709db607   Rafael J. Wysocki   swsusp: use GFP_K...
57
  		atomic_inc(&snapshot_device_available);
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
58
59
  		error = -ENOSYS;
  		goto Unlock;
1525a2ad7   Rafael J. Wysocki   swsusp: fix error...
60
  	}
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
61
62
63
64
65
  	nonseekable_open(inode, filp);
  	data = &snapshot_state;
  	filp->private_data = data;
  	memset(&data->handle, 0, sizeof(struct snapshot_handle));
  	if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
c75108594   Rafael J. Wysocki   PM/Hibernate: Wai...
66
  		/* Hibernating.  The image device should be accessible. */
915bae9eb   Rafael J. Wysocki   [PATCH] swsusp: u...
67
  		data->swap = swsusp_resume_device ?
7bf236874   Rafael J. Wysocki   [PATCH] swsusp: D...
68
  			swap_type_of(swsusp_resume_device, 0, NULL) : -1;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
69
  		data->mode = O_RDONLY;
6a0c7cd33   Rafael J. Wysocki   PM / Hibernate: D...
70
  		data->free_bitmaps = false;
ea00f4f4f   Lianwei Wang   PM / sleep: make ...
71
  		error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls);
c3e94d899   Alan Stern   Hibernation: Add ...
72
  		if (error)
ea00f4f4f   Lianwei Wang   PM / sleep: make ...
73
  			__pm_notifier_call_chain(PM_POST_HIBERNATION, --nr_calls, NULL);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
74
  	} else {
c75108594   Rafael J. Wysocki   PM/Hibernate: Wai...
75
76
77
78
79
  		/*
  		 * Resuming.  We may need to wait for the image device to
  		 * appear.
  		 */
  		wait_for_device_probe();
c75108594   Rafael J. Wysocki   PM/Hibernate: Wai...
80

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
81
82
  		data->swap = -1;
  		data->mode = O_WRONLY;
ea00f4f4f   Lianwei Wang   PM / sleep: make ...
83
  		error = __pm_notifier_call_chain(PM_RESTORE_PREPARE, -1, &nr_calls);
aab172891   Rafael J. Wysocki   PM / hibernate: F...
84
85
86
  		if (!error) {
  			error = create_basic_memory_bitmaps();
  			data->free_bitmaps = !error;
ea00f4f4f   Lianwei Wang   PM / sleep: make ...
87
88
  		} else
  			nr_calls--;
c3e94d899   Alan Stern   Hibernation: Add ...
89
  		if (error)
ea00f4f4f   Lianwei Wang   PM / sleep: make ...
90
  			__pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL);
c3e94d899   Alan Stern   Hibernation: Add ...
91
  	}
8fd37a4c9   Rafael J. Wysocki   PM / hibernate: C...
92
  	if (error)
c3e94d899   Alan Stern   Hibernation: Add ...
93
  		atomic_inc(&snapshot_device_available);
8fd37a4c9   Rafael J. Wysocki   PM / hibernate: C...
94

7bc9b1cff   Rafael J. Wysocki   PM / Hibernate: U...
95
96
97
  	data->frozen = false;
  	data->ready = false;
  	data->platform_support = false;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
98

25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
99
   Unlock:
bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
100
  	unlock_system_sleep();
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
101
102
  
  	return error;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
103
104
105
106
107
  }
  
  static int snapshot_release(struct inode *inode, struct file *filp)
  {
  	struct snapshot_data *data;
bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
108
  	lock_system_sleep();
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
109

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
110
111
  	swsusp_free();
  	data = filp->private_data;
d1d241cc2   Rafael J. Wysocki   swsusp: use rbtre...
112
  	free_all_swap_pages(data->swap);
9744997a8   Rafael J. Wysocki   PM / Hibernate: M...
113
114
  	if (data->frozen) {
  		pm_restore_gfp_mask();
8fd37a4c9   Rafael J. Wysocki   PM / hibernate: C...
115
  		free_basic_memory_bitmaps();
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
116
  		thaw_processes();
aab172891   Rafael J. Wysocki   PM / hibernate: F...
117
118
  	} else if (data->free_bitmaps) {
  		free_basic_memory_bitmaps();
9744997a8   Rafael J. Wysocki   PM / Hibernate: M...
119
  	}
1497dd1d2   Takashi Iwai   PM / Hibernate: F...
120
  	pm_notifier_call_chain(data->mode == O_RDONLY ?
c3e94d899   Alan Stern   Hibernation: Add ...
121
  			PM_POST_HIBERNATION : PM_POST_RESTORE);
0709db607   Rafael J. Wysocki   swsusp: use GFP_K...
122
  	atomic_inc(&snapshot_device_available);
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
123

bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
124
  	unlock_system_sleep();
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
125

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
126
127
128
129
130
131
132
133
  	return 0;
  }
  
  static ssize_t snapshot_read(struct file *filp, char __user *buf,
                               size_t count, loff_t *offp)
  {
  	struct snapshot_data *data;
  	ssize_t res;
d3c1b24c5   Jiri Slaby   PM / Hibernate: S...
134
  	loff_t pg_offp = *offp & ~PAGE_MASK;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
135

bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
136
  	lock_system_sleep();
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
137

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
138
  	data = filp->private_data;
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
139
140
141
142
  	if (!data->ready) {
  		res = -ENODATA;
  		goto Unlock;
  	}
d3c1b24c5   Jiri Slaby   PM / Hibernate: S...
143
144
145
146
147
148
  	if (!pg_offp) { /* on page boundary? */
  		res = snapshot_read_next(&data->handle);
  		if (res <= 0)
  			goto Unlock;
  	} else {
  		res = PAGE_SIZE - pg_offp;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
149
  	}
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
150

d3c1b24c5   Jiri Slaby   PM / Hibernate: S...
151
152
153
154
  	res = simple_read_from_buffer(buf, count, &pg_offp,
  			data_of(data->handle), res);
  	if (res > 0)
  		*offp += res;
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
155
   Unlock:
bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
156
  	unlock_system_sleep();
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
157

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
158
159
160
161
162
163
164
165
  	return res;
  }
  
  static ssize_t snapshot_write(struct file *filp, const char __user *buf,
                                size_t count, loff_t *offp)
  {
  	struct snapshot_data *data;
  	ssize_t res;
d3c1b24c5   Jiri Slaby   PM / Hibernate: S...
166
  	loff_t pg_offp = *offp & ~PAGE_MASK;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
167

bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
168
  	lock_system_sleep();
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
169

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
170
  	data = filp->private_data;
d3c1b24c5   Jiri Slaby   PM / Hibernate: S...
171
172
173
174
175
176
177
  
  	if (!pg_offp) {
  		res = snapshot_write_next(&data->handle);
  		if (res <= 0)
  			goto unlock;
  	} else {
  		res = PAGE_SIZE - pg_offp;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
178
  	}
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
179

fc14eebfc   Tetsuo Handa   PM / hibernate: F...
180
181
182
183
  	if (!data_of(data->handle)) {
  		res = -EINVAL;
  		goto unlock;
  	}
d3c1b24c5   Jiri Slaby   PM / Hibernate: S...
184
185
186
187
188
  	res = simple_write_to_buffer(data_of(data->handle), res, &pg_offp,
  			buf, count);
  	if (res > 0)
  		*offp += res;
  unlock:
bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
189
  	unlock_system_sleep();
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
190

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
191
192
  	return res;
  }
52d11025d   Alan Cox   snapshot: Push BK...
193
194
  static long snapshot_ioctl(struct file *filp, unsigned int cmd,
  							unsigned long arg)
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
195
196
197
  {
  	int error = 0;
  	struct snapshot_data *data;
af508b34d   Rafael J. Wysocki   Hibernation: Intr...
198
  	loff_t size;
3aef83e0e   Rafael J. Wysocki   [PATCH] swsusp: u...
199
  	sector_t offset;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
200
201
202
203
204
205
206
  
  	if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
  		return -ENOTTY;
  	if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR)
  		return -ENOTTY;
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
55f2503c3   Pingfan Liu   PM / reboot: Elim...
207
  	if (!mutex_trylock(&system_transition_mutex))
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
208
  		return -EBUSY;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
209

942f40155   Rafael J. Wysocki   PM / hibernate / ...
210
  	lock_device_hotplug();
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
211
  	data = filp->private_data;
52d11025d   Alan Cox   snapshot: Push BK...
212

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
213
214
215
216
217
  	switch (cmd) {
  
  	case SNAPSHOT_FREEZE:
  		if (data->frozen)
  			break;
1bfcf1304   Rafael J. Wysocki   pm: rework disabl...
218

b5dee3130   Harry Pan   PM / sleep: Refac...
219
  		ksys_sync_helper();
c3e94d899   Alan Stern   Hibernation: Add ...
220

1bfcf1304   Rafael J. Wysocki   pm: rework disabl...
221
  		error = freeze_processes();
8fd37a4c9   Rafael J. Wysocki   PM / hibernate: C...
222
223
224
225
226
227
228
  		if (error)
  			break;
  
  		error = create_basic_memory_bitmaps();
  		if (error)
  			thaw_processes();
  		else
7bc9b1cff   Rafael J. Wysocki   PM / Hibernate: U...
229
  			data->frozen = true;
8fd37a4c9   Rafael J. Wysocki   PM / hibernate: C...
230

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
231
232
233
  		break;
  
  	case SNAPSHOT_UNFREEZE:
2f41dddbb   Rafael J. Wysocki   swsusp: Fix userl...
234
  		if (!data->frozen || data->ready)
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
235
  			break;
c9e664f1f   Rafael J. Wysocki   PM / Hibernate: F...
236
  		pm_restore_gfp_mask();
8fd37a4c9   Rafael J. Wysocki   PM / hibernate: C...
237
  		free_basic_memory_bitmaps();
aab172891   Rafael J. Wysocki   PM / hibernate: F...
238
  		data->free_bitmaps = false;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
239
  		thaw_processes();
7bc9b1cff   Rafael J. Wysocki   PM / Hibernate: U...
240
  		data->frozen = false;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
241
  		break;
b694e52eb   Jiri Slaby   PM / Hibernate: R...
242
  	case SNAPSHOT_CREATE_IMAGE:
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
243
244
245
246
  		if (data->mode != O_RDONLY || !data->frozen  || data->ready) {
  			error = -EPERM;
  			break;
  		}
c9e664f1f   Rafael J. Wysocki   PM / Hibernate: F...
247
  		pm_restore_gfp_mask();
eb57c1cf0   Rafael J. Wysocki   Hibernation: Rewo...
248
  		error = hibernation_snapshot(data->platform_support);
51d6ff7ac   Srivatsa S. Bhat   PM / Hibernate: T...
249
  		if (!error) {
cc5d207c8   Rafael J. Wysocki   Hibernation: Corr...
250
  			error = put_user(in_suspend, (int __user *)arg);
a556d5b58   Srivatsa S. Bhat   PM / Hibernate: R...
251
252
  			data->ready = !freezer_test_done && !error;
  			freezer_test_done = false;
97819a262   Srivatsa S. Bhat   PM / Hibernate: T...
253
  		}
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
254
255
256
  		break;
  
  	case SNAPSHOT_ATOMIC_RESTORE:
8357376d3   Rafael J. Wysocki   [PATCH] swsusp: I...
257
  		snapshot_write_finalize(&data->handle);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
258
259
260
261
262
  		if (data->mode != O_WRONLY || !data->frozen ||
  		    !snapshot_image_loaded(&data->handle)) {
  			error = -EPERM;
  			break;
  		}
eb57c1cf0   Rafael J. Wysocki   Hibernation: Rewo...
263
  		error = hibernation_restore(data->platform_support);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
264
265
266
267
268
  		break;
  
  	case SNAPSHOT_FREE:
  		swsusp_free();
  		memset(&data->handle, 0, sizeof(struct snapshot_handle));
7bc9b1cff   Rafael J. Wysocki   PM / Hibernate: U...
269
  		data->ready = false;
181e9bdef   Rafael J. Wysocki   PM / Hibernate: F...
270
271
272
273
274
275
276
277
278
  		/*
  		 * It is necessary to thaw kernel threads here, because
  		 * SNAPSHOT_CREATE_IMAGE may be invoked directly after
  		 * SNAPSHOT_FREE.  In that case, if kernel threads were not
  		 * thawed, the preallocation of memory carried out by
  		 * hibernation_snapshot() might run into problems (i.e. it
  		 * might fail or even deadlock).
  		 */
  		thaw_kernel_threads();
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
279
  		break;
b694e52eb   Jiri Slaby   PM / Hibernate: R...
280
  	case SNAPSHOT_PREF_IMAGE_SIZE:
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
281
282
  		image_size = arg;
  		break;
af508b34d   Rafael J. Wysocki   Hibernation: Intr...
283
284
285
286
287
288
289
290
291
  	case SNAPSHOT_GET_IMAGE_SIZE:
  		if (!data->ready) {
  			error = -ENODATA;
  			break;
  		}
  		size = snapshot_get_image_size();
  		size <<= PAGE_SHIFT;
  		error = put_user(size, (loff_t __user *)arg);
  		break;
b694e52eb   Jiri Slaby   PM / Hibernate: R...
292
  	case SNAPSHOT_AVAIL_SWAP_SIZE:
af508b34d   Rafael J. Wysocki   Hibernation: Intr...
293
294
295
  		size = count_swap_pages(data->swap, 1);
  		size <<= PAGE_SHIFT;
  		error = put_user(size, (loff_t __user *)arg);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
296
  		break;
b694e52eb   Jiri Slaby   PM / Hibernate: R...
297
  	case SNAPSHOT_ALLOC_SWAP_PAGE:
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
298
299
300
301
  		if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
  			error = -ENODEV;
  			break;
  		}
d1d241cc2   Rafael J. Wysocki   swsusp: use rbtre...
302
  		offset = alloc_swapdev_block(data->swap);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
303
304
  		if (offset) {
  			offset <<= PAGE_SHIFT;
cc5d207c8   Rafael J. Wysocki   Hibernation: Corr...
305
  			error = put_user(offset, (loff_t __user *)arg);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
306
307
308
309
310
311
312
313
314
315
  		} else {
  			error = -ENOSPC;
  		}
  		break;
  
  	case SNAPSHOT_FREE_SWAP_PAGES:
  		if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
  			error = -ENODEV;
  			break;
  		}
d1d241cc2   Rafael J. Wysocki   swsusp: use rbtre...
316
  		free_all_swap_pages(data->swap);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
317
  		break;
9b238205b   Luca Tettamanti   [PATCH] swsusp: a...
318
319
320
321
322
  	case SNAPSHOT_S2RAM:
  		if (!data->frozen) {
  			error = -EPERM;
  			break;
  		}
6c961dfb7   Rafael J. Wysocki   PM: Reduce code d...
323
324
325
326
327
  		/*
  		 * Tasks are frozen and the notifiers have been called with
  		 * PM_HIBERNATION_PREPARE
  		 */
  		error = suspend_devices_and_enter(PM_SUSPEND_MEM);
7bc9b1cff   Rafael J. Wysocki   PM / Hibernate: U...
328
  		data->ready = false;
9b238205b   Luca Tettamanti   [PATCH] swsusp: a...
329
  		break;
eb57c1cf0   Rafael J. Wysocki   Hibernation: Rewo...
330
331
332
333
334
335
336
337
  	case SNAPSHOT_PLATFORM_SUPPORT:
  		data->platform_support = !!arg;
  		break;
  
  	case SNAPSHOT_POWER_OFF:
  		if (data->platform_support)
  			error = hibernation_platform_enter();
  		break;
37b2ba12d   Rafael J. Wysocki   [PATCH] swsusp: a...
338
  	case SNAPSHOT_SET_SWAP_AREA:
d1d241cc2   Rafael J. Wysocki   swsusp: use rbtre...
339
  		if (swsusp_swap_in_use()) {
37b2ba12d   Rafael J. Wysocki   [PATCH] swsusp: a...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  			error = -EPERM;
  		} else {
  			struct resume_swap_area swap_area;
  			dev_t swdev;
  
  			error = copy_from_user(&swap_area, (void __user *)arg,
  					sizeof(struct resume_swap_area));
  			if (error) {
  				error = -EFAULT;
  				break;
  			}
  
  			/*
  			 * User space encodes device types as two-byte values,
  			 * so we need to recode them
  			 */
d88d4050d   Jiri Slaby   PM / Hibernate: u...
356
  			swdev = new_decode_dev(swap_area.dev);
37b2ba12d   Rafael J. Wysocki   [PATCH] swsusp: a...
357
358
  			if (swdev) {
  				offset = swap_area.offset;
7bf236874   Rafael J. Wysocki   [PATCH] swsusp: D...
359
  				data->swap = swap_type_of(swdev, offset, NULL);
37b2ba12d   Rafael J. Wysocki   [PATCH] swsusp: a...
360
361
362
363
364
365
366
367
  				if (data->swap < 0)
  					error = -ENODEV;
  			} else {
  				data->swap = -1;
  				error = -EINVAL;
  			}
  		}
  		break;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
368
369
370
371
  	default:
  		error = -ENOTTY;
  
  	}
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
372

942f40155   Rafael J. Wysocki   PM / hibernate / ...
373
  	unlock_device_hotplug();
55f2503c3   Pingfan Liu   PM / reboot: Elim...
374
  	mutex_unlock(&system_transition_mutex);
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
375

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
376
377
  	return error;
  }
c336078bf   Ben Hutchings   PM / Hibernate: I...
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
  #ifdef CONFIG_COMPAT
  
  struct compat_resume_swap_area {
  	compat_loff_t offset;
  	u32 dev;
  } __packed;
  
  static long
  snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  {
  	BUILD_BUG_ON(sizeof(loff_t) != sizeof(compat_loff_t));
  
  	switch (cmd) {
  	case SNAPSHOT_GET_IMAGE_SIZE:
  	case SNAPSHOT_AVAIL_SWAP_SIZE:
  	case SNAPSHOT_ALLOC_SWAP_PAGE: {
  		compat_loff_t __user *uoffset = compat_ptr(arg);
  		loff_t offset;
  		mm_segment_t old_fs;
  		int err;
  
  		old_fs = get_fs();
  		set_fs(KERNEL_DS);
  		err = snapshot_ioctl(file, cmd, (unsigned long) &offset);
  		set_fs(old_fs);
  		if (!err && put_user(offset, uoffset))
  			err = -EFAULT;
  		return err;
  	}
  
  	case SNAPSHOT_CREATE_IMAGE:
  		return snapshot_ioctl(file, cmd,
  				      (unsigned long) compat_ptr(arg));
  
  	case SNAPSHOT_SET_SWAP_AREA: {
  		struct compat_resume_swap_area __user *u_swap_area =
  			compat_ptr(arg);
  		struct resume_swap_area swap_area;
  		mm_segment_t old_fs;
  		int err;
  
  		err = get_user(swap_area.offset, &u_swap_area->offset);
  		err |= get_user(swap_area.dev, &u_swap_area->dev);
  		if (err)
  			return -EFAULT;
  		old_fs = get_fs();
  		set_fs(KERNEL_DS);
  		err = snapshot_ioctl(file, SNAPSHOT_SET_SWAP_AREA,
  				     (unsigned long) &swap_area);
  		set_fs(old_fs);
  		return err;
  	}
  
  	default:
  		return snapshot_ioctl(file, cmd, arg);
  	}
  }
  
  #endif /* CONFIG_COMPAT */
15ad7cdcf   Helge Deller   [PATCH] struct se...
437
  static const struct file_operations snapshot_fops = {
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
438
439
440
441
442
  	.open = snapshot_open,
  	.release = snapshot_release,
  	.read = snapshot_read,
  	.write = snapshot_write,
  	.llseek = no_llseek,
52d11025d   Alan Cox   snapshot: Push BK...
443
  	.unlocked_ioctl = snapshot_ioctl,
c336078bf   Ben Hutchings   PM / Hibernate: I...
444
445
446
  #ifdef CONFIG_COMPAT
  	.compat_ioctl = snapshot_compat_ioctl,
  #endif
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
447
448
449
450
451
452
453
454
455
456
457
458
459
460
  };
  
  static struct miscdevice snapshot_device = {
  	.minor = SNAPSHOT_MINOR,
  	.name = "snapshot",
  	.fops = &snapshot_fops,
  };
  
  static int __init snapshot_device_init(void)
  {
  	return misc_register(&snapshot_device);
  };
  
  device_initcall(snapshot_device_init);