Blob Blame History Raw
From: Julian Wiedmann <jwi@linux.ibm.com>
Date: Wed, 16 May 2018 09:37:25 +0200
Subject: s390/qdio: reset old sbal_state flags
Patch-mainline: v4.19-rc1
Git-commit: 64e03ff72623b8c2ea89ca3cb660094e019ed4ae
References: LTC#171525, bsc#1106948

Description:  qdio: reset old sbal_state flags
Symptom:      af_iucv socket using HiperSockets may stall.
Problem:      When allocating a new AOB fails, handle_outbound() is
              still capable of transmitting the selected buffer
              (just without async completion).
              But if a previous transfer on this queue slot used
              async completion, its sbal_state flags field is still set
              to QDIO_OUTBUF_STATE_FLAG_PENDING.
              So when the upper layer driver sees this stale flag, it
              expects an async completion that never happens.
Solution:     Unconditionally clear the buffer's flags field.
Reproduction: Error inject, simulating out-of-memory.
Upstream-ID:  64e03ff72623b8c2ea89ca3cb660094e019ed4ae
Problem-ID:   171525

Upstream-Description:

              s390/qdio: reset old sbal_state flags

              When allocating a new AOB fails, handle_outbound() is still capable of
              transmitting the selected buffer (just without async completion).

              But if a previous transfer on this queue slot used async completion, its
              sbal_state flags field is still set to QDIO_OUTBUF_STATE_FLAG_PENDING.
              So when the upper layer driver sees this stale flag, it expects an async
              completion that never happens.

              Fix this by unconditionally clearing the flags field.

              Fixes: 104ea556ee7f ("qdio: support asynchronous delivery of storage blocks")
              Cc: <stable@vger.kernel.org> #v3.2+
              Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
              Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>


Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 arch/s390/include/asm/qdio.h |    1 -
 drivers/s390/cio/qdio_main.c |    5 ++---
 2 files changed, 2 insertions(+), 4 deletions(-)

--- a/arch/s390/include/asm/qdio.h
+++ b/arch/s390/include/asm/qdio.h
@@ -261,7 +261,6 @@ struct qdio_outbuf_state {
 	void *user;
 };
 
-#define QDIO_OUTBUF_STATE_FLAG_NONE	0x00
 #define QDIO_OUTBUF_STATE_FLAG_PENDING	0x01
 
 #define CHSC_AC1_INITIATE_INPUTQ	0x80
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -641,21 +641,20 @@ static inline unsigned long qdio_aob_for
 	unsigned long phys_aob = 0;
 
 	if (!q->use_cq)
-		goto out;
+		return 0;
 
 	if (!q->aobs[bufnr]) {
 		struct qaob *aob = qdio_allocate_aob();
 		q->aobs[bufnr] = aob;
 	}
 	if (q->aobs[bufnr]) {
-		q->sbal_state[bufnr].flags = QDIO_OUTBUF_STATE_FLAG_NONE;
 		q->sbal_state[bufnr].aob = q->aobs[bufnr];
 		q->aobs[bufnr]->user1 = (u64) q->sbal_state[bufnr].user;
 		phys_aob = virt_to_phys(q->aobs[bufnr]);
 		WARN_ON_ONCE(phys_aob & 0xFF);
 	}
 
-out:
+	q->sbal_state[bufnr].flags = 0;
 	return phys_aob;
 }