Merge git://git.infradead.org/users/willy/linux-nvme
Pull NVMe driver update from Matthew Wilcox: "Looks like I missed the merge window ... but these are almost all bugfixes anyway (the ones that aren't have been baking for months)" * git://git.infradead.org/users/willy/linux-nvme: NVMe: Namespace use after free on surprise removal NVMe: Correct uses of INIT_WORK NVMe: Include device and queue numbers in interrupt name NVMe: Add a pci_driver shutdown method NVMe: Disable admin queue on init failure NVMe: Dynamically allocate partition numbers NVMe: Async IO queue deletion NVMe: Surprise removal handling NVMe: Abort timed out commands NVMe: Schedule reset for failed controllers NVMe: Device resume error handling NVMe: Cache dev->pci_dev in a local pointer NVMe: Fix lockdep warnings NVMe: compat SG_IO ioctl NVMe: remove deprecated IRQF_DISABLED NVMe: Avoid shift operation when writing cq head doorbell
This commit is contained in:
commit
8352650a5c
File diff suppressed because it is too large
Load Diff
|
@ -25,6 +25,7 @@
|
|||
#include <linux/bio.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
|
@ -3038,6 +3039,152 @@ int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr)
|
|||
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)
|
||||
{
|
||||
return put_user(sg_version_num, ip);
|
||||
|
|
|
@ -80,13 +80,14 @@ struct nvme_dev {
|
|||
struct dma_pool *prp_small_pool;
|
||||
int instance;
|
||||
int queue_count;
|
||||
int db_stride;
|
||||
u32 db_stride;
|
||||
u32 ctrl_config;
|
||||
struct msix_entry *entry;
|
||||
struct nvme_bar __iomem *bar;
|
||||
struct list_head namespaces;
|
||||
struct kref kref;
|
||||
struct miscdevice miscdev;
|
||||
struct work_struct reset_work;
|
||||
char name[12];
|
||||
char serial[20];
|
||||
char model[40];
|
||||
|
@ -94,6 +95,8 @@ struct nvme_dev {
|
|||
u32 max_hw_sectors;
|
||||
u32 stripe_size;
|
||||
u16 oncs;
|
||||
u16 abort_limit;
|
||||
u8 initialized;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -165,6 +168,7 @@ int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11,
|
|||
struct sg_io_hdr;
|
||||
|
||||
int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr);
|
||||
int nvme_sg_io32(struct nvme_ns *ns, unsigned long arg);
|
||||
int nvme_sg_get_version_num(int __user *ip);
|
||||
|
||||
#endif /* _LINUX_NVME_H */
|
||||
|
|
|
@ -350,6 +350,16 @@ struct nvme_delete_queue {
|
|||
__u32 rsvd11[5];
|
||||
};
|
||||
|
||||
struct nvme_abort_cmd {
|
||||
__u8 opcode;
|
||||
__u8 flags;
|
||||
__u16 command_id;
|
||||
__u32 rsvd1[9];
|
||||
__le16 sqid;
|
||||
__u16 cid;
|
||||
__u32 rsvd11[5];
|
||||
};
|
||||
|
||||
struct nvme_download_firmware {
|
||||
__u8 opcode;
|
||||
__u8 flags;
|
||||
|
@ -384,6 +394,7 @@ struct nvme_command {
|
|||
struct nvme_download_firmware dlfw;
|
||||
struct nvme_format_cmd format;
|
||||
struct nvme_dsm_cmd dsm;
|
||||
struct nvme_abort_cmd abort;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue