diff options
Diffstat (limited to 'fs/seq_file.c')
| -rw-r--r-- | fs/seq_file.c | 50 | 
1 files changed, 40 insertions, 10 deletions
diff --git a/fs/seq_file.c b/fs/seq_file.c index 3135c2525c7..3857b720cb1 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -8,8 +8,10 @@  #include <linux/fs.h>  #include <linux/export.h>  #include <linux/seq_file.h> +#include <linux/vmalloc.h>  #include <linux/slab.h>  #include <linux/cred.h> +#include <linux/mm.h>  #include <asm/uaccess.h>  #include <asm/page.h> @@ -30,6 +32,16 @@ static void seq_set_overflow(struct seq_file *m)  	m->count = m->size;  } +static void *seq_buf_alloc(unsigned long size) +{ +	void *buf; + +	buf = kmalloc(size, GFP_KERNEL | __GFP_NOWARN); +	if (!buf && size > PAGE_SIZE) +		buf = vmalloc(size); +	return buf; +} +  /**   *	seq_open -	initialize sequential file   *	@file: file we initialize @@ -96,7 +108,7 @@ static int traverse(struct seq_file *m, loff_t offset)  		return 0;  	}  	if (!m->buf) { -		m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); +		m->buf = seq_buf_alloc(m->size = PAGE_SIZE);  		if (!m->buf)  			return -ENOMEM;  	} @@ -135,8 +147,9 @@ static int traverse(struct seq_file *m, loff_t offset)  Eoverflow:  	m->op->stop(m, p); -	kfree(m->buf); -	m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); +	kvfree(m->buf); +	m->count = 0; +	m->buf = seq_buf_alloc(m->size <<= 1);  	return !m->buf ? -ENOMEM : -EAGAIN;  } @@ -191,7 +204,7 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)  	/* grab buffer if we didn't have one */  	if (!m->buf) { -		m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); +		m->buf = seq_buf_alloc(m->size = PAGE_SIZE);  		if (!m->buf)  			goto Enomem;  	} @@ -231,11 +244,11 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)  		if (m->count < m->size)  			goto Fill;  		m->op->stop(m, p); -		kfree(m->buf); -		m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); +		kvfree(m->buf); +		m->count = 0; +		m->buf = seq_buf_alloc(m->size <<= 1);  		if (!m->buf)  			goto Enomem; -		m->count = 0;  		m->version = 0;  		pos = m->index;  		p = m->op->start(m, &pos); @@ -328,6 +341,8 @@ loff_t seq_lseek(struct file *file, loff_t offset, int whence)  				m->read_pos = offset;  				retval = file->f_pos = offset;  			} +		} else { +			file->f_pos = offset;  		}  	}  	file->f_version = m->version; @@ -347,7 +362,7 @@ EXPORT_SYMBOL(seq_lseek);  int seq_release(struct inode *inode, struct file *file)  {  	struct seq_file *m = file->private_data; -	kfree(m->buf); +	kvfree(m->buf);  	kfree(m);  	return 0;  } @@ -602,13 +617,13 @@ EXPORT_SYMBOL(single_open);  int single_open_size(struct file *file, int (*show)(struct seq_file *, void *),  		void *data, size_t size)  { -	char *buf = kmalloc(size, GFP_KERNEL); +	char *buf = seq_buf_alloc(size);  	int ret;  	if (!buf)  		return -ENOMEM;  	ret = single_open(file, show, data);  	if (ret) { -		kfree(buf); +		kvfree(buf);  		return ret;  	}  	((struct seq_file *)file->private_data)->buf = buf; @@ -764,6 +779,21 @@ int seq_write(struct seq_file *seq, const void *data, size_t len)  }  EXPORT_SYMBOL(seq_write); +/** + * seq_pad - write padding spaces to buffer + * @m: seq_file identifying the buffer to which data should be written + * @c: the byte to append after padding if non-zero + */ +void seq_pad(struct seq_file *m, char c) +{ +	int size = m->pad_until - m->count; +	if (size > 0) +		seq_printf(m, "%*s", size, ""); +	if (c) +		seq_putc(m, c); +} +EXPORT_SYMBOL(seq_pad); +  struct list_head *seq_list_start(struct list_head *head, loff_t pos)  {  	struct list_head *lh;  | 
