Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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 <martin@linux.vnet.ibm.com>
Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

authored by

Christof Schmitt and committed by
James Bottomley
70932935 3869bb6e

+24 -8
+1 -2
drivers/s390/scsi/zfcp_aux.c
··· 671 671 list_del(&port->list); 672 672 write_unlock_irq(&zfcp_data.config_lock); 673 673 if (port->rport) 674 - fc_remote_port_delete(port->rport); 675 - port->rport = NULL; 674 + port->rport->dd_data = NULL; 676 675 zfcp_adapter_put(port->adapter); 677 676 sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs); 678 677 device_unregister(&port->sysfs_device);
+4
drivers/s390/scsi/zfcp_fsf.c
··· 172 172 struct fsf_link_down_info *link_down) 173 173 { 174 174 struct zfcp_adapter *adapter = req->adapter; 175 + unsigned long flags; 175 176 176 177 if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED) 177 178 return; 178 179 179 180 atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); 181 + 182 + read_lock_irqsave(&zfcp_data.config_lock, flags); 180 183 zfcp_scsi_schedule_rports_block(adapter); 184 + read_unlock_irqrestore(&zfcp_data.config_lock, flags); 181 185 182 186 if (!link_down) 183 187 goto out;
+19 -6
drivers/s390/scsi/zfcp_scsi.c
··· 486 486 */ 487 487 static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport) 488 488 { 489 - struct zfcp_port *port = rport->dd_data; 489 + struct zfcp_port *port; 490 490 491 491 write_lock_irq(&zfcp_data.config_lock); 492 - port->rport = NULL; 492 + port = rport->dd_data; 493 + if (port) 494 + port->rport = NULL; 493 495 write_unlock_irq(&zfcp_data.config_lock); 494 496 } 495 497 ··· 505 503 */ 506 504 static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) 507 505 { 508 - struct zfcp_port *port = rport->dd_data; 506 + struct zfcp_port *port; 509 507 510 - zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL); 508 + write_lock_irq(&zfcp_data.config_lock); 509 + port = rport->dd_data; 510 + if (port) 511 + zfcp_port_get(port); 512 + write_unlock_irq(&zfcp_data.config_lock); 513 + 514 + if (port) { 515 + zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL); 516 + zfcp_port_put(port); 517 + } 511 518 } 512 519 513 520 static void zfcp_scsi_rport_register(struct zfcp_port *port) ··· 545 534 546 535 static void zfcp_scsi_rport_block(struct zfcp_port *port) 547 536 { 548 - if (port->rport) 549 - fc_remote_port_delete(port->rport); 537 + struct fc_rport *rport = port->rport; 538 + 539 + if (rport) 540 + fc_remote_port_delete(rport); 550 541 } 551 542 552 543 void zfcp_scsi_schedule_rport_register(struct zfcp_port *port)