[RFC PATCH 6.6.y 4/4] misc: ti-st: synchronize TTY teardown with transport removal

Hongyan Xu <[email protected]>
Newsgroups org.kernel.vger.linux-gpio,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
Unregistering the line discipline does not close an instance which is
already attached to a TTY.  Its callbacks and work_write_wakeup can keep
using the transport after st_core_exit() frees it.

Protect the attached TTY pointer with the core lock.  On removal, take a
TTY reference and synchronously hang it up, then cancel the wakeup work
before releasing the core.  Also cancel the work in normal close and clear
disc_data only after the close cleanup is complete.

Fixes: 53618cc1e51e ("Staging: sources for ST core")
Cc: [email protected]
Signed-off-by: Hongyan Xu <[email protected]>
---
 drivers/misc/ti-st/st_core.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 3aed6c3..7610656 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -723,13 +723,18 @@ EXPORT_SYMBOL_GPL(st_unregister);
 static int st_tty_open(struct tty_struct *tty)
 {
 	struct st_data_s *st_gdata __free(st_kim) = NULL;
+	unsigned long flags;
+
 	pr_info("%s ", __func__);
 
 	st_kim_ref(&st_gdata, 0);
 	if (!st_gdata)
 		return -ENODEV;
+
+	spin_lock_irqsave(&st_gdata->lock, flags);
 	st_gdata->tty = tty;
 	tty->disc_data = st_gdata;
+	spin_unlock_irqrestore(&st_gdata->lock, flags);
 
 	/* don't do an wakeup for now */
 	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
@@ -757,6 +762,7 @@ static void st_tty_close(struct tty_struct *tty)
 	struct	st_data_s *st_gdata = tty->disc_data;
 
 	pr_info("%s ", __func__);
+	cancel_work_sync(&st_gdata->work_write_wakeup);
 
 	/*
 	 * TODO:
@@ -777,7 +783,6 @@ static void st_tty_close(struct tty_struct *tty)
 	 * N_TI_WL ldisc is un-installed
 	 */
 	st_kim_complete(st_gdata->kim_data);
-	st_gdata->tty = NULL;
 	/* Flush any pending characters in the driver and discipline. */
 	tty_ldisc_flush(tty);
 	tty_driver_flush_buffer(tty);
@@ -791,6 +796,8 @@ static void st_tty_close(struct tty_struct *tty)
 	st_gdata->rx_state = ST_W4_PACKET_TYPE;
 	kfree_skb(st_gdata->rx_skb);
 	st_gdata->rx_skb = NULL;
+	st_gdata->tty = NULL;
+	tty->disc_data = NULL;
 	spin_unlock_irqrestore(&st_gdata->lock, flags);
 
 	pr_debug("%s: done ", __func__);
@@ -905,6 +912,8 @@ err_unreg_ldisc:
 
 void st_core_exit(struct st_data_s *st_gdata)
 {
+	struct tty_struct *tty;
+	unsigned long flags;
 	long err;
 
 	if (!st_gdata)
@@ -914,6 +923,14 @@ void st_core_exit(struct st_data_s *st_gdata)
 	wait_event(st_gdata->users_wait,
 		   !atomic_read(&st_gdata->active_users));
 
+	spin_lock_irqsave(&st_gdata->lock, flags);
+	tty = tty_kref_get(st_gdata->tty);
+	spin_unlock_irqrestore(&st_gdata->lock, flags);
+	if (tty)
+		tty_vhangup(tty);
+	cancel_work_sync(&st_gdata->work_write_wakeup);
+	tty_kref_put(tty);
+
 	/* internal module cleanup */
 	err = st_ll_deinit(st_gdata);
 	if (err)
-- 
2.50.1.windows.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.