#include <linux/blkpg.h>
#include <linux/backing-dev.h>
#include <linux/buffer_head.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
-static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
+static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg)
{
struct block_device *bdevp;
struct gendisk *disk;
static int put_ushort(unsigned long arg, unsigned short val)
{
- return put_user(val, (unsigned short *)arg);
+ return put_user(val, (unsigned short __user *)arg);
}
static int put_int(unsigned long arg, int val)
{
- return put_user(val, (int *)arg);
+ return put_user(val, (int __user *)arg);
}
static int put_long(unsigned long arg, long val)
{
- return put_user(val, (long *)arg);
+ return put_user(val, (long __user *)arg);
}
static int put_ulong(unsigned long arg, unsigned long val)
{
- return put_user(val, (unsigned long *)arg);
+ return put_user(val, (unsigned long __user *)arg);
}
static int put_u64(unsigned long arg, u64 val)
{
- return put_user(val, (u64 *)arg);
+ return put_user(val, (u64 __user *)arg);
}
int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
return -EACCES;
if (!arg)
return -EINVAL;
- if (get_user(n, (int *) arg))
+ if (get_user(n, (int __user *) arg))
return -EFAULT;
if (bd_claim(bdev, file) < 0)
return -EBUSY;
bd_release(bdev);
return ret;
case BLKPG:
- return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg *) arg);
+ return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg __user *) arg);
case BLKRRPART:
return blkdev_reread_part(bdev);
case BLKGETSIZE:
return -EACCES;
if (disk->fops->ioctl) {
ret = disk->fops->ioctl(inode, file, cmd, arg);
- if (ret != -EINVAL)
+ /* -EINVAL to handle old uncorrected drivers */
+ if (ret != -EINVAL && ret != -ENOTTY)
return ret;
}
fsync_bdev(bdev);
case BLKROSET:
if (disk->fops->ioctl) {
ret = disk->fops->ioctl(inode, file, cmd, arg);
- if (ret != -EINVAL)
+ /* -EINVAL to handle old uncorrected drivers */
+ if (ret != -EINVAL && ret != -ENOTTY)
return ret;
}
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (get_user(n, (int *)(arg)))
+ if (get_user(n, (int __user *)(arg)))
return -EFAULT;
set_device_ro(bdev, n);
return 0;
}
return -ENOTTY;
}
+
+/* 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)
+{
+ struct block_device *bdev = file->f_dentry->d_inode->i_bdev;
+ struct gendisk *disk = bdev->bd_disk;
+ int ret = -ENOIOCTLCMD;
+ if (disk->fops->compat_ioctl) {
+ lock_kernel();
+ ret = disk->fops->compat_ioctl(file, cmd, arg);
+ unlock_kernel();
+ }
+ return ret;
+}