aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorJohn Greene <jogreene@redhat.com>2012-12-19 04:47:48 -0500
committerDavid S. Miller <davem@davemloft.net>2012-12-19 17:30:59 -0500
commit83c34fd00d0c3989466e95808bf12af9bf87e383 (patch)
tree477e1bde4443e5708f4c1c7885c9c552dcd7d4d6 /drivers/net
parentf8b840344cbf4fa7212223b436adfb7559ca0e1e (diff)
8139cp: Prevent dev_close/cp_interrupt race on MTU change
commit: cb64edb6b89491edfdbae52ba7db9a8b8391d339 upstream Above commit may introduce a race between cp_interrupt and dev_close / change MTU / dev_open up state. Changes cp_interrupt to tolerate this. Change spin_locking in cp_interrupt to avoid possible but unobserved race. Reported-by: "Francois Romieu" <romieu@fr.zoreil.com> Tested on virtual hardware, Tx MTU size up to 4096, max tx payload was ping -s 4068 for MTU of 4096. No real hardware, need test assist. Signed-off-by: "John Greene" <jogreene@redhat.com> CC: "David S. Miller" <davem@davemloft.net> CC: "David Woodhouse" <David.Woodhouse@intel.com> Tested-by: David Woodhouse <David.Woodhouse@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c18
1 files changed, 11 insertions, 7 deletions
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index cb6fc5a743ca..5ac93323a40c 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -577,28 +577,30 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
577{ 577{
578 struct net_device *dev = dev_instance; 578 struct net_device *dev = dev_instance;
579 struct cp_private *cp; 579 struct cp_private *cp;
580 int handled = 0;
580 u16 status; 581 u16 status;
581 582
582 if (unlikely(dev == NULL)) 583 if (unlikely(dev == NULL))
583 return IRQ_NONE; 584 return IRQ_NONE;
584 cp = netdev_priv(dev); 585 cp = netdev_priv(dev);
585 586
587 spin_lock(&cp->lock);
588
586 status = cpr16(IntrStatus); 589 status = cpr16(IntrStatus);
587 if (!status || (status == 0xFFFF)) 590 if (!status || (status == 0xFFFF))
588 return IRQ_NONE; 591 goto out_unlock;
592
593 handled = 1;
589 594
590 netif_dbg(cp, intr, dev, "intr, status %04x cmd %02x cpcmd %04x\n", 595 netif_dbg(cp, intr, dev, "intr, status %04x cmd %02x cpcmd %04x\n",
591 status, cpr8(Cmd), cpr16(CpCmd)); 596 status, cpr8(Cmd), cpr16(CpCmd));
592 597
593 cpw16(IntrStatus, status & ~cp_rx_intr_mask); 598 cpw16(IntrStatus, status & ~cp_rx_intr_mask);
594 599
595 spin_lock(&cp->lock);
596
597 /* close possible race's with dev_close */ 600 /* close possible race's with dev_close */
598 if (unlikely(!netif_running(dev))) { 601 if (unlikely(!netif_running(dev))) {
599 cpw16(IntrMask, 0); 602 cpw16(IntrMask, 0);
600 spin_unlock(&cp->lock); 603 goto out_unlock;
601 return IRQ_HANDLED;
602 } 604 }
603 605
604 if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) 606 if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
@@ -612,7 +614,6 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
612 if (status & LinkChg) 614 if (status & LinkChg)
613 mii_check_media(&cp->mii_if, netif_msg_link(cp), false); 615 mii_check_media(&cp->mii_if, netif_msg_link(cp), false);
614 616
615 spin_unlock(&cp->lock);
616 617
617 if (status & PciErr) { 618 if (status & PciErr) {
618 u16 pci_status; 619 u16 pci_status;
@@ -625,7 +626,10 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
625 /* TODO: reset hardware */ 626 /* TODO: reset hardware */
626 } 627 }
627 628
628 return IRQ_HANDLED; 629out_unlock:
630 spin_unlock(&cp->lock);
631
632 return IRQ_RETVAL(handled);
629} 633}
630 634
631#ifdef CONFIG_NET_POLL_CONTROLLER 635#ifdef CONFIG_NET_POLL_CONTROLLER