summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Gorby <russ.gorby@intel.com>2012-08-13 13:44:40 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-10-07 08:35:55 -0700
commitf73fd7d132c40bb779017444da92aed6c5dfcd95 (patch)
tree7d827d70ce1d3626d2d69a16e3d5ca0fde62cd4a
parentfc8cb6c219bf26cb4712f7daf8e1096030e5d0c9 (diff)
downloadlwn-f73fd7d132c40bb779017444da92aed6c5dfcd95.tar.gz
lwn-f73fd7d132c40bb779017444da92aed6c5dfcd95.zip
n_gsm: added interlocking for gsm_data_lock for certain code paths
commit 5e44708f75b0f8712da715d6babb0c21089b2317 upstream. There were some locking holes in the management of the MUX's message queue for 2 code paths: 1) gsmld_write_wakeup 2) receipt of CMD_FCON flow-control message In both cases gsm_data_kick is called w/o locking so it can collide with other other instances of gsm_data_kick (pulling messages tx_tail) or potentially other instances of __gsm_data_queu (adding messages to tx_head) Changed to take the tx_lock in these 2 cases Signed-off-by: Russ Gorby <russ.gorby@intel.com> Tested-by: Yin, Fengwei <fengwei.yin@intel.com> Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/n_gsm.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 1720055ca97b..671fbc2d7935 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -1193,6 +1193,8 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
u8 *data, int clen)
{
u8 buf[1];
+ unsigned long flags;
+
switch (command) {
case CMD_CLD: {
struct gsm_dlci *dlci = gsm->dlci[0];
@@ -1218,7 +1220,9 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
gsm->constipated = 0;
gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
/* Kick the link in case it is idling */
+ spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_data_kick(gsm);
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
break;
case CMD_MSC:
/* Out of band modem line change indicator for a DLCI */
@@ -2380,12 +2384,12 @@ static void gsmld_write_wakeup(struct tty_struct *tty)
/* Queue poll */
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_data_kick(gsm);
if (gsm->tx_bytes < TX_THRESH_LO) {
- spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_dlci_data_sweep(gsm);
- spin_unlock_irqrestore(&gsm->tx_lock, flags);
}
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
}
/**