On (04/13/17 14:50), Sergey Senozhatsky wrote: [..] > On (04/12/17 01:19), Sergey Senozhatsky wrote: > [..] > > it does offloading after X printed lines by the same process. > > if we reschedule, then the counter resets. which is probably OK, > > we don't really want any process, except for printk_kthread, to > > stay in console_unlock() forever. > > may be this can be changed. we don't want even printk_kthread to keep > console_sem locked for too long, because other process that might want > to lock console_sem have to sleep in TASK_UNINTERRUPTIBLE as long as > printing thread has pending messages to print. so may be the rule can > be "every process prints up to `atomic_print_limit' lines and then > offloads printing - wake_up()s printk_kthread and up()s console_sem". > some other process (printk_kthread or a process from console_sem wait > list, let them compete for console_sem) will eventually down() > console_sem and print the next `atomic_print_limit' lines, while > current process will have a chance to return from console_unlock() and > do something else.
something like this, perhaps. static inline bool console_offload_printing(void) { static struct task_struct *printing_task; static unsigned long lines_printed; static bool did_wakeup; if (!atomic_print_limit || !printk_kthread_enabled()) return false; /* We rescheduled - reset the counters. */ if (printing_task != current) { did_wakeup = false; lines_printed = 0; printing_task = current; return false; } /* * Don't reset the counter, let CPU overrun the limit. * The idea is that * * a) woken up printk_kthread (if succeeded) * or * b) concurrent printk from another CPU (if any) * * will change `printing_task' and reset the counter. * If neither a) nor b) happens - we continue printing from * current process. Which is bad and can be risky, but we can't * wake_up() printk_kthread, so things already don't look normal. */ lines_printed++; if (lines_printed < atomic_print_limit) return false; if (current == printk_kthread) { /* * Reset the counter, just in case if printk_kthread is the * only process left that would down() console_sem. */ lines_printed = 0; return true; } /* * A trivial emergency enforcement - give up on printk_kthread if * we can't wake it up. This assumes that `atomic_print_limit' is * large enough. */ if (lines_printed > 2 * (unsigned long long)atomic_print_limit) { printk_enforce_emergency = true; pr_crit("Declaring printk emergency mode.\n"); return false; } /* * Must be executed in 'printk_safe' context. Call into the * scheduler just once, in case if it backfires on us with * warnings and backtraces. */ if (!did_wakeup) { did_wakeup = true; wake_up_process(printk_kthread); } return true; } -ss