NVMe: Remove duplicate compat SG_IO code
We can return -ENOIOCTLCMD and the ioctl will be handled by fs/compat_ioctl.c instead. This removes a lot of duplicate code in the nvme driver. Signed-off-by: Keith Busch <keith.busch@intel.com> Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com> Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
parent
a96d4f5c2d
commit
e179729a82
|
@ -1807,11 +1807,9 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
|
||||||
static int nvme_compat_ioctl(struct block_device *bdev, fmode_t mode,
|
static int nvme_compat_ioctl(struct block_device *bdev, fmode_t mode,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct nvme_ns *ns = bdev->bd_disk->private_data;
|
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SG_IO:
|
case SG_IO:
|
||||||
return nvme_sg_io32(ns, arg);
|
return -ENOIOCTLCMD;
|
||||||
}
|
}
|
||||||
return nvme_ioctl(bdev, mode, cmd, arg);
|
return nvme_ioctl(bdev, mode, cmd, arg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3016,152 +3016,6 @@ int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr)
|
||||||
return retcode;
|
return retcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_COMPAT
|
|
||||||
typedef struct sg_io_hdr32 {
|
|
||||||
compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */
|
|
||||||
compat_int_t dxfer_direction; /* [i] data transfer direction */
|
|
||||||
unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */
|
|
||||||
unsigned char mx_sb_len; /* [i] max length to write to sbp */
|
|
||||||
unsigned short iovec_count; /* [i] 0 implies no scatter gather */
|
|
||||||
compat_uint_t dxfer_len; /* [i] byte count of data transfer */
|
|
||||||
compat_uint_t dxferp; /* [i], [*io] points to data transfer memory
|
|
||||||
or scatter gather list */
|
|
||||||
compat_uptr_t cmdp; /* [i], [*i] points to command to perform */
|
|
||||||
compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */
|
|
||||||
compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */
|
|
||||||
compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */
|
|
||||||
compat_int_t pack_id; /* [i->o] unused internally (normally) */
|
|
||||||
compat_uptr_t usr_ptr; /* [i->o] unused internally */
|
|
||||||
unsigned char status; /* [o] scsi status */
|
|
||||||
unsigned char masked_status; /* [o] shifted, masked scsi status */
|
|
||||||
unsigned char msg_status; /* [o] messaging level data (optional) */
|
|
||||||
unsigned char sb_len_wr; /* [o] byte count actually written to sbp */
|
|
||||||
unsigned short host_status; /* [o] errors from host adapter */
|
|
||||||
unsigned short driver_status; /* [o] errors from software driver */
|
|
||||||
compat_int_t resid; /* [o] dxfer_len - actual_transferred */
|
|
||||||
compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */
|
|
||||||
compat_uint_t info; /* [o] auxiliary information */
|
|
||||||
} sg_io_hdr32_t; /* 64 bytes long (on sparc32) */
|
|
||||||
|
|
||||||
typedef struct sg_iovec32 {
|
|
||||||
compat_uint_t iov_base;
|
|
||||||
compat_uint_t iov_len;
|
|
||||||
} sg_iovec32_t;
|
|
||||||
|
|
||||||
static int sg_build_iovec(sg_io_hdr_t __user *sgio, void __user *dxferp, u16 iovec_count)
|
|
||||||
{
|
|
||||||
sg_iovec_t __user *iov = (sg_iovec_t __user *) (sgio + 1);
|
|
||||||
sg_iovec32_t __user *iov32 = dxferp;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < iovec_count; i++) {
|
|
||||||
u32 base, len;
|
|
||||||
|
|
||||||
if (get_user(base, &iov32[i].iov_base) ||
|
|
||||||
get_user(len, &iov32[i].iov_len) ||
|
|
||||||
put_user(compat_ptr(base), &iov[i].iov_base) ||
|
|
||||||
put_user(len, &iov[i].iov_len))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (put_user(iov, &sgio->dxferp))
|
|
||||||
return -EFAULT;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nvme_sg_io32(struct nvme_ns *ns, unsigned long arg)
|
|
||||||
{
|
|
||||||
sg_io_hdr32_t __user *sgio32 = (sg_io_hdr32_t __user *)arg;
|
|
||||||
sg_io_hdr_t __user *sgio;
|
|
||||||
u16 iovec_count;
|
|
||||||
u32 data;
|
|
||||||
void __user *dxferp;
|
|
||||||
int err;
|
|
||||||
int interface_id;
|
|
||||||
|
|
||||||
if (get_user(interface_id, &sgio32->interface_id))
|
|
||||||
return -EFAULT;
|
|
||||||
if (interface_id != 'S')
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (get_user(iovec_count, &sgio32->iovec_count))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
{
|
|
||||||
void __user *top = compat_alloc_user_space(0);
|
|
||||||
void __user *new = compat_alloc_user_space(sizeof(sg_io_hdr_t) +
|
|
||||||
(iovec_count * sizeof(sg_iovec_t)));
|
|
||||||
if (new > top)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
sgio = new;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ok, now construct. */
|
|
||||||
if (copy_in_user(&sgio->interface_id, &sgio32->interface_id,
|
|
||||||
(2 * sizeof(int)) +
|
|
||||||
(2 * sizeof(unsigned char)) +
|
|
||||||
(1 * sizeof(unsigned short)) +
|
|
||||||
(1 * sizeof(unsigned int))))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
if (get_user(data, &sgio32->dxferp))
|
|
||||||
return -EFAULT;
|
|
||||||
dxferp = compat_ptr(data);
|
|
||||||
if (iovec_count) {
|
|
||||||
if (sg_build_iovec(sgio, dxferp, iovec_count))
|
|
||||||
return -EFAULT;
|
|
||||||
} else {
|
|
||||||
if (put_user(dxferp, &sgio->dxferp))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
unsigned char __user *cmdp;
|
|
||||||
unsigned char __user *sbp;
|
|
||||||
|
|
||||||
if (get_user(data, &sgio32->cmdp))
|
|
||||||
return -EFAULT;
|
|
||||||
cmdp = compat_ptr(data);
|
|
||||||
|
|
||||||
if (get_user(data, &sgio32->sbp))
|
|
||||||
return -EFAULT;
|
|
||||||
sbp = compat_ptr(data);
|
|
||||||
|
|
||||||
if (put_user(cmdp, &sgio->cmdp) ||
|
|
||||||
put_user(sbp, &sgio->sbp))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy_in_user(&sgio->timeout, &sgio32->timeout,
|
|
||||||
3 * sizeof(int)))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
if (get_user(data, &sgio32->usr_ptr))
|
|
||||||
return -EFAULT;
|
|
||||||
if (put_user(compat_ptr(data), &sgio->usr_ptr))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
err = nvme_sg_io(ns, sgio);
|
|
||||||
if (err >= 0) {
|
|
||||||
void __user *datap;
|
|
||||||
|
|
||||||
if (copy_in_user(&sgio32->pack_id, &sgio->pack_id,
|
|
||||||
sizeof(int)) ||
|
|
||||||
get_user(datap, &sgio->usr_ptr) ||
|
|
||||||
put_user((u32)(unsigned long)datap,
|
|
||||||
&sgio32->usr_ptr) ||
|
|
||||||
copy_in_user(&sgio32->status, &sgio->status,
|
|
||||||
(4 * sizeof(unsigned char)) +
|
|
||||||
(2 * sizeof(unsigned short)) +
|
|
||||||
(3 * sizeof(int))))
|
|
||||||
err = -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int nvme_sg_get_version_num(int __user *ip)
|
int nvme_sg_get_version_num(int __user *ip)
|
||||||
{
|
{
|
||||||
return put_user(sg_version_num, ip);
|
return put_user(sg_version_num, ip);
|
||||||
|
|
Loading…
Reference in New Issue