aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/net
diff options
context:
space:
mode:
authorJulian Wiedmann <jwi@linux.vnet.ibm.com>2018-04-19 06:52:10 -0400
committerDavid S. Miller <davem@davemloft.net>2018-04-22 14:42:32 -0400
commitdb71bbbd11a4d314f0fa3fbf3369b71cf33ce33c (patch)
treeb4d33d750b092082be8932b91608b68be84aafa1 /drivers/s390/net
parentbcacfcbc82b4235d280ed9b067aa4567f4a0c756 (diff)
s390/qeth: fix request-side race during cmd IO timeout
Submitting a cmd IO request (usually on the WRITE device, but for IDX also on the READ device) is currently done with ccw_device_start() and a manual timeout in the caller. On timeout, the caller cleans up the related resources (eg. IO buffer). But 1) the IO might still be active and utilize those resources, and 2) when the IO completes, qeth_irq() will attempt to clean up the same resources again. Instead of introducing additional resource locking, switch to ccw_device_start_timeout() to ensure IO termination after timeout, and let the IRQ handler alone deal with cleaning up after a request. This also removes a stray write->irq_pending reset from clear_ipacmd_list(). The routine doesn't terminate any pending IO on the WRITE device, so this should be handled properly via IO timeout in the IRQ handler. Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/s390/net')
-rw-r--r--drivers/s390/net/qeth_core_main.c51
-rw-r--r--drivers/s390/net/qeth_core_mpc.h12
-rw-r--r--drivers/s390/net/qeth_l2_main.c4
3 files changed, 40 insertions, 27 deletions
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 9a08b545d018..9b22d5d496ae 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -706,7 +706,6 @@ void qeth_clear_ipacmd_list(struct qeth_card *card)
706 qeth_put_reply(reply); 706 qeth_put_reply(reply);
707 } 707 }
708 spin_unlock_irqrestore(&card->lock, flags); 708 spin_unlock_irqrestore(&card->lock, flags);
709 atomic_set(&card->write.irq_pending, 0);
710} 709}
711EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list); 710EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list);
712 711
@@ -1098,14 +1097,9 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
1098{ 1097{
1099 int rc; 1098 int rc;
1100 int cstat, dstat; 1099 int cstat, dstat;
1100 struct qeth_cmd_buffer *iob = NULL;
1101 struct qeth_channel *channel; 1101 struct qeth_channel *channel;
1102 struct qeth_card *card; 1102 struct qeth_card *card;
1103 struct qeth_cmd_buffer *iob;
1104
1105 if (__qeth_check_irb_error(cdev, intparm, irb))
1106 return;
1107 cstat = irb->scsw.cmd.cstat;
1108 dstat = irb->scsw.cmd.dstat;
1109 1103
1110 card = CARD_FROM_CDEV(cdev); 1104 card = CARD_FROM_CDEV(cdev);
1111 if (!card) 1105 if (!card)
@@ -1123,6 +1117,19 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
1123 channel = &card->data; 1117 channel = &card->data;
1124 QETH_CARD_TEXT(card, 5, "data"); 1118 QETH_CARD_TEXT(card, 5, "data");
1125 } 1119 }
1120
1121 if (qeth_intparm_is_iob(intparm))
1122 iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
1123
1124 if (__qeth_check_irb_error(cdev, intparm, irb)) {
1125 /* IO was terminated, free its resources. */
1126 if (iob)
1127 qeth_release_buffer(iob->channel, iob);
1128 atomic_set(&channel->irq_pending, 0);
1129 wake_up(&card->wait_q);
1130 return;
1131 }
1132
1126 atomic_set(&channel->irq_pending, 0); 1133 atomic_set(&channel->irq_pending, 0);
1127 1134
1128 if (irb->scsw.cmd.fctl & (SCSW_FCTL_CLEAR_FUNC)) 1135 if (irb->scsw.cmd.fctl & (SCSW_FCTL_CLEAR_FUNC))
@@ -1146,6 +1153,10 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
1146 /* we don't have to handle this further */ 1153 /* we don't have to handle this further */
1147 intparm = 0; 1154 intparm = 0;
1148 } 1155 }
1156
1157 cstat = irb->scsw.cmd.cstat;
1158 dstat = irb->scsw.cmd.dstat;
1159
1149 if ((dstat & DEV_STAT_UNIT_EXCEP) || 1160 if ((dstat & DEV_STAT_UNIT_EXCEP) ||
1150 (dstat & DEV_STAT_UNIT_CHECK) || 1161 (dstat & DEV_STAT_UNIT_CHECK) ||
1151 (cstat)) { 1162 (cstat)) {
@@ -1184,11 +1195,8 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
1184 channel->state == CH_STATE_UP) 1195 channel->state == CH_STATE_UP)
1185 __qeth_issue_next_read(card); 1196 __qeth_issue_next_read(card);
1186 1197
1187 if (intparm) { 1198 if (iob && iob->callback)
1188 iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm); 1199 iob->callback(iob->channel, iob);
1189 if (iob->callback)
1190 iob->callback(iob->channel, iob);
1191 }
1192 1200
1193out: 1201out:
1194 wake_up(&card->wait_q); 1202 wake_up(&card->wait_q);
@@ -1859,8 +1867,8 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel,
1859 atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0); 1867 atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
1860 QETH_DBF_TEXT(SETUP, 6, "noirqpnd"); 1868 QETH_DBF_TEXT(SETUP, 6, "noirqpnd");
1861 spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); 1869 spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
1862 rc = ccw_device_start(channel->ccwdev, 1870 rc = ccw_device_start_timeout(channel->ccwdev, &channel->ccw,
1863 &channel->ccw, (addr_t) iob, 0, 0); 1871 (addr_t) iob, 0, 0, QETH_TIMEOUT);
1864 spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); 1872 spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
1865 1873
1866 if (rc) { 1874 if (rc) {
@@ -1877,7 +1885,6 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel,
1877 if (channel->state != CH_STATE_UP) { 1885 if (channel->state != CH_STATE_UP) {
1878 rc = -ETIME; 1886 rc = -ETIME;
1879 QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); 1887 QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
1880 qeth_clear_cmd_buffers(channel);
1881 } else 1888 } else
1882 rc = 0; 1889 rc = 0;
1883 return rc; 1890 return rc;
@@ -1931,8 +1938,8 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel,
1931 atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0); 1938 atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
1932 QETH_DBF_TEXT(SETUP, 6, "noirqpnd"); 1939 QETH_DBF_TEXT(SETUP, 6, "noirqpnd");
1933 spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); 1940 spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
1934 rc = ccw_device_start(channel->ccwdev, 1941 rc = ccw_device_start_timeout(channel->ccwdev, &channel->ccw,
1935 &channel->ccw, (addr_t) iob, 0, 0); 1942 (addr_t) iob, 0, 0, QETH_TIMEOUT);
1936 spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); 1943 spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
1937 1944
1938 if (rc) { 1945 if (rc) {
@@ -1953,7 +1960,6 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel,
1953 QETH_DBF_MESSAGE(2, "%s IDX activate timed out\n", 1960 QETH_DBF_MESSAGE(2, "%s IDX activate timed out\n",
1954 dev_name(&channel->ccwdev->dev)); 1961 dev_name(&channel->ccwdev->dev));
1955 QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME); 1962 QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME);
1956 qeth_clear_cmd_buffers(channel);
1957 return -ETIME; 1963 return -ETIME;
1958 } 1964 }
1959 return qeth_idx_activate_get_answer(channel, idx_reply_cb); 1965 return qeth_idx_activate_get_answer(channel, idx_reply_cb);
@@ -2155,8 +2161,8 @@ int qeth_send_control_data(struct qeth_card *card, int len,
2155 2161
2156 QETH_CARD_TEXT(card, 6, "noirqpnd"); 2162 QETH_CARD_TEXT(card, 6, "noirqpnd");
2157 spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags); 2163 spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
2158 rc = ccw_device_start(card->write.ccwdev, &card->write.ccw, 2164 rc = ccw_device_start_timeout(CARD_WDEV(card), &card->write.ccw,
2159 (addr_t) iob, 0, 0); 2165 (addr_t) iob, 0, 0, event_timeout);
2160 spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags); 2166 spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
2161 if (rc) { 2167 if (rc) {
2162 QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: " 2168 QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: "
@@ -2188,8 +2194,6 @@ int qeth_send_control_data(struct qeth_card *card, int len,
2188 } 2194 }
2189 } 2195 }
2190 2196
2191 if (reply->rc == -EIO)
2192 goto error;
2193 rc = reply->rc; 2197 rc = reply->rc;
2194 qeth_put_reply(reply); 2198 qeth_put_reply(reply);
2195 return rc; 2199 return rc;
@@ -2200,9 +2204,6 @@ time_err:
2200 list_del_init(&reply->list); 2204 list_del_init(&reply->list);
2201 spin_unlock_irqrestore(&reply->card->lock, flags); 2205 spin_unlock_irqrestore(&reply->card->lock, flags);
2202 atomic_inc(&reply->received); 2206 atomic_inc(&reply->received);
2203error:
2204 atomic_set(&card->write.irq_pending, 0);
2205 qeth_release_buffer(iob->channel, iob);
2206 rc = reply->rc; 2207 rc = reply->rc;
2207 qeth_put_reply(reply); 2208 qeth_put_reply(reply);
2208 return rc; 2209 return rc;
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index 619f897b4bb0..f4d1ec0b8f5a 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -35,6 +35,18 @@ extern unsigned char IPA_PDU_HEADER[];
35#define QETH_HALT_CHANNEL_PARM -11 35#define QETH_HALT_CHANNEL_PARM -11
36#define QETH_RCD_PARM -12 36#define QETH_RCD_PARM -12
37 37
38static inline bool qeth_intparm_is_iob(unsigned long intparm)
39{
40 switch (intparm) {
41 case QETH_CLEAR_CHANNEL_PARM:
42 case QETH_HALT_CHANNEL_PARM:
43 case QETH_RCD_PARM:
44 case 0:
45 return false;
46 }
47 return true;
48}
49
38/*****************************************************************************/ 50/*****************************************************************************/
39/* IP Assist related definitions */ 51/* IP Assist related definitions */
40/*****************************************************************************/ 52/*****************************************************************************/
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 36f9b74848fe..b8079f2a65b3 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -1345,8 +1345,8 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len,
1345 qeth_prepare_control_data(card, len, iob); 1345 qeth_prepare_control_data(card, len, iob);
1346 QETH_CARD_TEXT(card, 6, "osnoirqp"); 1346 QETH_CARD_TEXT(card, 6, "osnoirqp");
1347 spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags); 1347 spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
1348 rc = ccw_device_start(card->write.ccwdev, &card->write.ccw, 1348 rc = ccw_device_start_timeout(CARD_WDEV(card), &card->write.ccw,
1349 (addr_t) iob, 0, 0); 1349 (addr_t) iob, 0, 0, QETH_IPA_TIMEOUT);
1350 spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags); 1350 spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
1351 if (rc) { 1351 if (rc) {
1352 QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: " 1352 QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: "