compat_ioctl: move cdrom handlers to block/compat_ioctl.c
[safe/jmp/linux-2.6] / block / compat_ioctl.c
1 #include <linux/blkdev.h>
2 #include <linux/blkpg.h>
3 #include <linux/blktrace_api.h>
4 #include <linux/cdrom.h>
5 #include <linux/compat.h>
6 #include <linux/elevator.h>
7 #include <linux/fd.h>
8 #include <linux/hdreg.h>
9 #include <linux/syscalls.h>
10 #include <linux/smp_lock.h>
11 #include <linux/types.h>
12 #include <linux/uaccess.h>
13
14 static int compat_put_ushort(unsigned long arg, unsigned short val)
15 {
16         return put_user(val, (unsigned short __user *)compat_ptr(arg));
17 }
18
19 static int compat_put_int(unsigned long arg, int val)
20 {
21         return put_user(val, (compat_int_t __user *)compat_ptr(arg));
22 }
23
24 static int compat_put_long(unsigned long arg, long val)
25 {
26         return put_user(val, (compat_long_t __user *)compat_ptr(arg));
27 }
28
29 static int compat_put_ulong(unsigned long arg, compat_ulong_t val)
30 {
31         return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
32 }
33
34 static int compat_put_u64(unsigned long arg, u64 val)
35 {
36         return put_user(val, (compat_u64 __user *)compat_ptr(arg));
37 }
38
39 struct compat_hd_geometry {
40         unsigned char heads;
41         unsigned char sectors;
42         unsigned short cylinders;
43         u32 start;
44 };
45
46 static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
47                         struct compat_hd_geometry __user *ugeo)
48 {
49         struct hd_geometry geo;
50         int ret;
51
52         if (!ugeo)
53                 return -EINVAL;
54         if (!disk->fops->getgeo)
55                 return -ENOTTY;
56
57         /*
58          * We need to set the startsect first, the driver may
59          * want to override it.
60          */
61         geo.start = get_start_sect(bdev);
62         ret = disk->fops->getgeo(bdev, &geo);
63         if (ret)
64                 return ret;
65
66         ret = copy_to_user(ugeo, &geo, 4);
67         ret |= __put_user(geo.start, &ugeo->start);
68         if (ret)
69                 ret = -EFAULT;
70
71         return ret;
72 }
73
74 static int compat_hdio_ioctl(struct inode *inode, struct file *file,
75                 struct gendisk *disk, unsigned int cmd, unsigned long arg)
76 {
77         mm_segment_t old_fs = get_fs();
78         unsigned long kval;
79         unsigned int __user *uvp;
80         int error;
81
82         set_fs(KERNEL_DS);
83         error = blkdev_driver_ioctl(inode, file, disk,
84                                 cmd, (unsigned long)(&kval));
85         set_fs(old_fs);
86
87         if (error == 0) {
88                 uvp = compat_ptr(arg);
89                 if (put_user(kval, uvp))
90                         error = -EFAULT;
91         }
92         return error;
93 }
94
95 struct compat_cdrom_read_audio {
96         union cdrom_addr        addr;
97         u8                      addr_format;
98         compat_int_t            nframes;
99         compat_caddr_t          buf;
100 };
101
102 struct compat_cdrom_generic_command {
103         unsigned char   cmd[CDROM_PACKET_SIZE];
104         compat_caddr_t  buffer;
105         compat_uint_t   buflen;
106         compat_int_t    stat;
107         compat_caddr_t  sense;
108         unsigned char   data_direction;
109         compat_int_t    quiet;
110         compat_int_t    timeout;
111         compat_caddr_t  reserved[1];
112 };
113
114 static int compat_cdrom_read_audio(struct inode *inode, struct file *file,
115                 struct gendisk *disk, unsigned int cmd, unsigned long arg)
116 {
117         struct cdrom_read_audio __user *cdread_audio;
118         struct compat_cdrom_read_audio __user *cdread_audio32;
119         __u32 data;
120         void __user *datap;
121
122         cdread_audio = compat_alloc_user_space(sizeof(*cdread_audio));
123         cdread_audio32 = compat_ptr(arg);
124
125         if (copy_in_user(&cdread_audio->addr,
126                          &cdread_audio32->addr,
127                          (sizeof(*cdread_audio32) -
128                           sizeof(compat_caddr_t))))
129                 return -EFAULT;
130
131         if (get_user(data, &cdread_audio32->buf))
132                 return -EFAULT;
133         datap = compat_ptr(data);
134         if (put_user(datap, &cdread_audio->buf))
135                 return -EFAULT;
136
137         return blkdev_driver_ioctl(inode, file, disk, cmd,
138                         (unsigned long)cdread_audio);
139 }
140
141 static int compat_cdrom_generic_command(struct inode *inode, struct file *file,
142                 struct gendisk *disk, unsigned int cmd, unsigned long arg)
143 {
144         struct cdrom_generic_command __user *cgc;
145         struct compat_cdrom_generic_command __user *cgc32;
146         u32 data;
147         unsigned char dir;
148         int itmp;
149
150         cgc = compat_alloc_user_space(sizeof(*cgc));
151         cgc32 = compat_ptr(arg);
152
153         if (copy_in_user(&cgc->cmd, &cgc32->cmd, sizeof(cgc->cmd)) ||
154             get_user(data, &cgc32->buffer) ||
155             put_user(compat_ptr(data), &cgc->buffer) ||
156             copy_in_user(&cgc->buflen, &cgc32->buflen,
157                          (sizeof(unsigned int) + sizeof(int))) ||
158             get_user(data, &cgc32->sense) ||
159             put_user(compat_ptr(data), &cgc->sense) ||
160             get_user(dir, &cgc32->data_direction) ||
161             put_user(dir, &cgc->data_direction) ||
162             get_user(itmp, &cgc32->quiet) ||
163             put_user(itmp, &cgc->quiet) ||
164             get_user(itmp, &cgc32->timeout) ||
165             put_user(itmp, &cgc->timeout) ||
166             get_user(data, &cgc32->reserved[0]) ||
167             put_user(compat_ptr(data), &cgc->reserved[0]))
168                 return -EFAULT;
169
170         return blkdev_driver_ioctl(inode, file, disk, cmd, (unsigned long)cgc);
171 }
172
173 struct compat_blkpg_ioctl_arg {
174         compat_int_t op;
175         compat_int_t flags;
176         compat_int_t datalen;
177         compat_caddr_t data;
178 };
179
180 static int compat_blkpg_ioctl(struct inode *inode, struct file *file,
181                 unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32)
182 {
183         struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a));
184         compat_caddr_t udata;
185         compat_int_t n;
186         int err;
187
188         err = get_user(n, &ua32->op);
189         err |= put_user(n, &a->op);
190         err |= get_user(n, &ua32->flags);
191         err |= put_user(n, &a->flags);
192         err |= get_user(n, &ua32->datalen);
193         err |= put_user(n, &a->datalen);
194         err |= get_user(udata, &ua32->data);
195         err |= put_user(compat_ptr(udata), &a->data);
196         if (err)
197                 return err;
198
199         return blkdev_ioctl(inode, file, cmd, (unsigned long)a);
200 }
201
202 #define BLKBSZGET_32            _IOR(0x12, 112, int)
203 #define BLKBSZSET_32            _IOW(0x12, 113, int)
204 #define BLKGETSIZE64_32         _IOR(0x12, 114, int)
205
206 struct compat_blk_user_trace_setup {
207         char name[32];
208         u16 act_mask;
209         u32 buf_size;
210         u32 buf_nr;
211         compat_u64 start_lba;
212         compat_u64 end_lba;
213         u32 pid;
214 };
215 #define BLKTRACESETUP32 _IOWR(0x12, 115, struct compat_blk_user_trace_setup)
216
217 static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg)
218 {
219         struct blk_user_trace_setup buts;
220         struct compat_blk_user_trace_setup cbuts;
221         struct request_queue *q;
222         int ret;
223
224         q = bdev_get_queue(bdev);
225         if (!q)
226                 return -ENXIO;
227
228         if (copy_from_user(&cbuts, arg, sizeof(cbuts)))
229                 return -EFAULT;
230
231         buts = (struct blk_user_trace_setup) {
232                 .act_mask = cbuts.act_mask,
233                 .buf_size = cbuts.buf_size,
234                 .buf_nr = cbuts.buf_nr,
235                 .start_lba = cbuts.start_lba,
236                 .end_lba = cbuts.end_lba,
237                 .pid = cbuts.pid,
238         };
239         memcpy(&buts.name, &cbuts.name, 32);
240
241         mutex_lock(&bdev->bd_mutex);
242         ret = do_blk_trace_setup(q, bdev, &buts);
243         mutex_unlock(&bdev->bd_mutex);
244         if (ret)
245                 return ret;
246
247         if (copy_to_user(arg, &buts.name, 32))
248                 return -EFAULT;
249
250         return 0;
251 }
252
253 static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file,
254                         struct gendisk *disk, unsigned cmd, unsigned long arg)
255 {
256         int ret;
257
258         switch (arg) {
259         case HDIO_GET_UNMASKINTR:
260         case HDIO_GET_MULTCOUNT:
261         case HDIO_GET_KEEPSETTINGS:
262         case HDIO_GET_32BIT:
263         case HDIO_GET_NOWERR:
264         case HDIO_GET_DMA:
265         case HDIO_GET_NICE:
266         case HDIO_GET_WCACHE:
267         case HDIO_GET_ACOUSTIC:
268         case HDIO_GET_ADDRESS:
269         case HDIO_GET_BUSSTATE:
270                 return compat_hdio_ioctl(inode, file, disk, cmd, arg);
271         case CDROMREADAUDIO:
272                 return compat_cdrom_read_audio(inode, file, disk, cmd, arg);
273         case CDROM_SEND_PACKET:
274                 return compat_cdrom_generic_command(inode, file, disk, cmd, arg);
275
276         /*
277          * No handler required for the ones below, we just need to
278          * convert arg to a 64 bit pointer.
279          */
280         case BLKSECTSET:
281         /*
282          * 0x03 -- HD/IDE ioctl's used by hdparm and friends.
283          *         Some need translations, these do not.
284          */
285         case HDIO_GET_IDENTITY:
286         case HDIO_DRIVE_TASK:
287         case HDIO_DRIVE_CMD:
288         case HDIO_SCAN_HWIF:
289         /* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
290         case 0x330:
291         /* 0x02 -- Floppy ioctls */
292         case FDMSGON:
293         case FDMSGOFF:
294         case FDSETEMSGTRESH:
295         case FDFLUSH:
296         case FDWERRORCLR:
297         case FDSETMAXERRS:
298         case FDGETMAXERRS:
299         case FDGETDRVTYP:
300         case FDEJECT:
301         case FDCLRPRM:
302         case FDFMTBEG:
303         case FDFMTEND:
304         case FDRESET:
305         case FDTWADDLE:
306         case FDFMTTRK:
307         case FDRAWCMD:
308         /* CDROM stuff */
309         case CDROMPAUSE:
310         case CDROMRESUME:
311         case CDROMPLAYMSF:
312         case CDROMPLAYTRKIND:
313         case CDROMREADTOCHDR:
314         case CDROMREADTOCENTRY:
315         case CDROMSTOP:
316         case CDROMSTART:
317         case CDROMEJECT:
318         case CDROMVOLCTRL:
319         case CDROMSUBCHNL:
320         case CDROMMULTISESSION:
321         case CDROM_GET_MCN:
322         case CDROMRESET:
323         case CDROMVOLREAD:
324         case CDROMSEEK:
325         case CDROMPLAYBLK:
326         case CDROMCLOSETRAY:
327         case CDROM_DISC_STATUS:
328         case CDROM_CHANGER_NSLOTS:
329         case CDROM_GET_CAPABILITY:
330         /* Ignore cdrom.h about these next 5 ioctls, they absolutely do
331          * not take a struct cdrom_read, instead they take a struct cdrom_msf
332          * which is compatible.
333          */
334         case CDROMREADMODE2:
335         case CDROMREADMODE1:
336         case CDROMREADRAW:
337         case CDROMREADCOOKED:
338         case CDROMREADALL:
339         /* DVD ioctls */
340         case DVD_READ_STRUCT:
341         case DVD_WRITE_STRUCT:
342         case DVD_AUTH:
343                 arg = (unsigned long)compat_ptr(arg);
344         /* These intepret arg as an unsigned long, not as a pointer,
345          * so we must not do compat_ptr() conversion. */
346         case HDIO_SET_MULTCOUNT:
347         case HDIO_SET_UNMASKINTR:
348         case HDIO_SET_KEEPSETTINGS:
349         case HDIO_SET_32BIT:
350         case HDIO_SET_NOWERR:
351         case HDIO_SET_DMA:
352         case HDIO_SET_PIO_MODE:
353         case HDIO_SET_NICE:
354         case HDIO_SET_WCACHE:
355         case HDIO_SET_ACOUSTIC:
356         case HDIO_SET_BUSSTATE:
357         case HDIO_SET_ADDRESS:
358         case CDROMEJECT_SW:
359         case CDROM_SET_OPTIONS:
360         case CDROM_CLEAR_OPTIONS:
361         case CDROM_SELECT_SPEED:
362         case CDROM_SELECT_DISC:
363         case CDROM_MEDIA_CHANGED:
364         case CDROM_DRIVE_STATUS:
365         case CDROM_LOCKDOOR:
366         case CDROM_DEBUG:
367                 break;
368         default:
369                 /* unknown ioctl number */
370                 return -ENOIOCTLCMD;
371         }
372
373         if (disk->fops->unlocked_ioctl)
374                 return disk->fops->unlocked_ioctl(file, cmd, arg);
375
376         if (disk->fops->ioctl) {
377                 lock_kernel();
378                 ret = disk->fops->ioctl(inode, file, cmd, arg);
379                 unlock_kernel();
380                 return ret;
381         }
382
383         return -ENOTTY;
384 }
385
386 static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file,
387                                 struct block_device *bdev,
388                                 unsigned cmd, unsigned long arg)
389 {
390         struct backing_dev_info *bdi;
391
392         switch (cmd) {
393         case BLKRAGET:
394         case BLKFRAGET:
395                 if (!arg)
396                         return -EINVAL;
397                 bdi = blk_get_backing_dev_info(bdev);
398                 if (bdi == NULL)
399                         return -ENOTTY;
400                 return compat_put_long(arg,
401                                        (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
402         case BLKROGET: /* compatible */
403                 return compat_put_int(arg, bdev_read_only(bdev) != 0);
404         case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
405                 return compat_put_int(arg, block_size(bdev));
406         case BLKSSZGET: /* get block device hardware sector size */
407                 return compat_put_int(arg, bdev_hardsect_size(bdev));
408         case BLKSECTGET:
409                 return compat_put_ushort(arg,
410                                          bdev_get_queue(bdev)->max_sectors);
411         case BLKRASET: /* compatible, but no compat_ptr (!) */
412         case BLKFRASET:
413                 if (!capable(CAP_SYS_ADMIN))
414                         return -EACCES;
415                 bdi = blk_get_backing_dev_info(bdev);
416                 if (bdi == NULL)
417                         return -ENOTTY;
418                 bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
419                 return 0;
420         case BLKGETSIZE:
421                 if ((bdev->bd_inode->i_size >> 9) > ~0UL)
422                         return -EFBIG;
423                 return compat_put_ulong(arg, bdev->bd_inode->i_size >> 9);
424
425         case BLKGETSIZE64_32:
426                 return compat_put_u64(arg, bdev->bd_inode->i_size);
427
428         case BLKTRACESETUP32:
429                 return compat_blk_trace_setup(bdev, compat_ptr(arg));
430         case BLKTRACESTART: /* compatible */
431         case BLKTRACESTOP:  /* compatible */
432         case BLKTRACETEARDOWN: /* compatible */
433                 return blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
434         }
435         return -ENOIOCTLCMD;
436 }
437
438 /* Most of the generic ioctls are handled in the normal fallback path.
439    This assumes the blkdev's low level compat_ioctl always returns
440    ENOIOCTLCMD for unknown ioctls. */
441 long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
442 {
443         int ret = -ENOIOCTLCMD;
444         struct inode *inode = file->f_mapping->host;
445         struct block_device *bdev = inode->i_bdev;
446         struct gendisk *disk = bdev->bd_disk;
447
448         switch (cmd) {
449         case HDIO_GETGEO:
450                 return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
451         case BLKFLSBUF:
452         case BLKROSET:
453         /*
454          * the ones below are implemented in blkdev_locked_ioctl,
455          * but we call blkdev_ioctl, which gets the lock for us
456          */
457         case BLKRRPART:
458                 return blkdev_ioctl(inode, file, cmd,
459                                 (unsigned long)compat_ptr(arg));
460         case BLKBSZSET_32:
461                 return blkdev_ioctl(inode, file, BLKBSZSET,
462                                 (unsigned long)compat_ptr(arg));
463         case BLKPG:
464                 return compat_blkpg_ioctl(inode, file, cmd, compat_ptr(arg));
465         }
466
467         lock_kernel();
468         ret = compat_blkdev_locked_ioctl(inode, file, bdev, cmd, arg);
469         /* FIXME: why do we assume -> compat_ioctl needs the BKL? */
470         if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
471                 ret = disk->fops->compat_ioctl(file, cmd, arg);
472         unlock_kernel();
473
474         if (ret != -ENOIOCTLCMD)
475                 return ret;
476
477         return compat_blkdev_driver_ioctl(inode, file, disk, cmd, arg);
478 }