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. Signed-off-by: Mathieu Desnoyers --- fs/seq_file.c | 40 ++++++++++++++++++++++++++++++++++++++++ include/linux/seq_file.h | 20 ++++++++++++++++++++ 2 files changed, 60 insertions(+) Index: linux-2.6-lttng/fs/seq_file.c =================================================================== --- linux-2.6-lttng.orig/fs/seq_file.c 2007-07-25 01:40:13.000000000 -0400 +++ linux-2.6-lttng/fs/seq_file.c 2007-07-25 02:47:55.000000000 -0400 @@ -485,3 +485,43 @@ struct list_head *seq_list_next(void *v, } EXPORT_SYMBOL(seq_list_next); + +struct list_head *seq_sorted_list_start(struct list_head *head, void *pos) +{ + struct list_head *lh; + + list_for_each(lh, head) + if ((void*)lh >= pos) + return lh; + return NULL; +} + +EXPORT_SYMBOL(seq_sorted_list_start); + +struct list_head *seq_sorted_list_start_head(struct list_head *head, void *pos) +{ + struct list_head *lh; + + if (!pos) + return head; + list_for_each(lh, head) + if ((void*)lh >= pos) + 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, + void **ppos) +{ + struct list_head *lh; + void *next; + + lh = ((struct list_head *)p)->next; + next = (lh == head) ? NULL : lh; + *ppos = next ? next : (void*)-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 2007-07-25 01:40:13.000000000 -0400 +++ linux-2.6-lttng/include/linux/seq_file.h 2007-07-25 02:41:22.000000000 -0400 @@ -61,5 +61,25 @@ 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, + void *pos); +extern struct list_head *seq_sorted_list_start_head(struct list_head *head, + void *pos); +/* + * next must be called with an existing p node + */ +extern struct list_head *seq_sorted_list_next(void *p, struct list_head *head, + void **ppos); + #endif #endif -- Mathieu Desnoyers Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal 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/