diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2010-08-08 02:02:59 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-08-08 02:02:59 -0400 |
commit | 1f6ea6e511e5ec730d8e88651da1b7b6e8fd1333 (patch) | |
tree | 58414d19e2477200b3e803f166567994a79972cb /drivers/atm | |
parent | eb4a5527b1f0d581ac217c80ef3278ed5e38693c (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.c | 7 |
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 | ||