aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/hamradio
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2009-07-13 00:09:20 -0400
committerDavid S. Miller <davem@davemloft.net>2009-07-13 00:09:20 -0400
commitadeab1afb7de89555c69aab5ca21300c14af6369 (patch)
tree9e300563895b33a75876be58f167006fa8cbde3d /drivers/net/hamradio
parent635ecaa70e862f85f652581305fe0074810893be (diff)
NET: Fix locking issues in PPP, 6pack, mkiss and strip line disciplines.
Guido Trentalancia reports: I am trying to use the kiss driver in the Linux kernel that is being shipped with Fedora 10 but unfortunately I get the following oops: mkiss: AX.25 Multikiss, Hans Albas PE1AYX mkiss: ax0: crc mode is auto. ADDRCONF(NETDEV_CHANGE): ax0: link becomes ready ------------[ cut here ]------------ WARNING: at kernel/softirq.c:77 __local_bh_disable+0x2f/0x83() (Not tainted) [...] unloaded: microcode] Pid: 0, comm: swapper Not tainted 2.6.27.25-170.2.72.fc10.i686 #1 [<c042ddfb>] warn_on_slowpath+0x65/0x8b [<c06ab62b>] ? _spin_unlock_irqrestore+0x22/0x38 [<c04228b4>] ? __enqueue_entity+0xe3/0xeb [<c042431e>] ? enqueue_entity+0x203/0x20b [<c0424361>] ? enqueue_task_fair+0x3b/0x3f [<c041f88c>] ? resched_task+0x3a/0x6e [<c06ab62b>] ? _spin_unlock_irqrestore+0x22/0x38 [<c06ab4e2>] ? _spin_lock_bh+0xb/0x16 [<c043255b>] __local_bh_disable+0x2f/0x83 [<c04325ba>] local_bh_disable+0xb/0xd [<c06ab4e2>] _spin_lock_bh+0xb/0x16 [<f8b6f600>] mkiss_receive_buf+0x2fb/0x3a6 [mkiss] [<c0572a30>] flush_to_ldisc+0xf7/0x198 [<c0572b12>] tty_flip_buffer_push+0x41/0x51 [<f89477f2>] ftdi_process_read+0x375/0x4ad [ftdi_sio] [<f8947a5a>] ftdi_read_bulk_callback+0x130/0x138 [ftdi_sio] [<c05d4bec>] usb_hcd_giveback_urb+0x63/0x93 [<c05ea290>] uhci_giveback_urb+0xe5/0x15f [<c05eaabf>] uhci_scan_schedule+0x52e/0x767 [<c05f6288>] ? psmouse_handle_byte+0xc/0xe5 [<c054df78>] ? acpi_ev_gpe_detect+0xd6/0xe1 [<c05ec5b0>] uhci_irq+0x110/0x125 [<c05d4834>] usb_hcd_irq+0x40/0xa3 [<c0465313>] handle_IRQ_event+0x2f/0x64 [<c046642b>] handle_level_irq+0x74/0xbe [<c04663b7>] ? handle_level_irq+0x0/0xbe [<c0406e6e>] do_IRQ+0xc7/0xfe [<c0405668>] common_interrupt+0x28/0x30 [<c056821a>] ? acpi_idle_enter_simple+0x162/0x19d [<c0617f52>] cpuidle_idle_call+0x60/0x92 [<c0403c61>] cpu_idle+0x101/0x134 [<c069b1ba>] rest_init+0x4e/0x50 ======================= ---[ end trace b7cc8076093467ad ]--- ------------[ cut here ]------------ WARNING: at kernel/softirq.c:136 _local_bh_enable_ip+0x3d/0xc4() [...] Pid: 0, comm: swapper Tainted: G W 2.6.27.25-170.2.72.fc10.i686 [<c042ddfb>] warn_on_slowpath+0x65/0x8b [<c06ab62b>] ? _spin_unlock_irqrestore+0x22/0x38 [<c04228b4>] ? __enqueue_entity+0xe3/0xeb [<c042431e>] ? enqueue_entity+0x203/0x20b [<c0424361>] ? enqueue_task_fair+0x3b/0x3f [<c041f88c>] ? resched_task+0x3a/0x6e [<c06ab62b>] ? _spin_unlock_irqrestore+0x22/0x38 [<c06ab4e2>] ? _spin_lock_bh+0xb/0x16 [<f8b6f642>] ? mkiss_receive_buf+0x33d/0x3a6 [mkiss] [<c04325f9>] _local_bh_enable_ip+0x3d/0xc4 [<c0432688>] local_bh_enable_ip+0x8/0xa [<c06ab54d>] _spin_unlock_bh+0x11/0x13 [<f8b6f642>] mkiss_receive_buf+0x33d/0x3a6 [mkiss] [<c0572a30>] flush_to_ldisc+0xf7/0x198 [<c0572b12>] tty_flip_buffer_push+0x41/0x51 [<f89477f2>] ftdi_process_read+0x375/0x4ad [ftdi_sio] [<f8947a5a>] ftdi_read_bulk_callback+0x130/0x138 [ftdi_sio] [<c05d4bec>] usb_hcd_giveback_urb+0x63/0x93 [<c05ea290>] uhci_giveback_urb+0xe5/0x15f [<c05eaabf>] uhci_scan_schedule+0x52e/0x767 [<c05f6288>] ? psmouse_handle_byte+0xc/0xe5 [<c054df78>] ? acpi_ev_gpe_detect+0xd6/0xe1 [<c05ec5b0>] uhci_irq+0x110/0x125 [<c05d4834>] usb_hcd_irq+0x40/0xa3 [<c0465313>] handle_IRQ_event+0x2f/0x64 [<c046642b>] handle_level_irq+0x74/0xbe [<c04663b7>] ? handle_level_irq+0x0/0xbe [<c0406e6e>] do_IRQ+0xc7/0xfe [<c0405668>] common_interrupt+0x28/0x30 [<c056821a>] ? acpi_idle_enter_simple+0x162/0x19d [<c0617f52>] cpuidle_idle_call+0x60/0x92 [<c0403c61>] cpu_idle+0x101/0x134 [<c069b1ba>] rest_init+0x4e/0x50 ======================= ---[ end trace b7cc8076093467ad ]--- mkiss: ax0: Trying crc-smack mkiss: ax0: Trying crc-flexnet The issue was, that the locking code in mkiss was assuming it was only ever being called in process or bh context. Fixed by converting the involved locking code to use irq-safe locks. Review of other networking line disciplines shows that 6pack, both sync and async PPP and STRIP have similar issues. The ppp_async one is the most interesting one as it sorts out half of the issue as far back as 2004 in commit http://git.kernel.org/?p=linux/kernel/git/tglx/history.git;a=commitdiff;h=2996d8deaeddd01820691a872550dc0cfba0c37d Signed-off-by: Ralf Baechle <ralf@linux-mips.org> Reported-by: Guido Trentalancia <guido@trentalancia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/hamradio')
-rw-r--r--drivers/net/hamradio/6pack.c10
-rw-r--r--drivers/net/hamradio/mkiss.c41
2 files changed, 30 insertions, 21 deletions
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 155160052c8..913a5640659 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -398,13 +398,14 @@ static DEFINE_RWLOCK(disc_data_lock);
398 398
399static struct sixpack *sp_get(struct tty_struct *tty) 399static struct sixpack *sp_get(struct tty_struct *tty)
400{ 400{
401 unsigned long flags;
401 struct sixpack *sp; 402 struct sixpack *sp;
402 403
403 read_lock(&disc_data_lock); 404 read_lock_irqsave(&disc_data_lock, flags);
404 sp = tty->disc_data; 405 sp = tty->disc_data;
405 if (sp) 406 if (sp)
406 atomic_inc(&sp->refcnt); 407 atomic_inc(&sp->refcnt);
407 read_unlock(&disc_data_lock); 408 read_unlock_irqrestore(&disc_data_lock, flags);
408 409
409 return sp; 410 return sp;
410} 411}
@@ -688,12 +689,13 @@ out:
688 */ 689 */
689static void sixpack_close(struct tty_struct *tty) 690static void sixpack_close(struct tty_struct *tty)
690{ 691{
692 unsigned long flags;
691 struct sixpack *sp; 693 struct sixpack *sp;
692 694
693 write_lock(&disc_data_lock); 695 write_lock_irqsave(&disc_data_lock, flags);
694 sp = tty->disc_data; 696 sp = tty->disc_data;
695 tty->disc_data = NULL; 697 tty->disc_data = NULL;
696 write_unlock(&disc_data_lock); 698 write_unlock_irqrestore(&disc_data_lock, flags);
697 if (!sp) 699 if (!sp)
698 return; 700 return;
699 701
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index fda2fc83e9a..a7286500c18 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -244,15 +244,16 @@ static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc,
244/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */ 244/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */
245static void ax_bump(struct mkiss *ax) 245static void ax_bump(struct mkiss *ax)
246{ 246{
247 unsigned long flags;
247 struct sk_buff *skb; 248 struct sk_buff *skb;
248 int count; 249 int count;
249 250
250 spin_lock_bh(&ax->buflock); 251 spin_lock_irqsave(&ax->buflock, flags);
251 if (ax->rbuff[0] > 0x0f) { 252 if (ax->rbuff[0] > 0x0f) {
252 if (ax->rbuff[0] & 0x80) { 253 if (ax->rbuff[0] & 0x80) {
253 if (check_crc_16(ax->rbuff, ax->rcount) < 0) { 254 if (check_crc_16(ax->rbuff, ax->rcount) < 0) {
254 ax->dev->stats.rx_errors++; 255 ax->dev->stats.rx_errors++;
255 spin_unlock_bh(&ax->buflock); 256 spin_unlock_irqrestore(&ax->buflock, flags);
256 257
257 return; 258 return;
258 } 259 }
@@ -267,7 +268,7 @@ static void ax_bump(struct mkiss *ax)
267 } else if (ax->rbuff[0] & 0x20) { 268 } else if (ax->rbuff[0] & 0x20) {
268 if (check_crc_flex(ax->rbuff, ax->rcount) < 0) { 269 if (check_crc_flex(ax->rbuff, ax->rcount) < 0) {
269 ax->dev->stats.rx_errors++; 270 ax->dev->stats.rx_errors++;
270 spin_unlock_bh(&ax->buflock); 271 spin_unlock_irqrestore(&ax->buflock, flags);
271 return; 272 return;
272 } 273 }
273 if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) { 274 if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) {
@@ -294,7 +295,7 @@ static void ax_bump(struct mkiss *ax)
294 printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", 295 printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n",
295 ax->dev->name); 296 ax->dev->name);
296 ax->dev->stats.rx_dropped++; 297 ax->dev->stats.rx_dropped++;
297 spin_unlock_bh(&ax->buflock); 298 spin_unlock_irqrestore(&ax->buflock, flags);
298 return; 299 return;
299 } 300 }
300 301
@@ -303,11 +304,13 @@ static void ax_bump(struct mkiss *ax)
303 netif_rx(skb); 304 netif_rx(skb);
304 ax->dev->stats.rx_packets++; 305 ax->dev->stats.rx_packets++;
305 ax->dev->stats.rx_bytes += count; 306 ax->dev->stats.rx_bytes += count;
306 spin_unlock_bh(&ax->buflock); 307 spin_unlock_irqrestore(&ax->buflock, flags);
307} 308}
308 309
309static void kiss_unesc(struct mkiss *ax, unsigned char s) 310static void kiss_unesc(struct mkiss *ax, unsigned char s)
310{ 311{
312 unsigned long flags;
313
311 switch (s) { 314 switch (s) {
312 case END: 315 case END:
313 /* drop keeptest bit = VSV */ 316 /* drop keeptest bit = VSV */
@@ -334,18 +337,18 @@ static void kiss_unesc(struct mkiss *ax, unsigned char s)
334 break; 337 break;
335 } 338 }
336 339
337 spin_lock_bh(&ax->buflock); 340 spin_lock_irqsave(&ax->buflock, flags);
338 if (!test_bit(AXF_ERROR, &ax->flags)) { 341 if (!test_bit(AXF_ERROR, &ax->flags)) {
339 if (ax->rcount < ax->buffsize) { 342 if (ax->rcount < ax->buffsize) {
340 ax->rbuff[ax->rcount++] = s; 343 ax->rbuff[ax->rcount++] = s;
341 spin_unlock_bh(&ax->buflock); 344 spin_unlock_irqrestore(&ax->buflock, flags);
342 return; 345 return;
343 } 346 }
344 347
345 ax->dev->stats.rx_over_errors++; 348 ax->dev->stats.rx_over_errors++;
346 set_bit(AXF_ERROR, &ax->flags); 349 set_bit(AXF_ERROR, &ax->flags);
347 } 350 }
348 spin_unlock_bh(&ax->buflock); 351 spin_unlock_irqrestore(&ax->buflock, flags);
349} 352}
350 353
351static int ax_set_mac_address(struct net_device *dev, void *addr) 354static int ax_set_mac_address(struct net_device *dev, void *addr)
@@ -367,6 +370,7 @@ static void ax_changedmtu(struct mkiss *ax)
367{ 370{
368 struct net_device *dev = ax->dev; 371 struct net_device *dev = ax->dev;
369 unsigned char *xbuff, *rbuff, *oxbuff, *orbuff; 372 unsigned char *xbuff, *rbuff, *oxbuff, *orbuff;
373 unsigned long flags;
370 int len; 374 int len;
371 375
372 len = dev->mtu * 2; 376 len = dev->mtu * 2;
@@ -392,7 +396,7 @@ static void ax_changedmtu(struct mkiss *ax)
392 return; 396 return;
393 } 397 }
394 398
395 spin_lock_bh(&ax->buflock); 399 spin_lock_irqsave(&ax->buflock, flags);
396 400
397 oxbuff = ax->xbuff; 401 oxbuff = ax->xbuff;
398 ax->xbuff = xbuff; 402 ax->xbuff = xbuff;
@@ -423,7 +427,7 @@ static void ax_changedmtu(struct mkiss *ax)
423 ax->mtu = dev->mtu + 73; 427 ax->mtu = dev->mtu + 73;
424 ax->buffsize = len; 428 ax->buffsize = len;
425 429
426 spin_unlock_bh(&ax->buflock); 430 spin_unlock_irqrestore(&ax->buflock, flags);
427 431
428 kfree(oxbuff); 432 kfree(oxbuff);
429 kfree(orbuff); 433 kfree(orbuff);
@@ -433,6 +437,7 @@ static void ax_changedmtu(struct mkiss *ax)
433static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) 437static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
434{ 438{
435 struct mkiss *ax = netdev_priv(dev); 439 struct mkiss *ax = netdev_priv(dev);
440 unsigned long flags;
436 unsigned char *p; 441 unsigned char *p;
437 int actual, count; 442 int actual, count;
438 443
@@ -449,7 +454,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
449 454
450 p = icp; 455 p = icp;
451 456
452 spin_lock_bh(&ax->buflock); 457 spin_lock_irqsave(&ax->buflock, flags);
453 if ((*p & 0x0f) != 0) { 458 if ((*p & 0x0f) != 0) {
454 /* Configuration Command (kissparms(1). 459 /* Configuration Command (kissparms(1).
455 * Protocol spec says: never append CRC. 460 * Protocol spec says: never append CRC.
@@ -479,7 +484,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
479 ax->crcauto = (cmd ? 0 : 1); 484 ax->crcauto = (cmd ? 0 : 1);
480 printk(KERN_INFO "mkiss: %s: crc mode %s %d\n", ax->dev->name, (len) ? "set to" : "is", cmd); 485 printk(KERN_INFO "mkiss: %s: crc mode %s %d\n", ax->dev->name, (len) ? "set to" : "is", cmd);
481 } 486 }
482 spin_unlock_bh(&ax->buflock); 487 spin_unlock_irqrestore(&ax->buflock, flags);
483 netif_start_queue(dev); 488 netif_start_queue(dev);
484 489
485 return; 490 return;
@@ -512,7 +517,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
512 count = kiss_esc(p, (unsigned char *)ax->xbuff, len); 517 count = kiss_esc(p, (unsigned char *)ax->xbuff, len);
513 } 518 }
514 } 519 }
515 spin_unlock_bh(&ax->buflock); 520 spin_unlock_irqrestore(&ax->buflock, flags);
516 521
517 set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); 522 set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
518 actual = ax->tty->ops->write(ax->tty, ax->xbuff, count); 523 actual = ax->tty->ops->write(ax->tty, ax->xbuff, count);
@@ -704,13 +709,14 @@ static DEFINE_RWLOCK(disc_data_lock);
704 709
705static struct mkiss *mkiss_get(struct tty_struct *tty) 710static struct mkiss *mkiss_get(struct tty_struct *tty)
706{ 711{
712 unsigned long flags;
707 struct mkiss *ax; 713 struct mkiss *ax;
708 714
709 read_lock(&disc_data_lock); 715 read_lock_irqsave(&disc_data_lock, flags);
710 ax = tty->disc_data; 716 ax = tty->disc_data;
711 if (ax) 717 if (ax)
712 atomic_inc(&ax->refcnt); 718 atomic_inc(&ax->refcnt);
713 read_unlock(&disc_data_lock); 719 read_unlock_irqrestore(&disc_data_lock, flags);
714 720
715 return ax; 721 return ax;
716} 722}
@@ -809,12 +815,13 @@ out:
809 815
810static void mkiss_close(struct tty_struct *tty) 816static void mkiss_close(struct tty_struct *tty)
811{ 817{
818 unsigned long flags;
812 struct mkiss *ax; 819 struct mkiss *ax;
813 820
814 write_lock(&disc_data_lock); 821 write_lock_irqsave(&disc_data_lock, flags);
815 ax = tty->disc_data; 822 ax = tty->disc_data;
816 tty->disc_data = NULL; 823 tty->disc_data = NULL;
817 write_unlock(&disc_data_lock); 824 write_unlock_irqrestore(&disc_data_lock, flags);
818 825
819 if (!ax) 826 if (!ax)
820 return; 827 return;