diff options
author | Russ Gorby <russ.gorby@intel.com> | 2012-08-13 08:44:40 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-08-16 15:03:30 -0400 |
commit | 5e44708f75b0f8712da715d6babb0c21089b2317 (patch) | |
tree | e5f4f2ecd25649b5d47589ba2cf919c4e92ed222 /drivers/tty/n_gsm.c | |
parent | 10c6c383e43565c9c6ec07ff8eb2825f8091bdf0 (diff) |
n_gsm: added interlocking for gsm_data_lock for certain code paths
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>
Cc: Riding School <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/n_gsm.c')
-rw-r--r-- | drivers/tty/n_gsm.c | 8 |
1 files changed, 6 insertions, 2 deletions
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 5f68f2a70c5c..0d93e51cb23d 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c | |||
@@ -1205,6 +1205,8 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, | |||
1205 | u8 *data, int clen) | 1205 | u8 *data, int clen) |
1206 | { | 1206 | { |
1207 | u8 buf[1]; | 1207 | u8 buf[1]; |
1208 | unsigned long flags; | ||
1209 | |||
1208 | switch (command) { | 1210 | switch (command) { |
1209 | case CMD_CLD: { | 1211 | case CMD_CLD: { |
1210 | struct gsm_dlci *dlci = gsm->dlci[0]; | 1212 | struct gsm_dlci *dlci = gsm->dlci[0]; |
@@ -1225,7 +1227,9 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, | |||
1225 | gsm->constipated = 0; | 1227 | gsm->constipated = 0; |
1226 | gsm_control_reply(gsm, CMD_FCON, NULL, 0); | 1228 | gsm_control_reply(gsm, CMD_FCON, NULL, 0); |
1227 | /* Kick the link in case it is idling */ | 1229 | /* Kick the link in case it is idling */ |
1230 | spin_lock_irqsave(&gsm->tx_lock, flags); | ||
1228 | gsm_data_kick(gsm); | 1231 | gsm_data_kick(gsm); |
1232 | spin_unlock_irqrestore(&gsm->tx_lock, flags); | ||
1229 | break; | 1233 | break; |
1230 | case CMD_FCOFF: | 1234 | case CMD_FCOFF: |
1231 | /* Modem wants us to STFU */ | 1235 | /* Modem wants us to STFU */ |
@@ -2392,12 +2396,12 @@ static void gsmld_write_wakeup(struct tty_struct *tty) | |||
2392 | 2396 | ||
2393 | /* Queue poll */ | 2397 | /* Queue poll */ |
2394 | clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); | 2398 | clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); |
2399 | spin_lock_irqsave(&gsm->tx_lock, flags); | ||
2395 | gsm_data_kick(gsm); | 2400 | gsm_data_kick(gsm); |
2396 | if (gsm->tx_bytes < TX_THRESH_LO) { | 2401 | if (gsm->tx_bytes < TX_THRESH_LO) { |
2397 | spin_lock_irqsave(&gsm->tx_lock, flags); | ||
2398 | gsm_dlci_data_sweep(gsm); | 2402 | gsm_dlci_data_sweep(gsm); |
2399 | spin_unlock_irqrestore(&gsm->tx_lock, flags); | ||
2400 | } | 2403 | } |
2404 | spin_unlock_irqrestore(&gsm->tx_lock, flags); | ||
2401 | } | 2405 | } |
2402 | 2406 | ||
2403 | /** | 2407 | /** |