diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-08-13 23:41:48 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-08-13 23:41:48 +0300 |
commit | e140f731f9807035e967c401198171f316744696 (patch) | |
tree | 7737c0d8135f12ac019d890af75a668585674dbe | |
parent | abe7a481aac9c277798661f846222f8ad7a6aed5 (diff) | |
parent | c6380f9924270d51cc233cfd592b279be3881e6d (diff) | |
download | linux-e140f731f9807035e967c401198171f316744696.tar.xz |
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull more SCSI updates from James Bottomley:
"Mostly small bug fixes and trivial updates.
The major new core update is a change to the way device, target and
host reference counting is done to try to make it more robust (this
change has soaked for a while to try to winkle out any bugs)"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
scsi: pm8001: Fix typo 'the the' in comment
scsi: megaraid_sas: Remove redundant variable cmd_type
scsi: FlashPoint: Remove redundant variable bm_int_st
scsi: zfcp: Fix missing auto port scan and thus missing target ports
scsi: core: Call blk_mq_free_tag_set() earlier
scsi: core: Simplify LLD module reference counting
scsi: core: Make sure that hosts outlive targets
scsi: core: Make sure that targets outlive devices
scsi: ufs: ufs-pci: Correct check for RESET DSM
scsi: target: core: De-RCU of se_lun and se_lun acl
scsi: target: core: Fix race during ACL removal
scsi: ufs: core: Correct ufshcd_shutdown() flow
scsi: ufs: core: Increase the maximum data buffer size
scsi: lpfc: Check the return value of alloc_workqueue()
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 29 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.h | 6 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 4 | ||||
-rw-r--r-- | drivers/scsi/FlashPoint.c | 4 | ||||
-rw-r--r-- | drivers/scsi/hosts.c | 18 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 2 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_fusion.c | 3 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_hwi.c | 2 | ||||
-rw-r--r-- | drivers/scsi/scsi.c | 9 | ||||
-rw-r--r-- | drivers/scsi/scsi_scan.c | 9 | ||||
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 29 | ||||
-rw-r--r-- | drivers/target/target_core_alua.c | 3 | ||||
-rw-r--r-- | drivers/target/target_core_device.c | 32 | ||||
-rw-r--r-- | drivers/target/target_core_pr.c | 28 | ||||
-rw-r--r-- | drivers/target/target_core_stat.c | 10 | ||||
-rw-r--r-- | drivers/target/target_core_xcopy.c | 2 | ||||
-rw-r--r-- | drivers/ufs/core/ufshcd.c | 7 | ||||
-rw-r--r-- | drivers/ufs/host/ufshcd-pci.c | 17 | ||||
-rw-r--r-- | include/scsi/scsi_device.h | 2 | ||||
-rw-r--r-- | include/scsi/scsi_host.h | 3 | ||||
-rw-r--r-- | include/target/target_core_base.h | 4 |
21 files changed, 124 insertions, 99 deletions
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 511bf8e0a436..b61acbb09be3 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -145,27 +145,33 @@ void zfcp_fc_enqueue_event(struct zfcp_adapter *adapter, static int zfcp_fc_wka_port_get(struct zfcp_fc_wka_port *wka_port) { + int ret = -EIO; + if (mutex_lock_interruptible(&wka_port->mutex)) return -ERESTARTSYS; if (wka_port->status == ZFCP_FC_WKA_PORT_OFFLINE || wka_port->status == ZFCP_FC_WKA_PORT_CLOSING) { wka_port->status = ZFCP_FC_WKA_PORT_OPENING; - if (zfcp_fsf_open_wka_port(wka_port)) + if (zfcp_fsf_open_wka_port(wka_port)) { + /* could not even send request, nothing to wait for */ wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; + goto out; + } } - mutex_unlock(&wka_port->mutex); - - wait_event(wka_port->completion_wq, + wait_event(wka_port->opened, wka_port->status == ZFCP_FC_WKA_PORT_ONLINE || wka_port->status == ZFCP_FC_WKA_PORT_OFFLINE); if (wka_port->status == ZFCP_FC_WKA_PORT_ONLINE) { atomic_inc(&wka_port->refcount); - return 0; + ret = 0; + goto out; } - return -EIO; +out: + mutex_unlock(&wka_port->mutex); + return ret; } static void zfcp_fc_wka_port_offline(struct work_struct *work) @@ -181,9 +187,12 @@ static void zfcp_fc_wka_port_offline(struct work_struct *work) wka_port->status = ZFCP_FC_WKA_PORT_CLOSING; if (zfcp_fsf_close_wka_port(wka_port)) { + /* could not even send request, nothing to wait for */ wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; - wake_up(&wka_port->completion_wq); + goto out; } + wait_event(wka_port->closed, + wka_port->status == ZFCP_FC_WKA_PORT_OFFLINE); out: mutex_unlock(&wka_port->mutex); } @@ -193,13 +202,15 @@ static void zfcp_fc_wka_port_put(struct zfcp_fc_wka_port *wka_port) if (atomic_dec_return(&wka_port->refcount) != 0) return; /* wait 10 milliseconds, other reqs might pop in */ - schedule_delayed_work(&wka_port->work, HZ / 100); + queue_delayed_work(wka_port->adapter->work_queue, &wka_port->work, + msecs_to_jiffies(10)); } static void zfcp_fc_wka_port_init(struct zfcp_fc_wka_port *wka_port, u32 d_id, struct zfcp_adapter *adapter) { - init_waitqueue_head(&wka_port->completion_wq); + init_waitqueue_head(&wka_port->opened); + init_waitqueue_head(&wka_port->closed); wka_port->adapter = adapter; wka_port->d_id = d_id; diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h index 8aaf409ce9cb..97755407ce1b 100644 --- a/drivers/s390/scsi/zfcp_fc.h +++ b/drivers/s390/scsi/zfcp_fc.h @@ -185,7 +185,8 @@ enum zfcp_fc_wka_status { /** * struct zfcp_fc_wka_port - representation of well-known-address (WKA) FC port * @adapter: Pointer to adapter structure this WKA port belongs to - * @completion_wq: Wait for completion of open/close command + * @opened: Wait for completion of open command + * @closed: Wait for completion of close command * @status: Current status of WKA port * @refcount: Reference count to keep port open as long as it is in use * @d_id: FC destination id or well-known-address @@ -195,7 +196,8 @@ enum zfcp_fc_wka_status { */ struct zfcp_fc_wka_port { struct zfcp_adapter *adapter; - wait_queue_head_t completion_wq; + wait_queue_head_t opened; + wait_queue_head_t closed; enum zfcp_fc_wka_status status; atomic_t refcount; u32 d_id; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 4f1e4385ce58..19223b075568 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1907,7 +1907,7 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req) wka_port->status = ZFCP_FC_WKA_PORT_ONLINE; } out: - wake_up(&wka_port->completion_wq); + wake_up(&wka_port->opened); } /** @@ -1966,7 +1966,7 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req) } wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; - wake_up(&wka_port->completion_wq); + wake_up(&wka_port->closed); } /** diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c index 90253208a72f..3d9c56ac8224 100644 --- a/drivers/scsi/FlashPoint.c +++ b/drivers/scsi/FlashPoint.c @@ -1712,7 +1712,7 @@ static unsigned char FlashPoint_InterruptPending(void *pCurrCard) static int FlashPoint_HandleInterrupt(void *pcard) { struct sccb *currSCCB; - unsigned char thisCard, result, bm_status, bm_int_st; + unsigned char thisCard, result, bm_status; unsigned short hp_int; unsigned char i, target; struct sccb_card *pCurrCard = pcard; @@ -1723,7 +1723,7 @@ static int FlashPoint_HandleInterrupt(void *pcard) MDISABLE_INT(ioport); - if ((bm_int_st = RD_HARPOON(ioport + hp_int_status)) & EXT_STATUS_ON) + if (RD_HARPOON(ioport + hp_int_status) & EXT_STATUS_ON) bm_status = RD_HARPOON(ioport + hp_ext_status) & (unsigned char)BAD_EXT_STATUS; else diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 26bf3b153595..0738238ed6cc 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -190,6 +190,15 @@ void scsi_remove_host(struct Scsi_Host *shost) transport_unregister_device(&shost->shost_gendev); device_unregister(&shost->shost_dev); device_del(&shost->shost_gendev); + + /* + * After scsi_remove_host() has returned the scsi LLD module can be + * unloaded and/or the host resources can be released. Hence wait until + * the dependent SCSI targets and devices are gone before returning. + */ + wait_event(shost->targets_wq, atomic_read(&shost->target_count) == 0); + + scsi_mq_destroy_tags(shost); } EXPORT_SYMBOL(scsi_remove_host); @@ -300,8 +309,8 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, return error; /* - * Any host allocation in this function will be freed in - * scsi_host_dev_release(). + * Any resources associated with the SCSI host in this function except + * the tag set will be freed by scsi_host_dev_release(). */ out_del_dev: device_del(&shost->shost_dev); @@ -317,6 +326,7 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, pm_runtime_disable(&shost->shost_gendev); pm_runtime_set_suspended(&shost->shost_gendev); pm_runtime_put_noidle(&shost->shost_gendev); + scsi_mq_destroy_tags(shost); fail: return error; } @@ -350,9 +360,6 @@ static void scsi_host_dev_release(struct device *dev) kfree(dev_name(&shost->shost_dev)); } - if (shost->tag_set.tags) - scsi_mq_destroy_tags(shost); - kfree(shost->shost_data); ida_free(&host_index_ida, shost->host_no); @@ -399,6 +406,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) INIT_LIST_HEAD(&shost->starved_list); init_waitqueue_head(&shost->host_wait); mutex_init(&shost->scan_mutex); + init_waitqueue_head(&shost->targets_wq); index = ida_alloc(&host_index_ida, GFP_KERNEL); if (index < 0) { diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 4a0eadd1c22c..c69c5a0979ec 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -7948,6 +7948,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* The lpfc_wq workqueue for deferred irq use */ phba->wq = alloc_workqueue("lpfc_wq", WQ_MEM_RECLAIM, 0); + if (!phba->wq) + return -ENOMEM; /* * Initialize timers used by driver diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 5b5885d9732b..e48d4261d0bc 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -3199,7 +3199,6 @@ megasas_build_io_fusion(struct megasas_instance *instance, struct megasas_cmd_fusion *cmd) { int sge_count; - u8 cmd_type; u16 pd_index = 0; u8 drive_type = 0; struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request; @@ -3225,7 +3224,7 @@ megasas_build_io_fusion(struct megasas_instance *instance, */ io_request->IoFlags = cpu_to_le16(scp->cmd_len); - switch (cmd_type = megasas_cmd_type(scp)) { + switch (megasas_cmd_type(scp)) { case READ_WRITE_LDIO: megasas_build_ldio_fusion(instance, scp, cmd); break; diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 4acaff479916..91d78d0a38fe 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -3138,7 +3138,7 @@ int pm8001_mpi_local_phy_ctl(struct pm8001_hba_info *pm8001_ha, void *piomb) * * when HBA driver received the identify done event or initiate FIS received * event(for SATA), it will invoke this function to notify the sas layer that - * the sas toplogy has formed, please discover the the whole sas domain, + * the sas toplogy has formed, please discover the whole sas domain, * while receive a broadcast(change) primitive just tell the sas * layer to discover the changed domain rather than the whole domain. */ diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index c59eac7a32f2..086ec5b5862d 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -586,10 +586,13 @@ EXPORT_SYMBOL(scsi_device_get); */ void scsi_device_put(struct scsi_device *sdev) { - struct module *mod = sdev->host->hostt->module; - + /* + * Decreasing the module reference count before the device reference + * count is safe since scsi_remove_host() only returns after all + * devices have been removed. + */ + module_put(sdev->host->hostt->module); put_device(&sdev->sdev_gendev); - module_put(mod); } EXPORT_SYMBOL(scsi_device_put); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 91ac901a6682..ac6059702d13 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -406,9 +406,14 @@ static void scsi_target_destroy(struct scsi_target *starget) static void scsi_target_dev_release(struct device *dev) { struct device *parent = dev->parent; + struct Scsi_Host *shost = dev_to_shost(parent); struct scsi_target *starget = to_scsi_target(dev); kfree(starget); + + if (atomic_dec_return(&shost->target_count) == 0) + wake_up(&shost->targets_wq); + put_device(parent); } @@ -521,6 +526,10 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, starget->state = STARGET_CREATED; starget->scsi_level = SCSI_2; starget->max_target_blocked = SCSI_DEFAULT_TARGET_BLOCKED; + init_waitqueue_head(&starget->sdev_wq); + + atomic_inc(&shost->target_count); + retry: spin_lock_irqsave(shost->host_lock, flags); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index aa70d9282161..9dad2fd5297f 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -443,18 +443,15 @@ static void scsi_device_cls_release(struct device *class_dev) static void scsi_device_dev_release_usercontext(struct work_struct *work) { - struct scsi_device *sdev; + struct scsi_device *sdev = container_of(work, struct scsi_device, + ew.work); + struct scsi_target *starget = sdev->sdev_target; struct device *parent; struct list_head *this, *tmp; struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL; struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL; struct scsi_vpd *vpd_pgb0 = NULL, *vpd_pgb1 = NULL, *vpd_pgb2 = NULL; unsigned long flags; - struct module *mod; - - sdev = container_of(work, struct scsi_device, ew.work); - - mod = sdev->host->hostt->module; scsi_dh_release_device(sdev); @@ -516,19 +513,16 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) kfree(sdev->inquiry); kfree(sdev); + if (starget && atomic_dec_return(&starget->sdev_count) == 0) + wake_up(&starget->sdev_wq); + if (parent) put_device(parent); - module_put(mod); } static void scsi_device_dev_release(struct device *dev) { struct scsi_device *sdp = to_scsi_device(dev); - - /* Set module pointer as NULL in case of module unloading */ - if (!try_module_get(sdp->host->hostt->module)) - sdp->host->hostt->module = NULL; - execute_in_process_context(scsi_device_dev_release_usercontext, &sdp->ew); } @@ -1535,6 +1529,14 @@ static void __scsi_remove_target(struct scsi_target *starget) goto restart; } spin_unlock_irqrestore(shost->host_lock, flags); + + /* + * After scsi_remove_target() returns its caller can remove resources + * associated with @starget, e.g. an rport or session. Wait until all + * devices associated with @starget have been removed to prevent that + * a SCSI error handling callback function triggers a use-after-free. + */ + wait_event(starget->sdev_wq, atomic_read(&starget->sdev_count) == 0); } /** @@ -1645,6 +1647,9 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev) list_add_tail(&sdev->same_target_siblings, &starget->devices); list_add_tail(&sdev->siblings, &shost->__devices); spin_unlock_irqrestore(shost->host_lock, flags); + + atomic_inc(&starget->sdev_count); + /* * device can now only be removed via __scsi_remove_device() so hold * the target. Target will be held in CREATED state until something diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 58df0145e8d0..fb91423a4e2e 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -934,8 +934,7 @@ static void core_alua_queue_state_change_ua(struct t10_alua_tg_pt_gp *tg_pt_gp) spin_lock(&lun->lun_deve_lock); list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link) { - lacl = rcu_dereference_check(se_deve->se_lun_acl, - lockdep_is_held(&lun->lun_deve_lock)); + lacl = se_deve->se_lun_acl; /* * spc4r37 p.242: diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 086ac9c9343c..b7f16ee8aa0e 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -75,7 +75,7 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd) return TCM_WRITE_PROTECTED; } - se_lun = rcu_dereference(deve->se_lun); + se_lun = deve->se_lun; if (!percpu_ref_tryget_live(&se_lun->lun_ref)) { se_lun = NULL; @@ -152,7 +152,7 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd) rcu_read_lock(); deve = target_nacl_find_deve(nacl, se_cmd->orig_fe_lun); if (deve) { - se_lun = rcu_dereference(deve->se_lun); + se_lun = deve->se_lun; if (!percpu_ref_tryget_live(&se_lun->lun_ref)) { se_lun = NULL; @@ -216,7 +216,7 @@ struct se_dev_entry *core_get_se_deve_from_rtpi( rcu_read_lock(); hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { - lun = rcu_dereference(deve->se_lun); + lun = deve->se_lun; if (!lun) { pr_err("%s device entries device pointer is" " NULL, but Initiator has access.\n", @@ -243,11 +243,8 @@ void core_free_device_list_for_node( struct se_dev_entry *deve; mutex_lock(&nacl->lun_entry_mutex); - hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { - struct se_lun *lun = rcu_dereference_check(deve->se_lun, - lockdep_is_held(&nacl->lun_entry_mutex)); - core_disable_device_list_for_node(lun, deve, nacl, tpg); - } + hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) + core_disable_device_list_for_node(deve->se_lun, deve, nacl, tpg); mutex_unlock(&nacl->lun_entry_mutex); } @@ -334,8 +331,7 @@ int core_enable_device_list_for_node( mutex_lock(&nacl->lun_entry_mutex); orig = target_nacl_find_deve(nacl, mapped_lun); if (orig && orig->se_lun) { - struct se_lun *orig_lun = rcu_dereference_check(orig->se_lun, - lockdep_is_held(&nacl->lun_entry_mutex)); + struct se_lun *orig_lun = orig->se_lun; if (orig_lun != lun) { pr_err("Existing orig->se_lun doesn't match new lun" @@ -355,8 +351,8 @@ int core_enable_device_list_for_node( return -EINVAL; } - rcu_assign_pointer(new->se_lun, lun); - rcu_assign_pointer(new->se_lun_acl, lun_acl); + new->se_lun = lun; + new->se_lun_acl = lun_acl; hlist_del_rcu(&orig->link); hlist_add_head_rcu(&new->link, &nacl->lun_entry_hlist); mutex_unlock(&nacl->lun_entry_mutex); @@ -374,8 +370,8 @@ int core_enable_device_list_for_node( return 0; } - rcu_assign_pointer(new->se_lun, lun); - rcu_assign_pointer(new->se_lun_acl, lun_acl); + new->se_lun = lun; + new->se_lun_acl = lun_acl; hlist_add_head_rcu(&new->link, &nacl->lun_entry_hlist); mutex_unlock(&nacl->lun_entry_mutex); @@ -434,9 +430,6 @@ void core_disable_device_list_for_node( kref_put(&orig->pr_kref, target_pr_kref_release); wait_for_completion(&orig->pr_comp); - rcu_assign_pointer(orig->se_lun, NULL); - rcu_assign_pointer(orig->se_lun_acl, NULL); - kfree_rcu(orig, rcu_head); core_scsi3_free_pr_reg_from_nacl(dev, nacl); @@ -457,10 +450,7 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg) mutex_lock(&nacl->lun_entry_mutex); hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { - struct se_lun *tmp_lun = rcu_dereference_check(deve->se_lun, - lockdep_is_held(&nacl->lun_entry_mutex)); - - if (lun != tmp_lun) + if (lun != deve->se_lun) continue; core_disable_device_list_for_node(lun, deve, nacl, tpg); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 3829b61b56c1..a1d67554709f 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -739,8 +739,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( if (!deve_tmp->se_lun_acl) continue; - lacl_tmp = rcu_dereference_check(deve_tmp->se_lun_acl, - lockdep_is_held(&lun_tmp->lun_deve_lock)); + lacl_tmp = deve_tmp->se_lun_acl; nacl_tmp = lacl_tmp->se_lun_nacl; /* * Skip the matching struct se_node_acl that is allocated @@ -784,8 +783,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( * the original *pr_reg is processed in * __core_scsi3_add_registration() */ - dest_lun = rcu_dereference_check(deve_tmp->se_lun, - kref_read(&deve_tmp->pr_kref) != 0); + dest_lun = deve_tmp->se_lun; pr_reg_atp = __core_scsi3_do_alloc_registration(dev, nacl_tmp, dest_lun, deve_tmp, @@ -1437,34 +1435,26 @@ static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl) static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve) { - struct se_lun_acl *lun_acl; - /* * For nacl->dynamic_node_acl=1 */ - lun_acl = rcu_dereference_check(se_deve->se_lun_acl, - kref_read(&se_deve->pr_kref) != 0); - if (!lun_acl) + if (!se_deve->se_lun_acl) return 0; - return target_depend_item(&lun_acl->se_lun_group.cg_item); + return target_depend_item(&se_deve->se_lun_acl->se_lun_group.cg_item); } static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve) { - struct se_lun_acl *lun_acl; - /* * For nacl->dynamic_node_acl=1 */ - lun_acl = rcu_dereference_check(se_deve->se_lun_acl, - kref_read(&se_deve->pr_kref) != 0); - if (!lun_acl) { + if (!se_deve->se_lun_acl) { kref_put(&se_deve->pr_kref, target_pr_kref_release); return; } - target_undepend_item(&lun_acl->se_lun_group.cg_item); + target_undepend_item(&se_deve->se_lun_acl->se_lun_group.cg_item); kref_put(&se_deve->pr_kref, target_pr_kref_release); } @@ -1751,8 +1741,7 @@ core_scsi3_decode_spec_i_port( * and then call __core_scsi3_add_registration() in the * 2nd loop which will never fail. */ - dest_lun = rcu_dereference_check(dest_se_deve->se_lun, - kref_read(&dest_se_deve->pr_kref) != 0); + dest_lun = dest_se_deve->se_lun; dest_pr_reg = __core_scsi3_alloc_registration(cmd->se_dev, dest_node_acl, dest_lun, dest_se_deve, @@ -3446,8 +3435,7 @@ after_iport_check: dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, iport_ptr); if (!dest_pr_reg) { - struct se_lun *dest_lun = rcu_dereference_check(dest_se_deve->se_lun, - kref_read(&dest_se_deve->pr_kref) != 0); + struct se_lun *dest_lun = dest_se_deve->se_lun; spin_unlock(&dev->dev_reservation_lock); if (core_scsi3_alloc_registration(cmd->se_dev, dest_node_acl, diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index 62d15bcc3d93..f85ee5b0fd80 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -877,7 +877,6 @@ static ssize_t target_stat_auth_dev_show(struct config_item *item, struct se_lun_acl *lacl = auth_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; - struct se_lun *lun; ssize_t ret; rcu_read_lock(); @@ -886,9 +885,9 @@ static ssize_t target_stat_auth_dev_show(struct config_item *item, rcu_read_unlock(); return -ENODEV; } - lun = rcu_dereference(deve->se_lun); + /* scsiDeviceIndex */ - ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_index); + ret = snprintf(page, PAGE_SIZE, "%u\n", deve->se_lun->lun_index); rcu_read_unlock(); return ret; } @@ -1217,7 +1216,6 @@ static ssize_t target_stat_iport_dev_show(struct config_item *item, struct se_lun_acl *lacl = iport_to_lacl(item); struct se_node_acl *nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; - struct se_lun *lun; ssize_t ret; rcu_read_lock(); @@ -1226,9 +1224,9 @@ static ssize_t target_stat_iport_dev_show(struct config_item *item, rcu_read_unlock(); return -ENODEV; } - lun = rcu_dereference(deve->se_lun); + /* scsiDeviceIndex */ - ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_index); + ret = snprintf(page, PAGE_SIZE, "%u\n", deve->se_lun->lun_index); rcu_read_unlock(); return ret; } diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 6bb20aa9c5bc..8713cda0c2fb 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -88,7 +88,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_session *sess, struct se_device *this_dev; int rc; - this_lun = rcu_dereference(deve->se_lun); + this_lun = deve->se_lun; this_dev = rcu_dereference_raw(this_lun->lun_se_dev); rc = target_xcopy_locate_se_dev_e4_iter(this_dev, dev_wwn); diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 3bc0709a5dc2..6bc679d22927 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8326,6 +8326,7 @@ static struct scsi_host_template ufshcd_driver_template = { .cmd_per_lun = UFSHCD_CMD_PER_LUN, .can_queue = UFSHCD_CAN_QUEUE, .max_segment_size = PRDT_DATA_BYTE_COUNT_MAX, + .max_sectors = (1 << 20) / SECTOR_SIZE, /* 1 MiB */ .max_host_blocked = 1, .track_queue_depth = 1, .sdev_groups = ufshcd_driver_groups, @@ -9508,12 +9509,8 @@ EXPORT_SYMBOL(ufshcd_runtime_resume); int ufshcd_shutdown(struct ufs_hba *hba) { if (ufshcd_is_ufs_dev_poweroff(hba) && ufshcd_is_link_off(hba)) - goto out; - - pm_runtime_get_sync(hba->dev); + ufshcd_suspend(hba); - ufshcd_suspend(hba); -out: hba->is_powered = false; /* allow force shutdown even in case of errors */ return 0; diff --git a/drivers/ufs/host/ufshcd-pci.c b/drivers/ufs/host/ufshcd-pci.c index 24af1f389bf2..1c91f43e15c8 100644 --- a/drivers/ufs/host/ufshcd-pci.c +++ b/drivers/ufs/host/ufshcd-pci.c @@ -24,7 +24,7 @@ struct ufs_host { void (*late_init)(struct ufs_hba *hba); }; -enum { +enum intel_ufs_dsm_func_id { INTEL_DSM_FNS = 0, INTEL_DSM_RESET = 1, }; @@ -42,6 +42,15 @@ static const guid_t intel_dsm_guid = GUID_INIT(0x1A4832A0, 0x7D03, 0x43CA, 0xB0, 0x20, 0xF6, 0xDC, 0xD1, 0x2A, 0x19, 0x50); +static bool __intel_dsm_supported(struct intel_host *host, + enum intel_ufs_dsm_func_id fn) +{ + return fn < 32 && fn >= 0 && (host->dsm_fns & (1u << fn)); +} + +#define INTEL_DSM_SUPPORTED(host, name) \ + __intel_dsm_supported(host, INTEL_DSM_##name) + static int __intel_dsm(struct intel_host *intel_host, struct device *dev, unsigned int fn, u32 *result) { @@ -71,7 +80,7 @@ out: static int intel_dsm(struct intel_host *intel_host, struct device *dev, unsigned int fn, u32 *result) { - if (fn > 31 || !(intel_host->dsm_fns & (1 << fn))) + if (!__intel_dsm_supported(intel_host, fn)) return -EOPNOTSUPP; return __intel_dsm(intel_host, dev, fn, result); @@ -300,7 +309,7 @@ static int ufs_intel_device_reset(struct ufs_hba *hba) { struct intel_host *host = ufshcd_get_variant(hba); - if (host->dsm_fns & INTEL_DSM_RESET) { + if (INTEL_DSM_SUPPORTED(host, RESET)) { u32 result = 0; int err; @@ -342,7 +351,7 @@ static int ufs_intel_common_init(struct ufs_hba *hba) return -ENOMEM; ufshcd_set_variant(hba, host); intel_dsm_init(host, hba->dev); - if (host->dsm_fns & INTEL_DSM_RESET) { + if (INTEL_DSM_SUPPORTED(host, RESET)) { if (hba->vops->device_reset) hba->caps |= UFSHCD_CAP_DEEPSLEEP; } else { diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 2493bd65351a..3113471ca375 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -309,6 +309,8 @@ struct scsi_target { struct list_head devices; struct device dev; struct kref reap_ref; /* last put renders target invisible */ + atomic_t sdev_count; + wait_queue_head_t sdev_wq; unsigned int channel; unsigned int id; /* target id ... replace * scsi_device.id eventually */ diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index b6e41ee3d566..aa7b7496c93a 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -690,6 +690,9 @@ struct Scsi_Host { /* ldm bits */ struct device shost_gendev, shost_dev; + atomic_t target_count; + wait_queue_head_t targets_wq; + /* * Points to the transport data (if any) which is allocated * separately diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index c2b36f7d917d..8c920456edd9 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -665,9 +665,9 @@ struct se_dev_entry { /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ struct kref pr_kref; struct completion pr_comp; - struct se_lun_acl __rcu *se_lun_acl; + struct se_lun_acl *se_lun_acl; spinlock_t ua_lock; - struct se_lun __rcu *se_lun; + struct se_lun *se_lun; #define DEF_PR_REG_ACTIVE 1 unsigned long deve_flags; struct list_head alua_port_list; |