Blame view

block/compat_ioctl.c 20.8 KB
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
1
2
3
4
5
6
7
8
  #include <linux/blkdev.h>
  #include <linux/blkpg.h>
  #include <linux/blktrace_api.h>
  #include <linux/cdrom.h>
  #include <linux/compat.h>
  #include <linux/elevator.h>
  #include <linux/fd.h>
  #include <linux/hdreg.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
9
  #include <linux/slab.h>
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
10
  #include <linux/syscalls.h>
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
11
12
13
14
15
16
17
18
19
20
21
22
  #include <linux/types.h>
  #include <linux/uaccess.h>
  
  static int compat_put_ushort(unsigned long arg, unsigned short val)
  {
  	return put_user(val, (unsigned short __user *)compat_ptr(arg));
  }
  
  static int compat_put_int(unsigned long arg, int val)
  {
  	return put_user(val, (compat_int_t __user *)compat_ptr(arg));
  }
ac481c20e   Martin K. Petersen   block: Topology i...
23
24
25
26
  static int compat_put_uint(unsigned long arg, unsigned int val)
  {
  	return put_user(val, (compat_uint_t __user *)compat_ptr(arg));
  }
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  static int compat_put_long(unsigned long arg, long val)
  {
  	return put_user(val, (compat_long_t __user *)compat_ptr(arg));
  }
  
  static int compat_put_ulong(unsigned long arg, compat_ulong_t val)
  {
  	return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
  }
  
  static int compat_put_u64(unsigned long arg, u64 val)
  {
  	return put_user(val, (compat_u64 __user *)compat_ptr(arg));
  }
9617db085   Arnd Bergmann   compat_ioctl: mov...
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  struct compat_hd_geometry {
  	unsigned char heads;
  	unsigned char sectors;
  	unsigned short cylinders;
  	u32 start;
  };
  
  static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
  			struct compat_hd_geometry __user *ugeo)
  {
  	struct hd_geometry geo;
  	int ret;
  
  	if (!ugeo)
  		return -EINVAL;
  	if (!disk->fops->getgeo)
  		return -ENOTTY;
  
  	/*
  	 * We need to set the startsect first, the driver may
  	 * want to override it.
  	 */
  	geo.start = get_start_sect(bdev);
  	ret = disk->fops->getgeo(bdev, &geo);
  	if (ret)
  		return ret;
  
  	ret = copy_to_user(ugeo, &geo, 4);
  	ret |= __put_user(geo.start, &ugeo->start);
  	if (ret)
  		ret = -EFAULT;
  
  	return ret;
  }
33c2dca49   Al Viro   [PATCH] trim file...
75
76
  static int compat_hdio_ioctl(struct block_device *bdev, fmode_t mode,
  		unsigned int cmd, unsigned long arg)
9617db085   Arnd Bergmann   compat_ioctl: mov...
77
78
79
80
81
82
83
  {
  	mm_segment_t old_fs = get_fs();
  	unsigned long kval;
  	unsigned int __user *uvp;
  	int error;
  
  	set_fs(KERNEL_DS);
33c2dca49   Al Viro   [PATCH] trim file...
84
  	error = __blkdev_driver_ioctl(bdev, mode,
9617db085   Arnd Bergmann   compat_ioctl: mov...
85
86
87
88
89
90
91
92
93
94
  				cmd, (unsigned long)(&kval));
  	set_fs(old_fs);
  
  	if (error == 0) {
  		uvp = compat_ptr(arg);
  		if (put_user(kval, uvp))
  			error = -EFAULT;
  	}
  	return error;
  }
b3087cc4f   Arnd Bergmann   compat_ioctl: mov...
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  struct compat_cdrom_read_audio {
  	union cdrom_addr	addr;
  	u8			addr_format;
  	compat_int_t		nframes;
  	compat_caddr_t		buf;
  };
  
  struct compat_cdrom_generic_command {
  	unsigned char	cmd[CDROM_PACKET_SIZE];
  	compat_caddr_t	buffer;
  	compat_uint_t	buflen;
  	compat_int_t	stat;
  	compat_caddr_t	sense;
  	unsigned char	data_direction;
  	compat_int_t	quiet;
  	compat_int_t	timeout;
  	compat_caddr_t	reserved[1];
  };
33c2dca49   Al Viro   [PATCH] trim file...
113
114
  static int compat_cdrom_read_audio(struct block_device *bdev, fmode_t mode,
  		unsigned int cmd, unsigned long arg)
b3087cc4f   Arnd Bergmann   compat_ioctl: mov...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
  {
  	struct cdrom_read_audio __user *cdread_audio;
  	struct compat_cdrom_read_audio __user *cdread_audio32;
  	__u32 data;
  	void __user *datap;
  
  	cdread_audio = compat_alloc_user_space(sizeof(*cdread_audio));
  	cdread_audio32 = compat_ptr(arg);
  
  	if (copy_in_user(&cdread_audio->addr,
  			 &cdread_audio32->addr,
  			 (sizeof(*cdread_audio32) -
  			  sizeof(compat_caddr_t))))
  		return -EFAULT;
  
  	if (get_user(data, &cdread_audio32->buf))
  		return -EFAULT;
  	datap = compat_ptr(data);
  	if (put_user(datap, &cdread_audio->buf))
  		return -EFAULT;
33c2dca49   Al Viro   [PATCH] trim file...
135
  	return __blkdev_driver_ioctl(bdev, mode, cmd,
b3087cc4f   Arnd Bergmann   compat_ioctl: mov...
136
137
  			(unsigned long)cdread_audio);
  }
33c2dca49   Al Viro   [PATCH] trim file...
138
139
  static int compat_cdrom_generic_command(struct block_device *bdev, fmode_t mode,
  		unsigned int cmd, unsigned long arg)
b3087cc4f   Arnd Bergmann   compat_ioctl: mov...
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
  {
  	struct cdrom_generic_command __user *cgc;
  	struct compat_cdrom_generic_command __user *cgc32;
  	u32 data;
  	unsigned char dir;
  	int itmp;
  
  	cgc = compat_alloc_user_space(sizeof(*cgc));
  	cgc32 = compat_ptr(arg);
  
  	if (copy_in_user(&cgc->cmd, &cgc32->cmd, sizeof(cgc->cmd)) ||
  	    get_user(data, &cgc32->buffer) ||
  	    put_user(compat_ptr(data), &cgc->buffer) ||
  	    copy_in_user(&cgc->buflen, &cgc32->buflen,
  			 (sizeof(unsigned int) + sizeof(int))) ||
  	    get_user(data, &cgc32->sense) ||
  	    put_user(compat_ptr(data), &cgc->sense) ||
  	    get_user(dir, &cgc32->data_direction) ||
  	    put_user(dir, &cgc->data_direction) ||
  	    get_user(itmp, &cgc32->quiet) ||
  	    put_user(itmp, &cgc->quiet) ||
  	    get_user(itmp, &cgc32->timeout) ||
  	    put_user(itmp, &cgc->timeout) ||
  	    get_user(data, &cgc32->reserved[0]) ||
  	    put_user(compat_ptr(data), &cgc->reserved[0]))
  		return -EFAULT;
33c2dca49   Al Viro   [PATCH] trim file...
166
  	return __blkdev_driver_ioctl(bdev, mode, cmd, (unsigned long)cgc);
b3087cc4f   Arnd Bergmann   compat_ioctl: mov...
167
  }
18cf7f872   Arnd Bergmann   compat_ioctl: mov...
168
169
170
171
172
173
  struct compat_blkpg_ioctl_arg {
  	compat_int_t op;
  	compat_int_t flags;
  	compat_int_t datalen;
  	compat_caddr_t data;
  };
56b26add0   Al Viro   [PATCH] kill the ...
174
  static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
18cf7f872   Arnd Bergmann   compat_ioctl: mov...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  		unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32)
  {
  	struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a));
  	compat_caddr_t udata;
  	compat_int_t n;
  	int err;
  
  	err = get_user(n, &ua32->op);
  	err |= put_user(n, &a->op);
  	err |= get_user(n, &ua32->flags);
  	err |= put_user(n, &a->flags);
  	err |= get_user(n, &ua32->datalen);
  	err |= put_user(n, &a->datalen);
  	err |= get_user(udata, &ua32->data);
  	err |= put_user(compat_ptr(udata), &a->data);
  	if (err)
  		return err;
56b26add0   Al Viro   [PATCH] kill the ...
192
  	return blkdev_ioctl(bdev, mode, cmd, (unsigned long)a);
18cf7f872   Arnd Bergmann   compat_ioctl: mov...
193
  }
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
194
195
196
  #define BLKBSZGET_32		_IOR(0x12, 112, int)
  #define BLKBSZSET_32		_IOW(0x12, 113, int)
  #define BLKGETSIZE64_32		_IOR(0x12, 114, int)
1ca91cd03   Arnd Bergmann   compat_ioctl: mov...
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  struct compat_floppy_drive_params {
  	char		cmos;
  	compat_ulong_t	max_dtr;
  	compat_ulong_t	hlt;
  	compat_ulong_t	hut;
  	compat_ulong_t	srt;
  	compat_ulong_t	spinup;
  	compat_ulong_t	spindown;
  	unsigned char	spindown_offset;
  	unsigned char	select_delay;
  	unsigned char	rps;
  	unsigned char	tracks;
  	compat_ulong_t	timeout;
  	unsigned char	interleave_sect;
  	struct floppy_max_errors max_errors;
  	char		flags;
  	char		read_track;
  	short		autodetect[8];
  	compat_int_t	checkfreq;
  	compat_int_t	native_format;
  };
  
  struct compat_floppy_drive_struct {
  	signed char	flags;
  	compat_ulong_t	spinup_date;
  	compat_ulong_t	select_date;
  	compat_ulong_t	first_read_date;
  	short		probed_format;
  	short		track;
  	short		maxblock;
  	short		maxtrack;
  	compat_int_t	generation;
  	compat_int_t	keep_data;
  	compat_int_t	fd_ref;
  	compat_int_t	fd_device;
  	compat_int_t	last_checked;
  	compat_caddr_t dmabuf;
  	compat_int_t	bufblocks;
  };
  
  struct compat_floppy_fdc_state {
  	compat_int_t	spec1;
  	compat_int_t	spec2;
  	compat_int_t	dtr;
  	unsigned char	version;
  	unsigned char	dor;
  	compat_ulong_t	address;
  	unsigned int	rawcmd:2;
  	unsigned int	reset:1;
  	unsigned int	need_configure:1;
  	unsigned int	perp_mode:2;
  	unsigned int	has_fifo:1;
  	unsigned int	driver_version;
  	unsigned char	track[4];
  };
  
  struct compat_floppy_write_errors {
  	unsigned int	write_errors;
  	compat_ulong_t	first_error_sector;
  	compat_int_t	first_error_generation;
  	compat_ulong_t	last_error_sector;
  	compat_int_t	last_error_generation;
  	compat_uint_t	badness;
  };
  
  #define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
  #define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
1ca91cd03   Arnd Bergmann   compat_ioctl: mov...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  #define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
  #define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
  #define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
  #define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
  #define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
  #define FDWERRORGET32  _IOR(2, 0x17, struct compat_floppy_write_errors)
  
  static struct {
  	unsigned int	cmd32;
  	unsigned int	cmd;
  } fd_ioctl_trans_table[] = {
  	{ FDSETPRM32, FDSETPRM },
  	{ FDDEFPRM32, FDDEFPRM },
  	{ FDGETPRM32, FDGETPRM },
  	{ FDSETDRVPRM32, FDSETDRVPRM },
  	{ FDGETDRVPRM32, FDGETDRVPRM },
  	{ FDGETDRVSTAT32, FDGETDRVSTAT },
  	{ FDPOLLDRVSTAT32, FDPOLLDRVSTAT },
  	{ FDGETFDCSTAT32, FDGETFDCSTAT },
  	{ FDWERRORGET32, FDWERRORGET }
  };
  
  #define NR_FD_IOCTL_TRANS ARRAY_SIZE(fd_ioctl_trans_table)
33c2dca49   Al Viro   [PATCH] trim file...
287
288
  static int compat_fd_ioctl(struct block_device *bdev, fmode_t mode,
  		unsigned int cmd, unsigned long arg)
1ca91cd03   Arnd Bergmann   compat_ioctl: mov...
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
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
  {
  	mm_segment_t old_fs = get_fs();
  	void *karg = NULL;
  	unsigned int kcmd = 0;
  	int i, err;
  
  	for (i = 0; i < NR_FD_IOCTL_TRANS; i++)
  		if (cmd == fd_ioctl_trans_table[i].cmd32) {
  			kcmd = fd_ioctl_trans_table[i].cmd;
  			break;
  		}
  	if (!kcmd)
  		return -EINVAL;
  
  	switch (cmd) {
  	case FDSETPRM32:
  	case FDDEFPRM32:
  	case FDGETPRM32:
  	{
  		compat_uptr_t name;
  		struct compat_floppy_struct __user *uf;
  		struct floppy_struct *f;
  
  		uf = compat_ptr(arg);
  		f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL);
  		if (!karg)
  			return -ENOMEM;
  		if (cmd == FDGETPRM32)
  			break;
  		err = __get_user(f->size, &uf->size);
  		err |= __get_user(f->sect, &uf->sect);
  		err |= __get_user(f->head, &uf->head);
  		err |= __get_user(f->track, &uf->track);
  		err |= __get_user(f->stretch, &uf->stretch);
  		err |= __get_user(f->gap, &uf->gap);
  		err |= __get_user(f->rate, &uf->rate);
  		err |= __get_user(f->spec1, &uf->spec1);
  		err |= __get_user(f->fmt_gap, &uf->fmt_gap);
  		err |= __get_user(name, &uf->name);
  		f->name = compat_ptr(name);
  		if (err) {
  			err = -EFAULT;
  			goto out;
  		}
  		break;
  	}
  	case FDSETDRVPRM32:
  	case FDGETDRVPRM32:
  	{
  		struct compat_floppy_drive_params __user *uf;
  		struct floppy_drive_params *f;
  
  		uf = compat_ptr(arg);
  		f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL);
  		if (!karg)
  			return -ENOMEM;
  		if (cmd == FDGETDRVPRM32)
  			break;
  		err = __get_user(f->cmos, &uf->cmos);
  		err |= __get_user(f->max_dtr, &uf->max_dtr);
  		err |= __get_user(f->hlt, &uf->hlt);
  		err |= __get_user(f->hut, &uf->hut);
  		err |= __get_user(f->srt, &uf->srt);
  		err |= __get_user(f->spinup, &uf->spinup);
  		err |= __get_user(f->spindown, &uf->spindown);
  		err |= __get_user(f->spindown_offset, &uf->spindown_offset);
  		err |= __get_user(f->select_delay, &uf->select_delay);
  		err |= __get_user(f->rps, &uf->rps);
  		err |= __get_user(f->tracks, &uf->tracks);
  		err |= __get_user(f->timeout, &uf->timeout);
  		err |= __get_user(f->interleave_sect, &uf->interleave_sect);
  		err |= __copy_from_user(&f->max_errors, &uf->max_errors, sizeof(f->max_errors));
  		err |= __get_user(f->flags, &uf->flags);
  		err |= __get_user(f->read_track, &uf->read_track);
  		err |= __copy_from_user(f->autodetect, uf->autodetect, sizeof(f->autodetect));
  		err |= __get_user(f->checkfreq, &uf->checkfreq);
  		err |= __get_user(f->native_format, &uf->native_format);
  		if (err) {
  			err = -EFAULT;
  			goto out;
  		}
  		break;
  	}
  	case FDGETDRVSTAT32:
  	case FDPOLLDRVSTAT32:
  		karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL);
  		if (!karg)
  			return -ENOMEM;
  		break;
  	case FDGETFDCSTAT32:
  		karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL);
  		if (!karg)
  			return -ENOMEM;
  		break;
  	case FDWERRORGET32:
  		karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL);
  		if (!karg)
  			return -ENOMEM;
  		break;
  	default:
  		return -EINVAL;
  	}
  	set_fs(KERNEL_DS);
33c2dca49   Al Viro   [PATCH] trim file...
392
  	err = __blkdev_driver_ioctl(bdev, mode, kcmd, (unsigned long)karg);
1ca91cd03   Arnd Bergmann   compat_ioctl: mov...
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
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
  	set_fs(old_fs);
  	if (err)
  		goto out;
  	switch (cmd) {
  	case FDGETPRM32:
  	{
  		struct floppy_struct *f = karg;
  		struct compat_floppy_struct __user *uf = compat_ptr(arg);
  
  		err = __put_user(f->size, &uf->size);
  		err |= __put_user(f->sect, &uf->sect);
  		err |= __put_user(f->head, &uf->head);
  		err |= __put_user(f->track, &uf->track);
  		err |= __put_user(f->stretch, &uf->stretch);
  		err |= __put_user(f->gap, &uf->gap);
  		err |= __put_user(f->rate, &uf->rate);
  		err |= __put_user(f->spec1, &uf->spec1);
  		err |= __put_user(f->fmt_gap, &uf->fmt_gap);
  		err |= __put_user((u64)f->name, (compat_caddr_t __user *)&uf->name);
  		break;
  	}
  	case FDGETDRVPRM32:
  	{
  		struct compat_floppy_drive_params __user *uf;
  		struct floppy_drive_params *f = karg;
  
  		uf = compat_ptr(arg);
  		err = __put_user(f->cmos, &uf->cmos);
  		err |= __put_user(f->max_dtr, &uf->max_dtr);
  		err |= __put_user(f->hlt, &uf->hlt);
  		err |= __put_user(f->hut, &uf->hut);
  		err |= __put_user(f->srt, &uf->srt);
  		err |= __put_user(f->spinup, &uf->spinup);
  		err |= __put_user(f->spindown, &uf->spindown);
  		err |= __put_user(f->spindown_offset, &uf->spindown_offset);
  		err |= __put_user(f->select_delay, &uf->select_delay);
  		err |= __put_user(f->rps, &uf->rps);
  		err |= __put_user(f->tracks, &uf->tracks);
  		err |= __put_user(f->timeout, &uf->timeout);
  		err |= __put_user(f->interleave_sect, &uf->interleave_sect);
  		err |= __copy_to_user(&uf->max_errors, &f->max_errors, sizeof(f->max_errors));
  		err |= __put_user(f->flags, &uf->flags);
  		err |= __put_user(f->read_track, &uf->read_track);
  		err |= __copy_to_user(uf->autodetect, f->autodetect, sizeof(f->autodetect));
  		err |= __put_user(f->checkfreq, &uf->checkfreq);
  		err |= __put_user(f->native_format, &uf->native_format);
  		break;
  	}
  	case FDGETDRVSTAT32:
  	case FDPOLLDRVSTAT32:
  	{
  		struct compat_floppy_drive_struct __user *uf;
  		struct floppy_drive_struct *f = karg;
  
  		uf = compat_ptr(arg);
  		err = __put_user(f->flags, &uf->flags);
  		err |= __put_user(f->spinup_date, &uf->spinup_date);
  		err |= __put_user(f->select_date, &uf->select_date);
  		err |= __put_user(f->first_read_date, &uf->first_read_date);
  		err |= __put_user(f->probed_format, &uf->probed_format);
  		err |= __put_user(f->track, &uf->track);
  		err |= __put_user(f->maxblock, &uf->maxblock);
  		err |= __put_user(f->maxtrack, &uf->maxtrack);
  		err |= __put_user(f->generation, &uf->generation);
  		err |= __put_user(f->keep_data, &uf->keep_data);
  		err |= __put_user(f->fd_ref, &uf->fd_ref);
  		err |= __put_user(f->fd_device, &uf->fd_device);
  		err |= __put_user(f->last_checked, &uf->last_checked);
  		err |= __put_user((u64)f->dmabuf, &uf->dmabuf);
  		err |= __put_user((u64)f->bufblocks, &uf->bufblocks);
  		break;
  	}
  	case FDGETFDCSTAT32:
  	{
  		struct compat_floppy_fdc_state __user *uf;
  		struct floppy_fdc_state *f = karg;
  
  		uf = compat_ptr(arg);
  		err = __put_user(f->spec1, &uf->spec1);
  		err |= __put_user(f->spec2, &uf->spec2);
  		err |= __put_user(f->dtr, &uf->dtr);
  		err |= __put_user(f->version, &uf->version);
  		err |= __put_user(f->dor, &uf->dor);
  		err |= __put_user(f->address, &uf->address);
  		err |= __copy_to_user((char __user *)&uf->address + sizeof(uf->address),
  				   (char *)&f->address + sizeof(f->address), sizeof(int));
  		err |= __put_user(f->driver_version, &uf->driver_version);
  		err |= __copy_to_user(uf->track, f->track, sizeof(f->track));
  		break;
  	}
  	case FDWERRORGET32:
  	{
  		struct compat_floppy_write_errors __user *uf;
  		struct floppy_write_errors *f = karg;
  
  		uf = compat_ptr(arg);
  		err = __put_user(f->write_errors, &uf->write_errors);
  		err |= __put_user(f->first_error_sector, &uf->first_error_sector);
  		err |= __put_user(f->first_error_generation, &uf->first_error_generation);
  		err |= __put_user(f->last_error_sector, &uf->last_error_sector);
  		err |= __put_user(f->last_error_generation, &uf->last_error_generation);
  		err |= __put_user(f->badness, &uf->badness);
  		break;
  	}
  	default:
  		break;
  	}
  	if (err)
  		err = -EFAULT;
  
  out:
  	kfree(karg);
  	return err;
  }
33c2dca49   Al Viro   [PATCH] trim file...
507
508
  static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
  			unsigned cmd, unsigned long arg)
7199d4cdd   Arnd Bergmann   compat_ioctl: add...
509
  {
33013a881   Philip Langdale   compat_ioctl: fix...
510
  	switch (cmd) {
9617db085   Arnd Bergmann   compat_ioctl: mov...
511
512
513
514
515
516
517
518
519
520
521
  	case HDIO_GET_UNMASKINTR:
  	case HDIO_GET_MULTCOUNT:
  	case HDIO_GET_KEEPSETTINGS:
  	case HDIO_GET_32BIT:
  	case HDIO_GET_NOWERR:
  	case HDIO_GET_DMA:
  	case HDIO_GET_NICE:
  	case HDIO_GET_WCACHE:
  	case HDIO_GET_ACOUSTIC:
  	case HDIO_GET_ADDRESS:
  	case HDIO_GET_BUSSTATE:
33c2dca49   Al Viro   [PATCH] trim file...
522
  		return compat_hdio_ioctl(bdev, mode, cmd, arg);
1ca91cd03   Arnd Bergmann   compat_ioctl: mov...
523
524
525
526
527
528
529
530
531
  	case FDSETPRM32:
  	case FDDEFPRM32:
  	case FDGETPRM32:
  	case FDSETDRVPRM32:
  	case FDGETDRVPRM32:
  	case FDGETDRVSTAT32:
  	case FDPOLLDRVSTAT32:
  	case FDGETFDCSTAT32:
  	case FDWERRORGET32:
33c2dca49   Al Viro   [PATCH] trim file...
532
  		return compat_fd_ioctl(bdev, mode, cmd, arg);
b3087cc4f   Arnd Bergmann   compat_ioctl: mov...
533
  	case CDROMREADAUDIO:
33c2dca49   Al Viro   [PATCH] trim file...
534
  		return compat_cdrom_read_audio(bdev, mode, cmd, arg);
b3087cc4f   Arnd Bergmann   compat_ioctl: mov...
535
  	case CDROM_SEND_PACKET:
33c2dca49   Al Viro   [PATCH] trim file...
536
  		return compat_cdrom_generic_command(bdev, mode, cmd, arg);
b3087cc4f   Arnd Bergmann   compat_ioctl: mov...
537

7199d4cdd   Arnd Bergmann   compat_ioctl: add...
538
539
540
541
542
543
544
545
546
547
548
549
  	/*
  	 * No handler required for the ones below, we just need to
  	 * convert arg to a 64 bit pointer.
  	 */
  	case BLKSECTSET:
  	/*
  	 * 0x03 -- HD/IDE ioctl's used by hdparm and friends.
  	 *         Some need translations, these do not.
  	 */
  	case HDIO_GET_IDENTITY:
  	case HDIO_DRIVE_TASK:
  	case HDIO_DRIVE_CMD:
7199d4cdd   Arnd Bergmann   compat_ioctl: add...
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
  	/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
  	case 0x330:
  	/* 0x02 -- Floppy ioctls */
  	case FDMSGON:
  	case FDMSGOFF:
  	case FDSETEMSGTRESH:
  	case FDFLUSH:
  	case FDWERRORCLR:
  	case FDSETMAXERRS:
  	case FDGETMAXERRS:
  	case FDGETDRVTYP:
  	case FDEJECT:
  	case FDCLRPRM:
  	case FDFMTBEG:
  	case FDFMTEND:
  	case FDRESET:
  	case FDTWADDLE:
  	case FDFMTTRK:
  	case FDRAWCMD:
  	/* CDROM stuff */
  	case CDROMPAUSE:
  	case CDROMRESUME:
  	case CDROMPLAYMSF:
  	case CDROMPLAYTRKIND:
  	case CDROMREADTOCHDR:
  	case CDROMREADTOCENTRY:
  	case CDROMSTOP:
  	case CDROMSTART:
  	case CDROMEJECT:
  	case CDROMVOLCTRL:
  	case CDROMSUBCHNL:
  	case CDROMMULTISESSION:
  	case CDROM_GET_MCN:
  	case CDROMRESET:
  	case CDROMVOLREAD:
  	case CDROMSEEK:
  	case CDROMPLAYBLK:
  	case CDROMCLOSETRAY:
  	case CDROM_DISC_STATUS:
  	case CDROM_CHANGER_NSLOTS:
  	case CDROM_GET_CAPABILITY:
  	/* Ignore cdrom.h about these next 5 ioctls, they absolutely do
  	 * not take a struct cdrom_read, instead they take a struct cdrom_msf
  	 * which is compatible.
  	 */
  	case CDROMREADMODE2:
  	case CDROMREADMODE1:
  	case CDROMREADRAW:
  	case CDROMREADCOOKED:
  	case CDROMREADALL:
  	/* DVD ioctls */
  	case DVD_READ_STRUCT:
  	case DVD_WRITE_STRUCT:
  	case DVD_AUTH:
  		arg = (unsigned long)compat_ptr(arg);
1c925604e   Andreas Schwab   [PATCH] Fix block...
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
  	/* These intepret arg as an unsigned long, not as a pointer,
  	 * so we must not do compat_ptr() conversion. */
  	case HDIO_SET_MULTCOUNT:
  	case HDIO_SET_UNMASKINTR:
  	case HDIO_SET_KEEPSETTINGS:
  	case HDIO_SET_32BIT:
  	case HDIO_SET_NOWERR:
  	case HDIO_SET_DMA:
  	case HDIO_SET_PIO_MODE:
  	case HDIO_SET_NICE:
  	case HDIO_SET_WCACHE:
  	case HDIO_SET_ACOUSTIC:
  	case HDIO_SET_BUSSTATE:
  	case HDIO_SET_ADDRESS:
  	case CDROMEJECT_SW:
  	case CDROM_SET_OPTIONS:
  	case CDROM_CLEAR_OPTIONS:
  	case CDROM_SELECT_SPEED:
  	case CDROM_SELECT_DISC:
  	case CDROM_MEDIA_CHANGED:
  	case CDROM_DRIVE_STATUS:
  	case CDROM_LOCKDOOR:
  	case CDROM_DEBUG:
7199d4cdd   Arnd Bergmann   compat_ioctl: add...
628
629
630
631
632
  		break;
  	default:
  		/* unknown ioctl number */
  		return -ENOIOCTLCMD;
  	}
33c2dca49   Al Viro   [PATCH] trim file...
633
  	return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
7199d4cdd   Arnd Bergmann   compat_ioctl: add...
634
  }
45048d096   Al Viro   [PATCH] get rid o...
635
636
637
638
  /* Most of the generic ioctls are handled in the normal fallback path.
     This assumes the blkdev's low level compat_ioctl always returns
     ENOIOCTLCMD for unknown ioctls. */
  long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
639
  {
45048d096   Al Viro   [PATCH] get rid o...
640
641
642
643
644
  	int ret = -ENOIOCTLCMD;
  	struct inode *inode = file->f_mapping->host;
  	struct block_device *bdev = inode->i_bdev;
  	struct gendisk *disk = bdev->bd_disk;
  	fmode_t mode = file->f_mode;
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
645
  	struct backing_dev_info *bdi;
45048d096   Al Viro   [PATCH] get rid o...
646
  	loff_t size;
fd4ce1acd   Christoph Hellwig   [PATCH 1/2] kill ...
647
648
649
650
  	/*
  	 * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
  	 * to updated it before every ioctl.
  	 */
45048d096   Al Viro   [PATCH] get rid o...
651
  	if (file->f_flags & O_NDELAY)
fd4ce1acd   Christoph Hellwig   [PATCH 1/2] kill ...
652
653
654
  		mode |= FMODE_NDELAY;
  	else
  		mode &= ~FMODE_NDELAY;
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
655
656
  
  	switch (cmd) {
45048d096   Al Viro   [PATCH] get rid o...
657
658
  	case HDIO_GETGEO:
  		return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
ac481c20e   Martin K. Petersen   block: Topology i...
659
660
661
662
663
664
665
666
  	case BLKPBSZGET:
  		return compat_put_uint(arg, bdev_physical_block_size(bdev));
  	case BLKIOMIN:
  		return compat_put_uint(arg, bdev_io_min(bdev));
  	case BLKIOOPT:
  		return compat_put_uint(arg, bdev_io_opt(bdev));
  	case BLKALIGNOFF:
  		return compat_put_int(arg, bdev_alignment_offset(bdev));
98262f276   Martin K. Petersen   block: Allow devi...
667
668
  	case BLKDISCARDZEROES:
  		return compat_put_uint(arg, bdev_discard_zeroes_data(bdev));
45048d096   Al Viro   [PATCH] get rid o...
669
670
671
  	case BLKFLSBUF:
  	case BLKROSET:
  	case BLKDISCARD:
8d57a98cc   Adrian Hunter   block: add secure...
672
  	case BLKSECDISCARD:
45048d096   Al Viro   [PATCH] get rid o...
673
674
675
676
677
  	/*
  	 * the ones below are implemented in blkdev_locked_ioctl,
  	 * but we call blkdev_ioctl, which gets the lock for us
  	 */
  	case BLKRRPART:
56b26add0   Al Viro   [PATCH] kill the ...
678
  		return blkdev_ioctl(bdev, mode, cmd,
45048d096   Al Viro   [PATCH] get rid o...
679
680
  				(unsigned long)compat_ptr(arg));
  	case BLKBSZSET_32:
56b26add0   Al Viro   [PATCH] kill the ...
681
  		return blkdev_ioctl(bdev, mode, BLKBSZSET,
45048d096   Al Viro   [PATCH] get rid o...
682
683
  				(unsigned long)compat_ptr(arg));
  	case BLKPG:
56b26add0   Al Viro   [PATCH] kill the ...
684
  		return compat_blkpg_ioctl(bdev, mode, cmd, compat_ptr(arg));
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  	case BLKRAGET:
  	case BLKFRAGET:
  		if (!arg)
  			return -EINVAL;
  		bdi = blk_get_backing_dev_info(bdev);
  		if (bdi == NULL)
  			return -ENOTTY;
  		return compat_put_long(arg,
  				       (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
  	case BLKROGET: /* compatible */
  		return compat_put_int(arg, bdev_read_only(bdev) != 0);
  	case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
  		return compat_put_int(arg, block_size(bdev));
  	case BLKSSZGET: /* get block device hardware sector size */
e1defc4ff   Martin K. Petersen   block: Do away wi...
699
  		return compat_put_int(arg, bdev_logical_block_size(bdev));
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
700
701
  	case BLKSECTGET:
  		return compat_put_ushort(arg,
ae03bf639   Martin K. Petersen   block: Use access...
702
  					 queue_max_sectors(bdev_get_queue(bdev)));
ef00f59c9   Martin K. Petersen   block: Add BLKROT...
703
704
705
  	case BLKROTATIONAL:
  		return compat_put_ushort(arg,
  					 !blk_queue_nonrot(bdev_get_queue(bdev)));
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
706
707
708
709
710
711
712
713
714
715
  	case BLKRASET: /* compatible, but no compat_ptr (!) */
  	case BLKFRASET:
  		if (!capable(CAP_SYS_ADMIN))
  			return -EACCES;
  		bdi = blk_get_backing_dev_info(bdev);
  		if (bdi == NULL)
  			return -ENOTTY;
  		bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
  		return 0;
  	case BLKGETSIZE:
77304d2ab   Mike Snitzer   block: read i_siz...
716
  		size = i_size_read(bdev->bd_inode);
45048d096   Al Viro   [PATCH] get rid o...
717
  		if ((size >> 9) > ~0UL)
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
718
  			return -EFBIG;
45048d096   Al Viro   [PATCH] get rid o...
719
  		return compat_put_ulong(arg, size >> 9);
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
720
721
  
  	case BLKGETSIZE64_32:
77304d2ab   Mike Snitzer   block: read i_siz...
722
  		return compat_put_u64(arg, i_size_read(bdev->bd_inode));
171044d44   Arnd Bergmann   compat_ioctl: han...
723
724
  
  	case BLKTRACESETUP32:
171044d44   Arnd Bergmann   compat_ioctl: han...
725
726
727
  	case BLKTRACESTART: /* compatible */
  	case BLKTRACESTOP:  /* compatible */
  	case BLKTRACETEARDOWN: /* compatible */
45048d096   Al Viro   [PATCH] get rid o...
728
  		ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
7199d4cdd   Arnd Bergmann   compat_ioctl: add...
729
  		return ret;
45048d096   Al Viro   [PATCH] get rid o...
730
731
732
733
734
735
736
  	default:
  		if (disk->fops->compat_ioctl)
  			ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
  		if (ret == -ENOIOCTLCMD)
  			ret = compat_blkdev_driver_ioctl(bdev, mode, cmd, arg);
  		return ret;
  	}
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
737
  }