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>
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>
14 static int compat_put_ushort(unsigned long arg, unsigned short val)
16 return put_user(val, (unsigned short __user *)compat_ptr(arg));
19 static int compat_put_int(unsigned long arg, int val)
21 return put_user(val, (compat_int_t __user *)compat_ptr(arg));
24 static int compat_put_long(unsigned long arg, long val)
26 return put_user(val, (compat_long_t __user *)compat_ptr(arg));
29 static int compat_put_ulong(unsigned long arg, compat_ulong_t val)
31 return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
34 static int compat_put_u64(unsigned long arg, u64 val)
36 return put_user(val, (compat_u64 __user *)compat_ptr(arg));
39 struct compat_hd_geometry {
41 unsigned char sectors;
42 unsigned short cylinders;
46 static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
47 struct compat_hd_geometry __user *ugeo)
49 struct hd_geometry geo;
54 if (!disk->fops->getgeo)
58 * We need to set the startsect first, the driver may
59 * want to override it.
61 geo.start = get_start_sect(bdev);
62 ret = disk->fops->getgeo(bdev, &geo);
66 ret = copy_to_user(ugeo, &geo, 4);
67 ret |= __put_user(geo.start, &ugeo->start);
74 static int compat_hdio_ioctl(struct inode *inode, struct file *file,
75 struct gendisk *disk, unsigned int cmd, unsigned long arg)
77 mm_segment_t old_fs = get_fs();
79 unsigned int __user *uvp;
83 error = blkdev_driver_ioctl(inode, file, disk,
84 cmd, (unsigned long)(&kval));
88 uvp = compat_ptr(arg);
89 if (put_user(kval, uvp))
95 struct compat_blkpg_ioctl_arg {
102 static int compat_blkpg_ioctl(struct inode *inode, struct file *file,
103 unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32)
105 struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a));
106 compat_caddr_t udata;
110 err = get_user(n, &ua32->op);
111 err |= put_user(n, &a->op);
112 err |= get_user(n, &ua32->flags);
113 err |= put_user(n, &a->flags);
114 err |= get_user(n, &ua32->datalen);
115 err |= put_user(n, &a->datalen);
116 err |= get_user(udata, &ua32->data);
117 err |= put_user(compat_ptr(udata), &a->data);
121 return blkdev_ioctl(inode, file, cmd, (unsigned long)a);
124 #define BLKBSZGET_32 _IOR(0x12, 112, int)
125 #define BLKBSZSET_32 _IOW(0x12, 113, int)
126 #define BLKGETSIZE64_32 _IOR(0x12, 114, int)
128 struct compat_blk_user_trace_setup {
133 compat_u64 start_lba;
137 #define BLKTRACESETUP32 _IOWR(0x12, 115, struct compat_blk_user_trace_setup)
139 static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg)
141 struct blk_user_trace_setup buts;
142 struct compat_blk_user_trace_setup cbuts;
143 struct request_queue *q;
146 q = bdev_get_queue(bdev);
150 if (copy_from_user(&cbuts, arg, sizeof(cbuts)))
153 buts = (struct blk_user_trace_setup) {
154 .act_mask = cbuts.act_mask,
155 .buf_size = cbuts.buf_size,
156 .buf_nr = cbuts.buf_nr,
157 .start_lba = cbuts.start_lba,
158 .end_lba = cbuts.end_lba,
161 memcpy(&buts.name, &cbuts.name, 32);
163 mutex_lock(&bdev->bd_mutex);
164 ret = do_blk_trace_setup(q, bdev, &buts);
165 mutex_unlock(&bdev->bd_mutex);
169 if (copy_to_user(arg, &buts.name, 32))
175 static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file,
176 struct gendisk *disk, unsigned cmd, unsigned long arg)
181 case HDIO_GET_UNMASKINTR:
182 case HDIO_GET_MULTCOUNT:
183 case HDIO_GET_KEEPSETTINGS:
185 case HDIO_GET_NOWERR:
188 case HDIO_GET_WCACHE:
189 case HDIO_GET_ACOUSTIC:
190 case HDIO_GET_ADDRESS:
191 case HDIO_GET_BUSSTATE:
192 return compat_hdio_ioctl(inode, file, disk, cmd, arg);
194 * No handler required for the ones below, we just need to
195 * convert arg to a 64 bit pointer.
199 * 0x03 -- HD/IDE ioctl's used by hdparm and friends.
200 * Some need translations, these do not.
202 case HDIO_GET_IDENTITY:
203 case HDIO_DRIVE_TASK:
206 /* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
208 /* 0x02 -- Floppy ioctls */
229 case CDROMPLAYTRKIND:
230 case CDROMREADTOCHDR:
231 case CDROMREADTOCENTRY:
237 case CDROMMULTISESSION:
244 case CDROM_DISC_STATUS:
245 case CDROM_CHANGER_NSLOTS:
246 case CDROM_GET_CAPABILITY:
247 /* Ignore cdrom.h about these next 5 ioctls, they absolutely do
248 * not take a struct cdrom_read, instead they take a struct cdrom_msf
249 * which is compatible.
254 case CDROMREADCOOKED:
257 case DVD_READ_STRUCT:
258 case DVD_WRITE_STRUCT:
260 arg = (unsigned long)compat_ptr(arg);
261 /* These intepret arg as an unsigned long, not as a pointer,
262 * so we must not do compat_ptr() conversion. */
263 case HDIO_SET_MULTCOUNT:
264 case HDIO_SET_UNMASKINTR:
265 case HDIO_SET_KEEPSETTINGS:
267 case HDIO_SET_NOWERR:
269 case HDIO_SET_PIO_MODE:
271 case HDIO_SET_WCACHE:
272 case HDIO_SET_ACOUSTIC:
273 case HDIO_SET_BUSSTATE:
274 case HDIO_SET_ADDRESS:
276 case CDROM_SET_OPTIONS:
277 case CDROM_CLEAR_OPTIONS:
278 case CDROM_SELECT_SPEED:
279 case CDROM_SELECT_DISC:
280 case CDROM_MEDIA_CHANGED:
281 case CDROM_DRIVE_STATUS:
286 /* unknown ioctl number */
290 if (disk->fops->unlocked_ioctl)
291 return disk->fops->unlocked_ioctl(file, cmd, arg);
293 if (disk->fops->ioctl) {
295 ret = disk->fops->ioctl(inode, file, cmd, arg);
303 static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file,
304 struct block_device *bdev,
305 unsigned cmd, unsigned long arg)
307 struct backing_dev_info *bdi;
314 bdi = blk_get_backing_dev_info(bdev);
317 return compat_put_long(arg,
318 (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
319 case BLKROGET: /* compatible */
320 return compat_put_int(arg, bdev_read_only(bdev) != 0);
321 case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
322 return compat_put_int(arg, block_size(bdev));
323 case BLKSSZGET: /* get block device hardware sector size */
324 return compat_put_int(arg, bdev_hardsect_size(bdev));
326 return compat_put_ushort(arg,
327 bdev_get_queue(bdev)->max_sectors);
328 case BLKRASET: /* compatible, but no compat_ptr (!) */
330 if (!capable(CAP_SYS_ADMIN))
332 bdi = blk_get_backing_dev_info(bdev);
335 bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
338 if ((bdev->bd_inode->i_size >> 9) > ~0UL)
340 return compat_put_ulong(arg, bdev->bd_inode->i_size >> 9);
342 case BLKGETSIZE64_32:
343 return compat_put_u64(arg, bdev->bd_inode->i_size);
345 case BLKTRACESETUP32:
346 return compat_blk_trace_setup(bdev, compat_ptr(arg));
347 case BLKTRACESTART: /* compatible */
348 case BLKTRACESTOP: /* compatible */
349 case BLKTRACETEARDOWN: /* compatible */
350 return blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
355 /* Most of the generic ioctls are handled in the normal fallback path.
356 This assumes the blkdev's low level compat_ioctl always returns
357 ENOIOCTLCMD for unknown ioctls. */
358 long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
360 int ret = -ENOIOCTLCMD;
361 struct inode *inode = file->f_mapping->host;
362 struct block_device *bdev = inode->i_bdev;
363 struct gendisk *disk = bdev->bd_disk;
367 return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
371 * the ones below are implemented in blkdev_locked_ioctl,
372 * but we call blkdev_ioctl, which gets the lock for us
375 return blkdev_ioctl(inode, file, cmd,
376 (unsigned long)compat_ptr(arg));
378 return blkdev_ioctl(inode, file, BLKBSZSET,
379 (unsigned long)compat_ptr(arg));
381 return compat_blkpg_ioctl(inode, file, cmd, compat_ptr(arg));
385 ret = compat_blkdev_locked_ioctl(inode, file, bdev, cmd, arg);
386 /* FIXME: why do we assume -> compat_ioctl needs the BKL? */
387 if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
388 ret = disk->fops->compat_ioctl(file, cmd, arg);
391 if (ret != -ENOIOCTLCMD)
394 return compat_blkdev_driver_ioctl(inode, file, disk, cmd, arg);