On (12/18/17 18:36), Sergey Senozhatsky wrote: [..] > I see *a lot* of cases when CPU that call printk in a loop does not > end up flushing its messages. And the problem seems to be - preemption. > > > CPU0 CPU1 > > for_each_process_thread(g, p) > printk() > console_unlock() printk > console_trylock() fails > sets console_owner > sees console_owner > sets console_waiter > call_console_drivers > clears console_owner > sees console_waiter > hand off spins with local_irq disabled > sees that it has acquired > console_sem ownership > > enables local_irq > printk > .. << preemption >> > printk > ... unbound number of printk-s > printk > .. > printk > back to TASK_RUNNING > goes to console_unlock() > printk > local_irq_save > > ??? > *** if it will see > console_waiter [being in any > context] it will hand off. > otherwise, preemption > again and CPU0 can add even > more messages to logbuf > > local_irq_restore > > << preemption >>
hm... adding preemption_disable()/preemption_enable() to vprintk_emit() does not fix the issues on my side. preemption_disable(); ... if (console_trylock()) { console_unlock(); } else { // console_owner check and loop if needed // console_unlock(); } preemption_enable(); the root cause seems to be the fact that log_store() is significantly faster than msg_print_text() + call_console_drivers(). looking at this systemd-udevd-671 [002] dn.3 66.736432: offloading: set console_owner :0 systemd-udevd-671 [002] dn.3 66.749927: offloading: clear console_owner waiter != NULL :0 systemd-udevd-671 [002] dn.3 66.749931: offloading: set console_owner :0 systemd-udevd-671 [002] dn.3 66.763426: offloading: clear console_owner waiter != NULL :0 systemd-udevd-671 [002] dn.3 66.763430: offloading: set console_owner :0 systemd-udevd-671 [002] dn.3 66.776925: offloading: clear console_owner waiter != NULL :0 which is this thing len += msg_print_text(msg, console_prev, false, text + len, sizeof(text) - len); console_idx = log_next(console_idx); console_seq++; console_prev = msg->flags; raw_spin_unlock(&logbuf_lock); /* * While actively printing out messages, if another printk() * were to occur on another CPU, it may wait for this one to * finish. This task can not be preempted if there is a * waiter waiting to take over. */ raw_spin_lock(&console_owner_lock); console_owner = current; raw_spin_unlock(&console_owner_lock); + trace_offloading("set console_owner", " ", 0); /* The waiter may spin on us after setting console_owner */ spin_acquire(&console_owner_dep_map, 0, 0, _THIS_IP_); stop_critical_timings(); /* don't trace print latency */ call_console_drivers(level, text, len); start_critical_timings(); raw_spin_lock(&console_owner_lock); waiter = READ_ONCE(console_waiter); console_owner = NULL; raw_spin_unlock(&console_owner_lock); + trace_offloading("clear console_owner", + " waiter != NULL ", !!waiter); it takes call_console_drivers() 0.01+ of a second to print some of the messages [I think we can ignore raw_spin_lock(&console_owner_lock) and fully blame call_console_drivers()]. so vprintk_emit() seems to be gazillion times faster and i_do_printks can add tons of messages while some other process prints just one. to be more precise, I see from the traces that i_do_printks can add 1100 messages to the logbuf while call_console_drivers() prints just one. systemd-udevd-671 owns the lock. sets the console_owner. i_do_printks keeps adding printks. there kworker/0:1-135 that just ahead of i_do_printks-1992 and registers itself as the console_sem waiter. systemd-udevd-671 [003] d..3 66.334866: offloading: set console_owner :0 kworker/0:1-135 [000] d..2 66.335999: offloading: vprintk_emit()->trylock FAIL will spin? :1 i_do_printks-1992 [002] d..2 66.345474: offloading: vprintk_emit()->trylock FAIL will spin? :0 x 1100 ... systemd-udevd-671 [003] d..3 66.345917: offloading: cleaar console_owner waiter != NULL :1 i_do_printks-1992 finishes printing [it does limited number of printks], it does not compete for console_sem anymore, so those are other tasks that have to flush pending messages stored by i_do_printks-1992 :( -ss