From 70932935b61ee3dcc5a419ec4c367feb2ff808e4 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Fri, 17 Apr 2009 15:08:15 +0200 Subject: [SCSI] zfcp: Fix oops when port disappears 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. Reviewed-by: Martin Petermann Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index a00d2bb..3ac27ee 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -671,8 +671,7 @@ void zfcp_port_dequeue(struct zfcp_port *port) list_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); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 3f365ac..74dee32 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -172,12 +172,16 @@ static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id, 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; diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index e7d0652..e8fbeae 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -486,10 +486,12 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) */ 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_callbk(struct fc_rport *rport) */ 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(struct zfcp_port *port) static 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) -- cgit v0.10.2