Implement ->proc_read_buf() so procfs copies what is read to userspace after it unpinned the entry. __read_vmcore() fills procfs' buffer through a kvec iov_iter. So a read goes through that buffer now instead of straight from the old memory into the reader's, which is what splice() did already. mmap() isn't affected. On ppc64 a machine check while reading the old memory used to be recovered through the exception table of copy_to_user(), by accident. copy_oldmem_page() copies with _copy_mc_to_iter() now, so a read through procfs' buffer recovers from it as well.
The buffer is 128k, which keeps the entry pinned for one such piece at a time, and /proc/vmcore asks for PROC_ENTRY_FULL_READS so that a larger read is filled in pieces. kexec-tools treats a short read of it as fatal. A read that faults on its buffer in a later piece returns the pieces before it now instead of failing with -EFAULT. fadump removes /proc/vmcore when its memory is released and that no longer waits for a reader that faults on its buffer. Signed-off-by: Christian Brauner (Amutable) <[email protected]> --- fs/proc/vmcore.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index ccb795b85509..1c1e71231f4e 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c @@ -27,6 +27,7 @@ #include <linux/mutex.h> #include <linux/vmalloc.h> #include <linux/pagemap.h> +#include <linux/sizes.h> #include <linux/uio.h> #include <linux/cc_platform.h> #include <asm/io.h> @@ -427,9 +428,14 @@ static ssize_t __read_vmcore(struct iov_iter *iter, loff_t *fpos) return acc; } -static ssize_t read_vmcore(struct kiocb *iocb, struct iov_iter *iter) +static ssize_t read_vmcore(struct file *file, char *buf, size_t count, + loff_t *ppos) { - return __read_vmcore(iter, &iocb->ki_pos); + struct kvec kvec = { .iov_base = buf, .iov_len = count }; + struct iov_iter iter; + + iov_iter_kvec(&iter, ITER_DEST, &kvec, 1, count); + return __read_vmcore(&iter, ppos); } /** @@ -709,9 +715,11 @@ static int mmap_vmcore(struct file *file, struct vm_area_struct *vma) #endif static const struct proc_ops vmcore_proc_ops = { + .proc_flags = PROC_ENTRY_FULL_READS, .proc_open = open_vmcore, .proc_release = release_vmcore, - .proc_read_iter = read_vmcore, + .proc_read_buf = read_vmcore, + .proc_read_size = SZ_128K, .proc_lseek = default_llseek, .proc_mmap = mmap_vmcore, }; -- 2.53.0
