aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorMartin Peschke <mpeschke@linux.vnet.ibm.com>2012-09-04 09:23:36 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-09-24 04:11:02 -0400
commitd436de8ce25f53a8a880a931886821f632247943 (patch)
treedf2f2056c79b3bd51d4f90fc0f272d46be1adec3 /drivers/s390
parent43f60cbd56c4a3a8f7fb009ac52d6d57ac864921 (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.c19
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:
801static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) 801static 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:
1886static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) 1890static 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: