forked from grate-driver/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
compat_ioctl: move common block ioctls to compat_blkdev_ioctl
Make compat_blkdev_ioctl and blkdev_ioctl reflect the respective native versions. This is somewhat more efficient and makes it easier to keep the two in sync. Also get rid of the bogus handling for broken_blkgetsize and the duplicate entry for BLKRASET. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
- Loading branch information
Showing
4 changed files
with
126 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
#include <linux/blkdev.h> | ||
#include <linux/blkpg.h> | ||
#include <linux/blktrace_api.h> | ||
#include <linux/cdrom.h> | ||
#include <linux/compat.h> | ||
#include <linux/elevator.h> | ||
#include <linux/fd.h> | ||
#include <linux/hdreg.h> | ||
#include <linux/syscalls.h> | ||
#include <linux/smp_lock.h> | ||
#include <linux/types.h> | ||
#include <linux/uaccess.h> | ||
|
||
static int compat_put_ushort(unsigned long arg, unsigned short val) | ||
{ | ||
return put_user(val, (unsigned short __user *)compat_ptr(arg)); | ||
} | ||
|
||
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_long(unsigned long arg, long val) | ||
{ | ||
return put_user(val, (compat_long_t __user *)compat_ptr(arg)); | ||
} | ||
|
||
static int compat_put_ulong(unsigned long arg, compat_ulong_t val) | ||
{ | ||
return put_user(val, (compat_ulong_t __user *)compat_ptr(arg)); | ||
} | ||
|
||
static int compat_put_u64(unsigned long arg, u64 val) | ||
{ | ||
return put_user(val, (compat_u64 __user *)compat_ptr(arg)); | ||
} | ||
|
||
#define BLKBSZGET_32 _IOR(0x12, 112, int) | ||
#define BLKBSZSET_32 _IOW(0x12, 113, int) | ||
#define BLKGETSIZE64_32 _IOR(0x12, 114, int) | ||
|
||
static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file, | ||
struct block_device *bdev, | ||
unsigned cmd, unsigned long arg) | ||
{ | ||
struct backing_dev_info *bdi; | ||
|
||
switch (cmd) { | ||
case BLKRAGET: | ||
case BLKFRAGET: | ||
if (!arg) | ||
return -EINVAL; | ||
bdi = blk_get_backing_dev_info(bdev); | ||
if (bdi == NULL) | ||
return -ENOTTY; | ||
return compat_put_long(arg, | ||
(bdi->ra_pages * PAGE_CACHE_SIZE) / 512); | ||
case BLKROGET: /* compatible */ | ||
return compat_put_int(arg, bdev_read_only(bdev) != 0); | ||
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)); | ||
case BLKSECTGET: | ||
return compat_put_ushort(arg, | ||
bdev_get_queue(bdev)->max_sectors); | ||
case BLKRASET: /* compatible, but no compat_ptr (!) */ | ||
case BLKFRASET: | ||
if (!capable(CAP_SYS_ADMIN)) | ||
return -EACCES; | ||
bdi = blk_get_backing_dev_info(bdev); | ||
if (bdi == NULL) | ||
return -ENOTTY; | ||
bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE; | ||
return 0; | ||
case BLKGETSIZE: | ||
if ((bdev->bd_inode->i_size >> 9) > ~0UL) | ||
return -EFBIG; | ||
return compat_put_ulong(arg, bdev->bd_inode->i_size >> 9); | ||
|
||
case BLKGETSIZE64_32: | ||
return compat_put_u64(arg, bdev->bd_inode->i_size); | ||
} | ||
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 BLKFLSBUF: | ||
case BLKROSET: | ||
/* | ||
* 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)); | ||
} | ||
|
||
lock_kernel(); | ||
ret = compat_blkdev_locked_ioctl(inode, file, bdev, cmd, arg); | ||
/* FIXME: why do we assume -> compat_ioctl needs the BKL? */ | ||
if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl) | ||
ret = disk->fops->compat_ioctl(file, cmd, arg); | ||
unlock_kernel(); | ||
|
||
return ret; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters