diff options
author | John Greene <jogreene@redhat.com> | 2012-12-19 04:47:48 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-12-19 17:30:59 -0500 |
commit | 83c34fd00d0c3989466e95808bf12af9bf87e383 (patch) | |
tree | 477e1bde4443e5708f4c1c7885c9c552dcd7d4d6 /drivers/net | |
parent | f8b840344cbf4fa7212223b436adfb7559ca0e1e (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.c | 18 |
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; | 629 | out_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 |