diff options
author | Girish Mahadevan <girishm@codeaurora.org> | 2016-04-15 15:08:07 -0600 |
---|---|---|
committer | Mukesh Kumar Savaliya <msavaliy@codeaurora.org> | 2016-07-12 19:41:59 +0530 |
commit | b663776b59caf5b9ed14693fec01fa9a47a907b7 (patch) | |
tree | f4664b616ed29a4000217dd6674e93cda1f0a9c2 /drivers/tty | |
parent | 400520a6e2f06cc7c45e386e769a85d4aded565b (diff) |
msm_serial_hs: Add defensive checks due to sudden port close
In certain scenarios, it is possible for a close to be called on the tty
port while the rx thread is still processing. In certain scenarios a
race between the 2 threads could lead to unexpected results such as making
BAM API calls after the pipes are disconnected or the thread accessing the
framework structures after they're freed.
Add defensive checks to:
- Check the state of the rx pipes and tty before running the rx work
thread.
- When closing the port, flush the rx work thread and wait till there
are no pending buffers before forcing a close. Currently the shutdown
waits on the flush state of the rx pipe to be in SHUTDOWN , but this
only happens after the rx thread runs, kicks the runtime pm which puts
it in the SHUTDOWN state. But since the port close calls the runtime pm
suspend callback, just wait on the thread to finish the buffer.
Change-Id: Ibf56e1aeb0c6811fec36f7618933d74c367ed305
Signed-off-by: Girish Mahadevan <girishm@codeaurora.org>
Signed-off-by: Mukesh Kumar Savaliya <msavaliy@codeaurora.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/msm_serial_hs.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index 6843711774b2..75cb4771d908 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -1576,6 +1576,16 @@ static void flip_insert_work(struct work_struct *work) struct tty_struct *tty = msm_uport->uport.state->port.tty; spin_lock_irqsave(&msm_uport->uport.lock, flags); + if (!tty || msm_uport->rx.flush == FLUSH_SHUTDOWN) { + dev_err(msm_uport->uport.dev, + "%s:Invalid driver state flush %d\n", + __func__, msm_uport->rx.flush); + MSM_HS_ERR("%s:Invalid driver state flush %d\n", + __func__, msm_uport->rx.flush); + spin_unlock_irqrestore(&msm_uport->uport.lock, flags); + return; + } + if (msm_uport->rx.buffer_pending == NONE_PENDING) { MSM_HS_ERR("Error: No buffer pending in %s", __func__); spin_unlock_irqrestore(&msm_uport->uport.lock, flags); @@ -1648,6 +1658,16 @@ static void msm_serial_hs_rx_work(struct kthread_work *work) spin_lock_irqsave(&uport->lock, flags); + if (!tty || rx->flush == FLUSH_SHUTDOWN) { + dev_err(uport->dev, "%s:Invalid driver state flush %d\n", + __func__, rx->flush); + MSM_HS_ERR("%s:Invalid driver state flush %d\n", + __func__, rx->flush); + spin_unlock_irqrestore(&uport->lock, flags); + msm_hs_resource_unvote(msm_uport); + return; + } + /* * Process all pending descs or if nothing is * queued - called from termios @@ -3582,12 +3602,12 @@ static void msm_hs_shutdown(struct uart_port *uport) if (msm_uport->rx.flush != FLUSH_SHUTDOWN) { /* disable and disconnect rx */ - msm_hs_disconnect_rx(uport); ret = wait_event_timeout(msm_uport->rx.wait, - msm_uport->rx.flush == FLUSH_SHUTDOWN, 500); + !msm_uport->rx.pending_flag, 500); if (!ret) MSM_HS_WARN("%s(): rx disconnect not complete", __func__); + msm_hs_disconnect_rx(uport); } cancel_delayed_work_sync(&msm_uport->rx.flip_insert_work); |