Message ID | 20221107141638.3790965-1-john.ogness@linutronix.de |
---|---|
Headers | show |
Series | reduce console_lock scope | expand |
On Mon, Nov 07, 2022 at 03:22:00PM +0106, John Ogness wrote: > From: Thomas Gleixner <tglx@linutronix.de> > > Unprotected list walks are not necessarily safe. > > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > Signed-off-by: John Ogness <john.ogness@linutronix.de> > Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> > Reviewed-by: Douglas Anderson <dianders@chromium.org> > Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org> > Reviewed-by: Petr Mladek <pmladek@suse.com> Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org> Daniel.
On Mon, Nov 07, 2022 at 03:22:34PM +0106, John Ogness wrote: > configure_kgdboc() uses the console_lock for console list iteration. Use > the console_list_lock instead because list synchronization responsibility > will be removed from the console_lock in a later change. > > The SRCU iterator could have been used here, but a later change will > relocate the locking of the console_list_lock to also provide > synchronization against register_console(). > > Note, the console_lock is still needed to serialize the device() > callback with other console operations. > > Signed-off-by: John Ogness <john.ogness@linutronix.de> > --- > drivers/tty/serial/kgdboc.c | 22 ++++++++++++++++++++-- > 1 file changed, 20 insertions(+), 2 deletions(-) > > diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c > index 5be381003e58..82b4b4d67823 100644 > --- a/drivers/tty/serial/kgdboc.c > +++ b/drivers/tty/serial/kgdboc.c > @@ -451,6 +463,7 @@ static void kgdboc_earlycon_pre_exp_handler(void) > { > struct console *con; > static bool already_warned; > + int cookie; > > if (already_warned) > return; > @@ -463,9 +476,14 @@ static void kgdboc_earlycon_pre_exp_handler(void) > * serial drivers might be OK with this, print a warning once per > * boot if we detect this case. > */ > - for_each_console(con) > + cookie = console_srcu_read_lock(); > + for_each_console_srcu(con) { > if (con == kgdboc_earlycon_io_ops.cons) > - return; > + break; > + } > + console_srcu_read_unlock(cookie); > + if (con) > + return; This change isn't mentioned in the patch description. Daniel.
On 2022-11-09, Daniel Thompson <daniel.thompson@linaro.org> wrote: >> @@ -463,9 +476,14 @@ static void kgdboc_earlycon_pre_exp_handler(void) >> * serial drivers might be OK with this, print a warning once per >> * boot if we detect this case. >> */ >> - for_each_console(con) >> + cookie = console_srcu_read_lock(); >> + for_each_console_srcu(con) { >> if (con == kgdboc_earlycon_io_ops.cons) >> - return; >> + break; >> + } >> + console_srcu_read_unlock(cookie); >> + if (con) >> + return; > > This change isn't mentioned in the patch description. I will move this change into its own separate patch. tty: serial: kgdboc: use srcu console list iterator Use srcu console list iteration for safe console list traversal. Thanks. John
On 2022-11-10, Petr Mladek <pmladek@suse.com> wrote: >>> -static inline bool uart_console_enabled(struct uart_port *port) >>> +/* Variant of uart_console_registered() when the console_list_lock is held. */ >>> +static inline bool uart_console_registered_locked(struct uart_port *port) >>> { >>> - return uart_console(port) && (port->cons->flags & CON_ENABLED); >>> + return uart_console(port) && console_is_registered_locked(port->cons); >>> +} >>> + >>> +static inline bool uart_console_registered(struct uart_port *port) >>> +{ >>> + bool ret; >>> + >>> + console_list_lock(); >>> + ret = uart_console_registered_locked(port); >>> + console_list_unlock(); >>> + return ret; >> >> Perhaps >> >> return uart_console(port) && console_is_registered(); >> >> to avoid locking the list when the first condition is not true? > > I do not have strong opinion on this. It is true that the code > duplication is trivial but it is a code duplication. Either > way would work for me. I will go with Geert's suggestion for v4. It is important that we reduce lock contention for non-console ports. > The reset of the code looks good. Feel free to use: > > Reviewed-by: Petr Mladek <pmladek@suse.com> Thanks. John
On Mon, Nov 07, 2022 at 03:22:36PM +0106, John Ogness wrote: > kgdboc_earlycon_init() uses the console_lock to ensure that no consoles > are unregistered until the kgdboc_earlycon is setup. The console_list_lock > should be used instead because list synchronization responsibility will > be removed from the console_lock in a later change. > > Signed-off-by: John Ogness <john.ogness@linutronix.de> I've not looked at the other patches in the series to understand the future tense here (e.g. why we need intermediate patches like this one). However I've no objections to the change so: Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org> Daniel. > --- > drivers/tty/serial/kgdboc.c | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c > index 8c2b7ccdfebf..a3ed9b34e2ab 100644 > --- a/drivers/tty/serial/kgdboc.c > +++ b/drivers/tty/serial/kgdboc.c > @@ -558,13 +558,13 @@ static int __init kgdboc_earlycon_init(char *opt) > */ > > /* > - * Hold the console_lock to guarantee that no consoles are > + * Hold the console_list_lock to guarantee that no consoles are > * unregistered until the kgdboc_earlycon setup is complete. > * Trapping the exit() callback relies on exit() not being > * called until the trap is setup. This also allows safe > * traversal of the console list and race-free reading of @flags. > */ > - console_lock(); > + console_list_lock(); > for_each_console(con) { > if (con->write && con->read && > (con->flags & (CON_BOOT | CON_ENABLED)) && > @@ -606,7 +606,7 @@ static int __init kgdboc_earlycon_init(char *opt) > } > > unlock: > - console_unlock(); > + console_list_unlock(); > > /* Non-zero means malformed option so we always return zero */ > return 0; > -- > 2.30.2 >
On Wed 2022-11-09 10:50:43, John Ogness wrote: > On 2022-11-09, Daniel Thompson <daniel.thompson@linaro.org> wrote: > >> @@ -463,9 +476,14 @@ static void kgdboc_earlycon_pre_exp_handler(void) > >> * serial drivers might be OK with this, print a warning once per > >> * boot if we detect this case. > >> */ > >> - for_each_console(con) > >> + cookie = console_srcu_read_lock(); > >> + for_each_console_srcu(con) { > >> if (con == kgdboc_earlycon_io_ops.cons) > >> - return; > >> + break; > >> + } > >> + console_srcu_read_unlock(cookie); > >> + if (con) > >> + return; > > > > This change isn't mentioned in the patch description. > > I will move this change into its own separate patch. > > tty: serial: kgdboc: use srcu console list iterator > > Use srcu console list iteration for safe console list traversal. Yes, split it please :-) Anyway, both changes look good to me. Best Regards, Petr
On Mon 2022-11-07 15:22:36, John Ogness wrote: > kgdboc_earlycon_init() uses the console_lock to ensure that no consoles > are unregistered until the kgdboc_earlycon is setup. The console_list_lock > should be used instead because list synchronization responsibility will > be removed from the console_lock in a later change. > > Signed-off-by: John Ogness <john.ogness@linutronix.de> Reviewed-by: Petr Mladek <pmladek@suse.com> Best Regards, Petr
On 2022-11-07 09:15, John Ogness wrote: [...] > > The base commit for this series is from Paul McKenney's RCU tree > and provides an NMI-safe SRCU implementation [1]. Without the > NMI-safe SRCU implementation, this series is not less safe than > mainline. But we will need the NMI-safe SRCU implementation for > atomic consoles anyway, so we might as well get it in > now. Especially since it _does_ increase the reliability for > mainline in the panic path. So, your email got me to review the SRCU nmi-safe series: [1] https://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git/log/?h=srcunmisafe.2022.10.21a Especially this commit: https://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git/commit/?h=srcunmisafe.2022.10.21a&id=5d0f5953b60f5f7a278085b55ddc73e2932f4c33 I disagree with the overall approach taken there, which is to create yet another SRCU flavor, this time with explicit "nmi-safe" read-locks. This adds complexity to the kernel APIs and I think we can be clever about this and make SRCU nmi-safe without requiring a whole new incompatible API. You can find the basic idea needed to achieve this in the libside RCU user-space implementation. I needed to introduce a split-counter concept to support rseq vs atomics to keep track of per-cpu grace period counters. The "rseq" counter is the fast-path, but if rseq fails, the abort handler uses the atomic counter instead. https://github.com/compudj/side/blob/main/src/rcu.h#L23 struct side_rcu_percpu_count { uintptr_t begin; uintptr_t rseq_begin; uintptr_t end; uintptr_t rseq_end; } __attribute__((__aligned__(SIDE_CACHE_LINE_SIZE))); The idea is to "split" each percpu counter into two counters, one for rseq, and the other for atomics. When a grace period wants to observe the value of a percpu counter, it simply sums the two counters: https://github.com/compudj/side/blob/main/src/rcu.c#L112 The same idea can be applied to SRCU in the kernel: one counter for percpu ops, and the other counter for nmi context, so basically: srcu_read_lock() if (likely(!in_nmi())) increment the percpu-ops lock counter else increment the atomic lock counter srcu_read_unlock() if (likely(!in_nmi())) increment the percpu-ops unlock counter else increment the atomic unlock counter Then in the grace period sum the percpu-ops and the atomic values whenever each counter value is read. This would allow SRCU to be NMI-safe without requiring the callers to explicitly state whether they need to be nmi-safe or not, and would only take the overhead of the atomics in the NMI handlers rather than for all users which happen to use SRCU read locks shared with nmi handlers. Thoughts ? Thanks, Mathieu