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
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);
|
||||
|
||||
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.
|
||||
* @file: the file to read from
|
||||
|
@ -186,63 +243,6 @@ Efault:
|
|||
}
|
||||
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.
|
||||
* @file: the file in question
|
||||
|
|
Loading…
Reference in New Issue