Re: [PATCH] tty: fix race between flush_to_ldisc and tty_open

2018-12-21 Thread kbuild test robot
Hi Li,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on tty/tty-testing]
[also build test ERROR on v4.20-rc7 next-20181221]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/Li-RongQing/tty-fix-race-between-flush_to_ldisc-and-tty_open/20181222-030046
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git 
tty-testing
config: x86_64-allmodconfig (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64 

All errors (new ones prefixed by >>):

>> ERROR: "tty_ldisc_unlock" [drivers/staging/speakup/speakup.ko] undefined!

---
0-DAY kernel test infrastructureOpen Source Technology Center
https://lists.01.org/pipermail/kbuild-all   Intel Corporation


.config.gz
Description: application/gzip


[PATCH] tty: fix race between flush_to_ldisc and tty_open

2018-12-21 Thread Li RongQing
There still can be a race after the commit b027e2298bd588
("tty: fix data race between tty_init_dev and flush of buf"),
if receive_buf call comes before tty initialization completes
in n_tty_open and tty->driver_data may be NULL.

CPU0CPU1

  n_tty_open
  tty_init_dev
  tty_ldisc_unlock
  schedule
flush_to_ldisc
n_tty_receive_buf
uart_flush_chars
uart_start

Extending ldisc semaphore lock in tty_init_dev till driver_data
initializes completely after tty->ops->open().

Signed-off-by: Zhang Yu 
Signed-off-by: Li RongQing 
---
we see this bug in centos 7.4, and think b027e2298bd588 can not
fix it, since driver_data is NULL;

the trace is that:

[exception RIP: uart_start+24]
RIP: 814908b8  RSP: 881c23ab7d18  RFLAGS: 00010282
RAX:   RBX: 88182bafc400  RCX: 
RDX: 00020001  RSI: 001d  RDI: 88182bafc400
RBP: 881c23ab7d30   R8: 881fff956060   R9: 81b5dc20
R10: 5a07  R11: 0001  R12: 88182bafc400
R13: 881ff90c852d  R14: 88182baff400  R15: 
ORIG_RAX:   CS: 0010  SS: 0018
#11 [881c23ab7d38] uart_flush_chars at 81490ade
#12 [881c23ab7d48] n_tty_receive_buf at 81478b1d
#13 [881c23ab7de0] flush_to_ldisc at 8147bdc4
#14 [881c23ab7e28] process_one_work at 8109e210
#15 [881c23ab7e70] worker_thread at 8109e69e
#16 [881c23ab7ec8] kthread at 810a62d1
#17 [881c23ab7f50] ret_from_fork at 8171d677

other one

PID: 922TASK: 881c7fbc1f40  CPU: 29  COMMAND: "agetty"
 #0 [8818e9677a20] __schedule at 817114f2
 #1 [8818e9677a78] preempt_schedule at 81711f4f
 #2 [8818e9677a90] _raw_spin_unlock_irqrestore at 81713f7d
 #3 [8818e9677aa8] __wake_up at 810b03c4
 #4 [8818e9677ae0] n_tty_set_termios at 814770d3
 #5 [8818e9677b10] n_tty_open at 814772ec` 
 
 
 drivers/staging/speakup/spk_ttyio.c |  1 +
 drivers/tty/pty.c   |  2 ++
 drivers/tty/serdev/serdev-ttyport.c |  2 ++
 drivers/tty/tty_io.c| 14 +++---
 4 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/speakup/spk_ttyio.c 
b/drivers/staging/speakup/spk_ttyio.c
index 979e3ae249c1..c31f08c98383 100644
--- a/drivers/staging/speakup/spk_ttyio.c
+++ b/drivers/staging/speakup/spk_ttyio.c
@@ -155,6 +155,7 @@ static int spk_ttyio_initialise_ldisc(struct spk_synth 
*synth)
else
ret = -ENODEV;
 
+   tty_ldisc_unlock(tty);
if (ret) {
tty_unlock(tty);
return ret;
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 00099a8439d2..1b9684d4f718 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -873,9 +873,11 @@ static int ptmx_open(struct inode *inode, struct file 
*filp)
 
tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
 
+   tty_ldisc_unlock(tty);
tty_unlock(tty);
return 0;
 err_release:
+   tty_ldisc_unlock(tty);
tty_unlock(tty);
// This will also put-ref the fsi
tty_release(inode, filp);
diff --git a/drivers/tty/serdev/serdev-ttyport.c 
b/drivers/tty/serdev/serdev-ttyport.c
index fa1672993b4c..ce16cb303e28 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -123,6 +123,7 @@ static int ttyport_open(struct serdev_controller *ctrl)
if (ret)
goto err_close;
 
+   tty_ldisc_unlock(tty);
tty_unlock(serport->tty);
 
/* Bring the UART into a known 8 bits no parity hw fc state */
@@ -145,6 +146,7 @@ static int ttyport_open(struct serdev_controller *ctrl)
 err_close:
tty->ops->close(tty, NULL);
 err_unlock:
+   tty_ldisc_unlock(tty);
tty_unlock(tty);
tty_release_struct(tty, serport->tty_idx);
 
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 687250ec8032..199f45e2e1b1 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1351,7 +1351,6 @@ struct tty_struct *tty_init_dev(struct tty_driver 
*driver, int idx)
retval = tty_ldisc_setup(tty, tty->link);
if (retval)
goto err_release_tty;
-   tty_ldisc_unlock(tty);
/* Return the tty locked so that it cannot vanish under the caller */
return tty;
 
@@ -1926,7 +1925,7 @@ EXPORT_SYMBOL_GPL(tty_kopen);
  *   - concurrent tty removal from driver table
  */
 static struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode,
-struct file *filp)
+struct file *filp, bool *unlock)
 {
struct