Commit 33da8892a2f9e7d4b2d9a35fc80833ba2d2b1aa6

Authored by Eric Biederman
Committed by Linus Torvalds
1 parent 361916a943

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

... ... @@ -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.