aboutsummaryrefslogtreecommitdiff
path: root/fs/seq_file.c
diff options
context:
space:
mode:
authorLinus Torvalds2012-03-23 16:59:10 -0700
committerLinus Torvalds2012-03-23 16:59:10 -0700
commit8e3ade251bc7c0a4f0777df4dd34343a03efadba (patch)
tree6c0b78731e3d6609057951d07660efbd90992ad0 /fs/seq_file.c
parente317234975cb7463b8ca21a93bb6862d9dcf113f (diff)
parente075f59152890ffd7e3d704afc997dd686c8a781 (diff)
Merge branch 'akpm' (Andrew's patch-bomb)
Merge second batch of patches from Andrew Morton: - various misc things - core kernel changes to prctl, exit, exec, init, etc. - kernel/watchdog.c updates - get_maintainer - MAINTAINERS - the backlight driver queue - core bitops code cleanups - the led driver queue - some core prio_tree work - checkpatch udpates - largeish crc32 update - a new poll() feature for the v4l guys - the rtc driver queue - fatfs - ptrace - signals - kmod/usermodehelper updates - coredump - procfs updates * emailed from Andrew Morton <akpm@linux-foundation.org>: (141 commits) seq_file: add seq_set_overflow(), seq_overflow() proc-ns: use d_set_d_op() API to set dentry ops in proc_ns_instantiate(). procfs: speed up /proc/pid/stat, statm procfs: add num_to_str() to speed up /proc/stat proc: speed up /proc/stat handling fs/proc/kcore.c: make get_sparsemem_vmemmap_info() static coredump: add VM_NODUMP, MADV_NODUMP, MADV_CLEAR_NODUMP coredump: remove VM_ALWAYSDUMP flag kmod: make __request_module() killable kmod: introduce call_modprobe() helper usermodehelper: ____call_usermodehelper() doesn't need do_exit() usermodehelper: kill umh_wait, renumber UMH_* constants usermodehelper: implement UMH_KILLABLE usermodehelper: introduce umh_complete(sub_info) usermodehelper: use UMH_WAIT_PROC consistently signal: zap_pid_ns_processes: s/SEND_SIG_NOINFO/SEND_SIG_FORCED/ signal: oom_kill_task: use SEND_SIG_FORCED instead of force_sig() signal: cosmetic, s/from_ancestor_ns/force/ in prepare_signal() paths signal: give SEND_SIG_FORCED more power to beat SIGNAL_UNKILLABLE Hexagon: use set_current_blocked() and block_sigmask() ...
Diffstat (limited to 'fs/seq_file.c')
-rw-r--r--fs/seq_file.c84
1 files changed, 76 insertions, 8 deletions
diff --git a/fs/seq_file.c b/fs/seq_file.c
index aa242dc99373..46cfb067fc3a 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -13,6 +13,22 @@
#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);