* [PATCH v2 1/3] vmcore: Convert __read_vmcore to use an iov_iter
2021-12-13 14:19 [PATCH v2 0/3] Convert vmcore to use an iov_iter Matthew Wilcox (Oracle)
@ 2021-12-13 14:19 ` Matthew Wilcox (Oracle)
2021-12-13 14:19 ` [PATCH v2 2/3] vmcore: Convert read_from_oldmem() to take " Matthew Wilcox (Oracle)
2021-12-13 14:19 ` [PATCH v2 3/3] iov-kaddr Matthew Wilcox (Oracle)
2 siblings, 0 replies; 5+ messages in thread
From: Matthew Wilcox (Oracle) @ 2021-12-13 14:19 UTC (permalink / raw)
To: Baoquan He, Vivek Goyal, Dave Young, kexec
Cc: Matthew Wilcox (Oracle),
Tiezhu Yang, linux-kernel, Amit Daniel Kachhap,
Christoph Hellwig, linux-fsdevel
This gets rid of copy_to() and let us use proc_read_iter() instead
of proc_read().
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
fs/proc/vmcore.c | 81 +++++++++++++++++-------------------------------
1 file changed, 29 insertions(+), 52 deletions(-)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 958cad6476e6..7b25f568d20d 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -252,22 +252,8 @@ ssize_t __weak copy_oldmem_page_encrypted(struct iov_iter *iter,
return copy_oldmem_page(iter, pfn, csize, offset);
}
-/*
- * Copy to either kernel or user space
- */
-static int copy_to(void *target, void *src, size_t size, int userbuf)
-{
- if (userbuf) {
- if (copy_to_user((char __user *) target, src, size))
- return -EFAULT;
- } else {
- memcpy(target, src, size);
- }
- return 0;
-}
-
#ifdef CONFIG_PROC_VMCORE_DEVICE_DUMP
-static int vmcoredd_copy_dumps(void *dst, u64 start, size_t size, int userbuf)
+static int vmcoredd_copy_dumps(struct iov_iter *iter, u64 start, size_t size)
{
struct vmcoredd_node *dump;
u64 offset = 0;
@@ -280,14 +266,13 @@ static int vmcoredd_copy_dumps(void *dst, u64 start, size_t size, int userbuf)
if (start < offset + dump->size) {
tsz = min(offset + (u64)dump->size - start, (u64)size);
buf = dump->buf + start - offset;
- if (copy_to(dst, buf, tsz, userbuf)) {
+ if (copy_to_iter(buf, tsz, iter) < tsz) {
ret = -EFAULT;
goto out_unlock;
}
size -= tsz;
start += tsz;
- dst += tsz;
/* Leave now if buffer filled already */
if (!size)
@@ -343,33 +328,28 @@ static int vmcoredd_mmap_dumps(struct vm_area_struct *vma, unsigned long dst,
/* Read from the ELF header and then the crash dump. On error, negative value is
* returned otherwise number of bytes read are returned.
*/
-static ssize_t __read_vmcore(char *buffer, size_t buflen, loff_t *fpos,
- int userbuf)
+static ssize_t __read_vmcore(struct iov_iter *iter, loff_t *fpos)
{
ssize_t acc = 0, tmp;
size_t tsz;
u64 start;
struct vmcore *m = NULL;
- if (buflen == 0 || *fpos >= vmcore_size)
+ if (iter->count == 0 || *fpos >= vmcore_size)
return 0;
- /* trim buflen to not go beyond EOF */
- if (buflen > vmcore_size - *fpos)
- buflen = vmcore_size - *fpos;
+ iov_iter_truncate(iter, vmcore_size - *fpos);
/* Read ELF core header */
if (*fpos < elfcorebuf_sz) {
- tsz = min(elfcorebuf_sz - (size_t)*fpos, buflen);
- if (copy_to(buffer, elfcorebuf + *fpos, tsz, userbuf))
+ tsz = min(elfcorebuf_sz - (size_t)*fpos, iter->count);
+ if (copy_to_iter(elfcorebuf + *fpos, tsz, iter) < tsz)
return -EFAULT;
- buflen -= tsz;
*fpos += tsz;
- buffer += tsz;
acc += tsz;
/* leave now if filled buffer already */
- if (buflen == 0)
+ if (iter->count == 0)
return acc;
}
@@ -390,35 +370,31 @@ static ssize_t __read_vmcore(char *buffer, size_t buflen, loff_t *fpos,
/* Read device dumps */
if (*fpos < elfcorebuf_sz + vmcoredd_orig_sz) {
tsz = min(elfcorebuf_sz + vmcoredd_orig_sz -
- (size_t)*fpos, buflen);
+ (size_t)*fpos, iter->count);
start = *fpos - elfcorebuf_sz;
- if (vmcoredd_copy_dumps(buffer, start, tsz, userbuf))
+ if (vmcoredd_copy_dumps(iter, start, tsz))
return -EFAULT;
- buflen -= tsz;
*fpos += tsz;
- buffer += tsz;
acc += tsz;
/* leave now if filled buffer already */
- if (!buflen)
+ if (!iter->count)
return acc;
}
#endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
/* Read remaining elf notes */
- tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)*fpos, buflen);
+ tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)*fpos, iter->count);
kaddr = elfnotes_buf + *fpos - elfcorebuf_sz - vmcoredd_orig_sz;
- if (copy_to(buffer, kaddr, tsz, userbuf))
+ if (copy_to_iter(kaddr, tsz, iter) < tsz)
return -EFAULT;
- buflen -= tsz;
*fpos += tsz;
- buffer += tsz;
acc += tsz;
/* leave now if filled buffer already */
- if (buflen == 0)
+ if (iter->count == 0)
return acc;
}
@@ -426,19 +402,17 @@ static ssize_t __read_vmcore(char *buffer, size_t buflen, loff_t *fpos,
if (*fpos < m->offset + m->size) {
tsz = (size_t)min_t(unsigned long long,
m->offset + m->size - *fpos,
- buflen);
+ iter->count);
start = m->paddr + *fpos - m->offset;
- tmp = read_from_oldmem(buffer, tsz, &start,
- userbuf, cc_platform_has(CC_ATTR_MEM_ENCRYPT));
+ tmp = read_from_oldmem_iter(iter, tsz, &start,
+ cc_platform_has(CC_ATTR_MEM_ENCRYPT));
if (tmp < 0)
return tmp;
- buflen -= tsz;
*fpos += tsz;
- buffer += tsz;
acc += tsz;
/* leave now if filled buffer already */
- if (buflen == 0)
+ if (iter->count == 0)
return acc;
}
}
@@ -446,15 +420,14 @@ static ssize_t __read_vmcore(char *buffer, size_t buflen, loff_t *fpos,
return acc;
}
-static ssize_t read_vmcore(struct file *file, char __user *buffer,
- size_t buflen, loff_t *fpos)
+static ssize_t read_vmcore(struct kiocb *iocb, struct iov_iter *iter)
{
- return __read_vmcore((__force char *) buffer, buflen, fpos, 1);
+ return __read_vmcore(iter, &iocb->ki_pos);
}
/*
* The vmcore fault handler uses the page cache and fills data using the
- * standard __vmcore_read() function.
+ * standard __read_vmcore() function.
*
* On s390 the fault handler is used for memory regions that can't be mapped
* directly with remap_pfn_range().
@@ -464,9 +437,10 @@ static vm_fault_t mmap_vmcore_fault(struct vm_fault *vmf)
#ifdef CONFIG_S390
struct address_space *mapping = vmf->vma->vm_file->f_mapping;
pgoff_t index = vmf->pgoff;
+ struct iov_iter iter;
+ struct kvec kvec;
struct page *page;
loff_t offset;
- char *buf;
int rc;
page = find_or_create_page(mapping, index, GFP_KERNEL);
@@ -474,8 +448,11 @@ static vm_fault_t mmap_vmcore_fault(struct vm_fault *vmf)
return VM_FAULT_OOM;
if (!PageUptodate(page)) {
offset = (loff_t) index << PAGE_SHIFT;
- buf = __va((page_to_pfn(page) << PAGE_SHIFT));
- rc = __read_vmcore(buf, PAGE_SIZE, &offset, 0);
+ kvec.iov_base = page_address(page);
+ kvec.iov_len = PAGE_SIZE;
+ iov_iter_kvec(&iter, READ, &kvec, 1, PAGE_SIZE);
+
+ rc = __read_vmcore(&iter, &offset);
if (rc < 0) {
unlock_page(page);
put_page(page);
@@ -725,7 +702,7 @@ static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
static const struct proc_ops vmcore_proc_ops = {
.proc_open = open_vmcore,
- .proc_read = read_vmcore,
+ .proc_read_iter = read_vmcore,
.proc_lseek = default_llseek,
.proc_mmap = mmap_vmcore,
};
--
2.33.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 2/3] vmcore: Convert read_from_oldmem() to take an iov_iter
2021-12-13 14:19 [PATCH v2 0/3] Convert vmcore to use an iov_iter Matthew Wilcox (Oracle)
2021-12-13 14:19 ` [PATCH v2 1/3] vmcore: Convert __read_vmcore " Matthew Wilcox (Oracle)
@ 2021-12-13 14:19 ` Matthew Wilcox (Oracle)
2021-12-13 14:19 ` [PATCH v2 3/3] iov-kaddr Matthew Wilcox (Oracle)
2 siblings, 0 replies; 5+ messages in thread
From: Matthew Wilcox (Oracle) @ 2021-12-13 14:19 UTC (permalink / raw)
To: Baoquan He, Vivek Goyal, Dave Young, kexec
Cc: Matthew Wilcox (Oracle),
Tiezhu Yang, linux-kernel, Amit Daniel Kachhap,
Christoph Hellwig, linux-fsdevel
Remove the read_from_oldmem() wrapper introduced earlier and convert
all the remaining callers to pass an iov_iter.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
arch/x86/kernel/crash_dump_64.c | 7 +++++-
fs/proc/vmcore.c | 40 +++++++++++++--------------------
include/linux/crash_dump.h | 10 ++++-----
3 files changed, 25 insertions(+), 32 deletions(-)
diff --git a/arch/x86/kernel/crash_dump_64.c b/arch/x86/kernel/crash_dump_64.c
index f922d51c9d1f..0fa87648e55c 100644
--- a/arch/x86/kernel/crash_dump_64.c
+++ b/arch/x86/kernel/crash_dump_64.c
@@ -55,6 +55,11 @@ ssize_t copy_oldmem_page_encrypted(struct iov_iter *iter, unsigned long pfn,
ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos)
{
- return read_from_oldmem(buf, count, ppos, 0,
+ struct kvec kvec = { .iov_base = buf, .iov_len = count };
+ struct iov_iter iter;
+
+ iov_iter_kvec(&iter, READ, &kvec, 1, count);
+
+ return read_from_oldmem(&iter, count, ppos,
cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT));
}
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 7b25f568d20d..bee05b40196b 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -133,7 +133,7 @@ static int open_vmcore(struct inode *inode, struct file *file)
}
/* Reads a page from the oldmem device from given offset. */
-static ssize_t read_from_oldmem_iter(struct iov_iter *iter, size_t count,
+ssize_t read_from_oldmem(struct iov_iter *iter, size_t count,
u64 *ppos, bool encrypted)
{
unsigned long pfn, offset;
@@ -181,27 +181,6 @@ static ssize_t read_from_oldmem_iter(struct iov_iter *iter, size_t count,
return read;
}
-ssize_t read_from_oldmem(char *buf, size_t count,
- u64 *ppos, int userbuf,
- bool encrypted)
-{
- struct iov_iter iter;
- struct iovec iov;
- struct kvec kvec;
-
- if (userbuf) {
- iov.iov_base = (__force void __user *)buf;
- iov.iov_len = count;
- iov_iter_init(&iter, READ, &iov, 1, count);
- } else {
- kvec.iov_base = buf;
- kvec.iov_len = count;
- iov_iter_kvec(&iter, READ, &kvec, 1, count);
- }
-
- return read_from_oldmem_iter(&iter, count, ppos, encrypted);
-}
-
/*
* Architectures may override this function to allocate ELF header in 2nd kernel
*/
@@ -221,7 +200,12 @@ void __weak elfcorehdr_free(unsigned long long addr)
*/
ssize_t __weak elfcorehdr_read(char *buf, size_t count, u64 *ppos)
{
- return read_from_oldmem(buf, count, ppos, 0, false);
+ struct kvec kvec = { .iov_base = buf, .iov_len = count };
+ struct iov_iter iter;
+
+ iov_iter_kvec(&iter, READ, &kvec, 1, count);
+
+ return read_from_oldmem(&iter, count, ppos, false);
}
/*
@@ -229,7 +213,13 @@ ssize_t __weak elfcorehdr_read(char *buf, size_t count, u64 *ppos)
*/
ssize_t __weak elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos)
{
- return read_from_oldmem(buf, count, ppos, 0, cc_platform_has(CC_ATTR_MEM_ENCRYPT));
+ struct kvec kvec = { .iov_base = buf, .iov_len = count };
+ struct iov_iter iter;
+
+ iov_iter_kvec(&iter, READ, &kvec, 1, count);
+
+ return read_from_oldmem(&iter, count, ppos,
+ cc_platform_has(CC_ATTR_MEM_ENCRYPT));
}
/*
@@ -404,7 +394,7 @@ static ssize_t __read_vmcore(struct iov_iter *iter, loff_t *fpos)
m->offset + m->size - *fpos,
iter->count);
start = m->paddr + *fpos - m->offset;
- tmp = read_from_oldmem_iter(iter, tsz, &start,
+ tmp = read_from_oldmem(iter, tsz, &start,
cc_platform_has(CC_ATTR_MEM_ENCRYPT));
if (tmp < 0)
return tmp;
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
index a1cf7d5c03c7..0f3a656293b0 100644
--- a/include/linux/crash_dump.h
+++ b/include/linux/crash_dump.h
@@ -134,13 +134,11 @@ static inline int vmcore_add_device_dump(struct vmcoredd_data *data)
#endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
#ifdef CONFIG_PROC_VMCORE
-ssize_t read_from_oldmem(char *buf, size_t count,
- u64 *ppos, int userbuf,
- bool encrypted);
+ssize_t read_from_oldmem(struct iov_iter *iter, size_t count,
+ u64 *ppos, bool encrypted);
#else
-static inline ssize_t read_from_oldmem(char *buf, size_t count,
- u64 *ppos, int userbuf,
- bool encrypted)
+static inline ssize_t read_from_oldmem(struct iov_iter *iter, size_t count,
+ u64 *ppos, bool encrypted)
{
return -EOPNOTSUPP;
}
--
2.33.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 3/3] iov-kaddr
2021-12-13 14:19 [PATCH v2 0/3] Convert vmcore to use an iov_iter Matthew Wilcox (Oracle)
2021-12-13 14:19 ` [PATCH v2 1/3] vmcore: Convert __read_vmcore " Matthew Wilcox (Oracle)
2021-12-13 14:19 ` [PATCH v2 2/3] vmcore: Convert read_from_oldmem() to take " Matthew Wilcox (Oracle)
@ 2021-12-13 14:19 ` Matthew Wilcox (Oracle)
2021-12-13 14:34 ` Matthew Wilcox
2 siblings, 1 reply; 5+ messages in thread
From: Matthew Wilcox (Oracle) @ 2021-12-13 14:19 UTC (permalink / raw)
To: Baoquan He, Vivek Goyal, Dave Young, kexec
Cc: Matthew Wilcox (Oracle),
Tiezhu Yang, linux-kernel, Amit Daniel Kachhap,
Christoph Hellwig, linux-fsdevel
---
fs/9p/vfs_dir.c | 5 +----
fs/9p/xattr.c | 6 ++----
include/linux/uio.h | 9 +++++++++
lib/iov_iter.c | 32 ++++++++++++++++++++++++++++++++
4 files changed, 44 insertions(+), 8 deletions(-)
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 8c854d8cb0cd..cad6c24f9f0d 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -90,7 +90,6 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
struct p9_fid *fid;
int buflen;
struct p9_rdir *rdir;
- struct kvec kvec;
p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
fid = file->private_data;
@@ -100,15 +99,13 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
rdir = v9fs_alloc_rdir_buf(file, buflen);
if (!rdir)
return -ENOMEM;
- kvec.iov_base = rdir->buf;
- kvec.iov_len = buflen;
while (1) {
if (rdir->tail == rdir->head) {
struct iov_iter to;
int n;
- iov_iter_kvec(&to, READ, &kvec, 1, buflen);
+ iov_iter_kaddr(&to, READ, rdir->buf, buflen);
n = p9_client_read(file->private_data, ctx->pos, &to,
&err);
if (err)
diff --git a/fs/9p/xattr.c b/fs/9p/xattr.c
index a824441b95a2..6fb0e7640605 100644
--- a/fs/9p/xattr.c
+++ b/fs/9p/xattr.c
@@ -20,11 +20,10 @@ ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name,
ssize_t retval;
u64 attr_size;
struct p9_fid *attr_fid;
- struct kvec kvec = {.iov_base = buffer, .iov_len = buffer_size};
struct iov_iter to;
int err;
- iov_iter_kvec(&to, READ, &kvec, 1, buffer_size);
+ iov_iter_kaddr(&to, READ, buffer, buffer_size);
attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
if (IS_ERR(attr_fid)) {
@@ -105,11 +104,10 @@ int v9fs_xattr_set(struct dentry *dentry, const char *name,
int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name,
const void *value, size_t value_len, int flags)
{
- struct kvec kvec = {.iov_base = (void *)value, .iov_len = value_len};
struct iov_iter from;
int retval, err;
- iov_iter_kvec(&from, WRITE, &kvec, 1, value_len);
+ iov_iter_kaddr(&from, WRITE, (void *)value, value_len);
p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu flags = %d\n",
name, value_len, flags);
diff --git a/include/linux/uio.h b/include/linux/uio.h
index 6350354f97e9..cedbc1ca5c15 100644
--- a/include/linux/uio.h
+++ b/include/linux/uio.h
@@ -23,6 +23,7 @@ enum iter_type {
ITER_KVEC,
ITER_BVEC,
ITER_PIPE,
+ ITER_KADDR,
ITER_XARRAY,
ITER_DISCARD,
};
@@ -43,6 +44,7 @@ struct iov_iter {
const struct iovec *iov;
const struct kvec *kvec;
const struct bio_vec *bvec;
+ void *kaddr;
struct xarray *xarray;
struct pipe_inode_info *pipe;
};
@@ -79,6 +81,11 @@ static inline bool iov_iter_is_kvec(const struct iov_iter *i)
return iov_iter_type(i) == ITER_KVEC;
}
+static inline bool iov_iter_is_kaddr(const struct iov_iter *i)
+{
+ return iov_iter_type(i) == ITER_KVEC;
+}
+
static inline bool iov_iter_is_bvec(const struct iov_iter *i)
{
return iov_iter_type(i) == ITER_BVEC;
@@ -236,6 +243,8 @@ void iov_iter_init(struct iov_iter *i, unsigned int direction, const struct iove
unsigned long nr_segs, size_t count);
void iov_iter_kvec(struct iov_iter *i, unsigned int direction, const struct kvec *kvec,
unsigned long nr_segs, size_t count);
+void iov_iter_kaddr(struct iov_iter *i, unsigned int direction, void *kaddr,
+ size_t count);
void iov_iter_bvec(struct iov_iter *i, unsigned int direction, const struct bio_vec *bvec,
unsigned long nr_segs, size_t count);
void iov_iter_pipe(struct iov_iter *i, unsigned int direction, struct pipe_inode_info *pipe,
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 66a740e6e153..64e6bc33176a 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -38,6 +38,22 @@
n = off; \
}
+#define iterate_kaddr(i, n, base, len, off, STEP) { \
+ void *base; \
+ size_t len; \
+ size_t off = 0; \
+ size_t skip = i->iov_offset; \
+ len = min(n, i->count - skip); \
+ if (likely(len)) { \
+ base = i->kaddr + skip; \
+ len -= (STEP); \
+ off += len; \
+ skip += len; \
+ } \
+ i->iov_offset = skip; \
+ n = off; \
+}
+
#define iterate_bvec(i, n, base, len, off, p, STEP) { \
size_t off = 0; \
unsigned skip = i->iov_offset; \
@@ -136,6 +152,8 @@ __out: \
kvec, (K)) \
i->nr_segs -= kvec - i->kvec; \
i->kvec = kvec; \
+ } else if (iov_iter_is_kaddr(i)) { \
+ iterate_kaddr(i, n, base, len, off, (K)) \
} else if (iov_iter_is_xarray(i)) { \
void *base; \
size_t len; \
@@ -1185,6 +1203,20 @@ void iov_iter_kvec(struct iov_iter *i, unsigned int direction,
}
EXPORT_SYMBOL(iov_iter_kvec);
+void iov_iter_kaddr(struct iov_iter *i, unsigned int direction,
+ void *kaddr, size_t count)
+{
+ WARN_ON(direction & ~(READ | WRITE));
+ *i = (struct iov_iter){
+ .iter_type = ITER_KADDR,
+ .data_source = direction,
+ .kaddr = kaddr,
+ .iov_offset = 0,
+ .count = count
+ };
+}
+EXPORT_SYMBOL(iov_iter_kaddr);
+
void iov_iter_bvec(struct iov_iter *i, unsigned int direction,
const struct bio_vec *bvec, unsigned long nr_segs,
size_t count)
--
2.33.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 3/3] iov-kaddr
2021-12-13 14:19 ` [PATCH v2 3/3] iov-kaddr Matthew Wilcox (Oracle)
@ 2021-12-13 14:34 ` Matthew Wilcox
0 siblings, 0 replies; 5+ messages in thread
From: Matthew Wilcox @ 2021-12-13 14:34 UTC (permalink / raw)
To: Baoquan He, Vivek Goyal, Dave Young, kexec
Cc: Tiezhu Yang, linux-kernel, Amit Daniel Kachhap,
Christoph Hellwig, linux-fsdevel
On Mon, Dec 13, 2021 at 02:19:07PM +0000, Matthew Wilcox (Oracle) wrote:
> ---
> fs/9p/vfs_dir.c | 5 +----
> fs/9p/xattr.c | 6 ++----
> include/linux/uio.h | 9 +++++++++
> lib/iov_iter.c | 32 ++++++++++++++++++++++++++++++++
> 4 files changed, 44 insertions(+), 8 deletions(-)
Ugh, this was NOT supposed to go out. Sorry, I'll do a v3.
^ permalink raw reply [flat|nested] 5+ messages in thread