summaryrefslogtreecommitdiff
path: root/drivers/s390/char/sclp_sd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/char/sclp_sd.c')
-rw-r--r--drivers/s390/char/sclp_sd.c30
1 files changed, 23 insertions, 7 deletions
diff --git a/drivers/s390/char/sclp_sd.c b/drivers/s390/char/sclp_sd.c
index f9e164be7568..8524c14affed 100644
--- a/drivers/s390/char/sclp_sd.c
+++ b/drivers/s390/char/sclp_sd.c
@@ -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;
@@ -194,6 +197,10 @@ static int sclp_sd_sync(unsigned long page, u8 eq, u8 di, u64 sat, u64 sa,
struct sclp_sd_evbuf *evbuf;
int rc;
+ if (!sclp_sd_register.sclp_send_mask ||
+ !sclp_sd_register.sclp_receive_mask)
+ return -EIO;
+
sclp_sd_listener_init(&listener, __pa(sccb));
sclp_sd_listener_add(&listener);
@@ -230,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) {
@@ -319,9 +329,15 @@ 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)
- sclp_sd_sync(page, SD_EQ_HALT, di, 0, 0, NULL, NULL);
+ /* 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);
+ data = NULL;
+ asce = 0;
+ }
+ }
vfree(data);
goto out;
}
@@ -460,7 +476,7 @@ static struct kobj_type sclp_sd_file_ktype = {
* on EOF.
*/
static ssize_t data_read(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buffer,
+ const struct bin_attribute *attr, char *buffer,
loff_t off, size_t size)
{
struct sclp_sd_file *sd_file = to_sd_file(kobj);
@@ -523,7 +539,7 @@ static __init struct sclp_sd_file *sclp_sd_file_create(const char *name, u8 di)
sysfs_bin_attr_init(&sd_file->data_attr);
sd_file->data_attr.attr.name = "data";
sd_file->data_attr.attr.mode = 0444;
- sd_file->data_attr.read = data_read;
+ sd_file->data_attr.read_new = data_read;
rc = sysfs_create_bin_file(&sd_file->kobj, &sd_file->data_attr);
if (rc) {