diff options
author | Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | 2011-03-16 19:04:10 -0400 |
---|---|---|
committer | Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> | 2011-03-16 19:04:10 -0400 |
commit | d724da946c6919c7240dbe7b201c06176a5266d8 (patch) | |
tree | 775edf23efa11b763b2d2b804ff617d98dea5a0a /fs | |
parent | 51faf68d803933510e8fa91b375eb0680d36b8e8 (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.c | 44 |
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); |