aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Naujoks <nautsch2@gmail.com>2013-09-13 13:37:11 -0400
committerDavid S. Miller <davem@davemloft.net>2013-09-20 15:38:26 -0400
commitcc9fa74e2a195f7bab27fbbc4896d2fe3ec32150 (patch)
tree73ac9a9033f828b7130f4717005eb4404b8e67c5
parentdcb30e659287a6b40dafed1362532da42ec27229 (diff)
slip/slcan: added locking in wakeup function
The locking is needed, since the the internal buffer for the CAN frames is changed during the wakeup call. This could cause buffer inconsistencies under high loads, especially for the outgoing short CAN packet skbuffs. The needed locks led to deadlocks before commit "5ede52538ee2b2202d9dff5b06c33bfde421e6e4 tty: Remove extra wakeup from pty write() path", which removed the direct callback to the wakeup function from the tty layer. As slcan.c is based on slip.c the issue in the original code is fixed, too. Signed-off-by: Andre Naujoks <nautsch2@gmail.com> Acked-by: Oliver Hartkopp <socketcan@hartkopp.net> Acked-by: Marc Kleine-Budde <mkl@pengutronix.de> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/can/slcan.c3
-rw-r--r--drivers/net/slip/slip.c3
2 files changed, 6 insertions, 0 deletions
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index 874188ba06f7..d571e2e9708f 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -286,11 +286,13 @@ static void slcan_write_wakeup(struct tty_struct *tty)
286 if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev)) 286 if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
287 return; 287 return;
288 288
289 spin_lock(&sl->lock);
289 if (sl->xleft <= 0) { 290 if (sl->xleft <= 0) {
290 /* Now serial buffer is almost free & we can start 291 /* Now serial buffer is almost free & we can start
291 * transmission of another packet */ 292 * transmission of another packet */
292 sl->dev->stats.tx_packets++; 293 sl->dev->stats.tx_packets++;
293 clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 294 clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
295 spin_unlock(&sl->lock);
294 netif_wake_queue(sl->dev); 296 netif_wake_queue(sl->dev);
295 return; 297 return;
296 } 298 }
@@ -298,6 +300,7 @@ static void slcan_write_wakeup(struct tty_struct *tty)
298 actual = tty->ops->write(tty, sl->xhead, sl->xleft); 300 actual = tty->ops->write(tty, sl->xhead, sl->xleft);
299 sl->xleft -= actual; 301 sl->xleft -= actual;
300 sl->xhead += actual; 302 sl->xhead += actual;
303 spin_unlock(&sl->lock);
301} 304}
302 305
303/* Send a can_frame to a TTY queue. */ 306/* Send a can_frame to a TTY queue. */
diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c
index a34d6bf5e43b..cc70ecfc7062 100644
--- a/drivers/net/slip/slip.c
+++ b/drivers/net/slip/slip.c
@@ -429,11 +429,13 @@ static void slip_write_wakeup(struct tty_struct *tty)
429 if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) 429 if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
430 return; 430 return;
431 431
432 spin_lock(&sl->lock);
432 if (sl->xleft <= 0) { 433 if (sl->xleft <= 0) {
433 /* Now serial buffer is almost free & we can start 434 /* Now serial buffer is almost free & we can start
434 * transmission of another packet */ 435 * transmission of another packet */
435 sl->dev->stats.tx_packets++; 436 sl->dev->stats.tx_packets++;
436 clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 437 clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
438 spin_unlock(&sl->lock);
437 sl_unlock(sl); 439 sl_unlock(sl);
438 return; 440 return;
439 } 441 }
@@ -441,6 +443,7 @@ static void slip_write_wakeup(struct tty_struct *tty)
441 actual = tty->ops->write(tty, sl->xhead, sl->xleft); 443 actual = tty->ops->write(tty, sl->xhead, sl->xleft);
442 sl->xleft -= actual; 444 sl->xleft -= actual;
443 sl->xhead += actual; 445 sl->xhead += actual;
446 spin_unlock(&sl->lock);
444} 447}
445 448
446static void sl_tx_timeout(struct net_device *dev) 449static void sl_tx_timeout(struct net_device *dev)