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 --- fs/seq_file.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- include/linux/seq_file.h | 20 ++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) Index: linux-2.6-lttng/fs/seq_file.c =================================================================== --- linux-2.6-lttng.orig/fs/seq_file.c 2009-03-05 15:44:04.000000000 -0500 +++ linux-2.6-lttng/fs/seq_file.c 2009-03-05 15:44:36.000000000 -0500 @@ -671,5 +671,48 @@ struct list_head *seq_list_next(void *v, ++*ppos; return lh == head ? NULL : lh; } - EXPORT_SYMBOL(seq_list_next); + +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); Index: linux-2.6-lttng/include/linux/seq_file.h =================================================================== --- linux-2.6-lttng.orig/include/linux/seq_file.h 2009-03-05 15:44:04.000000000 -0500 +++ linux-2.6-lttng/include/linux/seq_file.h 2009-03-05 15:44:05.000000000 -0500 @@ -95,4 +95,24 @@ extern struct list_head *seq_list_start_ extern struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos); +/* + * Helpers for iteration over a list sorted by ascending head pointer address. + * To be used in contexts where preemption cannot be disabled to insure to + * continue iteration on a modified list starting at the same location where it + * stopped, or at a following location. It insures that the lost information + * will only be in elements added/removed from the list between iterations. + * void *pos is only used to get the next list element and may not be a valid + * list_head anymore when given to seq_sorted_list_start() or + * seq_sorted_list_start_head(). + */ +extern struct list_head *seq_sorted_list_start(struct list_head *head, + loff_t *ppos); +extern struct list_head *seq_sorted_list_start_head(struct list_head *head, + loff_t *ppos); +/* + * next must be called with an existing p node + */ +extern struct list_head *seq_sorted_list_next(void *p, struct list_head *head, + loff_t *ppos); + #endif -- Mathieu Desnoyers OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/