partitions: enable EFI/GPT support by default
[linux-3.10.git] / block / compat_ioctl.c
index 576c4fd..7c668c8 100644 (file)
@@ -6,8 +6,8 @@
 #include <linux/elevator.h>
 #include <linux/fd.h>
 #include <linux/hdreg.h>
+#include <linux/slab.h>
 #include <linux/syscalls.h>
-#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/uaccess.h>
 
@@ -21,6 +21,11 @@ static int compat_put_int(unsigned long arg, int val)
        return put_user(val, (compat_int_t __user *)compat_ptr(arg));
 }
 
+static int compat_put_uint(unsigned long arg, unsigned int val)
+{
+       return put_user(val, (compat_uint_t __user *)compat_ptr(arg));
+}
+
 static int compat_put_long(unsigned long arg, long val)
 {
        return put_user(val, (compat_long_t __user *)compat_ptr(arg));
@@ -71,8 +76,8 @@ static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
        return ret;
 }
 
-static int compat_hdio_ioctl(struct inode *inode, struct file *file,
-               struct gendisk *disk, unsigned int cmd, unsigned long arg)
+static int compat_hdio_ioctl(struct block_device *bdev, fmode_t mode,
+               unsigned int cmd, unsigned long arg)
 {
        mm_segment_t old_fs = get_fs();
        unsigned long kval;
@@ -80,7 +85,7 @@ static int compat_hdio_ioctl(struct inode *inode, struct file *file,
        int error;
 
        set_fs(KERNEL_DS);
-       error = blkdev_driver_ioctl(inode, file, disk,
+       error = __blkdev_driver_ioctl(bdev, mode,
                                cmd, (unsigned long)(&kval));
        set_fs(old_fs);
 
@@ -111,8 +116,8 @@ struct compat_cdrom_generic_command {
        compat_caddr_t  reserved[1];
 };
 
-static int compat_cdrom_read_audio(struct inode *inode, struct file *file,
-               struct gendisk *disk, unsigned int cmd, unsigned long arg)
+static int compat_cdrom_read_audio(struct block_device *bdev, fmode_t mode,
+               unsigned int cmd, unsigned long arg)
 {
        struct cdrom_read_audio __user *cdread_audio;
        struct compat_cdrom_read_audio __user *cdread_audio32;
@@ -134,12 +139,12 @@ static int compat_cdrom_read_audio(struct inode *inode, struct file *file,
        if (put_user(datap, &cdread_audio->buf))
                return -EFAULT;
 
-       return blkdev_driver_ioctl(inode, file, disk, cmd,
+       return __blkdev_driver_ioctl(bdev, mode, cmd,
                        (unsigned long)cdread_audio);
 }
 
-static int compat_cdrom_generic_command(struct inode *inode, struct file *file,
-               struct gendisk *disk, unsigned int cmd, unsigned long arg)
+static int compat_cdrom_generic_command(struct block_device *bdev, fmode_t mode,
+               unsigned int cmd, unsigned long arg)
 {
        struct cdrom_generic_command __user *cgc;
        struct compat_cdrom_generic_command __user *cgc32;
@@ -167,7 +172,7 @@ static int compat_cdrom_generic_command(struct inode *inode, struct file *file,
            put_user(compat_ptr(data), &cgc->reserved[0]))
                return -EFAULT;
 
-       return blkdev_driver_ioctl(inode, file, disk, cmd, (unsigned long)cgc);
+       return __blkdev_driver_ioctl(bdev, mode, cmd, (unsigned long)cgc);
 }
 
 struct compat_blkpg_ioctl_arg {
@@ -177,7 +182,7 @@ struct compat_blkpg_ioctl_arg {
        compat_caddr_t data;
 };
 
-static int compat_blkpg_ioctl(struct inode *inode, struct file *file,
+static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
                unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32)
 {
        struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a));
@@ -196,26 +201,13 @@ static int compat_blkpg_ioctl(struct inode *inode, struct file *file,
        if (err)
                return err;
 
-       return blkdev_ioctl(inode, file, cmd, (unsigned long)a);
+       return blkdev_ioctl(bdev, mode, cmd, (unsigned long)a);
 }
 
 #define BLKBSZGET_32           _IOR(0x12, 112, int)
 #define BLKBSZSET_32           _IOW(0x12, 113, int)
 #define BLKGETSIZE64_32                _IOR(0x12, 114, int)
 
-struct compat_floppy_struct {
-       compat_uint_t   size;
-       compat_uint_t   sect;
-       compat_uint_t   head;
-       compat_uint_t   track;
-       compat_uint_t   stretch;
-       unsigned char   gap;
-       unsigned char   rate;
-       unsigned char   spec1;
-       unsigned char   fmt_gap;
-       const compat_caddr_t name;
-};
-
 struct compat_floppy_drive_params {
        char            cmos;
        compat_ulong_t  max_dtr;
@@ -283,7 +275,6 @@ struct compat_floppy_write_errors {
 
 #define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
 #define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
-#define FDGETPRM32 _IOR(2, 0x04, struct compat_floppy_struct)
 #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)
@@ -308,8 +299,8 @@ static struct {
 
 #define NR_FD_IOCTL_TRANS ARRAY_SIZE(fd_ioctl_trans_table)
 
-static int compat_fd_ioctl(struct inode *inode, struct file *file,
-               struct gendisk *disk, unsigned int cmd, unsigned long arg)
+static int compat_fd_ioctl(struct block_device *bdev, fmode_t mode,
+               unsigned int cmd, unsigned long arg)
 {
        mm_segment_t old_fs = get_fs();
        void *karg = NULL;
@@ -413,7 +404,7 @@ static int compat_fd_ioctl(struct inode *inode, struct file *file,
                return -EINVAL;
        }
        set_fs(KERNEL_DS);
-       err = blkdev_driver_ioctl(inode, file, disk, kcmd, (unsigned long)karg);
+       err = __blkdev_driver_ioctl(bdev, mode, kcmd, (unsigned long)karg);
        set_fs(old_fs);
        if (err)
                goto out;
@@ -529,61 +520,9 @@ out:
        return err;
 }
 
-struct compat_blk_user_trace_setup {
-       char name[32];
-       u16 act_mask;
-       u32 buf_size;
-       u32 buf_nr;
-       compat_u64 start_lba;
-       compat_u64 end_lba;
-       u32 pid;
-};
-#define BLKTRACESETUP32 _IOWR(0x12, 115, struct compat_blk_user_trace_setup)
-
-static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg)
-{
-       struct blk_user_trace_setup buts;
-       struct compat_blk_user_trace_setup cbuts;
-       struct request_queue *q;
-       char b[BDEVNAME_SIZE];
-       int ret;
-
-       q = bdev_get_queue(bdev);
-       if (!q)
-               return -ENXIO;
-
-       if (copy_from_user(&cbuts, arg, sizeof(cbuts)))
-               return -EFAULT;
-
-       bdevname(bdev, b);
-
-       buts = (struct blk_user_trace_setup) {
-               .act_mask = cbuts.act_mask,
-               .buf_size = cbuts.buf_size,
-               .buf_nr = cbuts.buf_nr,
-               .start_lba = cbuts.start_lba,
-               .end_lba = cbuts.end_lba,
-               .pid = cbuts.pid,
-       };
-       memcpy(&buts.name, &cbuts.name, 32);
-
-       mutex_lock(&bdev->bd_mutex);
-       ret = do_blk_trace_setup(q, b, bdev->bd_dev, &buts);
-       mutex_unlock(&bdev->bd_mutex);
-       if (ret)
-               return ret;
-
-       if (copy_to_user(arg, &buts.name, 32))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file,
-                       struct gendisk *disk, unsigned cmd, unsigned long arg)
+static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
+                       unsigned cmd, unsigned long arg)
 {
-       int ret;
-
        switch (cmd) {
        case HDIO_GET_UNMASKINTR:
        case HDIO_GET_MULTCOUNT:
@@ -596,7 +535,7 @@ static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file,
        case HDIO_GET_ACOUSTIC:
        case HDIO_GET_ADDRESS:
        case HDIO_GET_BUSSTATE:
-               return compat_hdio_ioctl(inode, file, disk, cmd, arg);
+               return compat_hdio_ioctl(bdev, mode, cmd, arg);
        case FDSETPRM32:
        case FDDEFPRM32:
        case FDGETPRM32:
@@ -606,11 +545,11 @@ static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file,
        case FDPOLLDRVSTAT32:
        case FDGETFDCSTAT32:
        case FDWERRORGET32:
-               return compat_fd_ioctl(inode, file, disk, cmd, arg);
+               return compat_fd_ioctl(bdev, mode, cmd, arg);
        case CDROMREADAUDIO:
-               return compat_cdrom_read_audio(inode, file, disk, cmd, arg);
+               return compat_cdrom_read_audio(bdev, mode, cmd, arg);
        case CDROM_SEND_PACKET:
-               return compat_cdrom_generic_command(inode, file, disk, cmd, arg);
+               return compat_cdrom_generic_command(bdev, mode, cmd, arg);
 
        /*
         * No handler required for the ones below, we just need to
@@ -708,26 +647,60 @@ static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file,
                return -ENOIOCTLCMD;
        }
 
-       if (disk->fops->__unlocked_ioctl)
-               return disk->fops->__unlocked_ioctl(file, cmd, arg);
-
-       if (disk->fops->__ioctl) {
-               lock_kernel();
-               ret = disk->fops->__ioctl(inode, file, cmd, arg);
-               unlock_kernel();
-               return ret;
-       }
-
-       return __blkdev_driver_ioctl(inode->i_bdev, file->f_mode, cmd, arg);
+       return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
 }
 
-static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file,
-                               struct block_device *bdev,
-                               unsigned cmd, unsigned long arg)
+/* 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)
 {
+       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;
        struct backing_dev_info *bdi;
+       loff_t size;
+
+       /*
+        * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
+        * to updated it before every ioctl.
+        */
+       if (file->f_flags & O_NDELAY)
+               mode |= FMODE_NDELAY;
+       else
+               mode &= ~FMODE_NDELAY;
 
        switch (cmd) {
+       case HDIO_GETGEO:
+               return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
+       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));
+       case BLKDISCARDZEROES:
+               return compat_put_uint(arg, bdev_discard_zeroes_data(bdev));
+       case BLKFLSBUF:
+       case BLKROSET:
+       case BLKDISCARD:
+       case BLKSECDISCARD:
+       /*
+        * the ones below are implemented in blkdev_locked_ioctl,
+        * but we call blkdev_ioctl, which gets the lock for us
+        */
+       case BLKRRPART:
+               return blkdev_ioctl(bdev, mode, cmd,
+                               (unsigned long)compat_ptr(arg));
+       case BLKBSZSET_32:
+               return blkdev_ioctl(bdev, mode, BLKBSZSET,
+                               (unsigned long)compat_ptr(arg));
+       case BLKPG:
+               return compat_blkpg_ioctl(bdev, mode, cmd, compat_ptr(arg));
        case BLKRAGET:
        case BLKFRAGET:
                if (!arg)
@@ -742,10 +715,13 @@ static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file,
        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 */
-               return compat_put_int(arg, bdev_hardsect_size(bdev));
+               return compat_put_int(arg, bdev_logical_block_size(bdev));
        case BLKSECTGET:
                return compat_put_ushort(arg,
-                                        bdev_get_queue(bdev)->max_sectors);
+                                        queue_max_sectors(bdev_get_queue(bdev)));
+       case BLKROTATIONAL:
+               return compat_put_ushort(arg,
+                                        !blk_queue_nonrot(bdev_get_queue(bdev)));
        case BLKRASET: /* compatible, but no compat_ptr (!) */
        case BLKFRASET:
                if (!capable(CAP_SYS_ADMIN))
@@ -756,63 +732,25 @@ static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file,
                bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
                return 0;
        case BLKGETSIZE:
-               if ((bdev->bd_inode->i_size >> 9) > ~0UL)
+               size = i_size_read(bdev->bd_inode);
+               if ((size >> 9) > ~0UL)
                        return -EFBIG;
-               return compat_put_ulong(arg, bdev->bd_inode->i_size >> 9);
+               return compat_put_ulong(arg, size >> 9);
 
        case BLKGETSIZE64_32:
-               return compat_put_u64(arg, bdev->bd_inode->i_size);
+               return compat_put_u64(arg, i_size_read(bdev->bd_inode));
 
        case BLKTRACESETUP32:
-               return compat_blk_trace_setup(bdev, compat_ptr(arg));
        case BLKTRACESTART: /* compatible */
        case BLKTRACESTOP:  /* compatible */
        case BLKTRACETEARDOWN: /* compatible */
-               return blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
-       }
-       return -ENOIOCTLCMD;
-}
-
-/* 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)
-{
-       int ret = -ENOIOCTLCMD;
-       struct inode *inode = file->f_mapping->host;
-       struct block_device *bdev = inode->i_bdev;
-       struct gendisk *disk = bdev->bd_disk;
-
-       switch (cmd) {
-       case HDIO_GETGEO:
-               return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
-       case BLKFLSBUF:
-       case BLKROSET:
-       case BLKDISCARD:
-       /*
-        * the ones below are implemented in blkdev_locked_ioctl,
-        * but we call blkdev_ioctl, which gets the lock for us
-        */
-       case BLKRRPART:
-               return blkdev_ioctl(inode, file, cmd,
-                               (unsigned long)compat_ptr(arg));
-       case BLKBSZSET_32:
-               return blkdev_ioctl(inode, file, BLKBSZSET,
-                               (unsigned long)compat_ptr(arg));
-       case BLKPG:
-               return compat_blkpg_ioctl(inode, file, cmd, compat_ptr(arg));
-       }
-
-       lock_kernel();
-       ret = compat_blkdev_locked_ioctl(inode, file, bdev, cmd, arg);
-       if (ret == -ENOIOCTLCMD && disk->fops->__compat_ioctl)
-               ret = disk->fops->__compat_ioctl(file, cmd, arg);
-       unlock_kernel();
-       if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
-               ret = disk->fops->compat_ioctl(bdev, file->f_mode, cmd, arg);
-
-       if (ret != -ENOIOCTLCMD)
+               ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
                return ret;
-
-       return compat_blkdev_driver_ioctl(inode, file, disk, cmd, arg);
+       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;
+       }
 }