diff options
author | Martin Peschke <mpeschke@linux.vnet.ibm.com> | 2012-09-04 09:23:36 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-09-24 04:11:02 -0400 |
commit | d436de8ce25f53a8a880a931886821f632247943 (patch) | |
tree | df2f2056c79b3bd51d4f90fc0f272d46be1adec3 /drivers/s390 | |
parent | 43f60cbd56c4a3a8f7fb009ac52d6d57ac864921 (diff) |
[SCSI] zfcp: only access zfcp_scsi_dev for valid scsi_device
__scsi_remove_device (e.g. due to dev_loss_tmo) calls
zfcp_scsi_slave_destroy which in turn sends a close LUN FSF request to
the adapter. After 30 seconds without response,
zfcp_erp_timeout_handler kicks the ERP thread failing the close LUN
ERP action. zfcp_erp_wait in zfcp_erp_lun_shutdown_wait and thus
zfcp_scsi_slave_destroy returns and then scsi_device is no longer
valid. Sometime later the response to the close LUN FSF request may
finally come in. However, commit
b62a8d9b45b971a67a0f8413338c230e3117dff5
"[SCSI] zfcp: Use SCSI device data zfcp_scsi_dev instead of zfcp_unit"
introduced a number of attempts to unconditionally access struct
zfcp_scsi_dev through struct scsi_device causing a use-after-free.
This leads to an Oops due to kernel page fault in one of:
zfcp_fsf_abort_fcp_command_handler, zfcp_fsf_open_lun_handler,
zfcp_fsf_close_lun_handler, zfcp_fsf_req_trace,
zfcp_fsf_fcp_handler_common.
Move dereferencing of zfcp private data zfcp_scsi_dev allocated in
scsi_device via scsi_transport_reserve_device after the check for
potentially aborted FSF request and thus no longer valid scsi_device.
Only then assign sdev_to_zfcp(sdev) to the local auto variable struct
zfcp_scsi_dev *zfcp_sdev.
Signed-off-by: Martin Peschke <mpeschke@linux.vnet.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.vnet.ibm.com>
Cc: <stable@vger.kernel.org> #2.6.37+
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 19 |
1 files changed, 14 insertions, 5 deletions
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 9ffdc335429c..c96320d79fbc 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -801,12 +801,14 @@ out: | |||
801 | static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) | 801 | static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) |
802 | { | 802 | { |
803 | struct scsi_device *sdev = req->data; | 803 | struct scsi_device *sdev = req->data; |
804 | struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); | 804 | struct zfcp_scsi_dev *zfcp_sdev; |
805 | union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual; | 805 | union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual; |
806 | 806 | ||
807 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) | 807 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
808 | return; | 808 | return; |
809 | 809 | ||
810 | zfcp_sdev = sdev_to_zfcp(sdev); | ||
811 | |||
810 | switch (req->qtcb->header.fsf_status) { | 812 | switch (req->qtcb->header.fsf_status) { |
811 | case FSF_PORT_HANDLE_NOT_VALID: | 813 | case FSF_PORT_HANDLE_NOT_VALID: |
812 | if (fsq->word[0] == fsq->word[1]) { | 814 | if (fsq->word[0] == fsq->word[1]) { |
@@ -1769,13 +1771,15 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) | |||
1769 | { | 1771 | { |
1770 | struct zfcp_adapter *adapter = req->adapter; | 1772 | struct zfcp_adapter *adapter = req->adapter; |
1771 | struct scsi_device *sdev = req->data; | 1773 | struct scsi_device *sdev = req->data; |
1772 | struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); | 1774 | struct zfcp_scsi_dev *zfcp_sdev; |
1773 | struct fsf_qtcb_header *header = &req->qtcb->header; | 1775 | struct fsf_qtcb_header *header = &req->qtcb->header; |
1774 | struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support; | 1776 | struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support; |
1775 | 1777 | ||
1776 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) | 1778 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
1777 | return; | 1779 | return; |
1778 | 1780 | ||
1781 | zfcp_sdev = sdev_to_zfcp(sdev); | ||
1782 | |||
1779 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | | 1783 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | |
1780 | ZFCP_STATUS_COMMON_ACCESS_BOXED | | 1784 | ZFCP_STATUS_COMMON_ACCESS_BOXED | |
1781 | ZFCP_STATUS_LUN_SHARED | | 1785 | ZFCP_STATUS_LUN_SHARED | |
@@ -1886,11 +1890,13 @@ out: | |||
1886 | static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) | 1890 | static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) |
1887 | { | 1891 | { |
1888 | struct scsi_device *sdev = req->data; | 1892 | struct scsi_device *sdev = req->data; |
1889 | struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); | 1893 | struct zfcp_scsi_dev *zfcp_sdev; |
1890 | 1894 | ||
1891 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) | 1895 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
1892 | return; | 1896 | return; |
1893 | 1897 | ||
1898 | zfcp_sdev = sdev_to_zfcp(sdev); | ||
1899 | |||
1894 | switch (req->qtcb->header.fsf_status) { | 1900 | switch (req->qtcb->header.fsf_status) { |
1895 | case FSF_PORT_HANDLE_NOT_VALID: | 1901 | case FSF_PORT_HANDLE_NOT_VALID: |
1896 | zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1"); | 1902 | zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1"); |
@@ -1980,7 +1986,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) | |||
1980 | { | 1986 | { |
1981 | struct fsf_qual_latency_info *lat_in; | 1987 | struct fsf_qual_latency_info *lat_in; |
1982 | struct latency_cont *lat = NULL; | 1988 | struct latency_cont *lat = NULL; |
1983 | struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scsi->device); | 1989 | struct zfcp_scsi_dev *zfcp_sdev; |
1984 | struct zfcp_blk_drv_data blktrc; | 1990 | struct zfcp_blk_drv_data blktrc; |
1985 | int ticks = req->adapter->timer_ticks; | 1991 | int ticks = req->adapter->timer_ticks; |
1986 | 1992 | ||
@@ -1995,6 +2001,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) | |||
1995 | 2001 | ||
1996 | if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA && | 2002 | if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA && |
1997 | !(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { | 2003 | !(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { |
2004 | zfcp_sdev = sdev_to_zfcp(scsi->device); | ||
1998 | blktrc.flags |= ZFCP_BLK_LAT_VALID; | 2005 | blktrc.flags |= ZFCP_BLK_LAT_VALID; |
1999 | blktrc.channel_lat = lat_in->channel_lat * ticks; | 2006 | blktrc.channel_lat = lat_in->channel_lat * ticks; |
2000 | blktrc.fabric_lat = lat_in->fabric_lat * ticks; | 2007 | blktrc.fabric_lat = lat_in->fabric_lat * ticks; |
@@ -2032,12 +2039,14 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) | |||
2032 | { | 2039 | { |
2033 | struct scsi_cmnd *scmnd = req->data; | 2040 | struct scsi_cmnd *scmnd = req->data; |
2034 | struct scsi_device *sdev = scmnd->device; | 2041 | struct scsi_device *sdev = scmnd->device; |
2035 | struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); | 2042 | struct zfcp_scsi_dev *zfcp_sdev; |
2036 | struct fsf_qtcb_header *header = &req->qtcb->header; | 2043 | struct fsf_qtcb_header *header = &req->qtcb->header; |
2037 | 2044 | ||
2038 | if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) | 2045 | if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) |
2039 | return; | 2046 | return; |
2040 | 2047 | ||
2048 | zfcp_sdev = sdev_to_zfcp(sdev); | ||
2049 | |||
2041 | switch (header->fsf_status) { | 2050 | switch (header->fsf_status) { |
2042 | case FSF_HANDLE_MISMATCH: | 2051 | case FSF_HANDLE_MISMATCH: |
2043 | case FSF_PORT_HANDLE_NOT_VALID: | 2052 | case FSF_PORT_HANDLE_NOT_VALID: |