zfcp fixes for 2.6.30-rc2
Subsystems (3)
cover zfcp fixes for 2.6.30-rc2
James,
here is the series of zfcp fixes for the current development cycle. The patches are based on top of the current linux-2.6 kernel (2.6.30-rc2).
--
Christof Schmitt
PATCH 1/15 zfcp: Avoid referencing freed memory in req send
From: Martin Petermann <[email protected]>
Avoid referencing a fsf request after sending it in fcp_fsf_req_send, it might have already completed and deallocated.
---
drivers/s390/scsi/zfcp_fsf.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/s390/scsi/zfcp_fsf.c +4 -3
@@ -766,8 +766,9 @@ static struct zfcp_fsf_req *zfcp_fsf_reqstatic int zfcp_fsf_req_send (struct zfcp_fsf_req *req) {struct zfcp_adapter *adapter = req->adapter; -unsigned long flags; -int idx; +unsigned long flags; +int idx; +int with_qtcb = (req->qtcb !=NULL );/* put allocated FSF request into hash table */ spin_lock_irqsave (&adapter->req_list_lock, flags);
@@ -789,7 +790,7 @@ static int zfcp_fsf_req_send(struct zfcp }/* Don't increase for unsolicited status */ -if (req->qtcb) +if (with_qtcb) adapter->fsf_req_seq_no++; adapter->req_no++;
PATCH 2/15 zfcp: Enable auto-port discovery for NPIV.
In reply to Christof SchmittFrom: Swen Schillig <[email protected]>
Since we're setting the host port type now to FC_PORTTYPE_NPIV for adapters running in NPIV mode we should allow this port type for auto-port scanning as well.
---
drivers/s390/scsi/zfcp_fc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/s390/scsi/zfcp_fc.c +2 -1
@@ -637,7 +637,8 @@ int zfcp_scan_ports(struct zfcp_adapter max_entries = chain ?ZFCP_GPN_FT_MAX_ENTRIES :ZFCP_GPN_FT_ENTRIES ; max_bytes = chain ?ZFCP_GPN_FT_MAX_SIZE :ZFCP_CT_SIZE_ONE_PAGE ; -if (fc_host_port_type (adapter->scsi_host) !=FC_PORTTYPE_NPORT ) +if (fc_host_port_type (adapter->scsi_host) !=FC_PORTTYPE_NPORT && +fc_host_port_type (adapter->scsi_host) !=FC_PORTTYPE_NPIV )return 0 ; ret =zfcp_wka_port_get (&adapter->nsp);
PATCH 3/15 zfcp: Dont call zfcp_fsf_req_free on NULL pointer
In reply to Christof SchmittFrom: Christof Schmitt <[email protected]>
Fix problem that zfcp_fsf_exchange_config_data_sync and zfcp_fsf_exchange_config_data_sync could try to call zfcp_fsf_req_free with a NULL pointer.
---
drivers/s390/scsi/zfcp_fsf.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
drivers/s390/scsi/zfcp_fsf.c +12 -6
@@ -1254,13 +1254,13 @@ int zfcp_fsf_exchange_config_data_sync(sspin_lock_bh (&adapter->req_q_lock);if (zfcp_fsf_req_sbal_get (adapter)) - goto out; + goto out_unlock; req =zfcp_fsf_req_create (adapter,FSF_QTCB_EXCHANGE_CONFIG_DATA ,0 ,NULL );if (IS_ERR (req)) { retval =PTR_ERR (req); - goto out; + goto out_unlock; } sbale =zfcp_qdio_sbale_req (req);
@@ -1279,14 +1279,16 @@ int zfcp_fsf_exchange_config_data_sync(szfcp_fsf_start_timer (req,ZFCP_FSF_REQUEST_TIMEOUT ); retval =zfcp_fsf_req_send (req); -out:spin_unlock_bh (&adapter->req_q_lock);if (!retval)wait_event (req->completion_wq, req->status &ZFCP_STATUS_FSFREQ_COMPLETED );zfcp_fsf_req_free (req); +return retval; +out_unlock: +spin_unlock_bh (&adapter->req_q_lock);return retval; }
@@ -1353,13 +1355,13 @@ int zfcp_fsf_exchange_port_data_sync(strspin_lock_bh (&adapter->req_q_lock);if (zfcp_fsf_req_sbal_get (adapter)) - goto out; + goto out_unlock; req =zfcp_fsf_req_create (adapter,FSF_QTCB_EXCHANGE_PORT_DATA ,0 ,NULL );if (IS_ERR (req)) { retval =PTR_ERR (req); - goto out; + goto out_unlock; }if (data)
@@ -1372,14 +1374,18 @@ int zfcp_fsf_exchange_port_data_sync(str req->handler = zfcp_fsf_exchange_port_data_handler;zfcp_fsf_start_timer (req,ZFCP_FSF_REQUEST_TIMEOUT ); retval =zfcp_fsf_req_send (req); -out:spin_unlock_bh (&adapter->req_q_lock); +if (!retval)wait_event (req->completion_wq, req->status &ZFCP_STATUS_FSFREQ_COMPLETED );zfcp_fsf_req_free (req);return retval; + +out_unlock: +spin_unlock_bh (&adapter->req_q_lock); +return retval; }static void zfcp_fsf_open_port_handler (struct zfcp_fsf_req *req)
PATCH 4/15 zfcp: Dont block zfcp_wq with scan
In reply to Christof SchmittFrom: Swen Schillig <[email protected]>
When running the scsi_scan from the zfcp workqueue and the target device does not respond, the zfcp workqueue can block until the scsi_scan hits a timeout. Move the work to the scsi host workqueue, since this one is also used for the scan from the SCSI midlayer.
--- drivers/s390/scsi/zfcp_aux.c | 5 +--- drivers/s390/scsi/zfcp_def.h | 2 - drivers/s390/scsi/zfcp_erp.c | 50 +++--------------------------------------- drivers/s390/scsi/zfcp_ext.h | 1 drivers/s390/scsi/zfcp_scsi.c | 17 ++++++++++++++ 5 files changed, 25 insertions(+), 50 deletions(-)
drivers/s390/scsi/zfcp_aux.c +2 -3
@@ -97,9 +97,7 @@ static void __init zfcp_init_device_confccw_device_set_online (adapter->ccw_device);zfcp_erp_wait (adapter); -wait_event (adapter->erp_done_wqh, - !(atomic_read (&unit->status) & -ZFCP_STATUS_UNIT_SCSI_WORK_PENDING )); +flush_work (&unit->scsi_work);down (&zfcp_data.config_sema);zfcp_unit_put (unit);
@@ -279,6 +277,7 @@ struct zfcp_unit *zfcp_unit_enqueue(struatomic_set (&unit->refcount,0 );init_waitqueue_head (&unit->remove_wq); +INIT_WORK (&unit->scsi_work, zfcp_scsi_scan); unit->port = port; unit->fcp_lun = fcp_lun;
drivers/s390/scsi/zfcp_def.h +1 -1
@@ -255,7 +255,6 @@ enum zfcp_wka_status {/* logical unit status */ #define ZFCP_STATUS_UNIT_SHARED 0x00000004#define ZFCP_STATUS_UNIT_READONLY 0x00000008 -#define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING 0x00000020/* FSF request status (this does not have a common part) */ #define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT 0x00000002
@@ -530,6 +529,7 @@ struct zfcp_unit {struct zfcp_erp_action erp_action;/* pending error recovery */ atomic_t erp_counter;struct zfcp_latencies latencies; +struct work_struct scsi_work; };/* FSF request */
drivers/s390/scsi/zfcp_erp.c +4 -46
63 lines not on this page · raw message
drivers/s390/scsi/zfcp_ext.h +1 -0
@@ -158,6 +158,7 @@ extern void zfcp_scsi_rport_work(structextern void zfcp_scsi_schedule_rport_register (struct zfcp_port *);extern void zfcp_scsi_schedule_rport_block (struct zfcp_port *);extern void zfcp_scsi_schedule_rports_block (struct zfcp_adapter *); +extern void zfcp_scsi_scan (struct work_struct *);/* zfcp_sysfs.c */ extern struct attribute_group zfcp_sysfs_unit_attrs;
drivers/s390/scsi/zfcp_scsi.c +17 -0
@@ -583,6 +583,23 @@ void zfcp_scsi_rport_work(struct work_st } +void zfcp_scsi_scan (struct work_struct *work) +{ + struct zfcp_unit *unit = container_of(work, struct zfcp_unit, + scsi_work); +struct fc_rport *rport; + +flush_work (&unit->port->rport_work); + rport = unit->port->rport; + +if (rport && rport->port_state ==FC_PORTSTATE_ONLINE ) +scsi_scan_target (&rport->dev,0 , rport->scsi_target_id, +scsilun_to_int ((struct scsi_lun *) + &unit->fcp_lun),0 ); + +zfcp_unit_put (unit); +} +struct fc_function_template zfcp_transport_functions = { .show_starget_port_id =1 , .show_starget_port_name =1 ,
PATCH 5/15 zfcp: Set WKA-port to offline on adapter deactivation
In reply to Christof SchmittFrom: Swen Schillig <[email protected]>
The nameserver port might be in state online when the adapter is offlined. On adapter reactivation the nameserver port is not re-opened due to the PORT_ONLINE status. This results in an unsuccessful recovery. In forcing the nameserver port status to offline on all adapter offline events this issue is prevented.
Waiting for the reference count to drop to zero in zfcp_wka_port_offline is not required, so remove it.
--- drivers/s390/scsi/zfcp_aux.c | 3 ++- drivers/s390/scsi/zfcp_ccw.c | 1 - drivers/s390/scsi/zfcp_erp.c | 1 + drivers/s390/scsi/zfcp_ext.h | 1 + drivers/s390/scsi/zfcp_fc.c | 15 ++++++++------- 5 files changed, 12 insertions(+), 9 deletions(-)
drivers/s390/scsi/zfcp_aux.c +2 -1
@@ -524,6 +524,8 @@ int zfcp_adapter_enqueue(struct ccw_deviatomic_clear_mask (ZFCP_STATUS_COMMON_REMOVE , &adapter->status); +zfcp_fc_nameserver_init (adapter); +if (!zfcp_adapter_scsi_register (adapter))return 0 ;
@@ -552,7 +554,6 @@ void zfcp_adapter_dequeue(struct zfcp_adcancel_work_sync (&adapter->scan_work);cancel_work_sync (&adapter->stat_work); -cancel_delayed_work_sync (&adapter->nsp.work);zfcp_adapter_scsi_unregister (adapter);sysfs_remove_group (&adapter->ccw_device->dev.kobj, &zfcp_sysfs_adapter_attrs);
drivers/s390/scsi/zfcp_ccw.c +0 -1
@@ -108,7 +108,6 @@ static int zfcp_ccw_set_online(struct cc/* initialize request counter */ BUG_ON (!zfcp_reqlist_isempty (adapter)); adapter->req_no =0 ; -zfcp_fc_nameserver_init (adapter);zfcp_erp_modify_adapter_status (adapter,"ccsonl1" ,NULL ,ZFCP_STATUS_COMMON_RUNNING ,ZFCP_SET );
drivers/s390/scsi/zfcp_erp.c +1 -0
@@ -719,6 +719,7 @@ static void zfcp_erp_adapter_strategy_clzfcp_qdio_close (adapter);zfcp_fsf_req_dismiss_all (adapter); adapter->fsf_req_seq_no =0 ; +zfcp_fc_wka_port_force_offline (&adapter->nsp);/* all ports and units are closed */ zfcp_erp_modify_adapter_status (adapter,"erascl1" ,NULL ,ZFCP_STATUS_COMMON_OPEN ,ZFCP_CLEAR );
drivers/s390/scsi/zfcp_ext.h +1 -0
@@ -106,6 +106,7 @@ extern void zfcp_fc_plogi_evaluate(strucextern void zfcp_test_link (struct zfcp_port *);extern void zfcp_fc_link_test_work (struct work_struct *);extern void zfcp_fc_nameserver_init (struct zfcp_adapter *); +extern void zfcp_fc_wka_port_force_offline (struct zfcp_wka_port *);/* zfcp_fsf.c */ extern int zfcp_fsf_open_port (struct zfcp_erp_action *);
drivers/s390/scsi/zfcp_fc.c +8 -7
@@ -98,13 +98,6 @@ static void zfcp_wka_port_offline(structstruct zfcp_wka_port *wka_port = container_of(dw, struct zfcp_wka_port, work); -/* Don't wait forvever. If the wka_port is too busy take it offline -through a new call later */ -if (!wait_event_timeout (wka_port->completion_wq, -atomic_read (&wka_port->refcount) ==0 , -HZ >>1 )) -return ; -mutex_lock (&wka_port->mutex);if ((atomic_read (&wka_port->refcount) !=0 ) || (wka_port->status !=ZFCP_WKA_PORT_ONLINE ))
@@ -142,6 +135,14 @@ void zfcp_fc_nameserver_init(struct zfcpINIT_DELAYED_WORK (&wka_port->work, zfcp_wka_port_offline); } +void zfcp_fc_wka_port_force_offline (struct zfcp_wka_port *wka) +{ +cancel_delayed_work_sync (&wka->work); +mutex_lock (&wka->mutex); + wka->status =ZFCP_WKA_PORT_OFFLINE ; +mutex_unlock (&wka->mutex); +} +static void _zfcp_fc_incoming_rscn (struct zfcp_fsf_req *fsf_req,u32 range,struct fcp_rscn_element *elem) {
PATCH 6/15 zfcp: avoid false ERP complete due to sema race
In reply to Christof SchmittFrom: Swen Schillig <[email protected]>
The ERP thread is performing a task before it is executing the corresponding down on the semaphore. The response handler of the just started exchange config should wait for the completion by performing a down on this semaphore. Since this semaphore is still positive from the ERP enqueue the handler won't wait and therefore the exchange config will always fail leaving the adapter in error. The problem can be solved by performing the down on the semaphore before starting an ERP task. This is the logically correct order. Only walk the ERP loop if there is a task to perform.
---
drivers/s390/scsi/zfcp_erp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/s390/scsi/zfcp_erp.c +5 -4
@@ -1311,6 +1311,11 @@ static int zfcp_erp_thread(void *data)while (!(atomic_read (&adapter->status) &ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL )) { + +zfcp_rec_dbf_event_thread_lock ("erthrd1" , adapter); + ignore =down_interruptible (&adapter->erp_ready_sem); +zfcp_rec_dbf_event_thread_lock ("erthrd2" , adapter); +write_lock_irqsave (&adapter->erp_lock, flags); next = adapter->erp_ready_head.next;write_unlock_irqrestore (&adapter->erp_lock, flags);
@@ -1322,10 +1327,6 @@ static int zfcp_erp_thread(void *data)if (zfcp_erp_strategy (act) !=ZFCP_ERP_DISMISSED )zfcp_erp_wakeup (adapter); } - -zfcp_rec_dbf_event_thread_lock ("erthrd1" , adapter); - ignore =down_interruptible (&adapter->erp_ready_sem); -zfcp_rec_dbf_event_thread_lock ("erthrd2" , adapter); }atomic_clear_mask (ZFCP_STATUS_ADAPTER_ERP_THREAD_UP , &adapter->status);
PATCH 7/15 zfcp: no port recovery after storage side error inject
In reply to Christof SchmittFrom: Swen Schillig <[email protected]>
The remote port remains in error state even if the connection is re-established. A wrong precondition check was performed on the port status leading to a cancellation of the port reopen. Remove the pre-req check because it's not required and better handled within the ERP.
---
drivers/s390/scsi/zfcp_fc.c | 5 ----- 1 file changed, 5 deletions(-)
drivers/s390/scsi/zfcp_fc.c +0 -5
@@ -432,11 +432,6 @@ void zfcp_fc_link_test_work(struct work_ container_of(work, struct zfcp_port, test_link_work);int retval; -if (!(atomic_read (&port->status) &ZFCP_STATUS_COMMON_UNBLOCKED )) { -zfcp_port_put (port); -return ;/* port erp is running and will update rport status */ - } -zfcp_port_get (port); port->rport_task =RPORT_DEL ;zfcp_scsi_rport_work (&port->rport_work);
PATCH 8/15 zfcp: remove unit will fail if add unit is not finished
In reply to Christof SchmittFrom: Martin Petermann <[email protected]>
On some hardware it can take some time to add a unit. If some remove this unit during this process the remove will fail.
---
drivers/s390/scsi/zfcp_sysfs.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-)
drivers/s390/scsi/zfcp_sysfs.c +15 -6
@@ -254,12 +254,21 @@ static ssize_t zfcp_sysfs_unit_remove_stwrite_lock_irq (&zfcp_data.config_lock); unit =zfcp_get_unit_by_lun (port, fcp_lun); -if (unit && (atomic_read (&unit->refcount) ==0 )) { -zfcp_unit_get (unit); -atomic_set_mask (ZFCP_STATUS_COMMON_REMOVE , &unit->status); -list_move (&unit->list, &unit_remove_lh); - }else - unit =NULL ; +if (unit) { +write_unlock_irq (&zfcp_data.config_lock); +/* wait for possible timeout during SCSI probe */ +flush_work (&unit->scsi_work); +write_lock_irq (&zfcp_data.config_lock); + +if (atomic_read (&unit->refcount) ==0 ) { +zfcp_unit_get (unit); +atomic_set_mask (ZFCP_STATUS_COMMON_REMOVE , + &unit->status); +list_move (&unit->list, &unit_remove_lh); + }else { + unit =NULL ; + } + }write_unlock_irq (&zfcp_data.config_lock);
PATCH 9/15 zfcp: Let actcli handle control file errors
In reply to Christof SchmittFrom: Christof Schmitt <[email protected]>
Error codes specific to the control file requests are evaluated by the actcli tool, so don't report -ENXIO for those. Generic problems are still checked for outside the command specific handler.
---
drivers/s390/scsi/zfcp_fsf.c | 2 -- 1 file changed, 2 deletions(-)
drivers/s390/scsi/zfcp_fsf.c +0 -2
@@ -2479,8 +2479,6 @@ out:static void zfcp_fsf_control_file_handler (struct zfcp_fsf_req *req) { -if (req->qtcb->header.fsf_status !=FSF_GOOD ) - req->status |=ZFCP_STATUS_FSFREQ_ERROR ; }/**
PATCH 10/15 zfcp: no port recovery after ADISC request timeout
In reply to Christof SchmittFrom: Swen Schillig <[email protected]>
A remote port remains in error state even if we receive a RSCN stating that the connection is re-established. The port recovery is not started due to a flag which is not reset.
The solution is to clear the flag in question before we trigger a ERP.
---
drivers/s390/scsi/zfcp_fc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/s390/scsi/zfcp_fc.c +2 -1
@@ -373,7 +373,8 @@ static void zfcp_fc_adisc_handler(unsignif (adisc->els.status) {/* request rejected or timed out */ -zfcp_erp_port_forced_reopen (port,0 ,"fcadh_1" ,NULL ); +zfcp_erp_port_forced_reopen (port,ZFCP_STATUS_COMMON_ERP_FAILED , +"fcadh_1" ,NULL ); goto out; }
PATCH 11/15 zfcp: Fix abort handler for completions in progress
In reply to Christof SchmittFrom: Christof Schmitt <[email protected]>
When the abort handler cannot find a pending FSF request, the request completion could just be running. This means we cannot return SUCCESS, since this would lead to call to scsi_done after exiting the SCSI error handler which is not allowed.
---
drivers/s390/scsi/zfcp_scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/s390/scsi/zfcp_scsi.c +1 -1
@@ -171,7 +171,7 @@ static int zfcp_scsi_eh_abort_handler(stwrite_unlock_irqrestore (&adapter->abort_lock, flags);zfcp_scsi_dbf_event_abort ("lte1" , adapter, scpnt,NULL , old_req_id); -return SUCCESS ; +return FAILED ;/* completion could be in progress */ } old_req->data =NULL ;
PATCH 12/15 zfcp: revert previous patch for sbal counting
In reply to Christof SchmittFrom: Martin Petermann <[email protected]>
The current sbal counting can be wrong if a fsf request is waiting for free sbals and at the same time qdio request queue is shutdown and re-opened. Revering a previous patch fixes this issue.
---
drivers/s390/scsi/zfcp_fsf.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
drivers/s390/scsi/zfcp_fsf.c +14 -14
@@ -645,30 +645,30 @@ static void zfcp_fsf_exchange_port_data_ } } -static int zfcp_fsf_req_sbal_get (struct zfcp_adapter *adapter) - __releases(&adapter->req_q_lock) - __acquires(&adapter->req_q_lock) +static int zfcp_fsf_sbal_check (struct zfcp_adapter *adapter) {struct zfcp_qdio_queue *req_q = &adapter->req_q; -long ret; -if (atomic_read (&req_q->count) <= -REQUEST_LIST_SIZE ) -return -EIO ; -if (atomic_read (&req_q->count) >0 ) -return 0 ; +spin_lock_bh (&adapter->req_q_lock); +if (atomic_read (&req_q->count)) +return 1 ; +spin_unlock_bh (&adapter->req_q_lock); +return 0 ; +} + +static int zfcp_fsf_req_sbal_get (struct zfcp_adapter *adapter) +{ +long ret; -atomic_dec (&req_q->count);spin_unlock_bh (&adapter->req_q_lock); ret =wait_event_interruptible_timeout (adapter->request_wq, -atomic_read (&req_q->count) >=0 , -5 *HZ ); -spin_lock_bh (&adapter->req_q_lock); -atomic_inc (&req_q->count); - +zfcp_fsf_sbal_check (adapter),5 *HZ );if (ret >0 )return 0 ;if (!ret)atomic_inc (&adapter->qdio_outb_full); + +spin_lock_bh (&adapter->req_q_lock);return -EIO ; }
PATCH 13/15 zfcp: Fix port reference counting
In reply to Christof SchmittFrom: Martin Petermann <[email protected]>
If this problem appears zfcp ports cannot be de-queued since it is checked for a zero refcount. The port reference counting is wrong for existing zfcp ports when e.g. an adapter gets on-line again. During port scanning the reference counting for existing ports should not be changed.
---
drivers/s390/scsi/zfcp_fc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/s390/scsi/zfcp_fc.c +4 -3
@@ -539,6 +539,9 @@ static void zfcp_validate_port(struct zf {struct zfcp_adapter *adapter = port->adapter; +if (!(atomic_read (&port->status) &ZFCP_STATUS_COMMON_NOESC )) +return ; +atomic_clear_mask (ZFCP_STATUS_COMMON_NOESC , &port->status); if ((port->supported_classes != 0) ||
@@ -599,10 +602,8 @@ static int zfcp_scan_eval_gpn_ft(structif (acc->wwpn ==fc_host_port_name (adapter->scsi_host))continue ; port =zfcp_get_port_by_wwpn (adapter, acc->wwpn); -if (port) { -zfcp_port_get (port); +if (port)continue ; - } port =zfcp_port_enqueue (adapter, acc->wwpn,ZFCP_STATUS_COMMON_NOESC , d_id);
PATCH 14/15 zfcp: Reference counting for cfdc requests
In reply to Christof SchmittFrom: Christof Schmitt <[email protected]>
Before dropping the reference count with zfcp_adapter_put, increase it with zfcp_adapter_get when issuing cfdc requests.
--- drivers/s390/scsi/zfcp_cfdc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/s390/scsi/zfcp_cfdc.c +2 -1
@@ -4,7 +4,7 @@* Userspace interface for accessing the * Access Control Lists / Control File Data Channel * -* Copyright IBM Corporation 2008 +* Copyright IBM Corporation 2008, 2009 */ #define KMSG_COMPONENT "zfcp"
@@ -197,6 +197,7 @@ static long zfcp_cfdc_dev_ioctl(struct f retval = -ENXIO ; goto free_buffer; } +zfcp_adapter_get (adapter); retval =zfcp_cfdc_sg_setup (data->command, fsf_cfdc->sg, data_user->control_file);
PATCH 15/15 zfcp: Fix oops when port disappears
In reply to Christof SchmittFrom: Christof Schmitt <[email protected]>
The zfcp_port might have been removed, while the FC fast_io_fail timer is still running and could trigger the terminate_rport_io callback. Set the pointer to the zfcp_port to NULL and check accordingly before using it.
--- drivers/s390/scsi/zfcp_aux.c | 3 +-- drivers/s390/scsi/zfcp_fsf.c | 4 ++++ drivers/s390/scsi/zfcp_scsi.c | 25 +++++++++++++++++++------ 3 files changed, 24 insertions(+), 8 deletions(-)
drivers/s390/scsi/zfcp_aux.c +1 -2
@@ -671,8 +671,7 @@ void zfcp_port_dequeue(struct zfcp_portlist_del (&port->list);write_unlock_irq (&zfcp_data.config_lock);if (port->rport) -fc_remote_port_delete (port->rport); - port->rport =NULL ; + port->rport->dd_data =NULL ;zfcp_adapter_put (port->adapter);sysfs_remove_group (&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs);device_unregister (&port->sysfs_device);
drivers/s390/scsi/zfcp_scsi.c +19 -6
@@ -486,10 +486,12 @@ static void zfcp_set_rport_dev_loss_tmo(*/ static void zfcp_scsi_dev_loss_tmo_callbk (struct fc_rport *rport) { -struct zfcp_port *port = rport->dd_data; +struct zfcp_port *port;write_lock_irq (&zfcp_data.config_lock); - port->rport =NULL ; + port = rport->dd_data; +if (port) + port->rport =NULL ;write_unlock_irq (&zfcp_data.config_lock); }
@@ -503,9 +505,18 @@ static void zfcp_scsi_dev_loss_tmo_callb*/ static void zfcp_scsi_terminate_rport_io (struct fc_rport *rport) { -struct zfcp_port *port = rport->dd_data; +struct zfcp_port *port; + +write_lock_irq (&zfcp_data.config_lock); + port = rport->dd_data; +if (port) +zfcp_port_get (port); +write_unlock_irq (&zfcp_data.config_lock); -zfcp_erp_port_reopen (port,0 ,"sctrpi1" ,NULL ); +if (port) { +zfcp_erp_port_reopen (port,0 ,"sctrpi1" ,NULL ); +zfcp_port_put (port); + } }static void zfcp_scsi_rport_register (struct zfcp_port *port)
@@ -534,8 +545,10 @@ static void zfcp_scsi_rport_register(strstatic void zfcp_scsi_rport_block (struct zfcp_port *port) { -if (port->rport) -fc_remote_port_delete (port->rport); +struct fc_rport *rport = port->rport; + +if (rport) +fc_remote_port_delete (rport); }void zfcp_scsi_schedule_rport_register (struct zfcp_port *port)
drivers/s390/scsi/zfcp_fsf.c +4 -0
@@ -172,12 +172,16 @@ static void zfcp_fsf_link_down_info_eval struct fsf_link_down_info *link_down) {struct zfcp_adapter *adapter = req->adapter; +unsigned long flags;if (atomic_read (&adapter->status) &ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED )return ;atomic_set_mask (ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED , &adapter->status); + +read_lock_irqsave (&zfcp_data.config_lock, flags);zfcp_scsi_schedule_rports_block (adapter); +read_unlock_irqrestore (&zfcp_data.config_lock, flags);if (!link_down) goto out;