diff options
Diffstat (limited to 'fs/seq_file.c')
-rw-r--r-- | fs/seq_file.c | 115 |
1 files changed, 58 insertions, 57 deletions
diff --git a/fs/seq_file.c b/fs/seq_file.c index b569ff1c4dc8..5267098532bf 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c | |||
@@ -54,6 +54,64 @@ 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 | m->index = index; | ||
106 | return error; | ||
107 | |||
108 | Eoverflow: | ||
109 | m->op->stop(m, p); | ||
110 | kfree(m->buf); | ||
111 | m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); | ||
112 | return !m->buf ? -ENOMEM : -EAGAIN; | ||
113 | } | ||
114 | |||
57 | /** | 115 | /** |
58 | * seq_read - ->read() method for sequential files. | 116 | * seq_read - ->read() method for sequential files. |
59 | * @file: the file to read from | 117 | * @file: the file to read from |
@@ -186,63 +244,6 @@ Efault: | |||
186 | } | 244 | } |
187 | EXPORT_SYMBOL(seq_read); | 245 | EXPORT_SYMBOL(seq_read); |
188 | 246 | ||
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 | /** | 247 | /** |
247 | * seq_lseek - ->llseek() method for sequential files. | 248 | * seq_lseek - ->llseek() method for sequential files. |
248 | * @file: the file in question | 249 | * @file: the file in question |