Commit d1cb5e49 authored by Sreekanth Reddy's avatar Sreekanth Reddy Committed by Martin K. Petersen

mpt3sas: Refcount sas_device objects and fix unsafe list usage

sas_device objects can be referenced concurrently throughout the driver.
We need a way to make sure threads can't delete them out from under each
other. This patch adds the refcount and refactors the code to use it.

Additionally, we cannot iterate over the sas_device_list without holding
the lock or we risk corrupting random memory if items are added or
deleted as we iterate. This patch refactors _scsih_probe_sas() to use
the sas_device_list in a safe way.

This patch is ported from the following mpt2sas driver commit
d224fe0d ("mpt2sas: Refcount sas_device objects and fix unsafe list
usage").
Signed-off-by: default avatarSreekanth Reddy <Sreekanth.Reddy@avagotech.com>
Acked-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 42263095
......@@ -273,6 +273,7 @@ struct Mpi2ManufacturingPage11_t {
* @flags: MPT_TARGET_FLAGS_XXX flags
* @deleted: target flaged for deletion
* @tm_busy: target is busy with TM request.
* @sdev: The sas_device associated with this target
*/
struct MPT3SAS_TARGET {
struct scsi_target *starget;
......@@ -283,6 +284,7 @@ struct MPT3SAS_TARGET {
u32 flags;
u8 deleted;
u8 tm_busy;
struct _sas_device *sdev;
};
......@@ -389,8 +391,24 @@ struct _sas_device {
u8 pend_sas_rphy_add;
u8 enclosure_level;
u8 connector_name[4];
struct kref refcount;
};
static inline void sas_device_get(struct _sas_device *s)
{
kref_get(&s->refcount);
}
static inline void sas_device_free(struct kref *r)
{
kfree(container_of(r, struct _sas_device, refcount));
}
static inline void sas_device_put(struct _sas_device *s)
{
kref_put(&s->refcount, sas_device_free);
}
/**
* struct _raid_device - raid volume link list
* @list: sas device list
......@@ -1148,8 +1166,10 @@ struct _sas_node *mpt3sas_scsih_expander_find_by_handle(
struct MPT3SAS_ADAPTER *ioc, u16 handle);
struct _sas_node *mpt3sas_scsih_expander_find_by_sas_address(
struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
struct _sas_device *mpt3sas_scsih_sas_device_find_by_sas_address(
struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
struct _sas_device *mpt3sas_get_sdev_by_addr(
struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
struct _sas_device *__mpt3sas_get_sdev_by_addr(
struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
void mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc);
......
This diff is collapsed.
......@@ -734,7 +734,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
rphy->identify = mpt3sas_port->remote_identify;
if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {
sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
sas_device = mpt3sas_get_sdev_by_addr(ioc,
mpt3sas_port->remote_identify.sas_address);
if (!sas_device) {
dfailprintk(ioc, printk(MPT3SAS_FMT
......@@ -750,8 +750,10 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
ioc->name, __FILE__, __LINE__, __func__);
}
if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE)
if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {
sas_device->pend_sas_rphy_add = 0;
sas_device_put(sas_device);
}
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
dev_printk(KERN_INFO, &rphy->dev,
......@@ -1324,15 +1326,17 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
int rc;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
sas_device = __mpt3sas_get_sdev_by_addr(ioc,
rphy->identify.sas_address);
if (sas_device) {
*identifier = sas_device->enclosure_logical_id;
rc = 0;
sas_device_put(sas_device);
} else {
*identifier = 0;
rc = -ENXIO;
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return rc;
}
......@@ -1352,12 +1356,14 @@ _transport_get_bay_identifier(struct sas_rphy *rphy)
int rc;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
sas_device = __mpt3sas_get_sdev_by_addr(ioc,
rphy->identify.sas_address);
if (sas_device)
if (sas_device) {
rc = sas_device->slot;
else
sas_device_put(sas_device);
} else {
rc = -ENXIO;
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return rc;
}
......
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