From e380a81e34375a38f253b42394ef06ca3127559f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:50 +0100 Subject: TTY: pdc_cons, fix racy tty test The tty->count test in the timer was racy. Let's remove the test and properly delete the timer and wait for the body to finish using _sync version of del_timer. Signed-off-by: Jiri Slaby Cc: Kyle McMartin Cc: Helge Deller Cc: "James E.J. Bottomley" Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/pdc_cons.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index fc770be465ff..c1db65fc4525 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -103,7 +103,7 @@ static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp) static void pdc_console_tty_close(struct tty_struct *tty, struct file *filp) { if (!tty->count) - del_timer(&pdc_console_timer); + del_timer_sync(&pdc_console_timer); } static int pdc_console_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) @@ -153,7 +153,7 @@ static void pdc_console_poll(unsigned long unused) if (count) tty_flip_buffer_push(tty); - if (tty->count && (pdc_cons.flags & CON_ENABLED)) + if (pdc_cons.flags & CON_ENABLED) mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY); } -- cgit v1.2.3-55-g7522 From 52b762f7a94c88e5a8aa2be67a06a6f01020cc82 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:51 +0100 Subject: TTY: pdc_cons, fix open vs timer race The timer is initialized too late. tty->open may fire an invalid timer. So initialize the timer earlier using DEFINE_TIMER. Signed-off-by: Jiri Slaby Cc: Kyle McMartin Cc: Helge Deller Cc: "James E.J. Bottomley" Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/pdc_cons.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index c1db65fc4525..8ad05215d4b1 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -90,7 +90,8 @@ static int pdc_console_setup(struct console *co, char *options) #define PDC_CONS_POLL_DELAY (30 * HZ / 1000) -static struct timer_list pdc_console_timer; +static void pdc_console_poll(unsigned long unused); +static DEFINE_TIMER(pdc_console_timer, pdc_console_poll, 0, 0); static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp) { @@ -205,10 +206,6 @@ static int __init pdc_console_tty_driver_init(void) pdc_console_tty_driver = drv; - /* No need to initialize the pdc_console_timer if tty isn't allocated */ - init_timer(&pdc_console_timer); - pdc_console_timer.function = pdc_console_poll; - return 0; } -- cgit v1.2.3-55-g7522 From 0b479d54ae7b79f62f09ef977c2228e579924d38 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:52 +0100 Subject: TTY: pdc_cons, fix open vs pdc_console_tty_driver race Assign the pointer to pdc_console_tty_driver (a tty_driver) earlier. Otherwise the timer may dereference NULL. Signed-off-by: Jiri Slaby Cc: Kyle McMartin Cc: Helge Deller Cc: "James E.J. Bottomley" Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/pdc_cons.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index 8ad05215d4b1..d14e20fc60df 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -160,9 +160,7 @@ static void pdc_console_poll(unsigned long unused) static int __init pdc_console_tty_driver_init(void) { - int err; - struct tty_driver *drv; /* Check if the console driver is still registered. * It is unregistered if the pdc console was not selected as the @@ -184,28 +182,27 @@ static int __init pdc_console_tty_driver_init(void) printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n"); pdc_cons.flags &= ~CON_BOOT; - drv = alloc_tty_driver(1); + pdc_console_tty_driver = alloc_tty_driver(1); - if (!drv) + if (!pdc_console_tty_driver) return -ENOMEM; - drv->driver_name = "pdc_cons"; - drv->name = "ttyB"; - drv->major = MUX_MAJOR; - drv->minor_start = 0; - drv->type = TTY_DRIVER_TYPE_SYSTEM; - drv->init_termios = tty_std_termios; - drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; - tty_set_operations(drv, &pdc_console_tty_ops); - - err = tty_register_driver(drv); + pdc_console_tty_driver->driver_name = "pdc_cons"; + pdc_console_tty_driver->name = "ttyB"; + pdc_console_tty_driver->major = MUX_MAJOR; + pdc_console_tty_driver->minor_start = 0; + pdc_console_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; + pdc_console_tty_driver->init_termios = tty_std_termios; + pdc_console_tty_driver->flags = TTY_DRIVER_REAL_RAW | + TTY_DRIVER_RESET_TERMIOS; + tty_set_operations(pdc_console_tty_driver, &pdc_console_tty_ops); + + err = tty_register_driver(pdc_console_tty_driver); if (err) { printk(KERN_ERR "Unable to register the PDC console TTY driver\n"); return err; } - pdc_console_tty_driver = drv; - return 0; } -- cgit v1.2.3-55-g7522 From 5dd5bc40f3b6e0ccdaad948dbadc94ad0906cb25 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 5 Mar 2012 14:52:53 +0100 Subject: TTY: pdc_cons, use tty_port Instead of digging a tty out of the tty_driver struct, which is not defined to work, use tty_port properly. This includes proper tty refcounting even though there is no possible race currently. But we will need tty_port for tty buffers in the future anyway. Signed-off-by: Jiri Slaby Cc: Kyle McMartin Cc: Helge Deller Cc: "James E.J. Bottomley" Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/pdc_cons.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'arch/parisc/kernel') diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index d14e20fc60df..4f004596a6e7 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -92,10 +92,11 @@ static int pdc_console_setup(struct console *co, char *options) static void pdc_console_poll(unsigned long unused); static DEFINE_TIMER(pdc_console_timer, pdc_console_poll, 0, 0); +static struct tty_port tty_port; static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp) { - + tty_port_tty_set(&tty_port, tty); mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY); return 0; @@ -103,8 +104,10 @@ static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp) static void pdc_console_tty_close(struct tty_struct *tty, struct file *filp) { - if (!tty->count) + if (!tty->count) { del_timer_sync(&pdc_console_timer); + tty_port_tty_set(&tty_port, NULL); + } } static int pdc_console_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) @@ -123,8 +126,6 @@ static int pdc_console_tty_chars_in_buffer(struct tty_struct *tty) return 0; /* no buffer */ } -static struct tty_driver *pdc_console_tty_driver; - static const struct tty_operations pdc_console_tty_ops = { .open = pdc_console_tty_open, .close = pdc_console_tty_close, @@ -135,10 +136,8 @@ static const struct tty_operations pdc_console_tty_ops = { static void pdc_console_poll(unsigned long unused) { - int data, count = 0; - - struct tty_struct *tty = pdc_console_tty_driver->ttys[0]; + struct tty_struct *tty = tty_port_tty_get(&tty_port); if (!tty) return; @@ -154,10 +153,14 @@ static void pdc_console_poll(unsigned long unused) if (count) tty_flip_buffer_push(tty); + tty_kref_put(tty); + if (pdc_cons.flags & CON_ENABLED) mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY); } +static struct tty_driver *pdc_console_tty_driver; + static int __init pdc_console_tty_driver_init(void) { int err; @@ -182,6 +185,8 @@ static int __init pdc_console_tty_driver_init(void) printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n"); pdc_cons.flags &= ~CON_BOOT; + tty_port_init(&tty_port); + pdc_console_tty_driver = alloc_tty_driver(1); if (!pdc_console_tty_driver) -- cgit v1.2.3-55-g7522