summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>2011-03-16 19:04:10 -0400
committerMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>2011-03-16 19:04:10 -0400
commitd724da946c6919c7240dbe7b201c06176a5266d8 (patch)
tree775edf23efa11b763b2d2b804ff617d98dea5a0a /fs
parent51faf68d803933510e8fa91b375eb0680d36b8e8 (diff)
seq_file_sorted
Seq_file add support for sorted list Add support for sorted list in seq_file. It aims at changing the way /proc/modules and kallsyms iterates on the module list to remove a race between module unload and module/symbol listing. The list is sorted by ascending list_head pointer address. Changelog: When reading the data by small chunks (i.e. byte by byte), the index (ppos) is incremented by seq_read() directly and no "next" callback is called when going to the next module. Therefore, use ppos instead of m->private to deal with the fact that this index is incremented directly to pass to the next module in seq_read() after the buffer has been emptied. Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> CC: Al Viro <viro@zeniv.linux.org.uk> CC: Rusty Russel <rusty@rustcorp.com.au>
Diffstat (limited to 'fs')
-rw-r--r--fs/seq_file.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 05d6b0e78c9..691c84baf4f 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -819,3 +819,47 @@ struct hlist_node *seq_hlist_next_rcu(void *v,
return rcu_dereference(node->next);
}
EXPORT_SYMBOL(seq_hlist_next_rcu);
+
+struct list_head *seq_sorted_list_start(struct list_head *head, loff_t *ppos)
+{
+ struct list_head *lh;
+
+ list_for_each(lh, head)
+ if ((unsigned long)lh >= *ppos) {
+ *ppos = (unsigned long)lh;
+ return lh;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(seq_sorted_list_start);
+
+struct list_head *seq_sorted_list_start_head(struct list_head *head,
+ loff_t *ppos)
+{
+ struct list_head *lh;
+
+ if (!*ppos) {
+ *ppos = (unsigned long)head;
+ return head;
+ }
+ list_for_each(lh, head)
+ if ((unsigned long)lh >= *ppos) {
+ *ppos = (long)lh->prev;
+ return lh->prev;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(seq_sorted_list_start_head);
+
+struct list_head *seq_sorted_list_next(void *p, struct list_head *head,
+ loff_t *ppos)
+{
+ struct list_head *lh;
+ void *next;
+
+ lh = ((struct list_head *)p)->next;
+ next = (lh == head) ? NULL : lh;
+ *ppos = next ? ((unsigned long)next) : (-1UL);
+ return next;
+}
+EXPORT_SYMBOL(seq_sorted_list_next);