Commit 33da8892a2f9e7d4b2d9a35fc80833ba2d2b1aa6
Committed by
Linus Torvalds
1 parent
361916a943
Exists in
master
and in
4 other branches
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>
Showing 1 changed file with 57 additions and 57 deletions Side-by-side Diff
fs/seq_file.c
... | ... | @@ -54,6 +54,63 @@ |
54 | 54 | } |
55 | 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 | 115 | * seq_read - ->read() method for sequential files. |
59 | 116 | * @file: the file to read from |
... | ... | @@ -185,63 +242,6 @@ |
185 | 242 | goto Done; |
186 | 243 | } |
187 | 244 | EXPORT_SYMBOL(seq_read); |
188 | - | |
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 | 245 | |
246 | 246 | /** |
247 | 247 | * seq_lseek - ->llseek() method for sequential files. |