diff options
| author | Eric Biederman <ebiederm@xmission.com> | 2009-02-04 18:12:25 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-02-05 15:56:49 -0500 |
| commit | 33da8892a2f9e7d4b2d9a35fc80833ba2d2b1aa6 (patch) | |
| tree | 4261b553653438775461fd408669f1942a383d2e /fs | |
| parent | 361916a943cd9dbda1c0b00879d0225cc919d868 (diff) | |
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>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/seq_file.c | 114 |
1 files changed, 57 insertions, 57 deletions
diff --git a/fs/seq_file.c b/fs/seq_file.c index b569ff1c4dc8..2716c12eacf5 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c | |||
| @@ -54,6 +54,63 @@ int seq_open(struct file *file, const struct seq_operations *op) | |||
| 54 | } | 54 | } |
| 55 | EXPORT_SYMBOL(seq_open); | 55 | EXPORT_SYMBOL(seq_open); |
| 56 | 56 | ||
| 57 | static int traverse(struct seq_file *m, loff_t offset) | ||
| 58 | { | ||
| 59 | loff_t pos = 0, index; | ||
| 60 | int error = 0; | ||
| 61 | void *p; | ||
| 62 | |||
| 63 | m->version = 0; | ||
| 64 | index = 0; | ||
| 65 | m->count = m->from = 0; | ||
| 66 | if (!offset) { | ||
| 67 | m->index = index; | ||
| 68 | return 0; | ||
| 69 | } | ||
| 70 | if (!m->buf) { | ||
| 71 | m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); | ||
| 72 | if (!m->buf) | ||
| 73 | return -ENOMEM; | ||
| 74 | } | ||
| 75 | p = m->op->start(m, &index); | ||
| 76 | while (p) { | ||
| 77 | error = PTR_ERR(p); | ||
| 78 | if (IS_ERR(p)) | ||
| 79 | break; | ||
| 80 | error = m->op->show(m, p); | ||
| 81 | if (error < 0) | ||
| 82 | break; | ||
| 83 | if (unlikely(error)) { | ||
| 84 | error = 0; | ||
| 85 | m->count = 0; | ||
| 86 | } | ||
| 87 | if (m->count == m->size) | ||
| 88 | goto Eoverflow; | ||
| 89 | if (pos + m->count > offset) { | ||
| 90 | m->from = offset - pos; | ||
| 91 | m->count -= m->from; | ||
| 92 | m->index = index; | ||
| 93 | break; | ||
| 94 | } | ||
| 95 | pos += m->count; | ||
| 96 | m->count = 0; | ||
| 97 | if (pos == offset) { | ||
| 98 | index++; | ||
| 99 | m->index = index; | ||
| 100 | break; | ||
| 101 | } | ||
| 102 | p = m->op->next(m, p, &index); | ||
| 103 | } | ||
| 104 | m->op->stop(m, p); | ||
| 105 | return error; | ||
| 106 | |||
| 107 | Eoverflow: | ||
| 108 | m->op->stop(m, p); | ||
| 109 | kfree(m->buf); | ||
| 110 | m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); | ||
| 111 | return !m->buf ? -ENOMEM : -EAGAIN; | ||
| 112 | } | ||
| 113 | |||
| 57 | /** | 114 | /** |
| 58 | * seq_read - ->read() method for sequential files. | 115 | * seq_read - ->read() method for sequential files. |
| 59 | * @file: the file to read from | 116 | * @file: the file to read from |
| @@ -186,63 +243,6 @@ Efault: | |||
| 186 | } | 243 | } |
| 187 | EXPORT_SYMBOL(seq_read); | 244 | EXPORT_SYMBOL(seq_read); |
| 188 | 245 | ||
| 189 | static int traverse(struct seq_file *m, loff_t offset) | ||
| 190 | { | ||
| 191 | loff_t pos = 0, index; | ||
| 192 | int error = 0; | ||
| 193 | void *p; | ||
| 194 | |||
| 195 | m->version = 0; | ||
| 196 | index = 0; | ||
| 197 | m->count = m->from = 0; | ||
| 198 | if (!offset) { | ||
| 199 | m->index = index; | ||
| 200 | return 0; | ||
| 201 | } | ||
| 202 | if (!m->buf) { | ||
| 203 | m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); | ||
| 204 | if (!m->buf) | ||
| 205 | return -ENOMEM; | ||
| 206 | } | ||
| 207 | p = m->op->start(m, &index); | ||
| 208 | while (p) { | ||
| 209 | error = PTR_ERR(p); | ||
| 210 | if (IS_ERR(p)) | ||
| 211 | break; | ||
| 212 | error = m->op->show(m, p); | ||
| 213 | if (error < 0) | ||
| 214 | break; | ||
| 215 | if (unlikely(error)) { | ||
| 216 | error = 0; | ||
| 217 | m->count = 0; | ||
| 218 | } | ||
| 219 | if (m->count == m->size) | ||
| 220 | goto Eoverflow; | ||
| 221 | if (pos + m->count > offset) { | ||
| 222 | m->from = offset - pos; | ||
| 223 | m->count -= m->from; | ||
| 224 | m->index = index; | ||
| 225 | break; | ||
| 226 | } | ||
| 227 | pos += m->count; | ||
| 228 | m->count = 0; | ||
| 229 | if (pos == offset) { | ||
| 230 | index++; | ||
| 231 | m->index = index; | ||
| 232 | break; | ||
| 233 | } | ||
| 234 | p = m->op->next(m, p, &index); | ||
| 235 | } | ||
| 236 | m->op->stop(m, p); | ||
| 237 | return error; | ||
| 238 | |||
| 239 | Eoverflow: | ||
| 240 | m->op->stop(m, p); | ||
| 241 | kfree(m->buf); | ||
| 242 | m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); | ||
| 243 | return !m->buf ? -ENOMEM : -EAGAIN; | ||
| 244 | } | ||
| 245 | |||
| 246 | /** | 246 | /** |
| 247 | * seq_lseek - ->llseek() method for sequential files. | 247 | * seq_lseek - ->llseek() method for sequential files. |
| 248 | * @file: the file in question | 248 | * @file: the file in question |
