soc: qcom: ramdump: Abort user-space read if timed-out
It's possible that the user-space process can be woken up very late to collect the ramdumps by which time, the ramdump collection timer would have expired. Following this, the PIL driver unmaps the memory and continues. The user-space process has no way to know about this and can make an attempt to read the unmapped memory, thus resulting in a data abort. Hence, notify the user-space process that the ramdump timer has expired such that it can reset its state machine. Also add the srcu related symbols to the allowed-list and update the ABI snapshot accordingly. Change-Id: Idb92d98406a9032c999c82e2089213883c5a65eb Signed-off-by: Raghavendra Rao Ananta <rananta@codeaurora.org>
This commit is contained in:
parent
1e4aef37ea
commit
aec59fab94
File diff suppressed because it is too large
Load Diff
@ -1098,6 +1098,7 @@
|
||||
init_net
|
||||
__init_rwsem
|
||||
init_special_inode
|
||||
init_srcu_struct
|
||||
init_timer_key
|
||||
init_uts_ns
|
||||
init_wait_entry
|
||||
@ -2275,6 +2276,8 @@
|
||||
srcu_notifier_call_chain
|
||||
srcu_notifier_chain_register
|
||||
srcu_notifier_chain_unregister
|
||||
__srcu_read_lock
|
||||
__srcu_read_unlock
|
||||
sscanf
|
||||
__stack_chk_fail
|
||||
__stack_chk_guard
|
||||
@ -2317,6 +2320,7 @@
|
||||
synchronize_irq
|
||||
synchronize_net
|
||||
synchronize_rcu
|
||||
synchronize_srcu
|
||||
syscon_node_to_regmap
|
||||
syscon_regmap_lookup_by_phandle
|
||||
sysfs_create_bin_file
|
||||
|
@ -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/of.h>
|
||||
@ -59,6 +60,8 @@ struct ramdump_device {
|
||||
size_t elfcore_size;
|
||||
char *elfcore_buf;
|
||||
bool complete_ramdump;
|
||||
bool abort_ramdump;
|
||||
struct srcu_struct rd_srcu;
|
||||
};
|
||||
|
||||
static int ramdump_open(struct inode *inode, struct file *filep)
|
||||
@ -158,15 +161,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);
|
||||
@ -178,8 +192,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,
|
||||
@ -252,9 +268,12 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count,
|
||||
pr_debug("Ramdump(%s): Read %zd bytes from address %lx.\n",
|
||||
rd_dev->name, copy_size, addr);
|
||||
|
||||
srcu_read_unlock(&rd_dev->rd_srcu, srcu_idx);
|
||||
|
||||
return *pos - orig_pos;
|
||||
|
||||
ramdump_done:
|
||||
srcu_read_unlock(&rd_dev->rd_srcu, srcu_idx);
|
||||
kfree(finalbuf);
|
||||
*pos = 0;
|
||||
reset_ramdump_entry(entry);
|
||||
@ -361,6 +380,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);
|
||||
@ -373,6 +393,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:
|
||||
@ -393,6 +414,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);
|
||||
}
|
||||
@ -473,6 +495,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);
|
||||
@ -489,6 +512,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;
|
||||
|
||||
@ -602,6 +630,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);
|
||||
@ -618,6 +647,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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user