compat_ioctl: handle blk_trace ioctls
[linux-2.6.git] / 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 #define BLKBSZGET_32            _IOR(0x12, 112, int)
40 #define BLKBSZSET_32            _IOW(0x12, 113, int)
41 #define BLKGETSIZE64_32         _IOR(0x12, 114, int)
42
43 struct compat_blk_user_trace_setup {
44         char name[32];
45         u16 act_mask;
46         u32 buf_size;
47         u32 buf_nr;
48         compat_u64 start_lba;
49         compat_u64 end_lba;
50         u32 pid;
51 };
52 #define BLKTRACESETUP32 _IOWR(0x12, 115, struct compat_blk_user_trace_setup)
53
54 static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg)
55 {
56         struct blk_user_trace_setup buts;
57         struct compat_blk_user_trace_setup cbuts;
58         struct request_queue *q;
59         int ret;
60
61         q = bdev_get_queue(bdev);
62         if (!q)
63                 return -ENXIO;
64
65         if (copy_from_user(&cbuts, arg, sizeof(cbuts)))
66                 return -EFAULT;
67
68         buts = (struct blk_user_trace_setup) {
69                 .act_mask = cbuts.act_mask,
70                 .buf_size = cbuts.buf_size,
71                 .buf_nr = cbuts.buf_nr,
72                 .start_lba = cbuts.start_lba,
73                 .end_lba = cbuts.end_lba,
74                 .pid = cbuts.pid,
75         };
76         memcpy(&buts.name, &cbuts.name, 32);
77
78         mutex_lock(&bdev->bd_mutex);
79         ret = do_blk_trace_setup(q, bdev, &buts);
80         mutex_unlock(&bdev->bd_mutex);
81         if (ret)
82                 return ret;
83
84         if (copy_to_user(arg, &buts.name, 32))
85                 return -EFAULT;
86
87         return 0;
88 }
89
90 static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file,
91                         struct gendisk *disk, unsigned cmd, unsigned long arg)
92 {
93         int ret;
94
95         switch (arg) {
96         /*
97          * No handler required for the ones below, we just need to
98          * convert arg to a 64 bit pointer.
99          */
100         case BLKSECTSET:
101         /*
102          * 0x03 -- HD/IDE ioctl's used by hdparm and friends.
103          *         Some need translations, these do not.
104          */
105         case HDIO_GET_IDENTITY:
106         case HDIO_DRIVE_TASK:
107         case HDIO_DRIVE_CMD:
108         case HDIO_SCAN_HWIF:
109         /* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
110         case 0x330:
111         /* 0x02 -- Floppy ioctls */
112         case FDMSGON:
113         case FDMSGOFF:
114         case FDSETEMSGTRESH:
115         case FDFLUSH:
116         case FDWERRORCLR:
117         case FDSETMAXERRS:
118         case FDGETMAXERRS:
119         case FDGETDRVTYP:
120         case FDEJECT:
121         case FDCLRPRM:
122         case FDFMTBEG:
123         case FDFMTEND:
124         case FDRESET:
125         case FDTWADDLE:
126         case FDFMTTRK:
127         case FDRAWCMD:
128         /* CDROM stuff */
129         case CDROMPAUSE:
130         case CDROMRESUME:
131         case CDROMPLAYMSF:
132         case CDROMPLAYTRKIND:
133         case CDROMREADTOCHDR:
134         case CDROMREADTOCENTRY:
135         case CDROMSTOP:
136         case CDROMSTART:
137         case CDROMEJECT:
138         case CDROMVOLCTRL:
139         case CDROMSUBCHNL:
140         case CDROMMULTISESSION:
141         case CDROM_GET_MCN:
142         case CDROMRESET:
143         case CDROMVOLREAD:
144         case CDROMSEEK:
145         case CDROMPLAYBLK:
146         case CDROMCLOSETRAY:
147         case CDROM_DISC_STATUS:
148         case CDROM_CHANGER_NSLOTS:
149         case CDROM_GET_CAPABILITY:
150         /* Ignore cdrom.h about these next 5 ioctls, they absolutely do
151          * not take a struct cdrom_read, instead they take a struct cdrom_msf
152          * which is compatible.
153          */
154         case CDROMREADMODE2:
155         case CDROMREADMODE1:
156         case CDROMREADRAW:
157         case CDROMREADCOOKED:
158         case CDROMREADALL:
159         /* DVD ioctls */
160         case DVD_READ_STRUCT:
161         case DVD_WRITE_STRUCT:
162         case DVD_AUTH:
163                 arg = (unsigned long)compat_ptr(arg);
164         /* These intepret arg as an unsigned long, not as a pointer,
165          * so we must not do compat_ptr() conversion. */
166         case HDIO_SET_MULTCOUNT:
167         case HDIO_SET_UNMASKINTR:
168         case HDIO_SET_KEEPSETTINGS:
169         case HDIO_SET_32BIT:
170         case HDIO_SET_NOWERR:
171         case HDIO_SET_DMA:
172         case HDIO_SET_PIO_MODE:
173         case HDIO_SET_NICE:
174         case HDIO_SET_WCACHE:
175         case HDIO_SET_ACOUSTIC:
176         case HDIO_SET_BUSSTATE:
177         case HDIO_SET_ADDRESS:
178         case CDROMEJECT_SW:
179         case CDROM_SET_OPTIONS:
180         case CDROM_CLEAR_OPTIONS:
181         case CDROM_SELECT_SPEED:
182         case CDROM_SELECT_DISC:
183         case CDROM_MEDIA_CHANGED:
184         case CDROM_DRIVE_STATUS:
185         case CDROM_LOCKDOOR:
186         case CDROM_DEBUG:
187                 break;
188         default:
189                 /* unknown ioctl number */
190                 return -ENOIOCTLCMD;
191         }
192
193         if (disk->fops->unlocked_ioctl)
194                 return disk->fops->unlocked_ioctl(file, cmd, arg);
195
196         if (disk->fops->ioctl) {
197                 lock_kernel();
198                 ret = disk->fops->ioctl(inode, file, cmd, arg);
199                 unlock_kernel();
200                 return ret;
201         }
202
203         return -ENOTTY;
204 }
205
206 static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file,
207                                 struct block_device *bdev,
208                                 unsigned cmd, unsigned long arg)
209 {
210         struct backing_dev_info *bdi;
211
212         switch (cmd) {
213         case BLKRAGET:
214         case BLKFRAGET:
215                 if (!arg)
216                         return -EINVAL;
217                 bdi = blk_get_backing_dev_info(bdev);
218                 if (bdi == NULL)
219                         return -ENOTTY;
220                 return compat_put_long(arg,
221                                        (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
222         case BLKROGET: /* compatible */
223                 return compat_put_int(arg, bdev_read_only(bdev) != 0);
224         case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
225                 return compat_put_int(arg, block_size(bdev));
226         case BLKSSZGET: /* get block device hardware sector size */
227                 return compat_put_int(arg, bdev_hardsect_size(bdev));
228         case BLKSECTGET:
229                 return compat_put_ushort(arg,
230                                          bdev_get_queue(bdev)->max_sectors);
231         case BLKRASET: /* compatible, but no compat_ptr (!) */
232         case BLKFRASET:
233                 if (!capable(CAP_SYS_ADMIN))
234                         return -EACCES;
235                 bdi = blk_get_backing_dev_info(bdev);
236                 if (bdi == NULL)
237                         return -ENOTTY;
238                 bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
239                 return 0;
240         case BLKGETSIZE:
241                 if ((bdev->bd_inode->i_size >> 9) > ~0UL)
242                         return -EFBIG;
243                 return compat_put_ulong(arg, bdev->bd_inode->i_size >> 9);
244
245         case BLKGETSIZE64_32:
246                 return compat_put_u64(arg, bdev->bd_inode->i_size);
247
248         case BLKTRACESETUP32:
249                 return compat_blk_trace_setup(bdev, compat_ptr(arg));
250         case BLKTRACESTART: /* compatible */
251         case BLKTRACESTOP:  /* compatible */
252         case BLKTRACETEARDOWN: /* compatible */
253                 return blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
254         }
255         return -ENOIOCTLCMD;
256 }
257
258 /* Most of the generic ioctls are handled in the normal fallback path.
259    This assumes the blkdev's low level compat_ioctl always returns
260    ENOIOCTLCMD for unknown ioctls. */
261 long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
262 {
263         int ret = -ENOIOCTLCMD;
264         struct inode *inode = file->f_mapping->host;
265         struct block_device *bdev = inode->i_bdev;
266         struct gendisk *disk = bdev->bd_disk;
267
268         switch (cmd) {
269         case BLKFLSBUF:
270         case BLKROSET:
271         /*
272          * the ones below are implemented in blkdev_locked_ioctl,
273          * but we call blkdev_ioctl, which gets the lock for us
274          */
275         case BLKRRPART:
276                 return blkdev_ioctl(inode, file, cmd,
277                                 (unsigned long)compat_ptr(arg));
278         case BLKBSZSET_32:
279                 return blkdev_ioctl(inode, file, BLKBSZSET,
280                                 (unsigned long)compat_ptr(arg));
281         }
282
283         lock_kernel();
284         ret = compat_blkdev_locked_ioctl(inode, file, bdev, cmd, arg);
285         /* FIXME: why do we assume -> compat_ioctl needs the BKL? */
286         if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
287                 ret = disk->fops->compat_ioctl(file, cmd, arg);
288         unlock_kernel();
289
290         if (ret != -ENOIOCTLCMD)
291                 return ret;
292
293         return compat_blkdev_driver_ioctl(inode, file, disk, cmd, arg);
294 }