A race that appears both in /proc/modules and in kallsyms: if, between the seq file reads, the process is put to sleep and at this moment a module is or removed from the module list, the listing will skip an amount of modules/symbols corresponding to the amount of elements present in the unloaded module, but at the current position in the list if the iteration is located after the removed module. The cleanest way I found to deal with this problem is to sort the module list. We can then keep the old struct module * as the old iterator, knowing the it may be removed between the seq file reads, but we only use it as "get next". If it is not present in the module list, the next pointer will be used. By doing this, removing a given module will now only fuzz the output related to this specific module, not any random module anymore. Since modprobe uses /proc/modules, it might be important to make sure multiple concurrent running modprobes won't interfere with each other. Small test program for this: #include #include #include #include #define BUFSIZE 1024 int main() { int fd = open("/proc/modules", O_RDONLY); char buf[BUFSIZE]; ssize_t size; do { size = read(fd, buf, 1); printf("%c", buf[0]); usleep(100000); } while(size > 0); close(fd); return 0; } Actual test (kernel 2.6.23-rc3): dijkstra:~# lsmod Module Size Used by pl2303 18564 0 usbserial 29032 1 pl2303 ppdev 7844 0 sky2 37476 0 skge 36368 0 rtc 10104 0 snd_hda_intel 265628 0 (here, while we are printing the 2nd line, I rmmod pl2303) compudj@dijkstra:~/test$ ./module pl2303 18564 0 - Live 0xf886e000 usbserial 29032 1 pl2303, Live 0xf8865000 sky2 37476 0 - Live 0xf884f000 skge 36368 0 - Live 0xf8838000 rtc 10104 0 - Live 0xf8825000 We see the the 2nd line is garbage. Now, with my patch applied: (here, while we are printing the rtc module, I rmmod rtc) nd_hda_intel 268708 0 - Live 0xf8820000 ltt_control 2372 0 - Live 0xf8866000 rtc 10392 0 - Live 0xf886d000 skge 36768 0 - Live 0xf8871000 ltt_statedump 8516 0 - Live 0xf887b000 We see that since the rtc line was already in the buffer, it has been printed completely. (here, while we are printing the skge module, I rmmod rtc) snd_hda_intel 268708 0 - Live 0xf8820000 ltt_control 2372 0 - Live 0xf8866000 rtc 10392 0 - Live 0xf886d000 skge 36768 0 - Live 0xf8871000 ltt_statedump 8516 0 - Live 0xf887b000 sky2 38420 0 - Live 0xf88cd000 We see that the iteration continued at the same position even though the rtc module, located in earlier addresses, was removed. 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. Before fix, it prints the first module indefinitely. The patch fixes this. Changelog: - Remove module_mutex usage: depend on functions implemented in module.c for that. Signed-off-by: Mathieu Desnoyers --- kernel/module.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) Index: linux-2.6-lttng/kernel/module.c =================================================================== --- linux-2.6-lttng.orig/kernel/module.c 2009-03-05 15:29:39.000000000 -0500 +++ linux-2.6-lttng/kernel/module.c 2009-03-05 15:45:33.000000000 -0500 @@ -66,7 +66,9 @@ #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) /* List of modules, protected by module_mutex or preempt_disable - * (delete uses stop_machine/add uses RCU list operations). */ + * (delete uses stop_machine/add uses RCU list operations). + * Sorted by ascending list node address. + */ static DEFINE_MUTEX(module_mutex); static LIST_HEAD(modules); @@ -1877,6 +1879,7 @@ static noinline struct module *load_modu void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ unsigned long *mseg; mm_segment_t old_fs; + struct module *iter; DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", umod, len, uargs); @@ -2260,8 +2263,24 @@ static noinline struct module *load_modu * function to insert in a way safe to concurrent readers. * The mutex protects against concurrent writers. */ - list_add_rcu(&mod->list, &modules); + /* + * We sort the modules by struct module pointer address to permit + * correct iteration over modules of, at least, kallsyms for preemptible + * operations, such as read(). Sorting by struct module pointer address + * is equivalent to sort by list node address. + */ + list_for_each_entry_reverse(iter, &modules, list) { + BUG_ON(iter == mod); /* Should never be in the list twice */ + if (iter < mod) { + /* We belong to the location right after iter. */ + list_add_rcu(&mod->list, &iter->list); + goto module_added; + } + } + /* We should be added at the head of the list */ + list_add_rcu(&mod->list, &modules); +module_added: err = parse_args(mod->name, mod->args, kp, num_kp, NULL); if (err < 0) goto unlink; @@ -2618,12 +2637,12 @@ static char *module_flags(struct module static void *m_start(struct seq_file *m, loff_t *pos) { mutex_lock(&module_mutex); - return seq_list_start(&modules, *pos); + return seq_sorted_list_start(&modules, pos); } static void *m_next(struct seq_file *m, void *p, loff_t *pos) { - return seq_list_next(p, &modules, pos); + return seq_sorted_list_next(p, &modules, pos); } static void m_stop(struct seq_file *m, void *p) -- 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/