From 91b9b7299f83e7dbc107860602fa1914c34e242a Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Thu, 24 Jul 2008 09:04:05 +0000 Subject: [PATCH] Fix for long standing protection problem in the initiator driver git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@474 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- qla2x00t/qla2x00-target/qla2x00t.c | 2 +- qla2x00t/qla_attr.c | 10 +++++----- qla2x00t/qla_def.h | 9 ++++++++- qla2x00t/qla_init.c | 27 +++++++++++++++------------ qla2x00t/qla_mid.c | 2 +- qla2x00t/qla_os.c | 8 ++++---- 6 files changed, 34 insertions(+), 24 deletions(-) diff --git a/qla2x00t/qla2x00-target/qla2x00t.c b/qla2x00t/qla2x00-target/qla2x00t.c index 3e0e78d3d..b08c66bf0 100644 --- a/qla2x00t/qla2x00-target/qla2x00t.c +++ b/qla2x00t/qla2x00-target/qla2x00t.c @@ -1315,7 +1315,7 @@ static char *q2t_find_name(scsi_qla_host_t *ha, int loop_id) } /* Find the WWN in the port db given the loop_id */ - list_for_each_entry(fcl, &ha->fcports, list) { + list_for_each_entry_rcu(fcl, &ha->fcports, list) { if (loop_id == (fcl->loop_id & 0xFF)) { sprintf(wwn_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", fcl->port_name[0], fcl->port_name[1], diff --git a/qla2x00t/qla_attr.c b/qla2x00t/qla_attr.c index c1b5e9cb2..0b40584bb 100644 --- a/qla2x00t/qla_attr.c +++ b/qla2x00t/qla_attr.c @@ -240,8 +240,8 @@ out_free: id_iter += ha->gid_list_info_size; } } -get_id_failed: +get_id_failed: if (size < max_size) { fc_port_t *fcport; char * state; @@ -250,7 +250,7 @@ get_id_failed: size += scnprintf(buf+size, max_size-size, "\nfc_ports database\n"); - list_for_each_entry(fcport, &ha->fcports, list) { + list_for_each_entry_rcu(fcport, &ha->fcports, list) { if (size >= max_size) goto out; switch (atomic_read(&fcport->state)) { @@ -1237,7 +1237,7 @@ qla2x00_get_starget_node_name(struct scsi_target *starget) fc_port_t *fcport; u64 node_name = 0; - list_for_each_entry(fcport, &ha->fcports, list) { + list_for_each_entry_rcu(fcport, &ha->fcports, list) { if (fcport->rport && starget->id == fcport->rport->scsi_target_id) { node_name = wwn_to_u64(fcport->node_name); @@ -1256,7 +1256,7 @@ qla2x00_get_starget_port_name(struct scsi_target *starget) fc_port_t *fcport; u64 port_name = 0; - list_for_each_entry(fcport, &ha->fcports, list) { + list_for_each_entry_rcu(fcport, &ha->fcports, list) { if (fcport->rport && starget->id == fcport->rport->scsi_target_id) { port_name = wwn_to_u64(fcport->port_name); @@ -1275,7 +1275,7 @@ qla2x00_get_starget_port_id(struct scsi_target *starget) fc_port_t *fcport; uint32_t port_id = ~0U; - list_for_each_entry(fcport, &ha->fcports, list) { + list_for_each_entry_rcu(fcport, &ha->fcports, list) { if (fcport->rport && starget->id == fcport->rport->scsi_target_id) { port_id = fcport->d_id.b.domain << 16 | diff --git a/qla2x00t/qla_def.h b/qla2x00t/qla_def.h index 4ae216d0e..1a1c67623 100644 --- a/qla2x00t/qla_def.h +++ b/qla2x00t/qla_def.h @@ -2407,7 +2407,14 @@ typedef struct scsi_qla_host { struct list_head work_list; - /* Fibre Channel Device List. */ + /* + * Fibre Channel Device List. + * + * This list can be accessed from many contexts, including concurrently. + * So, although anything never deleted from this list, it needs the + * corresponding protection anyway. Let's do it by making access to + * it using RCU functions. + */ struct list_head fcports; /* RSCN queue. */ diff --git a/qla2x00t/qla_init.c b/qla2x00t/qla_init.c index fdd699bf7..7f262bc13 100644 --- a/qla2x00t/qla_init.c +++ b/qla2x00t/qla_init.c @@ -2107,7 +2107,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha) /* * Mark local devices that were present with FCF_DEVICE_LOST for now. */ - list_for_each_entry(fcport, &pha->fcports, list) { + list_for_each_entry_rcu(fcport, &pha->fcports, list) { if (fcport->vp_idx != ha->vp_idx) continue; @@ -2172,7 +2172,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha) /* Check for matching device in port list. */ found = 0; fcport = NULL; - list_for_each_entry(fcport, &pha->fcports, list) { + list_for_each_entry_rcu(fcport, &pha->fcports, list) { if (fcport->vp_idx != ha->vp_idx) continue; @@ -2201,7 +2201,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha) list_add_tail(&new_fcport->vp_fcport, &ha->vp_fcports); } - list_add_tail(&new_fcport->list, &pha->fcports); + list_add_tail_rcu(&new_fcport->list, &pha->fcports); /* Allocate a new replacement fcport. */ fcport = new_fcport; @@ -2441,7 +2441,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) * Logout all previous fabric devices marked lost, except * tape devices. */ - list_for_each_entry(fcport, &pha->fcports, list) { + list_for_each_entry_rcu(fcport, &pha->fcports, list) { if (fcport->vp_idx !=ha->vp_idx) continue; @@ -2475,7 +2475,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) * Scan through our port list and login entries that need to be * logged in. */ - list_for_each_entry(fcport, &pha->fcports, list) { + list_for_each_entry_rcu(fcport, &pha->fcports, list) { if (fcport->vp_idx != ha->vp_idx) continue; @@ -2530,10 +2530,13 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) fcport->vp_idx = ha->vp_idx; list_add_tail(&fcport->vp_fcport, &ha->vp_fcports); - list_move_tail(&fcport->list, + list_del(&fcport->list); + list_add_tail_rcu(&fcport->list, &ha->parent->fcports); - } else - list_move_tail(&fcport->list, &ha->fcports); + } else { + list_del(&fcport->list); + list_add_tail_rcu(&fcport->list, &ha->fcports); + } } } while (0); @@ -2716,7 +2719,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) /* Locate matching device in database. */ found = 0; - list_for_each_entry(fcport, &pha->fcports, list) { + list_for_each_entry_rcu(fcport, &pha->fcports, list) { if (new_fcport->vp_idx != fcport->vp_idx) continue; if (memcmp(new_fcport->port_name, fcport->port_name, @@ -2846,7 +2849,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev) /* Check for loop ID being already in use. */ found = 0; fcport = NULL; - list_for_each_entry(fcport, &pha->fcports, list) { + list_for_each_entry_rcu(fcport, &pha->fcports, list) { if (fcport->loop_id == dev->loop_id && fcport != dev) { /* ID possibly in use */ found++; @@ -2960,7 +2963,7 @@ qla2x00_device_resync(scsi_qla_host_t *ha) rval = QLA_SUCCESS; - list_for_each_entry(fcport, &pha->fcports, list) { + list_for_each_entry_rcu(fcport, &pha->fcports, list) { if (fcport->vp_idx != ha->vp_idx) continue; @@ -3255,7 +3258,7 @@ qla2x00_update_fcports(scsi_qla_host_t *ha) fc_port_t *fcport; /* Go with deferred removal of rport references. */ - list_for_each_entry(fcport, &ha->fcports, list) + list_for_each_entry_rcu(fcport, &ha->fcports, list) if (fcport->drport) qla2x00_rport_del(fcport); } diff --git a/qla2x00t/qla_mid.c b/qla2x00t/qla_mid.c index 62a3ad6e8..0fd28ac3a 100644 --- a/qla2x00t/qla_mid.c +++ b/qla2x00t/qla_mid.c @@ -95,7 +95,7 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha) fc_port_t *fcport; scsi_qla_host_t *pha = to_qla_parent(vha); - list_for_each_entry(fcport, &pha->fcports, list) { + list_for_each_entry_rcu(fcport, &pha->fcports, list) { if (fcport->vp_idx != vha->vp_idx) continue; diff --git a/qla2x00t/qla_os.c b/qla2x00t/qla_os.c index a7eecf682..11df40e9f 100644 --- a/qla2x00t/qla_os.c +++ b/qla2x00t/qla_os.c @@ -1007,7 +1007,7 @@ qla2x00_loop_reset(scsi_qla_host_t *ha) } if (ha->flags.enable_target_reset) { - list_for_each_entry(fcport, &ha->fcports, list) { + list_for_each_entry_rcu(fcport, &ha->fcports, list) { if (fcport->port_type != FCT_TARGET) continue; @@ -1919,7 +1919,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer) fc_port_t *fcport; scsi_qla_host_t *pha = to_qla_parent(ha); - list_for_each_entry(fcport, &pha->fcports, list) { + list_for_each_entry_rcu(fcport, &pha->fcports, list) { if (ha->vp_idx != 0 && ha->vp_idx != fcport->vp_idx) continue; /* @@ -2352,7 +2352,7 @@ qla2x00_do_dpc(void *data) ha->host_no)); next_loopid = 0; - list_for_each_entry(fcport, &ha->fcports, list) { + list_for_each_entry_rcu(fcport, &ha->fcports, list) { /* * If the port is not ONLINE then try to login * to it if we haven't run out of retries. @@ -2528,7 +2528,7 @@ qla2x00_timer(scsi_qla_host_t *ha) * the port it marked DEAD. */ t = 0; - list_for_each_entry(fcport, &ha->fcports, list) { + list_for_each_entry_rcu(fcport, &ha->fcports, list) { if (fcport->port_type != FCT_TARGET) continue;