]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
s390/sclp: Add timeout to Store Data requests
authorPeter Oberparleiter <oberpar@linux.ibm.com>
Thu, 20 Jun 2024 12:20:28 +0000 (14:20 +0200)
committerAlexander Gordeev <agordeev@linux.ibm.com>
Mon, 1 Jul 2024 15:47:01 +0000 (17:47 +0200)
Due to a bug in some firmware versions, Store Data requests might not
get an event response in certain situations. As a result, the boot
process will be blocked indefinitely.

Fix this by introducing timeout handling for Store Data requests. In
case a timeout occurs, the Store Data operation is halted and no data
is retrieved from the SCLP facility.

Note: A minority of installed systems rely on Store Data result for
device auto-configuration. These systems will fail to boot in case of a
Store Data timeout and will need to be switched to manual device
configuration as workaround.

Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
drivers/s390/char/sclp_sd.c

index 322700b96207da03aea5f1a15df2e043c8e4a26a..c2dc9aadb7d2c213c93c4fb5e4cdf66d18fc1f78 100644 (file)
@@ -9,6 +9,7 @@
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
 #include <linux/completion.h>
+#include <linux/jiffies.h>
 #include <linux/kobject.h>
 #include <linux/list.h>
 #include <linux/printk.h>
@@ -28,6 +29,8 @@
 
 #define SD_DI_CONFIG           3
 
+#define SD_TIMEOUT             msecs_to_jiffies(30000)
+
 struct sclp_sd_evbuf {
        struct evbuf_header hdr;
        u8 eq;
@@ -234,9 +237,12 @@ static int sclp_sd_sync(unsigned long page, u8 eq, u8 di, u64 sat, u64 sa,
                goto out;
        }
        if (!(evbuf->rflags & 0x80)) {
-               rc = wait_for_completion_interruptible(&listener.completion);
-               if (rc)
+               rc = wait_for_completion_interruptible_timeout(&listener.completion, SD_TIMEOUT);
+               if (rc == 0)
+                       rc = -ETIME;
+               if (rc < 0)
                        goto out;
+               rc = 0;
                evbuf = &listener.evbuf;
        }
        switch (evbuf->status) {
@@ -323,8 +329,8 @@ static int sclp_sd_store_data(struct sclp_sd_data *result, u8 di)
        rc = sclp_sd_sync(page, SD_EQ_STORE_DATA, di, asce, (u64) data, &dsize,
                          &esize);
        if (rc) {
-               /* Cancel running request if interrupted */
-               if (rc == -ERESTARTSYS) {
+               /* Cancel running request if interrupted or timed out */
+               if (rc == -ERESTARTSYS || rc == -ETIME) {
                        if (sclp_sd_sync(page, SD_EQ_HALT, di, 0, 0, NULL, NULL)) {
                                pr_warn("Could not stop Store Data request - leaking at least %zu bytes\n",
                                        (size_t)dsize * PAGE_SIZE);