mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-05 01:54:09 +08:00
[SCSI] mptfc: race between mptfc_register_dev and mptfc_target_alloc
A race condition exists in mptfc between the thread registering a device with the fc transport and the scan work generated by the transport. This race existed prior to the application of the mptfc bug fix patch. mptfc_register_dev() calls fc_remote_port_add() with the FC_RPORT_ROLE_TARGET bit set in the rport ids passed to the function. Having this bit set causes fc_remote_port_add() to schedule a scan of the device. This scan can execute before mptfc_register_dev() can fill in the dd_data in the rport structure. When this happens, mptfc_target_alloc() will fail because dd_data is null. Attached is a patch which fixes the problem. The patch changes the rport ids passed to fc_remote_port_add() to not have the TARGET bit set. This prevents the scan from being scheduled. After mptfc_register_dev() fills in the rport dd_data field, fc_remote_port_rolechg() is called, changing the role of the rport to TARGET. Thus, the scan is scheduled after dd_data is filled in which prevents the failure in mptfc_target_alloc(). Signed-off-by: Michael Reed <mdr@sgi.com> Signed-off-by: Eric Moore <Eric.Moore@lsil.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
parent
0b18ac42aa
commit
6dd727da92
@ -341,9 +341,6 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
|
||||
rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
|
||||
rid->port_id = pg0->PortIdentifier;
|
||||
rid->roles = FC_RPORT_ROLE_UNKNOWN;
|
||||
rid->roles |= FC_RPORT_ROLE_FCP_TARGET;
|
||||
if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
|
||||
rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -357,10 +354,15 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
|
||||
int new_ri = 1;
|
||||
u64 pn, nn;
|
||||
VirtTarget *vtarget;
|
||||
u32 roles = FC_RPORT_ROLE_UNKNOWN;
|
||||
|
||||
if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
|
||||
return;
|
||||
|
||||
roles |= FC_RPORT_ROLE_FCP_TARGET;
|
||||
if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
|
||||
roles |= FC_RPORT_ROLE_FCP_INITIATOR;
|
||||
|
||||
/* scan list looking for a match */
|
||||
list_for_each_entry(ri, &ioc->fc_rports, list) {
|
||||
pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
|
||||
@ -400,8 +402,9 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
|
||||
vtarget->bus_id = pg0->CurrentBus;
|
||||
}
|
||||
}
|
||||
/* once dd_data is filled in, commands will issue to hardware */
|
||||
*((struct mptfc_rport_info **)rport->dd_data) = ri;
|
||||
/* scan will be scheduled once rport becomes a target */
|
||||
fc_remote_port_rolechg(rport,roles);
|
||||
|
||||
pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
|
||||
nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
|
||||
|
Loading…
Reference in New Issue
Block a user