mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
[PATCH] block: add unlocked_ioctl support for block devices
This patch allows block device drivers to convert their ioctl functions to unlocked_ioctl() like character devices and other subsystems. All functions that were called with the BKL held before are still used that way, but I would not be surprised if it could be removed from the ioctl functions in drivers/block/ioctl.c themselves. As a side note, I found that compat_blkdev_ioctl() acquires the BKL as well, which looks like a bug. I have checked that every user of disk->fops->compat_ioctl() in the current git tree gets the BKL itself, so it could easily be removed from compat_blkdev_ioctl(). Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
0d77e5a2c2
commit
bb93e3a52f
3 changed files with 57 additions and 23 deletions
|
@ -133,11 +133,9 @@ static int put_u64(unsigned long arg, u64 val)
|
||||||
return put_user(val, (u64 __user *)arg);
|
return put_user(val, (u64 __user *)arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
|
static int blkdev_locked_ioctl(struct file *file, struct block_device *bdev,
|
||||||
unsigned long arg)
|
unsigned cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct block_device *bdev = inode->i_bdev;
|
|
||||||
struct gendisk *disk = bdev->bd_disk;
|
|
||||||
struct backing_dev_info *bdi;
|
struct backing_dev_info *bdi;
|
||||||
int ret, n;
|
int ret, n;
|
||||||
|
|
||||||
|
@ -190,36 +188,72 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
|
||||||
return put_ulong(arg, bdev->bd_inode->i_size >> 9);
|
return put_ulong(arg, bdev->bd_inode->i_size >> 9);
|
||||||
case BLKGETSIZE64:
|
case BLKGETSIZE64:
|
||||||
return put_u64(arg, bdev->bd_inode->i_size);
|
return put_u64(arg, bdev->bd_inode->i_size);
|
||||||
|
}
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int blkdev_driver_ioctl(struct inode *inode, struct file *file,
|
||||||
|
struct gendisk *disk, unsigned cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
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 -ENOTTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
|
||||||
|
unsigned long arg)
|
||||||
|
{
|
||||||
|
struct block_device *bdev = inode->i_bdev;
|
||||||
|
struct gendisk *disk = bdev->bd_disk;
|
||||||
|
int ret, n;
|
||||||
|
|
||||||
|
switch(cmd) {
|
||||||
case BLKFLSBUF:
|
case BLKFLSBUF:
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
if (disk->fops->ioctl) {
|
|
||||||
ret = disk->fops->ioctl(inode, file, cmd, arg);
|
ret = blkdev_driver_ioctl(inode, file, disk, cmd, arg);
|
||||||
/* -EINVAL to handle old uncorrected drivers */
|
/* -EINVAL to handle old uncorrected drivers */
|
||||||
if (ret != -EINVAL && ret != -ENOTTY)
|
if (ret != -EINVAL && ret != -ENOTTY)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
|
lock_kernel();
|
||||||
fsync_bdev(bdev);
|
fsync_bdev(bdev);
|
||||||
invalidate_bdev(bdev, 0);
|
invalidate_bdev(bdev, 0);
|
||||||
|
unlock_kernel();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case BLKROSET:
|
case BLKROSET:
|
||||||
if (disk->fops->ioctl) {
|
ret = blkdev_driver_ioctl(inode, file, disk, cmd, arg);
|
||||||
ret = disk->fops->ioctl(inode, file, cmd, arg);
|
/* -EINVAL to handle old uncorrected drivers */
|
||||||
/* -EINVAL to handle old uncorrected drivers */
|
if (ret != -EINVAL && ret != -ENOTTY)
|
||||||
if (ret != -EINVAL && ret != -ENOTTY)
|
return ret;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
if (get_user(n, (int __user *)(arg)))
|
if (get_user(n, (int __user *)(arg)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
lock_kernel();
|
||||||
set_device_ro(bdev, n);
|
set_device_ro(bdev, n);
|
||||||
|
unlock_kernel();
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
|
||||||
if (disk->fops->ioctl)
|
|
||||||
return disk->fops->ioctl(inode, file, cmd, arg);
|
|
||||||
}
|
}
|
||||||
return -ENOTTY;
|
|
||||||
|
lock_kernel();
|
||||||
|
ret = blkdev_locked_ioctl(file, bdev, cmd, arg);
|
||||||
|
unlock_kernel();
|
||||||
|
if (ret != -ENOIOCTLCMD)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return blkdev_driver_ioctl(inode, file, disk, cmd, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Most of the generic ioctls are handled in the normal fallback path.
|
/* Most of the generic ioctls are handled in the normal fallback path.
|
||||||
|
|
|
@ -777,8 +777,7 @@ static ssize_t blkdev_file_aio_write(struct kiocb *iocb, const char __user *buf,
|
||||||
return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
|
return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int block_ioctl(struct inode *inode, struct file *file, unsigned cmd,
|
static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||||
unsigned long arg)
|
|
||||||
{
|
{
|
||||||
return blkdev_ioctl(file->f_mapping->host, file, cmd, arg);
|
return blkdev_ioctl(file->f_mapping->host, file, cmd, arg);
|
||||||
}
|
}
|
||||||
|
@ -803,7 +802,7 @@ struct file_operations def_blk_fops = {
|
||||||
.aio_write = blkdev_file_aio_write,
|
.aio_write = blkdev_file_aio_write,
|
||||||
.mmap = generic_file_mmap,
|
.mmap = generic_file_mmap,
|
||||||
.fsync = block_fsync,
|
.fsync = block_fsync,
|
||||||
.ioctl = block_ioctl,
|
.unlocked_ioctl = block_ioctl,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
.compat_ioctl = compat_blkdev_ioctl,
|
.compat_ioctl = compat_blkdev_ioctl,
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -884,6 +884,7 @@ struct block_device_operations {
|
||||||
int (*open) (struct inode *, struct file *);
|
int (*open) (struct inode *, struct file *);
|
||||||
int (*release) (struct inode *, struct file *);
|
int (*release) (struct inode *, struct file *);
|
||||||
int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
|
int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
|
||||||
|
long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
|
||||||
long (*compat_ioctl) (struct file *, unsigned, unsigned long);
|
long (*compat_ioctl) (struct file *, unsigned, unsigned long);
|
||||||
int (*media_changed) (struct gendisk *);
|
int (*media_changed) (struct gendisk *);
|
||||||
int (*revalidate_disk) (struct gendisk *);
|
int (*revalidate_disk) (struct gendisk *);
|
||||||
|
|
Loading…
Reference in a new issue