[SCSI] mpt2sas: Improvement were made to better protect the sas_device, raid_device, and expander_device lists
There were possible race conditions surrounding reading an object from the link list while from another context in the driver was removing it. The nature of this enhancement is to rearrange locking so the link lists are better protected. Change set: (1) numerous routines were rearranged so spin locks are held through the entire time a link list object is being read from or written to. (2) added new routines for object deletion from link list. Thus ensuring lock was held during the deletion of the link list object, then and memory for object freed outside the lock. The memory was freed outside the lock so driver had access to device object info which was required for notifying the scsi mid layer that a device was getting deleted. (3) added the ioc->blocking_handles parameter. This is a bitmask used to identify which devices need blocking when there is device loss. This was introduced so that lock can be held for the entire time traversing the link list objects, and the bitmask was set to indicate which device handles need blocking. Oustide the lock the ioc->blocking_handles bitmask is traversed, with the respective device handle the scsi mid layer is called for moving devices into blocking state. Signed-off-by: Nagalakshmi Nandigama <nagalakshmi.nandigama@lsi.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
Родитель
acafc892b0
Коммит
09da0b32d0
|
@ -4279,7 +4279,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
|
|||
goto out_free_resources;
|
||||
|
||||
init_waitqueue_head(&ioc->reset_wq);
|
||||
|
||||
/* allocate memory pd handle bitmask list */
|
||||
ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8);
|
||||
if (ioc->facts.MaxDevHandle % 8)
|
||||
|
@ -4290,7 +4289,12 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
|
|||
r = -ENOMEM;
|
||||
goto out_free_resources;
|
||||
}
|
||||
|
||||
ioc->blocking_handles = kzalloc(ioc->pd_handles_sz,
|
||||
GFP_KERNEL);
|
||||
if (!ioc->blocking_handles) {
|
||||
r = -ENOMEM;
|
||||
goto out_free_resources;
|
||||
}
|
||||
ioc->fwfault_debug = mpt2sas_fwfault_debug;
|
||||
|
||||
/* base internal command bits */
|
||||
|
@ -4377,6 +4381,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
|
|||
if (ioc->is_warpdrive)
|
||||
kfree(ioc->reply_post_host_index);
|
||||
kfree(ioc->pd_handles);
|
||||
kfree(ioc->blocking_handles);
|
||||
kfree(ioc->tm_cmds.reply);
|
||||
kfree(ioc->transport_cmds.reply);
|
||||
kfree(ioc->scsih_cmds.reply);
|
||||
|
@ -4418,6 +4423,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
|
|||
if (ioc->is_warpdrive)
|
||||
kfree(ioc->reply_post_host_index);
|
||||
kfree(ioc->pd_handles);
|
||||
kfree(ioc->blocking_handles);
|
||||
kfree(ioc->pfacts);
|
||||
kfree(ioc->ctl_cmds.reply);
|
||||
kfree(ioc->ctl_cmds.sense);
|
||||
|
|
|
@ -720,6 +720,7 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
|
|||
* @io_missing_delay: time for IO completed by fw when PDR enabled
|
||||
* @device_missing_delay: time for device missing by fw when PDR enabled
|
||||
* @sas_id : used for setting volume target IDs
|
||||
* @blocking_handles: bitmask used to identify which devices need blocking
|
||||
* @pd_handles : bitmask for PD handles
|
||||
* @pd_handles_sz : size of pd_handle bitmask
|
||||
* @config_page_sz: config page size
|
||||
|
@ -889,7 +890,7 @@ struct MPT2SAS_ADAPTER {
|
|||
u8 io_missing_delay;
|
||||
u16 device_missing_delay;
|
||||
int sas_id;
|
||||
|
||||
void *blocking_handles;
|
||||
void *pd_handles;
|
||||
u16 pd_handles_sz;
|
||||
|
||||
|
@ -1058,7 +1059,8 @@ int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle,
|
|||
void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
|
||||
void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
|
||||
void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
|
||||
void mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
|
||||
void mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
|
||||
u64 sas_address);
|
||||
struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc,
|
||||
u16 handle);
|
||||
struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -163,7 +163,7 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
memset(identify, 0, sizeof(*identify));
|
||||
memset(identify, 0, sizeof(struct sas_identify));
|
||||
device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
|
||||
|
||||
/* sas_address */
|
||||
|
@ -484,7 +484,7 @@ _transport_delete_port(struct MPT2SAS_ADAPTER *ioc,
|
|||
|
||||
ioc->logging_level |= MPT_DEBUG_TRANSPORT;
|
||||
if (device_type == SAS_END_DEVICE)
|
||||
mpt2sas_device_remove(ioc, sas_address);
|
||||
mpt2sas_device_remove_by_sas_address(ioc, sas_address);
|
||||
else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||
|
||||
device_type == SAS_FANOUT_EXPANDER_DEVICE)
|
||||
mpt2sas_expander_remove(ioc, sas_address);
|
||||
|
@ -792,9 +792,10 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
|
|||
spin_lock_irqsave(&ioc->sas_node_lock, flags);
|
||||
sas_node = _transport_sas_node_find_by_sas_address(ioc,
|
||||
sas_address_parent);
|
||||
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
|
||||
if (!sas_node)
|
||||
if (!sas_node) {
|
||||
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
|
||||
return;
|
||||
}
|
||||
list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
|
||||
port_list) {
|
||||
if (mpt2sas_port->remote_identify.sas_address != sas_address)
|
||||
|
@ -804,8 +805,10 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
|
|||
goto out;
|
||||
}
|
||||
out:
|
||||
if (!found)
|
||||
if (!found) {
|
||||
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < sas_node->num_phys; i++) {
|
||||
if (sas_node->phy[i].remote_identify.sas_address == sas_address)
|
||||
|
@ -813,6 +816,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
|
|||
sizeof(struct sas_identify));
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
|
||||
list_for_each_entry_safe(mpt2sas_phy, next_phy,
|
||||
&mpt2sas_port->phy_list, port_siblings) {
|
||||
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
|
||||
|
@ -986,12 +990,14 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
|
|||
|
||||
spin_lock_irqsave(&ioc->sas_node_lock, flags);
|
||||
sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
|
||||
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
|
||||
if (!sas_node)
|
||||
if (!sas_node) {
|
||||
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
mpt2sas_phy = &sas_node->phy[phy_number];
|
||||
mpt2sas_phy->attached_handle = handle;
|
||||
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
|
||||
if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) {
|
||||
_transport_set_identify(ioc, handle,
|
||||
&mpt2sas_phy->remote_identify);
|
||||
|
@ -1310,17 +1316,20 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
|
|||
struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
|
||||
struct _sas_device *sas_device;
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
|
||||
spin_lock_irqsave(&ioc->sas_device_lock, flags);
|
||||
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
|
||||
rphy->identify.sas_address);
|
||||
if (sas_device) {
|
||||
*identifier = sas_device->enclosure_logical_id;
|
||||
rc = 0;
|
||||
} else {
|
||||
*identifier = 0;
|
||||
rc = -ENXIO;
|
||||
}
|
||||
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
|
||||
|
||||
if (!sas_device)
|
||||
return -ENXIO;
|
||||
|
||||
*identifier = sas_device->enclosure_logical_id;
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1335,16 +1344,17 @@ _transport_get_bay_identifier(struct sas_rphy *rphy)
|
|||
struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
|
||||
struct _sas_device *sas_device;
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
|
||||
spin_lock_irqsave(&ioc->sas_device_lock, flags);
|
||||
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
|
||||
rphy->identify.sas_address);
|
||||
if (sas_device)
|
||||
rc = sas_device->slot;
|
||||
else
|
||||
rc = -ENXIO;
|
||||
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
|
||||
|
||||
if (!sas_device)
|
||||
return -ENXIO;
|
||||
|
||||
return sas_device->slot;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* phy control request structure */
|
||||
|
|
Загрузка…
Ссылка в новой задаче