seq_file: add seq_read_iter
authorChristoph Hellwig <hch@lst.de>
Wed, 4 Nov 2020 08:27:33 +0000 (09:27 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 6 Nov 2020 18:05:18 +0000 (10:05 -0800)
iov_iter based variant for reading a seq_file.  seq_read is
reimplemented on top of the iter variant.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Tested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/seq_file.c
include/linux/seq_file.h

index 31219c1..3b20e21 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/printk.h>
 #include <linux/string_helpers.h>
+#include <linux/uio.h>
 
 #include <linux/uaccess.h>
 #include <asm/page.h>
@@ -146,7 +147,28 @@ Eoverflow:
  */
 ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
 {
-       struct seq_file *m = file->private_data;
+       struct iovec iov = { .iov_base = buf, .iov_len = size};
+       struct kiocb kiocb;
+       struct iov_iter iter;
+       ssize_t ret;
+
+       init_sync_kiocb(&kiocb, file);
+       iov_iter_init(&iter, READ, &iov, 1, size);
+
+       kiocb.ki_pos = *ppos;
+       ret = seq_read_iter(&kiocb, &iter);
+       *ppos = kiocb.ki_pos;
+       return ret;
+}
+EXPORT_SYMBOL(seq_read);
+
+/*
+ * Ready-made ->f_op->read_iter()
+ */
+ssize_t seq_read_iter(struct kiocb *iocb, struct iov_iter *iter)
+{
+       struct seq_file *m = iocb->ki_filp->private_data;
+       size_t size = iov_iter_count(iter);
        size_t copied = 0;
        size_t n;
        void *p;
@@ -158,14 +180,14 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
         * if request is to read from zero offset, reset iterator to first
         * record as it might have been already advanced by previous requests
         */
-       if (*ppos == 0) {
+       if (iocb->ki_pos == 0) {
                m->index = 0;
                m->count = 0;
        }
 
-       /* Don't assume *ppos is where we left it */
-       if (unlikely(*ppos != m->read_pos)) {
-               while ((err = traverse(m, *ppos)) == -EAGAIN)
+       /* Don't assume ki_pos is where we left it */
+       if (unlikely(iocb->ki_pos != m->read_pos)) {
+               while ((err = traverse(m, iocb->ki_pos)) == -EAGAIN)
                        ;
                if (err) {
                        /* With prejudice... */
@@ -174,7 +196,7 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
                        m->count = 0;
                        goto Done;
                } else {
-                       m->read_pos = *ppos;
+                       m->read_pos = iocb->ki_pos;
                }
        }
 
@@ -187,13 +209,11 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
        /* if not empty - flush it first */
        if (m->count) {
                n = min(m->count, size);
-               err = copy_to_user(buf, m->buf + m->from, n);
-               if (err)
+               if (copy_to_iter(m->buf + m->from, n, iter) != n)
                        goto Efault;
                m->count -= n;
                m->from += n;
                size -= n;
-               buf += n;
                copied += n;
                if (!size)
                        goto Done;
@@ -254,8 +274,7 @@ Fill:
        }
        m->op->stop(m, p);
        n = min(m->count, size);
-       err = copy_to_user(buf, m->buf, n);
-       if (err)
+       if (copy_to_iter(m->buf, n, iter) != n)
                goto Efault;
        copied += n;
        m->count -= n;
@@ -264,7 +283,7 @@ Done:
        if (!copied)
                copied = err;
        else {
-               *ppos += copied;
+               iocb->ki_pos += copied;
                m->read_pos += copied;
        }
        mutex_unlock(&m->lock);
@@ -276,7 +295,7 @@ Efault:
        err = -EFAULT;
        goto Done;
 }
-EXPORT_SYMBOL(seq_read);
+EXPORT_SYMBOL(seq_read_iter);
 
 /**
  *     seq_lseek -     ->llseek() method for sequential files.
index 813614d..b83b3ae 100644 (file)
@@ -107,6 +107,7 @@ void seq_pad(struct seq_file *m, char c);
 char *mangle_path(char *s, const char *p, const char *esc);
 int seq_open(struct file *, const struct seq_operations *);
 ssize_t seq_read(struct file *, char __user *, size_t, loff_t *);
+ssize_t seq_read_iter(struct kiocb *iocb, struct iov_iter *iter);
 loff_t seq_lseek(struct file *, loff_t, int);
 int seq_release(struct inode *, struct file *);
 int seq_write(struct seq_file *seq, const void *data, size_t len);