]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/seq_file.c
Merge tag 'module-for-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/paulg...
[karo-tx-linux.git] / fs / seq_file.c
index aa242dc99373bec0fe981d22508921454759bd14..0cbd0494b79e0fe13f7b73a9273013f12f98e818 100644 (file)
@@ -6,13 +6,29 @@
  */
 
 #include <linux/fs.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
 
+
+/*
+ * seq_files have a buffer which can may overflow. When this happens a larger
+ * buffer is reallocated and all the data will be printed again.
+ * The overflow state is true when m->count == m->size.
+ */
+static bool seq_overflow(struct seq_file *m)
+{
+       return m->count == m->size;
+}
+
+static void seq_set_overflow(struct seq_file *m)
+{
+       m->count = m->size;
+}
+
 /**
  *     seq_open -      initialize sequential file
  *     @file: file we initialize
@@ -92,7 +108,7 @@ static int traverse(struct seq_file *m, loff_t offset)
                        error = 0;
                        m->count = 0;
                }
-               if (m->count == m->size)
+               if (seq_overflow(m))
                        goto Eoverflow;
                if (pos + m->count > offset) {
                        m->from = offset - pos;
@@ -234,7 +250,7 @@ Fill:
                        break;
                }
                err = m->op->show(m, p);
-               if (m->count == m->size || err) {
+               if (seq_overflow(m) || err) {
                        m->count = offs;
                        if (likely(err <= 0))
                                break;
@@ -361,7 +377,7 @@ int seq_escape(struct seq_file *m, const char *s, const char *esc)
                        *p++ = '0' + (c & 07);
                        continue;
                }
-               m->count = m->size;
+               seq_set_overflow(m);
                return -1;
         }
        m->count = p - m->buf;
@@ -383,7 +399,7 @@ int seq_printf(struct seq_file *m, const char *f, ...)
                        return 0;
                }
        }
-       m->count = m->size;
+       seq_set_overflow(m);
        return -1;
 }
 EXPORT_SYMBOL(seq_printf);
@@ -512,7 +528,7 @@ int seq_bitmap(struct seq_file *m, const unsigned long *bits,
                        return 0;
                }
        }
-       m->count = m->size;
+       seq_set_overflow(m);
        return -1;
 }
 EXPORT_SYMBOL(seq_bitmap);
@@ -528,7 +544,7 @@ int seq_bitmap_list(struct seq_file *m, const unsigned long *bits,
                        return 0;
                }
        }
-       m->count = m->size;
+       seq_set_overflow(m);
        return -1;
 }
 EXPORT_SYMBOL(seq_bitmap_list);
@@ -639,11 +655,63 @@ int seq_puts(struct seq_file *m, const char *s)
                m->count += len;
                return 0;
        }
-       m->count = m->size;
+       seq_set_overflow(m);
        return -1;
 }
 EXPORT_SYMBOL(seq_puts);
 
+/*
+ * A helper routine for putting decimal numbers without rich format of printf().
+ * only 'unsigned long long' is supported.
+ * This routine will put one byte delimiter + number into seq_file.
+ * This routine is very quick when you show lots of numbers.
+ * In usual cases, it will be better to use seq_printf(). It's easier to read.
+ */
+int seq_put_decimal_ull(struct seq_file *m, char delimiter,
+                       unsigned long long num)
+{
+       int len;
+
+       if (m->count + 2 >= m->size) /* we'll write 2 bytes at least */
+               goto overflow;
+
+       if (delimiter)
+               m->buf[m->count++] = delimiter;
+
+       if (num < 10) {
+               m->buf[m->count++] = num + '0';
+               return 0;
+       }
+
+       len = num_to_str(m->buf + m->count, m->size - m->count, num);
+       if (!len)
+               goto overflow;
+       m->count += len;
+       return 0;
+overflow:
+       seq_set_overflow(m);
+       return -1;
+}
+EXPORT_SYMBOL(seq_put_decimal_ull);
+
+int seq_put_decimal_ll(struct seq_file *m, char delimiter,
+                       long long num)
+{
+       if (num < 0) {
+               if (m->count + 3 >= m->size) {
+                       seq_set_overflow(m);
+                       return -1;
+               }
+               if (delimiter)
+                       m->buf[m->count++] = delimiter;
+               num = -num;
+               delimiter = '-';
+       }
+       return seq_put_decimal_ull(m, delimiter, num);
+
+}
+EXPORT_SYMBOL(seq_put_decimal_ll);
+
 /**
  * seq_write - write arbitrary data to buffer
  * @seq: seq_file identifying the buffer to which data should be written
@@ -659,7 +727,7 @@ int seq_write(struct seq_file *seq, const void *data, size_t len)
                seq->count += len;
                return 0;
        }
-       seq->count = seq->size;
+       seq_set_overflow(seq);
        return -1;
 }
 EXPORT_SYMBOL(seq_write);