aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/net/hamradio/6pack.c10
-rw-r--r--drivers/net/hamradio/mkiss.c41
-rw-r--r--drivers/net/ppp_async.c11
-rw-r--r--drivers/net/ppp_synctty.c11
-rw-r--r--drivers/net/wireless/strip.c39
5 files changed, 68 insertions, 44 deletions
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 155160052c8b..913a56406594 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 fda2fc83e9a1..a7286500c186 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;
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index 17c116bb332c..1fd319bf758e 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -132,13 +132,15 @@ static DEFINE_RWLOCK(disc_data_lock);
132 132
133static struct asyncppp *ap_get(struct tty_struct *tty) 133static struct asyncppp *ap_get(struct tty_struct *tty)
134{ 134{
135 unsigned long flags;
135 struct asyncppp *ap; 136 struct asyncppp *ap;
136 137
137 read_lock(&disc_data_lock); 138 read_lock_irqsave(&disc_data_lock, flags);
138 ap = tty->disc_data; 139 ap = tty->disc_data;
139 if (ap != NULL) 140 if (ap != NULL)
140 atomic_inc(&ap->refcnt); 141 atomic_inc(&ap->refcnt);
141 read_unlock(&disc_data_lock); 142 read_unlock_irqrestore(&disc_data_lock, flags);
143
142 return ap; 144 return ap;
143} 145}
144 146
@@ -215,12 +217,13 @@ ppp_asynctty_open(struct tty_struct *tty)
215static void 217static void
216ppp_asynctty_close(struct tty_struct *tty) 218ppp_asynctty_close(struct tty_struct *tty)
217{ 219{
220 unsigned long flags;
218 struct asyncppp *ap; 221 struct asyncppp *ap;
219 222
220 write_lock_irq(&disc_data_lock); 223 write_lock_irqsave(&disc_data_lock, flags);
221 ap = tty->disc_data; 224 ap = tty->disc_data;
222 tty->disc_data = NULL; 225 tty->disc_data = NULL;
223 write_unlock_irq(&disc_data_lock); 226 write_unlock_irqrestore(&disc_data_lock, flags);
224 if (!ap) 227 if (!ap)
225 return; 228 return;
226 229
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index aa3d39f38e22..1b3f75febee1 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -182,13 +182,15 @@ static DEFINE_RWLOCK(disc_data_lock);
182 182
183static struct syncppp *sp_get(struct tty_struct *tty) 183static struct syncppp *sp_get(struct tty_struct *tty)
184{ 184{
185 unsigned long flags;
185 struct syncppp *ap; 186 struct syncppp *ap;
186 187
187 read_lock(&disc_data_lock); 188 read_lock_irqsave(&disc_data_lock, flags);
188 ap = tty->disc_data; 189 ap = tty->disc_data;
189 if (ap != NULL) 190 if (ap != NULL)
190 atomic_inc(&ap->refcnt); 191 atomic_inc(&ap->refcnt);
191 read_unlock(&disc_data_lock); 192 read_unlock_irqrestore(&disc_data_lock, flags);
193
192 return ap; 194 return ap;
193} 195}
194 196
@@ -262,12 +264,13 @@ ppp_sync_open(struct tty_struct *tty)
262static void 264static void
263ppp_sync_close(struct tty_struct *tty) 265ppp_sync_close(struct tty_struct *tty)
264{ 266{
267 unsigned long flags;
265 struct syncppp *ap; 268 struct syncppp *ap;
266 269
267 write_lock_irq(&disc_data_lock); 270 write_lock_irqsave(&disc_data_lock, flags);
268 ap = tty->disc_data; 271 ap = tty->disc_data;
269 tty->disc_data = NULL; 272 tty->disc_data = NULL;
270 write_unlock_irq(&disc_data_lock); 273 write_unlock_irqrestore(&disc_data_lock, flags);
271 if (!ap) 274 if (!ap)
272 return; 275 return;
273 276
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 38366a56b71f..3d39f6587eb9 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -856,6 +856,7 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu)
856 unsigned char *orbuff = strip_info->rx_buff; 856 unsigned char *orbuff = strip_info->rx_buff;
857 unsigned char *osbuff = strip_info->sx_buff; 857 unsigned char *osbuff = strip_info->sx_buff;
858 unsigned char *otbuff = strip_info->tx_buff; 858 unsigned char *otbuff = strip_info->tx_buff;
859 unsigned long flags;
859 860
860 if (new_mtu > MAX_SEND_MTU) { 861 if (new_mtu > MAX_SEND_MTU) {
861 printk(KERN_ERR 862 printk(KERN_ERR
@@ -864,11 +865,11 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu)
864 return -EINVAL; 865 return -EINVAL;
865 } 866 }
866 867
867 spin_lock_bh(&strip_lock); 868 spin_lock_irqsave(&strip_lock, flags);
868 if (!allocate_buffers(strip_info, new_mtu)) { 869 if (!allocate_buffers(strip_info, new_mtu)) {
869 printk(KERN_ERR "%s: unable to grow strip buffers, MTU change cancelled.\n", 870 printk(KERN_ERR "%s: unable to grow strip buffers, MTU change cancelled.\n",
870 strip_info->dev->name); 871 strip_info->dev->name);
871 spin_unlock_bh(&strip_lock); 872 spin_unlock_irqrestore(&strip_lock, flags);
872 return -ENOMEM; 873 return -ENOMEM;
873 } 874 }
874 875
@@ -892,7 +893,7 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu)
892 } 893 }
893 } 894 }
894 strip_info->tx_head = strip_info->tx_buff; 895 strip_info->tx_head = strip_info->tx_buff;
895 spin_unlock_bh(&strip_lock); 896 spin_unlock_irqrestore(&strip_lock, flags);
896 897
897 printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n", 898 printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n",
898 strip_info->dev->name, old_mtu, strip_info->mtu); 899 strip_info->dev->name, old_mtu, strip_info->mtu);
@@ -983,10 +984,13 @@ static void strip_seq_neighbours(struct seq_file *seq,
983 const MetricomNodeTable * table, 984 const MetricomNodeTable * table,
984 const char *title) 985 const char *title)
985{ 986{
986 /* We wrap this in a do/while loop, so if the table changes */ 987 unsigned long flags;
987 /* while we're reading it, we just go around and try again. */
988 struct timeval t; 988 struct timeval t;
989 989
990 /*
991 * We wrap this in a do/while loop, so if the table changes
992 * while we're reading it, we just go around and try again.
993 */
990 do { 994 do {
991 int i; 995 int i;
992 t = table->timestamp; 996 t = table->timestamp;
@@ -995,9 +999,9 @@ static void strip_seq_neighbours(struct seq_file *seq,
995 for (i = 0; i < table->num_nodes; i++) { 999 for (i = 0; i < table->num_nodes; i++) {
996 MetricomNode node; 1000 MetricomNode node;
997 1001
998 spin_lock_bh(&strip_lock); 1002 spin_lock_irqsave(&strip_lock, flags);
999 node = table->node[i]; 1003 node = table->node[i];
1000 spin_unlock_bh(&strip_lock); 1004 spin_unlock_irqrestore(&strip_lock, flags);
1001 seq_printf(seq, " %s\n", node.c); 1005 seq_printf(seq, " %s\n", node.c);
1002 } 1006 }
1003 } while (table->timestamp.tv_sec != t.tv_sec 1007 } while (table->timestamp.tv_sec != t.tv_sec
@@ -1536,6 +1540,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
1536static int strip_xmit(struct sk_buff *skb, struct net_device *dev) 1540static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
1537{ 1541{
1538 struct strip *strip_info = netdev_priv(dev); 1542 struct strip *strip_info = netdev_priv(dev);
1543 unsigned long flags;
1539 1544
1540 if (!netif_running(dev)) { 1545 if (!netif_running(dev)) {
1541 printk(KERN_ERR "%s: xmit call when iface is down\n", 1546 printk(KERN_ERR "%s: xmit call when iface is down\n",
@@ -1574,11 +1579,11 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
1574 strip_info->dev->name, sx_pps_count / 8); 1579 strip_info->dev->name, sx_pps_count / 8);
1575 } 1580 }
1576 1581
1577 spin_lock_bh(&strip_lock); 1582 spin_lock_irqsave(&strip_lock, flags);
1578 1583
1579 strip_send(strip_info, skb); 1584 strip_send(strip_info, skb);
1580 1585
1581 spin_unlock_bh(&strip_lock); 1586 spin_unlock_irqrestore(&strip_lock, flags);
1582 1587
1583 if (skb) 1588 if (skb)
1584 dev_kfree_skb(skb); 1589 dev_kfree_skb(skb);
@@ -2263,12 +2268,13 @@ static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
2263{ 2268{
2264 struct strip *strip_info = tty->disc_data; 2269 struct strip *strip_info = tty->disc_data;
2265 const unsigned char *end = cp + count; 2270 const unsigned char *end = cp + count;
2271 unsigned long flags;
2266 2272
2267 if (!strip_info || strip_info->magic != STRIP_MAGIC 2273 if (!strip_info || strip_info->magic != STRIP_MAGIC
2268 || !netif_running(strip_info->dev)) 2274 || !netif_running(strip_info->dev))
2269 return; 2275 return;
2270 2276
2271 spin_lock_bh(&strip_lock); 2277 spin_lock_irqsave(&strip_lock, flags);
2272#if 0 2278#if 0
2273 { 2279 {
2274 struct timeval tv; 2280 struct timeval tv;
@@ -2335,7 +2341,7 @@ static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
2335 } 2341 }
2336 cp++; 2342 cp++;
2337 } 2343 }
2338 spin_unlock_bh(&strip_lock); 2344 spin_unlock_irqrestore(&strip_lock, flags);
2339} 2345}
2340 2346
2341 2347
@@ -2523,9 +2529,11 @@ static void strip_dev_setup(struct net_device *dev)
2523 2529
2524static void strip_free(struct strip *strip_info) 2530static void strip_free(struct strip *strip_info)
2525{ 2531{
2526 spin_lock_bh(&strip_lock); 2532 unsigned long flags;
2533
2534 spin_lock_irqsave(&strip_lock, flags);
2527 list_del_rcu(&strip_info->list); 2535 list_del_rcu(&strip_info->list);
2528 spin_unlock_bh(&strip_lock); 2536 spin_unlock_irqrestore(&strip_lock, flags);
2529 2537
2530 strip_info->magic = 0; 2538 strip_info->magic = 0;
2531 2539
@@ -2539,6 +2547,7 @@ static void strip_free(struct strip *strip_info)
2539static struct strip *strip_alloc(void) 2547static struct strip *strip_alloc(void)
2540{ 2548{
2541 struct list_head *n; 2549 struct list_head *n;
2550 unsigned long flags;
2542 struct net_device *dev; 2551 struct net_device *dev;
2543 struct strip *strip_info; 2552 struct strip *strip_info;
2544 2553
@@ -2562,7 +2571,7 @@ static struct strip *strip_alloc(void)
2562 strip_info->idle_timer.function = strip_IdleTask; 2571 strip_info->idle_timer.function = strip_IdleTask;
2563 2572
2564 2573
2565 spin_lock_bh(&strip_lock); 2574 spin_lock_irqsave(&strip_lock, flags);
2566 rescan: 2575 rescan:
2567 /* 2576 /*
2568 * Search the list to find where to put our new entry 2577 * Search the list to find where to put our new entry
@@ -2581,7 +2590,7 @@ static struct strip *strip_alloc(void)
2581 sprintf(dev->name, "st%ld", dev->base_addr); 2590 sprintf(dev->name, "st%ld", dev->base_addr);
2582 2591
2583 list_add_tail_rcu(&strip_info->list, &strip_list); 2592 list_add_tail_rcu(&strip_info->list, &strip_list);
2584 spin_unlock_bh(&strip_lock); 2593 spin_unlock_irqrestore(&strip_lock, flags);
2585 2594
2586 return strip_info; 2595 return strip_info;
2587} 2596}