Commit 71159b6e authored by Benjamin Block's avatar Benjamin Block Committed by Martin K. Petersen

scsi: zfcp: Fence early sysfs interfaces for accesses of shost objects

When setting an adapter online for the first time, we also create a couple
of entries for it in the sysfs device tree. This is also true even if the
adapter has not yet ever gone successfully through exchange config and
exchange port data.

When moving the scsi host object allocation and registration to after the
first exchange config and exchange port data, this make the `port_rescan`
attribute susceptible to invalid pointer-dereferences of the shost field
before the adapter is fully initialized.

When written to, it schedules a `scan_work` item that will in turn make use
of the associated fibre channel host object to check the topology used for
this FCP device.

Because scanning for remote ports can't be done successfully without
completing exchange config and exchange port data first, we can simply
fence `port_rescan`, and so prevent the illegal access.

As with cases where we can't get a reference to the adapter, we also return
-ENODEV here. Applications need to handle that errno today already.

After a successful allocation of the scsi host object nothing changes in
the work flow.

Link: https://lore.kernel.org/r/ef65366d309993ca91b6917727590ca7ca166c8f.1588956679.git.bblock@linux.ibm.comReviewed-by: default avatarSteffen Maier <maier@linux.ibm.com>
Signed-off-by: default avatarBenjamin Block <bblock@linux.ibm.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 971f2abb
...@@ -216,10 +216,22 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, ...@@ -216,10 +216,22 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev,
{ {
struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device *cdev = to_ccwdev(dev);
struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
int retval = 0;
if (!adapter) if (!adapter)
return -ENODEV; return -ENODEV;
/*
* If `scsi_host` is missing, we can't schedule `scan_work`, as it
* makes use of the corresponding fc_host object. But this state is
* only possible if xconfig/xport data has never completed yet,
* and we couldn't successfully scan for ports anyway.
*/
if (adapter->scsi_host == NULL) {
retval = -ENODEV;
goto out;
}
/* /*
* Users wish is our command: immediately schedule and flush a * Users wish is our command: immediately schedule and flush a
* worker to conduct a synchronous port scan, that is, neither * worker to conduct a synchronous port scan, that is, neither
...@@ -227,9 +239,9 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, ...@@ -227,9 +239,9 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev,
*/ */
queue_delayed_work(adapter->work_queue, &adapter->scan_work, 0); queue_delayed_work(adapter->work_queue, &adapter->scan_work, 0);
flush_delayed_work(&adapter->scan_work); flush_delayed_work(&adapter->scan_work);
out:
zfcp_ccw_adapter_put(adapter); zfcp_ccw_adapter_put(adapter);
return retval ? retval : (ssize_t) count;
return (ssize_t) count;
} }
static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL,
zfcp_sysfs_port_rescan_store); zfcp_sysfs_port_rescan_store);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment