aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/atm
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2010-08-08 02:02:59 -0400
committerDavid S. Miller <davem@davemloft.net>2010-08-08 02:02:59 -0400
commit1f6ea6e511e5ec730d8e88651da1b7b6e8fd1333 (patch)
tree58414d19e2477200b3e803f166567994a79972cb /drivers/atm
parenteb4a5527b1f0d581ac217c80ef3278ed5e38693c (diff)
solos-pci: Fix race condition in tasklet RX handling
We were seeing faults in the solos-pci receive tasklet when packets arrived for a VCC which was currently being closed: [18842.727906] EIP: [<e082f490>] br2684_push+0x19/0x234 [br2684] SS:ESP 0068:dfb89d14 [18845.090712] [<c13ecff3>] ? do_page_fault+0x0/0x2e1 [18845.120042] [<e082f490>] ? br2684_push+0x19/0x234 [br2684] [18845.153530] [<e084fa13>] solos_bh+0x28b/0x7c8 [solos_pci] [18845.186488] [<e084f711>] ? solos_irq+0x2d/0x51 [solos_pci] [18845.219960] [<c100387b>] ? handle_irq+0x3b/0x48 [18845.247732] [<c10265cb>] ? irq_exit+0x34/0x57 [18845.274437] [<c1025720>] tasklet_action+0x42/0x69 [18845.303247] [<c102643f>] __do_softirq+0x8e/0x129 [18845.331540] [<c10264ff>] do_softirq+0x25/0x2a [18845.358274] [<c102664c>] _local_bh_enable_ip+0x5e/0x6a [18845.389677] [<c102666d>] local_bh_enable+0xb/0xe [18845.417944] [<e08490a8>] ppp_unregister_channel+0x32/0xbb [ppp_generic] [18845.458193] [<e08731ad>] pppox_unbind_sock+0x18/0x1f [pppox] This patch uses an RCU-inspired approach to fix it. In the RX tasklet's find_vcc() function we first refuse to use a VCC which already has the ATM_VF_READY bit cleared. And in the VCC close function, we synchronise with the tasklet to ensure that it can't still be using the VCC before we continue and allow the VCC to be destroyed. Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> Tested-by: Nathan Williams <nathan@traverse.com.au> Cc: stable@kernel.org Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/atm')
-rw-r--r--drivers/atm/solos-pci.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 6174965d9a4..f916ddf6393 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -781,7 +781,8 @@ static struct atm_vcc *find_vcc(struct atm_dev *dev, short vpi, int vci)
781 sk_for_each(s, node, head) { 781 sk_for_each(s, node, head) {
782 vcc = atm_sk(s); 782 vcc = atm_sk(s);
783 if (vcc->dev == dev && vcc->vci == vci && 783 if (vcc->dev == dev && vcc->vci == vci &&
784 vcc->vpi == vpi && vcc->qos.rxtp.traffic_class != ATM_NONE) 784 vcc->vpi == vpi && vcc->qos.rxtp.traffic_class != ATM_NONE &&
785 test_bit(ATM_VF_READY, &vcc->flags))
785 goto out; 786 goto out;
786 } 787 }
787 vcc = NULL; 788 vcc = NULL;
@@ -907,6 +908,10 @@ static void pclose(struct atm_vcc *vcc)
907 clear_bit(ATM_VF_ADDR, &vcc->flags); 908 clear_bit(ATM_VF_ADDR, &vcc->flags);
908 clear_bit(ATM_VF_READY, &vcc->flags); 909 clear_bit(ATM_VF_READY, &vcc->flags);
909 910
911 /* Hold up vcc_destroy_socket() (our caller) until solos_bh() in the
912 tasklet has finished processing any incoming packets (and, more to
913 the point, using the vcc pointer). */
914 tasklet_unlock_wait(&card->tlet);
910 return; 915 return;
911} 916}
912 917