forked from mirrors/linux
		
	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 <hch@lst.de> Tested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									3cea11cd5e
								
							
						
					
					
						commit
						d4d50710a8
					
				
					 2 changed files with 33 additions and 13 deletions
				
			
		| 
						 | 
					@ -18,6 +18,7 @@
 | 
				
			||||||
#include <linux/mm.h>
 | 
					#include <linux/mm.h>
 | 
				
			||||||
#include <linux/printk.h>
 | 
					#include <linux/printk.h>
 | 
				
			||||||
#include <linux/string_helpers.h>
 | 
					#include <linux/string_helpers.h>
 | 
				
			||||||
 | 
					#include <linux/uio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/uaccess.h>
 | 
					#include <linux/uaccess.h>
 | 
				
			||||||
#include <asm/page.h>
 | 
					#include <asm/page.h>
 | 
				
			||||||
| 
						 | 
					@ -146,7 +147,28 @@ static int traverse(struct seq_file *m, loff_t offset)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
 | 
					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 copied = 0;
 | 
				
			||||||
	size_t n;
 | 
						size_t n;
 | 
				
			||||||
	void *p;
 | 
						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
 | 
						 * if request is to read from zero offset, reset iterator to first
 | 
				
			||||||
	 * record as it might have been already advanced by previous requests
 | 
						 * record as it might have been already advanced by previous requests
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (*ppos == 0) {
 | 
						if (iocb->ki_pos == 0) {
 | 
				
			||||||
		m->index = 0;
 | 
							m->index = 0;
 | 
				
			||||||
		m->count = 0;
 | 
							m->count = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Don't assume *ppos is where we left it */
 | 
						/* Don't assume ki_pos is where we left it */
 | 
				
			||||||
	if (unlikely(*ppos != m->read_pos)) {
 | 
						if (unlikely(iocb->ki_pos != m->read_pos)) {
 | 
				
			||||||
		while ((err = traverse(m, *ppos)) == -EAGAIN)
 | 
							while ((err = traverse(m, iocb->ki_pos)) == -EAGAIN)
 | 
				
			||||||
			;
 | 
								;
 | 
				
			||||||
		if (err) {
 | 
							if (err) {
 | 
				
			||||||
			/* With prejudice... */
 | 
								/* 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;
 | 
								m->count = 0;
 | 
				
			||||||
			goto Done;
 | 
								goto Done;
 | 
				
			||||||
		} else {
 | 
							} 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 not empty - flush it first */
 | 
				
			||||||
	if (m->count) {
 | 
						if (m->count) {
 | 
				
			||||||
		n = min(m->count, size);
 | 
							n = min(m->count, size);
 | 
				
			||||||
		err = copy_to_user(buf, m->buf + m->from, n);
 | 
							if (copy_to_iter(m->buf + m->from, n, iter) != n)
 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			goto Efault;
 | 
								goto Efault;
 | 
				
			||||||
		m->count -= n;
 | 
							m->count -= n;
 | 
				
			||||||
		m->from += n;
 | 
							m->from += n;
 | 
				
			||||||
		size -= n;
 | 
							size -= n;
 | 
				
			||||||
		buf += n;
 | 
					 | 
				
			||||||
		copied += n;
 | 
							copied += n;
 | 
				
			||||||
		if (!size)
 | 
							if (!size)
 | 
				
			||||||
			goto Done;
 | 
								goto Done;
 | 
				
			||||||
| 
						 | 
					@ -254,8 +274,7 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	m->op->stop(m, p);
 | 
						m->op->stop(m, p);
 | 
				
			||||||
	n = min(m->count, size);
 | 
						n = min(m->count, size);
 | 
				
			||||||
	err = copy_to_user(buf, m->buf, n);
 | 
						if (copy_to_iter(m->buf, n, iter) != n)
 | 
				
			||||||
	if (err)
 | 
					 | 
				
			||||||
		goto Efault;
 | 
							goto Efault;
 | 
				
			||||||
	copied += n;
 | 
						copied += n;
 | 
				
			||||||
	m->count -= n;
 | 
						m->count -= n;
 | 
				
			||||||
| 
						 | 
					@ -264,7 +283,7 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
 | 
				
			||||||
	if (!copied)
 | 
						if (!copied)
 | 
				
			||||||
		copied = err;
 | 
							copied = err;
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		*ppos += copied;
 | 
							iocb->ki_pos += copied;
 | 
				
			||||||
		m->read_pos += copied;
 | 
							m->read_pos += copied;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mutex_unlock(&m->lock);
 | 
						mutex_unlock(&m->lock);
 | 
				
			||||||
| 
						 | 
					@ -276,7 +295,7 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
 | 
				
			||||||
	err = -EFAULT;
 | 
						err = -EFAULT;
 | 
				
			||||||
	goto Done;
 | 
						goto Done;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(seq_read);
 | 
					EXPORT_SYMBOL(seq_read_iter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 *	seq_lseek -	->llseek() method for sequential files.
 | 
					 *	seq_lseek -	->llseek() method for sequential files.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -107,6 +107,7 @@ void seq_pad(struct seq_file *m, char c);
 | 
				
			||||||
char *mangle_path(char *s, const char *p, const char *esc);
 | 
					char *mangle_path(char *s, const char *p, const char *esc);
 | 
				
			||||||
int seq_open(struct file *, const struct seq_operations *);
 | 
					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(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);
 | 
					loff_t seq_lseek(struct file *, loff_t, int);
 | 
				
			||||||
int seq_release(struct inode *, struct file *);
 | 
					int seq_release(struct inode *, struct file *);
 | 
				
			||||||
int seq_write(struct seq_file *seq, const void *data, size_t len);
 | 
					int seq_write(struct seq_file *seq, const void *data, size_t len);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue