diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2020-08-27 03:55:53 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2020-08-27 03:55:52 -0700 |
commit | 09e08c4172e3bc01055d220b1c09c3fa7222fb6d (patch) | |
tree | 05ee7ef4347e8954fc23493bf27bb996e5f32aa1 | |
parent | 2aa52622e2d9a169a5df7acf86b5035b50b7a166 (diff) | |
parent | 43733cedc7186c44f323f857b12b5accb2f68af6 (diff) |
Merge "soc: qcom: ramdump: Abort user-space read if timed-out"LA.UM.8.13.r1-09800-SAIPAN.0
-rw-r--r-- | drivers/soc/qcom/ramdump.c | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/drivers/soc/qcom/ramdump.c b/drivers/soc/qcom/ramdump.c index 4746a9fea2a9..1555c4f44475 100644 --- a/drivers/soc/qcom/ramdump.c +++ b/drivers/soc/qcom/ramdump.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. */ #include <linux/kernel.h> @@ -17,6 +17,7 @@ #include <linux/elf.h> #include <linux/wait.h> #include <linux/cdev.h> +#include <linux/srcu.h> #include <linux/atomic.h> #include <soc/qcom/ramdump.h> #include <linux/dma-mapping.h> @@ -61,6 +62,8 @@ struct ramdump_device { char *elfcore_buf; unsigned long attrs; bool complete_ramdump; + bool abort_ramdump; + struct srcu_struct rd_srcu; }; static int ramdump_open(struct inode *inode, struct file *filep) @@ -160,15 +163,26 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count, size_t copy_size = 0, alignsize; unsigned char *alignbuf = NULL, *finalbuf = NULL; int ret = 0; + int srcu_idx; loff_t orig_pos = *pos; if ((filep->f_flags & O_NONBLOCK) && !entry->data_ready) return -EAGAIN; - ret = wait_event_interruptible(rd_dev->dump_wait_q, entry->data_ready); + ret = wait_event_interruptible(rd_dev->dump_wait_q, + (entry->data_ready || rd_dev->abort_ramdump)); if (ret) return ret; + srcu_idx = srcu_read_lock(&rd_dev->rd_srcu); + + if (rd_dev->abort_ramdump) { + pr_err("Ramdump(%s): Ramdump aborted\n", rd_dev->name); + rd_dev->ramdump_status = -1; + ret = -ETIME; + goto ramdump_done; + } + if (*pos < rd_dev->elfcore_size) { copy_size = rd_dev->elfcore_size - *pos; copy_size = min(copy_size, count); @@ -180,8 +194,10 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count, *pos += copy_size; count -= copy_size; buf += copy_size; - if (count == 0) + if (count == 0) { + srcu_read_unlock(&rd_dev->rd_srcu, srcu_idx); return copy_size; + } } addr = offset_translate(*pos - rd_dev->elfcore_size, rd_dev, @@ -258,12 +274,15 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count, pr_debug("Ramdump(%s): Read %zd bytes from address %lx.", rd_dev->name, copy_size, addr); + srcu_read_unlock(&rd_dev->rd_srcu, srcu_idx); + return *pos - orig_pos; ramdump_done: if (!vaddr && origdevice_mem) dma_unremap(rd_dev->dev->parent, origdevice_mem, copy_size); + srcu_read_unlock(&rd_dev->rd_srcu, srcu_idx); kfree(finalbuf); *pos = 0; reset_ramdump_entry(entry); @@ -368,6 +387,7 @@ void *create_ramdump_device(const char *dev_name, struct device *parent) mutex_init(&rd_dev->consumer_lock); atomic_set(&rd_dev->readers_left, 0); + init_srcu_struct(&rd_dev->rd_srcu); cdev_init(&rd_dev->cdev, &ramdump_file_ops); ret = cdev_add(&rd_dev->cdev, MKDEV(MAJOR(ramdump_dev), minor), 1); @@ -380,6 +400,7 @@ void *create_ramdump_device(const char *dev_name, struct device *parent) return (void *)rd_dev; fail_cdev_add: + cleanup_srcu_struct(&rd_dev->rd_srcu); mutex_destroy(&rd_dev->consumer_lock); device_unregister(rd_dev->dev); fail_return_minor: @@ -400,6 +421,7 @@ void destroy_ramdump_device(void *dev) cdev_del(&rd_dev->cdev); device_unregister(rd_dev->dev); + cleanup_srcu_struct(&rd_dev->rd_srcu); ida_simple_remove(&rd_minor_id, minor); kfree(rd_dev); } @@ -480,6 +502,7 @@ static int _do_ramdump(void *handle, struct ramdump_segment *segments, list_for_each_entry(entry, &rd_dev->consumer_list, list) entry->data_ready = true; rd_dev->ramdump_status = -1; + rd_dev->abort_ramdump = false; reinit_completion(&rd_dev->ramdump_complete); atomic_set(&rd_dev->readers_left, rd_dev->consumers); @@ -496,6 +519,11 @@ static int _do_ramdump(void *handle, struct ramdump_segment *segments, pr_err("Ramdump(%s): Timed out waiting for userspace.\n", rd_dev->name); ret = -EPIPE; + rd_dev->abort_ramdump = true; + + /* Wait for pending readers to complete (if any) */ + synchronize_srcu(&rd_dev->rd_srcu); + } else ret = (rd_dev->ramdump_status == 0) ? 0 : -EPIPE; @@ -609,6 +637,7 @@ static int _do_minidump(void *handle, struct ramdump_segment *segments, list_for_each_entry(entry, &rd_dev->consumer_list, list) entry->data_ready = true; rd_dev->ramdump_status = -1; + rd_dev->abort_ramdump = false; reinit_completion(&rd_dev->ramdump_complete); atomic_set(&rd_dev->readers_left, rd_dev->consumers); @@ -625,6 +654,10 @@ static int _do_minidump(void *handle, struct ramdump_segment *segments, pr_err("Ramdump(%s): Timed out waiting for userspace.\n", rd_dev->name); ret = -EPIPE; + rd_dev->abort_ramdump = true; + + /* Wait for pending readers to complete (if any) */ + synchronize_srcu(&rd_dev->rd_srcu); } else { ret = (rd_dev->ramdump_status == 0) ? 0 : -EPIPE; } |