Skip to content

Commit d320a95

Browse files
committed
compat_ioctl: scsi: move ioctl handling into drivers
Each driver calling scsi_ioctl() gets an equivalent compat_ioctl() handler that implements the same commands by calling scsi_compat_ioctl(). The scsi_cmd_ioctl() and scsi_cmd_blk_ioctl() functions are compatible at this point, so any driver that calls those can do so for both native and compat mode, with the argument passed through compat_ptr(). With this, we can remove the entries from fs/compat_ioctl.c. The new code is larger, but should be easier to maintain and keep updated with newly added commands. Reviewed-by: Ben Hutchings <[email protected]> Acked-by: Stefan Hajnoczi <[email protected]> Signed-off-by: Arnd Bergmann <[email protected]>
1 parent c103d6e commit d320a95

File tree

7 files changed

+142
-204
lines changed

7 files changed

+142
-204
lines changed

drivers/block/virtio_blk.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
405405

406406
static const struct block_device_operations virtblk_fops = {
407407
.ioctl = virtblk_ioctl,
408+
#ifdef CONFIG_COMPAT
409+
.compat_ioctl = blkdev_compat_ptr_ioctl,
410+
#endif
408411
.owner = THIS_MODULE,
409412
.getgeo = virtblk_getgeo,
410413
};

drivers/scsi/ch.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,10 @@ static long ch_ioctl_compat(struct file * file,
872872
unsigned int cmd, unsigned long arg)
873873
{
874874
scsi_changer *ch = file->private_data;
875+
int retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd,
876+
file->f_flags & O_NDELAY);
877+
if (retval)
878+
return retval;
875879

876880
switch (cmd) {
877881
case CHIOGPARAMS:
@@ -883,7 +887,7 @@ static long ch_ioctl_compat(struct file * file,
883887
case CHIOINITELEM:
884888
case CHIOSVOLTAG:
885889
/* compatible */
886-
return ch_ioctl(file, cmd, arg);
890+
return ch_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
887891
case CHIOGSTATUS32:
888892
{
889893
struct changer_element_status32 ces32;
@@ -898,8 +902,7 @@ static long ch_ioctl_compat(struct file * file,
898902
return ch_gstatus(ch, ces32.ces_type, data);
899903
}
900904
default:
901-
// return scsi_ioctl_compat(ch->device, cmd, (void*)arg);
902-
return -ENOIOCTLCMD;
905+
return scsi_compat_ioctl(ch->device, cmd, compat_ptr(arg));
903906

904907
}
905908
}

drivers/scsi/sd.c

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,13 +1465,12 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
14651465
* Note: most ioctls are forward onto the block subsystem or further
14661466
* down in the scsi subsystem.
14671467
**/
1468-
static int sd_ioctl(struct block_device *bdev, fmode_t mode,
1469-
unsigned int cmd, unsigned long arg)
1468+
static int sd_ioctl_common(struct block_device *bdev, fmode_t mode,
1469+
unsigned int cmd, void __user *p)
14701470
{
14711471
struct gendisk *disk = bdev->bd_disk;
14721472
struct scsi_disk *sdkp = scsi_disk(disk);
14731473
struct scsi_device *sdp = sdkp->device;
1474-
void __user *p = (void __user *)arg;
14751474
int error;
14761475

14771476
SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, "
@@ -1507,9 +1506,6 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
15071506
break;
15081507
default:
15091508
error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p);
1510-
if (error != -ENOTTY)
1511-
break;
1512-
error = scsi_ioctl(sdp, cmd, p);
15131509
break;
15141510
}
15151511
out:
@@ -1691,39 +1687,31 @@ static void sd_rescan(struct device *dev)
16911687
revalidate_disk(sdkp->disk);
16921688
}
16931689

1690+
static int sd_ioctl(struct block_device *bdev, fmode_t mode,
1691+
unsigned int cmd, unsigned long arg)
1692+
{
1693+
void __user *p = (void __user *)arg;
1694+
int ret;
1695+
1696+
ret = sd_ioctl_common(bdev, mode, cmd, p);
1697+
if (ret != -ENOTTY)
1698+
return ret;
1699+
1700+
return scsi_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p);
1701+
}
16941702

16951703
#ifdef CONFIG_COMPAT
1696-
/*
1697-
* This gets directly called from VFS. When the ioctl
1698-
* is not recognized we go back to the other translation paths.
1699-
*/
17001704
static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
17011705
unsigned int cmd, unsigned long arg)
17021706
{
1703-
struct gendisk *disk = bdev->bd_disk;
1704-
struct scsi_disk *sdkp = scsi_disk(disk);
1705-
struct scsi_device *sdev = sdkp->device;
17061707
void __user *p = compat_ptr(arg);
1707-
int error;
1708-
1709-
error = scsi_verify_blk_ioctl(bdev, cmd);
1710-
if (error < 0)
1711-
return error;
1708+
int ret;
17121709

1713-
error = scsi_ioctl_block_when_processing_errors(sdev, cmd,
1714-
(mode & FMODE_NDELAY) != 0);
1715-
if (error)
1716-
return error;
1710+
ret = sd_ioctl_common(bdev, mode, cmd, p);
1711+
if (ret != -ENOTTY)
1712+
return ret;
17171713

1718-
if (is_sed_ioctl(cmd))
1719-
return sed_ioctl(sdkp->opal_dev, cmd, p);
1720-
1721-
/*
1722-
* Let the static ioctl translation table take care of it.
1723-
*/
1724-
if (!sdev->host->hostt->compat_ioctl)
1725-
return -ENOIOCTLCMD;
1726-
return sdev->host->hostt->compat_ioctl(sdev, cmd, p);
1714+
return scsi_compat_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p);
17271715
}
17281716
#endif
17291717

drivers/scsi/sg.c

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -911,19 +911,14 @@ static int put_compat_request_table(struct compat_sg_req_info __user *o,
911911
#endif
912912

913913
static long
914-
sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
914+
sg_ioctl_common(struct file *filp, Sg_device *sdp, Sg_fd *sfp,
915+
unsigned int cmd_in, void __user *p)
915916
{
916-
void __user *p = (void __user *)arg;
917917
int __user *ip = p;
918918
int result, val, read_only;
919-
Sg_device *sdp;
920-
Sg_fd *sfp;
921919
Sg_request *srp;
922920
unsigned long iflags;
923921

924-
if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
925-
return -ENXIO;
926-
927922
SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp,
928923
"sg_ioctl: cmd=0x%x\n", (int) cmd_in));
929924
read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
@@ -1146,29 +1141,44 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
11461141
cmd_in, filp->f_flags & O_NDELAY);
11471142
if (result)
11481143
return result;
1144+
1145+
return -ENOIOCTLCMD;
1146+
}
1147+
1148+
static long
1149+
sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
1150+
{
1151+
void __user *p = (void __user *)arg;
1152+
Sg_device *sdp;
1153+
Sg_fd *sfp;
1154+
int ret;
1155+
1156+
if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
1157+
return -ENXIO;
1158+
1159+
ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p);
1160+
if (ret != -ENOIOCTLCMD)
1161+
return ret;
1162+
11491163
return scsi_ioctl(sdp->device, cmd_in, p);
11501164
}
11511165

11521166
#ifdef CONFIG_COMPAT
11531167
static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
11541168
{
1169+
void __user *p = compat_ptr(arg);
11551170
Sg_device *sdp;
11561171
Sg_fd *sfp;
1157-
struct scsi_device *sdev;
1172+
int ret;
11581173

11591174
if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
11601175
return -ENXIO;
11611176

1162-
sdev = sdp->device;
1163-
if (sdev->host->hostt->compat_ioctl) {
1164-
int ret;
1165-
1166-
ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
1167-
1177+
ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p);
1178+
if (ret != -ENOIOCTLCMD)
11681179
return ret;
1169-
}
1170-
1171-
return -ENOIOCTLCMD;
1180+
1181+
return scsi_compat_ioctl(sdp->device, cmd_in, p);
11721182
}
11731183
#endif
11741184

drivers/scsi/sr.c

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <linux/kernel.h>
3939
#include <linux/mm.h>
4040
#include <linux/bio.h>
41+
#include <linux/compat.h>
4142
#include <linux/string.h>
4243
#include <linux/errno.h>
4344
#include <linux/cdrom.h>
@@ -598,6 +599,55 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
598599
return ret;
599600
}
600601

602+
#ifdef CONFIG_COMPAT
603+
static int sr_block_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
604+
unsigned long arg)
605+
{
606+
struct scsi_cd *cd = scsi_cd(bdev->bd_disk);
607+
struct scsi_device *sdev = cd->device;
608+
void __user *argp = compat_ptr(arg);
609+
int ret;
610+
611+
mutex_lock(&sr_mutex);
612+
613+
ret = scsi_ioctl_block_when_processing_errors(sdev, cmd,
614+
(mode & FMODE_NDELAY) != 0);
615+
if (ret)
616+
goto out;
617+
618+
scsi_autopm_get_device(sdev);
619+
620+
/*
621+
* Send SCSI addressing ioctls directly to mid level, send other
622+
* ioctls to cdrom/block level.
623+
*/
624+
switch (cmd) {
625+
case SCSI_IOCTL_GET_IDLUN:
626+
case SCSI_IOCTL_GET_BUS_NUMBER:
627+
ret = scsi_compat_ioctl(sdev, cmd, argp);
628+
goto put;
629+
}
630+
631+
/*
632+
* CDROM ioctls are handled in the block layer, but
633+
* do the scsi blk ioctls here.
634+
*/
635+
ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
636+
if (ret != -ENOTTY)
637+
goto put;
638+
639+
ret = scsi_compat_ioctl(sdev, cmd, argp);
640+
641+
put:
642+
scsi_autopm_put_device(sdev);
643+
644+
out:
645+
mutex_unlock(&sr_mutex);
646+
return ret;
647+
648+
}
649+
#endif
650+
601651
static unsigned int sr_block_check_events(struct gendisk *disk,
602652
unsigned int clearing)
603653
{
@@ -641,12 +691,11 @@ static const struct block_device_operations sr_bdops =
641691
.open = sr_block_open,
642692
.release = sr_block_release,
643693
.ioctl = sr_block_ioctl,
694+
#ifdef CONFIG_COMPAT
695+
.ioctl = sr_block_compat_ioctl,
696+
#endif
644697
.check_events = sr_block_check_events,
645698
.revalidate_disk = sr_block_revalidate_disk,
646-
/*
647-
* No compat_ioctl for now because sr_block_ioctl never
648-
* seems to pass arbitrary ioctls down to host drivers.
649-
*/
650699
};
651700

652701
static int sr_open(struct cdrom_device_info *cdi, int purpose)

drivers/scsi/st.c

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3501,15 +3501,14 @@ static int partition_tape(struct scsi_tape *STp, int size)
35013501

35023502

35033503
/* The ioctl command */
3504-
static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
3504+
static long st_ioctl_common(struct file *file, unsigned int cmd_in, void __user *p)
35053505
{
35063506
int i, cmd_nr, cmd_type, bt;
35073507
int retval = 0;
35083508
unsigned int blk;
35093509
struct scsi_tape *STp = file->private_data;
35103510
struct st_modedef *STm;
35113511
struct st_partstat *STps;
3512-
void __user *p = (void __user *)arg;
35133512

35143513
if (mutex_lock_interruptible(&STp->lock))
35153514
return -ERESTARTSYS;
@@ -3824,9 +3823,19 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
38243823
}
38253824
mutex_unlock(&STp->lock);
38263825
switch (cmd_in) {
3826+
case SCSI_IOCTL_STOP_UNIT:
3827+
/* unload */
3828+
retval = scsi_ioctl(STp->device, cmd_in, p);
3829+
if (!retval) {
3830+
STp->rew_at_close = 0;
3831+
STp->ready = ST_NO_TAPE;
3832+
}
3833+
return retval;
3834+
38273835
case SCSI_IOCTL_GET_IDLUN:
38283836
case SCSI_IOCTL_GET_BUS_NUMBER:
38293837
break;
3838+
38303839
default:
38313840
if ((cmd_in == SG_IO ||
38323841
cmd_in == SCSI_IOCTL_SEND_COMMAND ||
@@ -3840,42 +3849,46 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
38403849
return i;
38413850
break;
38423851
}
3843-
retval = scsi_ioctl(STp->device, cmd_in, p);
3844-
if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) { /* unload */
3845-
STp->rew_at_close = 0;
3846-
STp->ready = ST_NO_TAPE;
3847-
}
3848-
return retval;
3852+
return -ENOTTY;
38493853

38503854
out:
38513855
mutex_unlock(&STp->lock);
38523856
return retval;
38533857
}
38543858

3859+
static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
3860+
{
3861+
void __user *p = (void __user *)arg;
3862+
struct scsi_tape *STp = file->private_data;
3863+
int ret;
3864+
3865+
ret = st_ioctl_common(file, cmd_in, p);
3866+
if (ret != -ENOTTY)
3867+
return ret;
3868+
3869+
return scsi_ioctl(STp->device, cmd_in, p);
3870+
}
3871+
38553872
#ifdef CONFIG_COMPAT
38563873
static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
38573874
{
38583875
void __user *p = compat_ptr(arg);
38593876
struct scsi_tape *STp = file->private_data;
3860-
struct scsi_device *sdev = STp->device;
3861-
int ret = -ENOIOCTLCMD;
3877+
int ret;
38623878

38633879
/* argument conversion is handled using put_user_mtpos/put_user_mtget */
38643880
switch (cmd_in) {
3865-
case MTIOCTOP:
3866-
return st_ioctl(file, MTIOCTOP, (unsigned long)p);
38673881
case MTIOCPOS32:
3868-
return st_ioctl(file, MTIOCPOS, (unsigned long)p);
3882+
return st_ioctl_common(file, MTIOCPOS, p);
38693883
case MTIOCGET32:
3870-
return st_ioctl(file, MTIOCGET, (unsigned long)p);
3884+
return st_ioctl_common(file, MTIOCGET, p);
38713885
}
38723886

3873-
if (sdev->host->hostt->compat_ioctl) {
3887+
ret = st_ioctl_common(file, cmd_in, p);
3888+
if (ret != -ENOTTY)
3889+
return ret;
38743890

3875-
ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
3876-
3877-
}
3878-
return ret;
3891+
return scsi_compat_ioctl(STp->device, cmd_in, p);
38793892
}
38803893
#endif
38813894

0 commit comments

Comments
 (0)