SCSI fixes on 20170808
Two small fixes, one re-fix of a previous fix and five patches sorting out hotplug in the bnx2X class of drivers. The latter is rather involved, but necessary because these drivers have started dropping lockdep recursion warnings on the hotplug lock because of its conversion to a percpu rwsem. Signed-off-by: James E.J. Bottomley <jejb@linux.vnet.ibm.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABAgAGBQJZidgyAAoJEAVr7HOZEZN4tzEQAJsrO6rW6ng/LGIbf+oYdNFY lPcdC3wCJHpPJLzvd0yPu0Davu+m1bCtke8XctWKRcj2QO9YvDmwCrJ6nVNMPO8p LFz0rYSma5VDXyPVcUn+rtMDY3eRVQG8oukVdMzFRtAAlXMDpDl4gaITp4X2HX78 7hSt/SdmpKAgidrvgln7hHvVJKE+Z3Tzp2asS5ygfle+1/u0ByMskiyo6tR/zz8I uf8Y2s5GeiHBe5K6bi4j+xSmC7evxqnDZpQAHeeT/weJQ8l96SIrPN66W9IjJWnD D0P10ctFYS5WfQAB6Fd3UHilVDYOeGOXHOIdWBqEbpi2OtsstihsQy95tQmRxgN7 uBBkCanPbcLm1J9Vg/K08wY8TUdsjg+zJbq+Q+u4q37xJUjz6SYDSMzQyUNT4W1u 3+dB9ImjBZjisg1stokuUTM5lbd9V/SvZngs7nzzi0siRXQI4oTKbGkS1PZUYnly rBfSpnakuraKnQqs0s0c1y0+bcGT4AVMGkzaZ0ivtk4JGWmmkXSoAurByfu9Eq87 7feVyl9QxTBQAD1bl5IaRA/cxBhqe31FwvIpM8ik9zUF5hqt8vAZszB0Yi9MqyvM 3ZCR0poMk8e2ZE+vMcH304uQ9CW3jG7cgWwZgfvWBmd/NgMOKgFhY3PAScmGkFex EgeDmxx+/uctEHQYYV3g =Lg/x -----END PGP SIGNATURE----- Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi Pull SCSI fixes from James Bottomley: "Two small fixes, one re-fix of a previous fix and five patches sorting out hotplug in the bnx2X class of drivers. The latter is rather involved, but necessary because these drivers have started dropping lockdep recursion warnings on the hotplug lock because of its conversion to a percpu rwsem" * tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: scsi: sg: only check for dxfer_len greater than 256M scsi: aacraid: reading out of bounds scsi: qedf: Limit number of CQs scsi: bnx2i: Simplify cpu hotplug code scsi: bnx2fc: Simplify CPU hotplug code scsi: bnx2i: Prevent recursive cpuhotplug locking scsi: bnx2fc: Prevent recursive cpuhotplug locking scsi: bnx2fc: Plug CPU hotplug race
This commit is contained in:
Коммит
de70be0ae3
|
@ -3198,10 +3198,11 @@ static int query_disk(struct aac_dev *dev, void __user *arg)
|
|||
return -EBUSY;
|
||||
if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk)))
|
||||
return -EFAULT;
|
||||
if (qd.cnum == -1)
|
||||
if (qd.cnum == -1) {
|
||||
if (qd.id < 0 || qd.id >= dev->maximum_num_containers)
|
||||
return -EINVAL;
|
||||
qd.cnum = qd.id;
|
||||
else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1))
|
||||
{
|
||||
} else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) {
|
||||
if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers)
|
||||
return -EINVAL;
|
||||
qd.instance = dev->scsi_host_ptr->host_no;
|
||||
|
|
|
@ -2624,12 +2624,11 @@ static struct fcoe_transport bnx2fc_transport = {
|
|||
};
|
||||
|
||||
/**
|
||||
* bnx2fc_percpu_thread_create - Create a receive thread for an
|
||||
* online CPU
|
||||
* bnx2fc_cpu_online - Create a receive thread for an online CPU
|
||||
*
|
||||
* @cpu: cpu index for the online cpu
|
||||
*/
|
||||
static void bnx2fc_percpu_thread_create(unsigned int cpu)
|
||||
static int bnx2fc_cpu_online(unsigned int cpu)
|
||||
{
|
||||
struct bnx2fc_percpu_s *p;
|
||||
struct task_struct *thread;
|
||||
|
@ -2639,15 +2638,17 @@ static void bnx2fc_percpu_thread_create(unsigned int cpu)
|
|||
thread = kthread_create_on_node(bnx2fc_percpu_io_thread,
|
||||
(void *)p, cpu_to_node(cpu),
|
||||
"bnx2fc_thread/%d", cpu);
|
||||
if (IS_ERR(thread))
|
||||
return PTR_ERR(thread);
|
||||
|
||||
/* bind thread to the cpu */
|
||||
if (likely(!IS_ERR(thread))) {
|
||||
kthread_bind(thread, cpu);
|
||||
p->iothread = thread;
|
||||
wake_up_process(thread);
|
||||
}
|
||||
kthread_bind(thread, cpu);
|
||||
p->iothread = thread;
|
||||
wake_up_process(thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bnx2fc_percpu_thread_destroy(unsigned int cpu)
|
||||
static int bnx2fc_cpu_offline(unsigned int cpu)
|
||||
{
|
||||
struct bnx2fc_percpu_s *p;
|
||||
struct task_struct *thread;
|
||||
|
@ -2661,7 +2662,6 @@ static void bnx2fc_percpu_thread_destroy(unsigned int cpu)
|
|||
thread = p->iothread;
|
||||
p->iothread = NULL;
|
||||
|
||||
|
||||
/* Free all work in the list */
|
||||
list_for_each_entry_safe(work, tmp, &p->work_list, list) {
|
||||
list_del_init(&work->list);
|
||||
|
@ -2673,20 +2673,6 @@ static void bnx2fc_percpu_thread_destroy(unsigned int cpu)
|
|||
|
||||
if (thread)
|
||||
kthread_stop(thread);
|
||||
}
|
||||
|
||||
|
||||
static int bnx2fc_cpu_online(unsigned int cpu)
|
||||
{
|
||||
printk(PFX "CPU %x online: Create Rx thread\n", cpu);
|
||||
bnx2fc_percpu_thread_create(cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bnx2fc_cpu_dead(unsigned int cpu)
|
||||
{
|
||||
printk(PFX "CPU %x offline: Remove Rx thread\n", cpu);
|
||||
bnx2fc_percpu_thread_destroy(cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2761,30 +2747,16 @@ static int __init bnx2fc_mod_init(void)
|
|||
spin_lock_init(&p->fp_work_lock);
|
||||
}
|
||||
|
||||
get_online_cpus();
|
||||
|
||||
for_each_online_cpu(cpu)
|
||||
bnx2fc_percpu_thread_create(cpu);
|
||||
|
||||
rc = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
|
||||
"scsi/bnx2fc:online",
|
||||
bnx2fc_cpu_online, NULL);
|
||||
rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "scsi/bnx2fc:online",
|
||||
bnx2fc_cpu_online, bnx2fc_cpu_offline);
|
||||
if (rc < 0)
|
||||
goto stop_threads;
|
||||
goto stop_thread;
|
||||
bnx2fc_online_state = rc;
|
||||
|
||||
cpuhp_setup_state_nocalls(CPUHP_SCSI_BNX2FC_DEAD, "scsi/bnx2fc:dead",
|
||||
NULL, bnx2fc_cpu_dead);
|
||||
put_online_cpus();
|
||||
|
||||
cnic_register_driver(CNIC_ULP_FCOE, &bnx2fc_cnic_cb);
|
||||
|
||||
return 0;
|
||||
|
||||
stop_threads:
|
||||
for_each_online_cpu(cpu)
|
||||
bnx2fc_percpu_thread_destroy(cpu);
|
||||
put_online_cpus();
|
||||
stop_thread:
|
||||
kthread_stop(l2_thread);
|
||||
free_wq:
|
||||
destroy_workqueue(bnx2fc_wq);
|
||||
|
@ -2803,7 +2775,6 @@ static void __exit bnx2fc_mod_exit(void)
|
|||
struct fcoe_percpu_s *bg;
|
||||
struct task_struct *l2_thread;
|
||||
struct sk_buff *skb;
|
||||
unsigned int cpu = 0;
|
||||
|
||||
/*
|
||||
* NOTE: Since cnic calls register_driver routine rtnl_lock,
|
||||
|
@ -2844,16 +2815,7 @@ static void __exit bnx2fc_mod_exit(void)
|
|||
if (l2_thread)
|
||||
kthread_stop(l2_thread);
|
||||
|
||||
get_online_cpus();
|
||||
/* Destroy per cpu threads */
|
||||
for_each_online_cpu(cpu) {
|
||||
bnx2fc_percpu_thread_destroy(cpu);
|
||||
}
|
||||
|
||||
cpuhp_remove_state_nocalls(bnx2fc_online_state);
|
||||
cpuhp_remove_state_nocalls(CPUHP_SCSI_BNX2FC_DEAD);
|
||||
|
||||
put_online_cpus();
|
||||
cpuhp_remove_state(bnx2fc_online_state);
|
||||
|
||||
destroy_workqueue(bnx2fc_wq);
|
||||
/*
|
||||
|
|
|
@ -1008,6 +1008,28 @@ static struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe)
|
|||
return work;
|
||||
}
|
||||
|
||||
/* Pending work request completion */
|
||||
static void bnx2fc_pending_work(struct bnx2fc_rport *tgt, unsigned int wqe)
|
||||
{
|
||||
unsigned int cpu = wqe % num_possible_cpus();
|
||||
struct bnx2fc_percpu_s *fps;
|
||||
struct bnx2fc_work *work;
|
||||
|
||||
fps = &per_cpu(bnx2fc_percpu, cpu);
|
||||
spin_lock_bh(&fps->fp_work_lock);
|
||||
if (fps->iothread) {
|
||||
work = bnx2fc_alloc_work(tgt, wqe);
|
||||
if (work) {
|
||||
list_add_tail(&work->list, &fps->work_list);
|
||||
wake_up_process(fps->iothread);
|
||||
spin_unlock_bh(&fps->fp_work_lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&fps->fp_work_lock);
|
||||
bnx2fc_process_cq_compl(tgt, wqe);
|
||||
}
|
||||
|
||||
int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt)
|
||||
{
|
||||
struct fcoe_cqe *cq;
|
||||
|
@ -1042,28 +1064,7 @@ int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt)
|
|||
/* Unsolicited event notification */
|
||||
bnx2fc_process_unsol_compl(tgt, wqe);
|
||||
} else {
|
||||
/* Pending work request completion */
|
||||
struct bnx2fc_work *work = NULL;
|
||||
struct bnx2fc_percpu_s *fps = NULL;
|
||||
unsigned int cpu = wqe % num_possible_cpus();
|
||||
|
||||
fps = &per_cpu(bnx2fc_percpu, cpu);
|
||||
spin_lock_bh(&fps->fp_work_lock);
|
||||
if (unlikely(!fps->iothread))
|
||||
goto unlock;
|
||||
|
||||
work = bnx2fc_alloc_work(tgt, wqe);
|
||||
if (work)
|
||||
list_add_tail(&work->list,
|
||||
&fps->work_list);
|
||||
unlock:
|
||||
spin_unlock_bh(&fps->fp_work_lock);
|
||||
|
||||
/* Pending work request completion */
|
||||
if (fps->iothread && work)
|
||||
wake_up_process(fps->iothread);
|
||||
else
|
||||
bnx2fc_process_cq_compl(tgt, wqe);
|
||||
bnx2fc_pending_work(tgt, wqe);
|
||||
num_free_sqes++;
|
||||
}
|
||||
cqe++;
|
||||
|
|
|
@ -404,12 +404,11 @@ int bnx2i_get_stats(void *handle)
|
|||
|
||||
|
||||
/**
|
||||
* bnx2i_percpu_thread_create - Create a receive thread for an
|
||||
* online CPU
|
||||
* bnx2i_cpu_online - Create a receive thread for an online CPU
|
||||
*
|
||||
* @cpu: cpu index for the online cpu
|
||||
*/
|
||||
static void bnx2i_percpu_thread_create(unsigned int cpu)
|
||||
static int bnx2i_cpu_online(unsigned int cpu)
|
||||
{
|
||||
struct bnx2i_percpu_s *p;
|
||||
struct task_struct *thread;
|
||||
|
@ -419,16 +418,17 @@ static void bnx2i_percpu_thread_create(unsigned int cpu)
|
|||
thread = kthread_create_on_node(bnx2i_percpu_io_thread, (void *)p,
|
||||
cpu_to_node(cpu),
|
||||
"bnx2i_thread/%d", cpu);
|
||||
if (IS_ERR(thread))
|
||||
return PTR_ERR(thread);
|
||||
|
||||
/* bind thread to the cpu */
|
||||
if (likely(!IS_ERR(thread))) {
|
||||
kthread_bind(thread, cpu);
|
||||
p->iothread = thread;
|
||||
wake_up_process(thread);
|
||||
}
|
||||
kthread_bind(thread, cpu);
|
||||
p->iothread = thread;
|
||||
wake_up_process(thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void bnx2i_percpu_thread_destroy(unsigned int cpu)
|
||||
static int bnx2i_cpu_offline(unsigned int cpu)
|
||||
{
|
||||
struct bnx2i_percpu_s *p;
|
||||
struct task_struct *thread;
|
||||
|
@ -451,19 +451,6 @@ static void bnx2i_percpu_thread_destroy(unsigned int cpu)
|
|||
spin_unlock_bh(&p->p_work_lock);
|
||||
if (thread)
|
||||
kthread_stop(thread);
|
||||
}
|
||||
|
||||
static int bnx2i_cpu_online(unsigned int cpu)
|
||||
{
|
||||
pr_info("bnx2i: CPU %x online: Create Rx thread\n", cpu);
|
||||
bnx2i_percpu_thread_create(cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bnx2i_cpu_dead(unsigned int cpu)
|
||||
{
|
||||
pr_info("CPU %x offline: Remove Rx thread\n", cpu);
|
||||
bnx2i_percpu_thread_destroy(cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -511,27 +498,14 @@ static int __init bnx2i_mod_init(void)
|
|||
p->iothread = NULL;
|
||||
}
|
||||
|
||||
get_online_cpus();
|
||||
|
||||
for_each_online_cpu(cpu)
|
||||
bnx2i_percpu_thread_create(cpu);
|
||||
|
||||
err = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
|
||||
"scsi/bnx2i:online",
|
||||
bnx2i_cpu_online, NULL);
|
||||
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "scsi/bnx2i:online",
|
||||
bnx2i_cpu_online, bnx2i_cpu_offline);
|
||||
if (err < 0)
|
||||
goto remove_threads;
|
||||
goto unreg_driver;
|
||||
bnx2i_online_state = err;
|
||||
|
||||
cpuhp_setup_state_nocalls(CPUHP_SCSI_BNX2I_DEAD, "scsi/bnx2i:dead",
|
||||
NULL, bnx2i_cpu_dead);
|
||||
put_online_cpus();
|
||||
return 0;
|
||||
|
||||
remove_threads:
|
||||
for_each_online_cpu(cpu)
|
||||
bnx2i_percpu_thread_destroy(cpu);
|
||||
put_online_cpus();
|
||||
unreg_driver:
|
||||
cnic_unregister_driver(CNIC_ULP_ISCSI);
|
||||
unreg_xport:
|
||||
iscsi_unregister_transport(&bnx2i_iscsi_transport);
|
||||
|
@ -551,7 +525,6 @@ out:
|
|||
static void __exit bnx2i_mod_exit(void)
|
||||
{
|
||||
struct bnx2i_hba *hba;
|
||||
unsigned cpu = 0;
|
||||
|
||||
mutex_lock(&bnx2i_dev_lock);
|
||||
while (!list_empty(&adapter_list)) {
|
||||
|
@ -569,14 +542,7 @@ static void __exit bnx2i_mod_exit(void)
|
|||
}
|
||||
mutex_unlock(&bnx2i_dev_lock);
|
||||
|
||||
get_online_cpus();
|
||||
|
||||
for_each_online_cpu(cpu)
|
||||
bnx2i_percpu_thread_destroy(cpu);
|
||||
|
||||
cpuhp_remove_state_nocalls(bnx2i_online_state);
|
||||
cpuhp_remove_state_nocalls(CPUHP_SCSI_BNX2I_DEAD);
|
||||
put_online_cpus();
|
||||
cpuhp_remove_state(bnx2i_online_state);
|
||||
|
||||
iscsi_unregister_transport(&bnx2i_iscsi_transport);
|
||||
cnic_unregister_driver(CNIC_ULP_ISCSI);
|
||||
|
|
|
@ -528,7 +528,8 @@ struct fip_vlan {
|
|||
#define QEDF_WRITE (1 << 0)
|
||||
#define MAX_FIBRE_LUNS 0xffffffff
|
||||
|
||||
#define QEDF_MAX_NUM_CQS 8
|
||||
#define MIN_NUM_CPUS_MSIX(x) min_t(u32, x->dev_info.num_cqs, \
|
||||
num_online_cpus())
|
||||
|
||||
/*
|
||||
* PCI function probe defines
|
||||
|
|
|
@ -2760,11 +2760,9 @@ static int qedf_set_fcoe_pf_param(struct qedf_ctx *qedf)
|
|||
* we allocation is the minimum off:
|
||||
*
|
||||
* Number of CPUs
|
||||
* Number of MSI-X vectors
|
||||
* Max number allocated in hardware (QEDF_MAX_NUM_CQS)
|
||||
* Number allocated by qed for our PCI function
|
||||
*/
|
||||
qedf->num_queues = min((unsigned int)QEDF_MAX_NUM_CQS,
|
||||
num_online_cpus());
|
||||
qedf->num_queues = MIN_NUM_CPUS_MSIX(qedf);
|
||||
|
||||
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Number of CQs is %d.\n",
|
||||
qedf->num_queues);
|
||||
|
@ -2962,6 +2960,13 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
|
|||
goto err1;
|
||||
}
|
||||
|
||||
/* Learn information crucial for qedf to progress */
|
||||
rc = qed_ops->fill_dev_info(qedf->cdev, &qedf->dev_info);
|
||||
if (rc) {
|
||||
QEDF_ERR(&(qedf->dbg_ctx), "Failed to dev info.\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/* queue allocation code should come here
|
||||
* order should be
|
||||
* slowpath_start
|
||||
|
@ -2977,13 +2982,6 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
|
|||
}
|
||||
qed_ops->common->update_pf_params(qedf->cdev, &qedf->pf_params);
|
||||
|
||||
/* Learn information crucial for qedf to progress */
|
||||
rc = qed_ops->fill_dev_info(qedf->cdev, &qedf->dev_info);
|
||||
if (rc) {
|
||||
QEDF_ERR(&(qedf->dbg_ctx), "Failed to dev info.\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/* Record BDQ producer doorbell addresses */
|
||||
qedf->bdq_primary_prod = qedf->dev_info.primary_dbq_rq_addr;
|
||||
qedf->bdq_secondary_prod = qedf->dev_info.secondary_bdq_rq_addr;
|
||||
|
|
|
@ -751,35 +751,6 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
|
|||
return count;
|
||||
}
|
||||
|
||||
static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
|
||||
{
|
||||
switch (hp->dxfer_direction) {
|
||||
case SG_DXFER_NONE:
|
||||
if (hp->dxferp || hp->dxfer_len > 0)
|
||||
return false;
|
||||
return true;
|
||||
case SG_DXFER_FROM_DEV:
|
||||
/*
|
||||
* for SG_DXFER_FROM_DEV we always set dxfer_len to > 0. dxferp
|
||||
* can either be NULL or != NULL so there's no point in checking
|
||||
* it either. So just return true.
|
||||
*/
|
||||
return true;
|
||||
case SG_DXFER_TO_DEV:
|
||||
case SG_DXFER_TO_FROM_DEV:
|
||||
if (!hp->dxferp || hp->dxfer_len == 0)
|
||||
return false;
|
||||
return true;
|
||||
case SG_DXFER_UNKNOWN:
|
||||
if ((!hp->dxferp && hp->dxfer_len) ||
|
||||
(hp->dxferp && hp->dxfer_len == 0))
|
||||
return false;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
sg_common_write(Sg_fd * sfp, Sg_request * srp,
|
||||
unsigned char *cmnd, int timeout, int blocking)
|
||||
|
@ -800,7 +771,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
|
|||
"sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n",
|
||||
(int) cmnd[0], (int) hp->cmd_len));
|
||||
|
||||
if (!sg_is_valid_dxfer(hp))
|
||||
if (hp->dxfer_len >= SZ_256M)
|
||||
return -EINVAL;
|
||||
|
||||
k = sg_start_req(srp, cmnd);
|
||||
|
|
|
@ -39,8 +39,6 @@ enum cpuhp_state {
|
|||
CPUHP_PCI_XGENE_DEAD,
|
||||
CPUHP_IOMMU_INTEL_DEAD,
|
||||
CPUHP_LUSTRE_CFS_DEAD,
|
||||
CPUHP_SCSI_BNX2FC_DEAD,
|
||||
CPUHP_SCSI_BNX2I_DEAD,
|
||||
CPUHP_WORKQUEUE_PREP,
|
||||
CPUHP_POWER_NUMA_PREPARE,
|
||||
CPUHP_HRTIMERS_PREPARE,
|
||||
|
|
Загрузка…
Ссылка в новой задаче