Home Home > GIT Browse > SLE12-SP4
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Tesarik <ptesarik@suse.cz>2019-08-08 18:50:45 +0200
committerPetr Tesarik <ptesarik@suse.cz>2019-08-08 18:50:45 +0200
commit9e0538c9935aefc93b37920e4606a72687d12db5 (patch)
treec24c247d069431723583637210eba5f2bf29bf24
parentcc12236f00fda3d3cf1e7cfb09bb341e2e89dd8b (diff)
- s390/qeth: fix request-side race during cmd IO timeout
(bsc#1142109 LTC#179339). - Refresh patches.arch/s390-sles15-17-02-02-s390-qeth-sanitize-strings-in-debug-messages.patch.
-rw-r--r--patches.arch/s390-sles15-17-02-02-s390-qeth-sanitize-strings-in-debug-messages.patch4
-rw-r--r--patches.fixes/s390-qeth-fix-request-side-race-during-cmd-io-timeout206
-rw-r--r--series.conf1
3 files changed, 209 insertions, 2 deletions
diff --git a/patches.arch/s390-sles15-17-02-02-s390-qeth-sanitize-strings-in-debug-messages.patch b/patches.arch/s390-sles15-17-02-02-s390-qeth-sanitize-strings-in-debug-messages.patch
index 624f9b88bb..1409f62a6d 100644
--- a/patches.arch/s390-sles15-17-02-02-s390-qeth-sanitize-strings-in-debug-messages.patch
+++ b/patches.arch/s390-sles15-17-02-02-s390-qeth-sanitize-strings-in-debug-messages.patch
@@ -182,8 +182,8 @@ Acked-by: Petr Tesarik <ptesarik@suse.com>
+ QETH_DBF_MESSAGE(2, "IDX activate timed out on channel %x\n",
+ CCW_DEVID(channel->ccwdev));
QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME);
- qeth_clear_cmd_buffers(channel);
return -ETIME;
+ }
@@ -1959,17 +1957,15 @@ static void qeth_idx_write_cb(struct qet
"The adapter is used exclusively by another "
"host\n");
@@ -234,7 +234,7 @@ Acked-by: Petr Tesarik <ptesarik@suse.com>
}
memcpy(&card->token.issuer_rm_r,
@@ -2129,9 +2123,8 @@ int qeth_send_control_data(struct qeth_c
- (addr_t) iob, 0, 0);
+ (addr_t) iob, 0, 0, event_timeout);
spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
if (rc) {
- QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: "
diff --git a/patches.fixes/s390-qeth-fix-request-side-race-during-cmd-io-timeout b/patches.fixes/s390-qeth-fix-request-side-race-during-cmd-io-timeout
new file mode 100644
index 0000000000..5f6850e412
--- /dev/null
+++ b/patches.fixes/s390-qeth-fix-request-side-race-during-cmd-io-timeout
@@ -0,0 +1,206 @@
+From: Julian Wiedmann <jwi@linux.vnet.ibm.com>
+Date: Thu, 19 Apr 2018 12:52:10 +0200
+Subject: s390/qeth: fix request-side race during cmd IO timeout
+Git-commit: db71bbbd11a4d314f0fa3fbf3369b71cf33ce33c
+Patch-mainline: v4.17-rc3
+References: bsc#1142109 LTC#179339
+
+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>
+Acked-by: Petr Tesarik <ptesarik@suse.com>
+---
+ drivers/s390/net/qeth_core_main.c | 51 +++++++++++++++++++-------------------
+ drivers/s390/net/qeth_core_mpc.h | 12 ++++++++
+ drivers/s390/net/qeth_l2_main.c | 4 +-
+ 3 files changed, 40 insertions(+), 27 deletions(-)
+
+--- a/drivers/s390/net/qeth_core_main.c
++++ b/drivers/s390/net/qeth_core_main.c
+@@ -707,7 +707,6 @@ void qeth_clear_ipacmd_list(struct qeth_
+ qeth_put_reply(reply);
+ }
+ spin_unlock_irqrestore(&card->lock, flags);
+- atomic_set(&card->write.irq_pending, 0);
+ }
+ EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list);
+
+@@ -1099,14 +1098,9 @@ static void qeth_irq(struct ccw_device *
+ {
+ int rc;
+ int cstat, dstat;
++ struct qeth_cmd_buffer *iob = NULL;
+ struct qeth_channel *channel;
+ struct qeth_card *card;
+- struct qeth_cmd_buffer *iob;
+-
+- if (__qeth_check_irb_error(cdev, intparm, irb))
+- return;
+- cstat = irb->scsw.cmd.cstat;
+- dstat = irb->scsw.cmd.dstat;
+
+ card = CARD_FROM_CDEV(cdev);
+ if (!card)
+@@ -1124,6 +1118,19 @@ static void qeth_irq(struct ccw_device *
+ channel = &card->data;
+ QETH_CARD_TEXT(card, 5, "data");
+ }
++
++ if (qeth_intparm_is_iob(intparm))
++ iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
++
++ if (__qeth_check_irb_error(cdev, intparm, irb)) {
++ /* IO was terminated, free its resources. */
++ if (iob)
++ qeth_release_buffer(iob->channel, iob);
++ atomic_set(&channel->irq_pending, 0);
++ wake_up(&card->wait_q);
++ return;
++ }
++
+ atomic_set(&channel->irq_pending, 0);
+
+ if (irb->scsw.cmd.fctl & (SCSW_FCTL_CLEAR_FUNC))
+@@ -1147,6 +1154,10 @@ static void qeth_irq(struct ccw_device *
+ /* we don't have to handle this further */
+ intparm = 0;
+ }
++
++ cstat = irb->scsw.cmd.cstat;
++ dstat = irb->scsw.cmd.dstat;
++
+ if ((dstat & DEV_STAT_UNIT_EXCEP) ||
+ (dstat & DEV_STAT_UNIT_CHECK) ||
+ (cstat)) {
+@@ -1185,11 +1196,8 @@ static void qeth_irq(struct ccw_device *
+ channel->state == CH_STATE_UP)
+ __qeth_issue_next_read(card);
+
+- if (intparm) {
+- iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
+- if (iob->callback)
+- iob->callback(iob->channel, iob);
+- }
++ if (iob && iob->callback)
++ iob->callback(iob->channel, iob);
+
+ out:
+ wake_up(&card->wait_q);
+@@ -1812,8 +1820,8 @@ static int qeth_idx_activate_get_answer(
+ atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
+ QETH_DBF_TEXT(SETUP, 6, "noirqpnd");
+ spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+- rc = ccw_device_start(channel->ccwdev,
+- &channel->ccw, (addr_t) iob, 0, 0);
++ rc = ccw_device_start_timeout(channel->ccwdev, &channel->ccw,
++ (addr_t) iob, 0, 0, QETH_TIMEOUT);
+ spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+
+ if (rc) {
+@@ -1830,7 +1838,6 @@ static int qeth_idx_activate_get_answer(
+ if (channel->state != CH_STATE_UP) {
+ rc = -ETIME;
+ QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+- qeth_clear_cmd_buffers(channel);
+ } else
+ rc = 0;
+ return rc;
+@@ -1884,8 +1891,8 @@ static int qeth_idx_activate_channel(str
+ atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
+ QETH_DBF_TEXT(SETUP, 6, "noirqpnd");
+ spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+- rc = ccw_device_start(channel->ccwdev,
+- &channel->ccw, (addr_t) iob, 0, 0);
++ rc = ccw_device_start_timeout(channel->ccwdev, &channel->ccw,
++ (addr_t) iob, 0, 0, QETH_TIMEOUT);
+ spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+
+ if (rc) {
+@@ -1906,7 +1913,6 @@ static int qeth_idx_activate_channel(str
+ QETH_DBF_MESSAGE(2, "%s IDX activate timed out\n",
+ dev_name(&channel->ccwdev->dev));
+ QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME);
+- qeth_clear_cmd_buffers(channel);
+ return -ETIME;
+ }
+ return qeth_idx_activate_get_answer(channel, idx_reply_cb);
+@@ -2107,8 +2113,8 @@ int qeth_send_control_data(struct qeth_c
+
+ QETH_CARD_TEXT(card, 6, "noirqpnd");
+ spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
+- rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
+- (addr_t) iob, 0, 0);
++ rc = ccw_device_start_timeout(CARD_WDEV(card), &card->write.ccw,
++ (addr_t) iob, 0, 0, event_timeout);
+ spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
+ if (rc) {
+ QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: "
+@@ -2140,8 +2146,6 @@ int qeth_send_control_data(struct qeth_c
+ }
+ }
+
+- if (reply->rc == -EIO)
+- goto error;
+ rc = reply->rc;
+ qeth_put_reply(reply);
+ return rc;
+@@ -2152,9 +2156,6 @@ time_err:
+ list_del_init(&reply->list);
+ spin_unlock_irqrestore(&reply->card->lock, flags);
+ atomic_inc(&reply->received);
+-error:
+- atomic_set(&card->write.irq_pending, 0);
+- qeth_release_buffer(iob->channel, iob);
+ rc = reply->rc;
+ qeth_put_reply(reply);
+ return rc;
+--- a/drivers/s390/net/qeth_core_mpc.h
++++ b/drivers/s390/net/qeth_core_mpc.h
+@@ -34,6 +34,18 @@ extern unsigned char IPA_PDU_HEADER[];
+ #define QETH_HALT_CHANNEL_PARM -11
+ #define QETH_RCD_PARM -12
+
++static inline bool qeth_intparm_is_iob(unsigned long intparm)
++{
++ switch (intparm) {
++ case QETH_CLEAR_CHANNEL_PARM:
++ case QETH_HALT_CHANNEL_PARM:
++ case QETH_RCD_PARM:
++ case 0:
++ return false;
++ }
++ return true;
++}
++
+ /*****************************************************************************/
+ /* IP Assist related definitions */
+ /*****************************************************************************/
+--- a/drivers/s390/net/qeth_l2_main.c
++++ b/drivers/s390/net/qeth_l2_main.c
+@@ -1391,8 +1391,8 @@ static int qeth_osn_send_control_data(st
+ qeth_prepare_control_data(card, len, iob);
+ QETH_CARD_TEXT(card, 6, "osnoirqp");
+ spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
+- rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
+- (addr_t) iob, 0, 0);
++ rc = ccw_device_start_timeout(CARD_WDEV(card), &card->write.ccw,
++ (addr_t) iob, 0, 0, QETH_IPA_TIMEOUT);
+ spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
+ if (rc) {
+ QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: "
diff --git a/series.conf b/series.conf
index 53b06646a0..559956938d 100644
--- a/series.conf
+++ b/series.conf
@@ -15879,6 +15879,7 @@
patches.fixes/s390-qeth-avoid-control-io-completion-stalls
patches.arch/s390-qeth-handle-failure-on-workqueue-creation.patch
patches.arch/s390-qeth-fix-MAC-address-update-sequence.patch
+ patches.fixes/s390-qeth-fix-request-side-race-during-cmd-io-timeout
patches.suse/llc-delete-timers-synchronously-in-llc_sk_free.patch
patches.suse/net-ethernet-ti-cpsw-fix-tx-vlan-priority-mapping.patch
patches.suse/llc-fix-NULL-pointer-deref-for-SOCK_ZAPPED.patch