seq_file: move traverse so it can be used from seq_read
In 2.6.25 some /proc files were converted to use the seq_file infrastructure. But seq_files do not correctly support pread(), which broke some usersapce applications. To handle pread correctly we can't assume that f_pos is where we left it in seq_read. So move traverse() so that we can eventually use it in seq_read and do thus some day support pread(). Signed-off-by: Eric Biederman <ebiederm@xmission.com> Cc: Paul Turner <pjt@google.com> Cc: Alexey Dobriyan <adobriyan@gmail.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
361916a943
commit
33da8892a2
1 changed files with 57 additions and 57 deletions
114
fs/seq_file.c
114
fs/seq_file.c
|
@ -54,6 +54,63 @@ int seq_open(struct file *file, const struct seq_operations *op)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(seq_open);
|
EXPORT_SYMBOL(seq_open);
|
||||||
|
|
||||||
|
static int traverse(struct seq_file *m, loff_t offset)
|
||||||
|
{
|
||||||
|
loff_t pos = 0, index;
|
||||||
|
int error = 0;
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
m->version = 0;
|
||||||
|
index = 0;
|
||||||
|
m->count = m->from = 0;
|
||||||
|
if (!offset) {
|
||||||
|
m->index = index;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!m->buf) {
|
||||||
|
m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
|
||||||
|
if (!m->buf)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
p = m->op->start(m, &index);
|
||||||
|
while (p) {
|
||||||
|
error = PTR_ERR(p);
|
||||||
|
if (IS_ERR(p))
|
||||||
|
break;
|
||||||
|
error = m->op->show(m, p);
|
||||||
|
if (error < 0)
|
||||||
|
break;
|
||||||
|
if (unlikely(error)) {
|
||||||
|
error = 0;
|
||||||
|
m->count = 0;
|
||||||
|
}
|
||||||
|
if (m->count == m->size)
|
||||||
|
goto Eoverflow;
|
||||||
|
if (pos + m->count > offset) {
|
||||||
|
m->from = offset - pos;
|
||||||
|
m->count -= m->from;
|
||||||
|
m->index = index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos += m->count;
|
||||||
|
m->count = 0;
|
||||||
|
if (pos == offset) {
|
||||||
|
index++;
|
||||||
|
m->index = index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p = m->op->next(m, p, &index);
|
||||||
|
}
|
||||||
|
m->op->stop(m, p);
|
||||||
|
return error;
|
||||||
|
|
||||||
|
Eoverflow:
|
||||||
|
m->op->stop(m, p);
|
||||||
|
kfree(m->buf);
|
||||||
|
m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
|
||||||
|
return !m->buf ? -ENOMEM : -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* seq_read - ->read() method for sequential files.
|
* seq_read - ->read() method for sequential files.
|
||||||
* @file: the file to read from
|
* @file: the file to read from
|
||||||
|
@ -186,63 +243,6 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(seq_read);
|
EXPORT_SYMBOL(seq_read);
|
||||||
|
|
||||||
static int traverse(struct seq_file *m, loff_t offset)
|
|
||||||
{
|
|
||||||
loff_t pos = 0, index;
|
|
||||||
int error = 0;
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
m->version = 0;
|
|
||||||
index = 0;
|
|
||||||
m->count = m->from = 0;
|
|
||||||
if (!offset) {
|
|
||||||
m->index = index;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!m->buf) {
|
|
||||||
m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
|
|
||||||
if (!m->buf)
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
p = m->op->start(m, &index);
|
|
||||||
while (p) {
|
|
||||||
error = PTR_ERR(p);
|
|
||||||
if (IS_ERR(p))
|
|
||||||
break;
|
|
||||||
error = m->op->show(m, p);
|
|
||||||
if (error < 0)
|
|
||||||
break;
|
|
||||||
if (unlikely(error)) {
|
|
||||||
error = 0;
|
|
||||||
m->count = 0;
|
|
||||||
}
|
|
||||||
if (m->count == m->size)
|
|
||||||
goto Eoverflow;
|
|
||||||
if (pos + m->count > offset) {
|
|
||||||
m->from = offset - pos;
|
|
||||||
m->count -= m->from;
|
|
||||||
m->index = index;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pos += m->count;
|
|
||||||
m->count = 0;
|
|
||||||
if (pos == offset) {
|
|
||||||
index++;
|
|
||||||
m->index = index;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
p = m->op->next(m, p, &index);
|
|
||||||
}
|
|
||||||
m->op->stop(m, p);
|
|
||||||
return error;
|
|
||||||
|
|
||||||
Eoverflow:
|
|
||||||
m->op->stop(m, p);
|
|
||||||
kfree(m->buf);
|
|
||||||
m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
|
|
||||||
return !m->buf ? -ENOMEM : -EAGAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* seq_lseek - ->llseek() method for sequential files.
|
* seq_lseek - ->llseek() method for sequential files.
|
||||||
* @file: the file in question
|
* @file: the file in question
|
||||||
|
|
Loading…
Reference in a new issue