diff options
author | Swen Schillig <swen@vnet.ibm.com> | 2009-11-24 10:54:06 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-12-04 13:02:08 -0500 |
commit | 9eae07ef6bb5988163d8bb82cd952905db47b721 (patch) | |
tree | 97a7f5c98c760b6232e5cdb60e5da58414079981 | |
parent | 6b183334c23969d52d4d9f775da554480d05ca4d (diff) |
[SCSI] zfcp: Assign scheduled work to driver queue
The port_scan work was scheduled to the work_queue provided by the
kernel. This resulted on SMP systems to a likely situation that more
than one scan_work were processed in parallel. This is not required
and openes the possibility of race conditions between the removal of
invalid ports and the enqueue of just scanned ports. This patch
synchronizes the scan_work tasks by scheduling them to adapter local
work_queue.
Signed-off-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 3 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 25 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_sysfs.c | 7 |
6 files changed, 17 insertions, 24 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 6b94f8d0609c..107d3f2b6e94 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -522,7 +522,7 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
522 | adapter->ccw_device = ccw_device; | 522 | adapter->ccw_device = ccw_device; |
523 | 523 | ||
524 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); | 524 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); |
525 | INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later); | 525 | INIT_WORK(&adapter->scan_work, zfcp_fc_scan_ports); |
526 | 526 | ||
527 | if (zfcp_qdio_setup(adapter)) | 527 | if (zfcp_qdio_setup(adapter)) |
528 | goto failed; | 528 | goto failed; |
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 3454c2a3b6b1..b51a11a82e63 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -1197,7 +1197,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) | |||
1197 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 1197 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
1198 | if (result == ZFCP_ERP_SUCCEEDED) { | 1198 | if (result == ZFCP_ERP_SUCCEEDED) { |
1199 | register_service_level(&adapter->service_level); | 1199 | register_service_level(&adapter->service_level); |
1200 | schedule_work(&adapter->scan_work); | 1200 | queue_work(adapter->work_queue, &adapter->scan_work); |
1201 | } else | 1201 | } else |
1202 | unregister_service_level(&adapter->service_level); | 1202 | unregister_service_level(&adapter->service_level); |
1203 | kref_put(&adapter->ref, zfcp_adapter_release); | 1203 | kref_put(&adapter->ref, zfcp_adapter_release); |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 5f205f85e6f9..d372146af38d 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -94,8 +94,7 @@ extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *, | |||
94 | extern void zfcp_erp_timeout_handler(unsigned long); | 94 | extern void zfcp_erp_timeout_handler(unsigned long); |
95 | 95 | ||
96 | /* zfcp_fc.c */ | 96 | /* zfcp_fc.c */ |
97 | extern int zfcp_fc_scan_ports(struct zfcp_adapter *); | 97 | extern void zfcp_fc_scan_ports(struct work_struct *); |
98 | extern void _zfcp_fc_scan_ports_later(struct work_struct *); | ||
99 | extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); | 98 | extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); |
100 | extern void zfcp_fc_port_did_lookup(struct work_struct *); | 99 | extern void zfcp_fc_port_did_lookup(struct work_struct *); |
101 | extern void zfcp_fc_trigger_did_lookup(struct zfcp_port *); | 100 | extern void zfcp_fc_trigger_did_lookup(struct zfcp_port *); |
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 9252b65a13a5..7d6b3cadfb73 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c | |||
@@ -184,7 +184,7 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) | |||
184 | range_mask = rscn_range_mask[fcp_rscn_element->addr_format]; | 184 | range_mask = rscn_range_mask[fcp_rscn_element->addr_format]; |
185 | _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); | 185 | _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); |
186 | } | 186 | } |
187 | schedule_work(&fsf_req->adapter->scan_work); | 187 | queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work); |
188 | } | 188 | } |
189 | 189 | ||
190 | static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn) | 190 | static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn) |
@@ -664,10 +664,12 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) | |||
664 | 664 | ||
665 | /** | 665 | /** |
666 | * zfcp_fc_scan_ports - scan remote ports and attach new ports | 666 | * zfcp_fc_scan_ports - scan remote ports and attach new ports |
667 | * @adapter: pointer to struct zfcp_adapter | 667 | * @work: reference to scheduled work |
668 | */ | 668 | */ |
669 | int zfcp_fc_scan_ports(struct zfcp_adapter *adapter) | 669 | void zfcp_fc_scan_ports(struct work_struct *work) |
670 | { | 670 | { |
671 | struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter, | ||
672 | scan_work); | ||
671 | int ret, i; | 673 | int ret, i; |
672 | struct zfcp_gpn_ft *gpn_ft; | 674 | struct zfcp_gpn_ft *gpn_ft; |
673 | int chain, max_entries, buf_num, max_bytes; | 675 | int chain, max_entries, buf_num, max_bytes; |
@@ -679,17 +681,14 @@ int zfcp_fc_scan_ports(struct zfcp_adapter *adapter) | |||
679 | 681 | ||
680 | if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT && | 682 | if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT && |
681 | fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) | 683 | fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) |
682 | return 0; | 684 | return; |
683 | 685 | ||
684 | ret = zfcp_fc_wka_port_get(&adapter->gs->ds); | 686 | if (zfcp_fc_wka_port_get(&adapter->gs->ds)) |
685 | if (ret) | 687 | return; |
686 | return ret; | ||
687 | 688 | ||
688 | gpn_ft = zfcp_alloc_sg_env(buf_num); | 689 | gpn_ft = zfcp_alloc_sg_env(buf_num); |
689 | if (!gpn_ft) { | 690 | if (!gpn_ft) |
690 | ret = -ENOMEM; | ||
691 | goto out; | 691 | goto out; |
692 | } | ||
693 | 692 | ||
694 | for (i = 0; i < 3; i++) { | 693 | for (i = 0; i < 3; i++) { |
695 | ret = zfcp_fc_send_gpn_ft(gpn_ft, adapter, max_bytes); | 694 | ret = zfcp_fc_send_gpn_ft(gpn_ft, adapter, max_bytes); |
@@ -704,15 +703,9 @@ int zfcp_fc_scan_ports(struct zfcp_adapter *adapter) | |||
704 | zfcp_free_sg_env(gpn_ft, buf_num); | 703 | zfcp_free_sg_env(gpn_ft, buf_num); |
705 | out: | 704 | out: |
706 | zfcp_fc_wka_port_put(&adapter->gs->ds); | 705 | zfcp_fc_wka_port_put(&adapter->gs->ds); |
707 | return ret; | ||
708 | } | 706 | } |
709 | 707 | ||
710 | 708 | ||
711 | void _zfcp_fc_scan_ports_later(struct work_struct *work) | ||
712 | { | ||
713 | zfcp_fc_scan_ports(container_of(work, struct zfcp_adapter, scan_work)); | ||
714 | } | ||
715 | |||
716 | struct zfcp_els_fc_job { | 709 | struct zfcp_els_fc_job { |
717 | struct zfcp_send_els els; | 710 | struct zfcp_send_els els; |
718 | struct fc_bsg_job *job; | 711 | struct fc_bsg_job *job; |
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 5eb96052941a..b6f12c826b79 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -287,7 +287,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) | |||
287 | zfcp_erp_adapter_access_changed(adapter, "fssrh_3", | 287 | zfcp_erp_adapter_access_changed(adapter, "fssrh_3", |
288 | req); | 288 | req); |
289 | if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) | 289 | if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) |
290 | schedule_work(&adapter->scan_work); | 290 | queue_work(adapter->work_queue, &adapter->scan_work); |
291 | break; | 291 | break; |
292 | case FSF_STATUS_READ_CFDC_UPDATED: | 292 | case FSF_STATUS_READ_CFDC_UPDATED: |
293 | zfcp_erp_adapter_access_changed(adapter, "fssrh_4", req); | 293 | zfcp_erp_adapter_access_changed(adapter, "fssrh_4", req); |
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 35e920b4fd8a..f539e006683c 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c | |||
@@ -184,15 +184,16 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, | |||
184 | { | 184 | { |
185 | struct ccw_device *cdev = to_ccwdev(dev); | 185 | struct ccw_device *cdev = to_ccwdev(dev); |
186 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); | 186 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
187 | int ret; | ||
188 | 187 | ||
189 | if (!adapter) | 188 | if (!adapter) |
190 | return -ENODEV; | 189 | return -ENODEV; |
191 | 190 | ||
192 | ret = zfcp_fc_scan_ports(adapter); | 191 | /* sync the user-space- with the kernel-invocation of scan_work */ |
192 | queue_work(adapter->work_queue, &adapter->scan_work); | ||
193 | flush_work(&adapter->scan_work); | ||
193 | zfcp_ccw_adapter_put(adapter); | 194 | zfcp_ccw_adapter_put(adapter); |
194 | 195 | ||
195 | return ret ? ret : (ssize_t) count; | 196 | return (ssize_t) count; |
196 | } | 197 | } |
197 | static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, | 198 | static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, |
198 | zfcp_sysfs_port_rescan_store); | 199 | zfcp_sysfs_port_rescan_store); |