Blame view

kernel/power/user.c 9.56 KB
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * 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>
   *
   * This file is released under the GPLv2.
   *
   */
  
  #include <linux/suspend.h>
  #include <linux/syscalls.h>
3592695c3   Stefan Seyfried   [PATCH] uswsusp: ...
14
  #include <linux/reboot.h>
74da1ff71   Paul Gortmaker   kernel: fix sever...
15
  #include <linux/kmod.h>
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
16
17
18
19
20
21
22
23
  #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...
24
  #include <linux/compat.h>
97c7801cd   Rafael J. Wysocki   [PATCH] swsusp: U...
25
  #include <linux/console.h>
e3920fb42   Rafael J. Wysocki   [PATCH] Disable C...
26
  #include <linux/cpu.h>
7dfb71030   Nigel Cunningham   [PATCH] Add inclu...
27
  #include <linux/freezer.h>
c75108594   Rafael J. Wysocki   PM/Hibernate: Wai...
28
  #include <scsi/scsi_scan.h>
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
29
30
31
32
  
  #include <asm/uaccess.h>
  
  #include "power.h"
eb57c1cf0   Rafael J. Wysocki   Hibernation: Rewo...
33

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
34
35
36
37
38
  #define SNAPSHOT_MINOR	231
  
  static struct snapshot_data {
  	struct snapshot_handle handle;
  	int swap;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
39
40
41
  	int mode;
  	char frozen;
  	char ready;
eb57c1cf0   Rafael J. Wysocki   Hibernation: Rewo...
42
  	char platform_support;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
43
  } snapshot_state;
0709db607   Rafael J. Wysocki   swsusp: use GFP_K...
44
  atomic_t snapshot_device_available = ATOMIC_INIT(1);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
45
46
47
48
  
  static int snapshot_open(struct inode *inode, struct file *filp)
  {
  	struct snapshot_data *data;
c3e94d899   Alan Stern   Hibernation: Add ...
49
  	int error;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
50

bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
51
  	lock_system_sleep();
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
52
53
54
55
56
  
  	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
  		error = -EBUSY;
  		goto Unlock;
  	}
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
57

1525a2ad7   Rafael J. Wysocki   swsusp: fix error...
58
  	if ((filp->f_flags & O_ACCMODE) == O_RDWR) {
0709db607   Rafael J. Wysocki   swsusp: use GFP_K...
59
  		atomic_inc(&snapshot_device_available);
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
60
61
  		error = -ENOSYS;
  		goto Unlock;
1525a2ad7   Rafael J. Wysocki   swsusp: fix error...
62
63
  	}
  	if(create_basic_memory_bitmaps()) {
0709db607   Rafael J. Wysocki   swsusp: use GFP_K...
64
  		atomic_inc(&snapshot_device_available);
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
65
66
  		error = -ENOMEM;
  		goto Unlock;
1525a2ad7   Rafael J. Wysocki   swsusp: fix error...
67
  	}
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
68
69
70
71
72
  	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...
73
  		/* Hibernating.  The image device should be accessible. */
915bae9eb   Rafael J. Wysocki   [PATCH] swsusp: u...
74
  		data->swap = swsusp_resume_device ?
7bf236874   Rafael J. Wysocki   [PATCH] swsusp: D...
75
  			swap_type_of(swsusp_resume_device, 0, NULL) : -1;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
76
  		data->mode = O_RDONLY;
ebae2604f   Andrey Borzenkov   PM: Fix pm_notifi...
77
  		error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
c3e94d899   Alan Stern   Hibernation: Add ...
78
  		if (error)
ebae2604f   Andrey Borzenkov   PM: Fix pm_notifi...
79
  			pm_notifier_call_chain(PM_POST_HIBERNATION);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
80
  	} else {
c75108594   Rafael J. Wysocki   PM/Hibernate: Wai...
81
82
83
84
85
86
  		/*
  		 * Resuming.  We may need to wait for the image device to
  		 * appear.
  		 */
  		wait_for_device_probe();
  		scsi_complete_async_scans();
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
87
88
  		data->swap = -1;
  		data->mode = O_WRONLY;
ebae2604f   Andrey Borzenkov   PM: Fix pm_notifi...
89
  		error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
c3e94d899   Alan Stern   Hibernation: Add ...
90
  		if (error)
ebae2604f   Andrey Borzenkov   PM: Fix pm_notifi...
91
  			pm_notifier_call_chain(PM_POST_RESTORE);
c3e94d899   Alan Stern   Hibernation: Add ...
92
  	}
8440f4b19   Michal Kubecek   PM: Free memory b...
93
94
  	if (error) {
  		free_basic_memory_bitmaps();
c3e94d899   Alan Stern   Hibernation: Add ...
95
  		atomic_inc(&snapshot_device_available);
8440f4b19   Michal Kubecek   PM: Free memory b...
96
  	}
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
97
98
  	data->frozen = 0;
  	data->ready = 0;
eb57c1cf0   Rafael J. Wysocki   Hibernation: Rewo...
99
  	data->platform_support = 0;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
100

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

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
112
  	swsusp_free();
74dfd666d   Rafael J. Wysocki   swsusp: do not us...
113
  	free_basic_memory_bitmaps();
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
114
  	data = filp->private_data;
d1d241cc2   Rafael J. Wysocki   swsusp: use rbtre...
115
  	free_all_swap_pages(data->swap);
9744997a8   Rafael J. Wysocki   PM / Hibernate: M...
116
117
  	if (data->frozen) {
  		pm_restore_gfp_mask();
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
118
  		thaw_processes();
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

d3c1b24c5   Jiri Slaby   PM / Hibernate: S...
180
181
182
183
184
  	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...
185
  	unlock_system_sleep();
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
186

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
187
188
  	return res;
  }
52d11025d   Alan Cox   snapshot: Push BK...
189
190
  static long snapshot_ioctl(struct file *filp, unsigned int cmd,
  							unsigned long arg)
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
191
192
193
  {
  	int error = 0;
  	struct snapshot_data *data;
af508b34d   Rafael J. Wysocki   Hibernation: Intr...
194
  	loff_t size;
3aef83e0e   Rafael J. Wysocki   [PATCH] swsusp: u...
195
  	sector_t offset;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
196
197
198
199
200
201
202
  
  	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;
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
203
204
  	if (!mutex_trylock(&pm_mutex))
  		return -EBUSY;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
205

25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
206
  	data = filp->private_data;
52d11025d   Alan Cox   snapshot: Push BK...
207

6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
208
209
210
211
212
  	switch (cmd) {
  
  	case SNAPSHOT_FREEZE:
  		if (data->frozen)
  			break;
1bfcf1304   Rafael J. Wysocki   pm: rework disabl...
213

c3e94d899   Alan Stern   Hibernation: Add ...
214
215
216
217
  		printk("Syncing filesystems ... ");
  		sys_sync();
  		printk("done.
  ");
1bfcf1304   Rafael J. Wysocki   pm: rework disabl...
218
  		error = usermodehelper_disable();
b10d91174   Rafael J. Wysocki   PM: introduce hib...
219
  		if (error)
1bfcf1304   Rafael J. Wysocki   pm: rework disabl...
220
221
222
  			break;
  
  		error = freeze_processes();
03afed8bc   Tejun Heo   freezer: clean up...
223
  		if (error)
1bfcf1304   Rafael J. Wysocki   pm: rework disabl...
224
  			usermodehelper_enable();
e5b16746f   Srivatsa S. Bhat   PM / Hibernate: R...
225
  		else
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
226
227
228
229
  			data->frozen = 1;
  		break;
  
  	case SNAPSHOT_UNFREEZE:
2f41dddbb   Rafael J. Wysocki   swsusp: Fix userl...
230
  		if (!data->frozen || data->ready)
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
231
  			break;
c9e664f1f   Rafael J. Wysocki   PM / Hibernate: F...
232
  		pm_restore_gfp_mask();
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
233
  		thaw_processes();
1bfcf1304   Rafael J. Wysocki   pm: rework disabl...
234
  		usermodehelper_enable();
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
235
236
  		data->frozen = 0;
  		break;
b694e52eb   Jiri Slaby   PM / Hibernate: R...
237
  	case SNAPSHOT_CREATE_IMAGE:
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
238
239
240
241
  		if (data->mode != O_RDONLY || !data->frozen  || data->ready) {
  			error = -EPERM;
  			break;
  		}
c9e664f1f   Rafael J. Wysocki   PM / Hibernate: F...
242
  		pm_restore_gfp_mask();
eb57c1cf0   Rafael J. Wysocki   Hibernation: Rewo...
243
  		error = hibernation_snapshot(data->platform_support);
97819a262   Srivatsa S. Bhat   PM / Hibernate: T...
244
  		if (!error) {
cc5d207c8   Rafael J. Wysocki   Hibernation: Corr...
245
  			error = put_user(in_suspend, (int __user *)arg);
97819a262   Srivatsa S. Bhat   PM / Hibernate: T...
246
247
248
249
250
251
252
  			if (!error && !freezer_test_done)
  				data->ready = 1;
  			if (freezer_test_done) {
  				freezer_test_done = false;
  				thaw_processes();
  			}
  		}
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
253
254
255
  		break;
  
  	case SNAPSHOT_ATOMIC_RESTORE:
8357376d3   Rafael J. Wysocki   [PATCH] swsusp: I...
256
  		snapshot_write_finalize(&data->handle);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
257
258
259
260
261
  		if (data->mode != O_WRONLY || !data->frozen ||
  		    !snapshot_image_loaded(&data->handle)) {
  			error = -EPERM;
  			break;
  		}
eb57c1cf0   Rafael J. Wysocki   Hibernation: Rewo...
262
  		error = hibernation_restore(data->platform_support);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
263
264
265
266
267
268
269
  		break;
  
  	case SNAPSHOT_FREE:
  		swsusp_free();
  		memset(&data->handle, 0, sizeof(struct snapshot_handle));
  		data->ready = 0;
  		break;
b694e52eb   Jiri Slaby   PM / Hibernate: R...
270
  	case SNAPSHOT_PREF_IMAGE_SIZE:
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
271
272
  		image_size = arg;
  		break;
af508b34d   Rafael J. Wysocki   Hibernation: Intr...
273
274
275
276
277
278
279
280
281
  	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...
282
  	case SNAPSHOT_AVAIL_SWAP_SIZE:
af508b34d   Rafael J. Wysocki   Hibernation: Intr...
283
284
285
  		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...
286
  		break;
b694e52eb   Jiri Slaby   PM / Hibernate: R...
287
  	case SNAPSHOT_ALLOC_SWAP_PAGE:
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
288
289
290
291
  		if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
  			error = -ENODEV;
  			break;
  		}
d1d241cc2   Rafael J. Wysocki   swsusp: use rbtre...
292
  		offset = alloc_swapdev_block(data->swap);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
293
294
  		if (offset) {
  			offset <<= PAGE_SHIFT;
cc5d207c8   Rafael J. Wysocki   Hibernation: Corr...
295
  			error = put_user(offset, (loff_t __user *)arg);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
296
297
298
299
300
301
302
303
304
305
  		} 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...
306
  		free_all_swap_pages(data->swap);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
307
  		break;
9b238205b   Luca Tettamanti   [PATCH] swsusp: a...
308
309
310
311
312
  	case SNAPSHOT_S2RAM:
  		if (!data->frozen) {
  			error = -EPERM;
  			break;
  		}
6c961dfb7   Rafael J. Wysocki   PM: Reduce code d...
313
314
315
316
317
  		/*
  		 * Tasks are frozen and the notifiers have been called with
  		 * PM_HIBERNATION_PREPARE
  		 */
  		error = suspend_devices_and_enter(PM_SUSPEND_MEM);
36cb7035e   Rafael J. Wysocki   PM / Hibernate: F...
318
  		data->ready = 0;
9b238205b   Luca Tettamanti   [PATCH] swsusp: a...
319
  		break;
eb57c1cf0   Rafael J. Wysocki   Hibernation: Rewo...
320
321
322
323
324
325
326
327
  	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...
328
  	case SNAPSHOT_SET_SWAP_AREA:
d1d241cc2   Rafael J. Wysocki   swsusp: use rbtre...
329
  		if (swsusp_swap_in_use()) {
37b2ba12d   Rafael J. Wysocki   [PATCH] swsusp: a...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
  			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...
346
  			swdev = new_decode_dev(swap_area.dev);
37b2ba12d   Rafael J. Wysocki   [PATCH] swsusp: a...
347
348
  			if (swdev) {
  				offset = swap_area.offset;
7bf236874   Rafael J. Wysocki   [PATCH] swsusp: D...
349
  				data->swap = swap_type_of(swdev, offset, NULL);
37b2ba12d   Rafael J. Wysocki   [PATCH] swsusp: a...
350
351
352
353
354
355
356
357
  				if (data->swap < 0)
  					error = -ENODEV;
  			} else {
  				data->swap = -1;
  				error = -EINVAL;
  			}
  		}
  		break;
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
358
359
360
361
  	default:
  		error = -ENOTTY;
  
  	}
25f2f3daa   Rafael J. Wysocki   snapshot: Use pm_...
362
363
  
  	mutex_unlock(&pm_mutex);
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
364
365
  	return error;
  }
c336078bf   Ben Hutchings   PM / Hibernate: I...
366
367
368
369
370
371
372
373
374
375
376
377
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
  #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...
425
  static const struct file_operations snapshot_fops = {
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
426
427
428
429
430
  	.open = snapshot_open,
  	.release = snapshot_release,
  	.read = snapshot_read,
  	.write = snapshot_write,
  	.llseek = no_llseek,
52d11025d   Alan Cox   snapshot: Push BK...
431
  	.unlocked_ioctl = snapshot_ioctl,
c336078bf   Ben Hutchings   PM / Hibernate: I...
432
433
434
  #ifdef CONFIG_COMPAT
  	.compat_ioctl = snapshot_compat_ioctl,
  #endif
6e1819d61   Rafael J. Wysocki   [PATCH] swsusp: u...
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  };
  
  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);