On Thu, Jan 09, 2020 at 09:54:44PM +0000, Dmitry Safonov wrote: > Many embedded boards have a disconnected TTL level serial which can > generate some garbage that can lead to spurious false sysrq detects. > > Currently, sysrq can be either completely disabled for serial console > or always disabled (with CONFIG_MAGIC_SYSRQ_SERIAL), since > commit 732dbf3a6104 ("serial: do not accept sysrq characters via serial port") > > At Arista, we have such boards that can generate BREAK and random > garbage. While disabling sysrq for serial console would solve > the problem with spurious false sysrq triggers, it's also desirable > to have a way to enable sysrq back. > > As a measure of balance between on and off options, add > MAGIC_SYSRQ_SERIAL_SEQUENCE which is a string sequence that can enable > sysrq if it follows BREAK on a serial line. The longer the string - the > less likely it may be in the garbage. > > Having the way to enable sysrq was beneficial to debug lockups with > a manual investigation in field and on the other side preventing false > sysrq detections. > > Based-on-patch-by: Vasiliy Khoruzhick <vasilykh@xxxxxxxxxx> > Signed-off-by: Dmitry Safonov <dima@xxxxxxxxxx> > --- > drivers/tty/serial/serial_core.c | 52 ++++++++++++++++++++++++++++---- > include/linux/serial_core.h | 2 +- > lib/Kconfig.debug | 8 +++++ > 3 files changed, 55 insertions(+), 7 deletions(-) > > diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c > index 6ac9dfed3423..f70eba032d0b 100644 > --- a/drivers/tty/serial/serial_core.c > +++ b/drivers/tty/serial/serial_core.c > @@ -3081,6 +3081,38 @@ void uart_insert_char(struct uart_port *port, unsigned int status, > } > EXPORT_SYMBOL_GPL(uart_insert_char); > > +const char sysrq_toggle_seq[] = CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE; > + > +static void uart_sysrq_on(struct work_struct *w) > +{ > + sysrq_toggle_support(1); > + pr_info("SysRq is enabled by magic sequience on serial\n"); Do we want to say what serial port it is enabled on? And why is this done in a workqueue? > +} > +static DECLARE_WORK(sysrq_enable_work, uart_sysrq_on); > + > +static int uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch) > +{ > + if (sysrq_toggle_seq[0] == '\0') > + return 0; Is constantly checking the data stream like this going to slow things down overall? Ah, we are just checking this after BREAK, right? So that hopefully will not be that bad... > + > + BUILD_BUG_ON(ARRAY_SIZE(sysrq_toggle_seq) >= sizeof(port->sysrq_seq)*U8_MAX); > + if (sysrq_toggle_seq[port->sysrq_seq] != ch) { > + port->sysrq_seq = 0; > + return 0; > + } > + > + /* Without the last \0 */ > + if (++port->sysrq_seq < (ARRAY_SIZE(sysrq_toggle_seq) - 1)) { > + port->sysrq = jiffies + HZ*5; 5 second delay? You should document what this value is for somewhere here... > + return 1; > + } > + > + schedule_work(&sysrq_enable_work); > + > + port->sysrq = 0; > + return 1; > +} > + > int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) > { > if (!IS_ENABLED(CONFIG_MAGIC_SYSRQ_SERIAL)) > @@ -3090,9 +3122,13 @@ int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) > return 0; > > if (ch && time_before(jiffies, port->sysrq)) { > - handle_sysrq(ch); > - port->sysrq = 0; > - return 1; > + if (sysrq_get_mask()) { > + handle_sysrq(ch); > + port->sysrq = 0; > + return 1; > + } Isn't this change to test for sysrq_get_mask() a different change than checking for the "magic" data stream? > + if (uart_try_toggle_sysrq(port, ch)) > + return 1; > } > port->sysrq = 0; > > @@ -3109,9 +3145,13 @@ int uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch) > return 0; > > if (ch && time_before(jiffies, port->sysrq)) { > - port->sysrq_ch = ch; > - port->sysrq = 0; > - return 1; > + if (sysrq_get_mask()) { > + port->sysrq_ch = ch; > + port->sysrq = 0; > + return 1; > + } > + if (uart_try_toggle_sysrq(port, ch)) > + return 1; > } > port->sysrq = 0; > > diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h > index 255e86a474e9..1f4443db5474 100644 > --- a/include/linux/serial_core.h > +++ b/include/linux/serial_core.h > @@ -243,10 +243,10 @@ struct uart_port { > unsigned long sysrq; /* sysrq timeout */ > unsigned int sysrq_ch; /* char for sysrq */ > unsigned char has_sysrq; > + unsigned char sysrq_seq; /* index in sysrq_toggle_seq */ > > unsigned char hub6; /* this should be in the 8250 driver */ > unsigned char suspended; > - unsigned char unused; This is an unrelated change, let's leave it for a different patch that cleans up the layout of this structure, ok? thanks, greg k-h