Skip to content

Commit

Permalink
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/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()
  • Loading branch information
Linus Torvalds committed Aug 13, 2022
2 parents abe7a48 + c6380f9 commit e140f73
Show file tree
Hide file tree
Showing 21 changed files with 124 additions and 99 deletions.
29 changes: 20 additions & 9 deletions drivers/s390/scsi/zfcp_fc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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);
}
Expand All @@ -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;
Expand Down
6 changes: 4 additions & 2 deletions drivers/s390/scsi/zfcp_fc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions drivers/s390/scsi/zfcp_fsf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
Expand Down Expand Up @@ -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);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions drivers/scsi/FlashPoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down
18 changes: 13 additions & 5 deletions drivers/scsi/hosts.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions drivers/scsi/lpfc/lpfc_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions drivers/scsi/megaraid/megaraid_sas_fusion.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion drivers/scsi/pm8001/pm8001_hwi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
9 changes: 6 additions & 3 deletions drivers/scsi/scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
9 changes: 9 additions & 0 deletions drivers/scsi/scsi_scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);

Expand Down
29 changes: 17 additions & 12 deletions drivers/scsi/scsi_sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}

/**
Expand Down Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions drivers/target/target_core_alua.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Loading

0 comments on commit e140f73

Please sign in to comment.