Skip to content

Commit d4d5071

Browse files
Christoph Hellwigtorvalds
authored andcommitted
seq_file: add seq_read_iter
iov_iter based variant for reading a seq_file. seq_read is reimplemented on top of the iter variant. Signed-off-by: Christoph Hellwig <[email protected]> Tested-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 3cea11c commit d4d5071

File tree

2 files changed

+33
-13
lines changed

2 files changed

+33
-13
lines changed

fs/seq_file.c

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/mm.h>
1919
#include <linux/printk.h>
2020
#include <linux/string_helpers.h>
21+
#include <linux/uio.h>
2122

2223
#include <linux/uaccess.h>
2324
#include <asm/page.h>
@@ -146,7 +147,28 @@ static int traverse(struct seq_file *m, loff_t offset)
146147
*/
147148
ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
148149
{
149-
struct seq_file *m = file->private_data;
150+
struct iovec iov = { .iov_base = buf, .iov_len = size};
151+
struct kiocb kiocb;
152+
struct iov_iter iter;
153+
ssize_t ret;
154+
155+
init_sync_kiocb(&kiocb, file);
156+
iov_iter_init(&iter, READ, &iov, 1, size);
157+
158+
kiocb.ki_pos = *ppos;
159+
ret = seq_read_iter(&kiocb, &iter);
160+
*ppos = kiocb.ki_pos;
161+
return ret;
162+
}
163+
EXPORT_SYMBOL(seq_read);
164+
165+
/*
166+
* Ready-made ->f_op->read_iter()
167+
*/
168+
ssize_t seq_read_iter(struct kiocb *iocb, struct iov_iter *iter)
169+
{
170+
struct seq_file *m = iocb->ki_filp->private_data;
171+
size_t size = iov_iter_count(iter);
150172
size_t copied = 0;
151173
size_t n;
152174
void *p;
@@ -158,14 +180,14 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
158180
* if request is to read from zero offset, reset iterator to first
159181
* record as it might have been already advanced by previous requests
160182
*/
161-
if (*ppos == 0) {
183+
if (iocb->ki_pos == 0) {
162184
m->index = 0;
163185
m->count = 0;
164186
}
165187

166-
/* Don't assume *ppos is where we left it */
167-
if (unlikely(*ppos != m->read_pos)) {
168-
while ((err = traverse(m, *ppos)) == -EAGAIN)
188+
/* Don't assume ki_pos is where we left it */
189+
if (unlikely(iocb->ki_pos != m->read_pos)) {
190+
while ((err = traverse(m, iocb->ki_pos)) == -EAGAIN)
169191
;
170192
if (err) {
171193
/* With prejudice... */
@@ -174,7 +196,7 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
174196
m->count = 0;
175197
goto Done;
176198
} else {
177-
m->read_pos = *ppos;
199+
m->read_pos = iocb->ki_pos;
178200
}
179201
}
180202

@@ -187,13 +209,11 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
187209
/* if not empty - flush it first */
188210
if (m->count) {
189211
n = min(m->count, size);
190-
err = copy_to_user(buf, m->buf + m->from, n);
191-
if (err)
212+
if (copy_to_iter(m->buf + m->from, n, iter) != n)
192213
goto Efault;
193214
m->count -= n;
194215
m->from += n;
195216
size -= n;
196-
buf += n;
197217
copied += n;
198218
if (!size)
199219
goto Done;
@@ -254,8 +274,7 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
254274
}
255275
m->op->stop(m, p);
256276
n = min(m->count, size);
257-
err = copy_to_user(buf, m->buf, n);
258-
if (err)
277+
if (copy_to_iter(m->buf, n, iter) != n)
259278
goto Efault;
260279
copied += n;
261280
m->count -= n;
@@ -264,7 +283,7 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
264283
if (!copied)
265284
copied = err;
266285
else {
267-
*ppos += copied;
286+
iocb->ki_pos += copied;
268287
m->read_pos += copied;
269288
}
270289
mutex_unlock(&m->lock);
@@ -276,7 +295,7 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
276295
err = -EFAULT;
277296
goto Done;
278297
}
279-
EXPORT_SYMBOL(seq_read);
298+
EXPORT_SYMBOL(seq_read_iter);
280299

281300
/**
282301
* seq_lseek - ->llseek() method for sequential files.

include/linux/seq_file.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ void seq_pad(struct seq_file *m, char c);
107107
char *mangle_path(char *s, const char *p, const char *esc);
108108
int seq_open(struct file *, const struct seq_operations *);
109109
ssize_t seq_read(struct file *, char __user *, size_t, loff_t *);
110+
ssize_t seq_read_iter(struct kiocb *iocb, struct iov_iter *iter);
110111
loff_t seq_lseek(struct file *, loff_t, int);
111112
int seq_release(struct inode *, struct file *);
112113
int seq_write(struct seq_file *seq, const void *data, size_t len);

0 commit comments

Comments
 (0)