diff options
Diffstat (limited to 'drivers/net/ppp/ppp_generic.c')
-rw-r--r-- | drivers/net/ppp/ppp_generic.c | 30 |
1 files changed, 21 insertions, 9 deletions
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 13028833bee3..bd4303944e44 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c | |||
@@ -120,6 +120,7 @@ struct ppp { | |||
120 | int n_channels; /* how many channels are attached 54 */ | 120 | int n_channels; /* how many channels are attached 54 */ |
121 | spinlock_t rlock; /* lock for receive side 58 */ | 121 | spinlock_t rlock; /* lock for receive side 58 */ |
122 | spinlock_t wlock; /* lock for transmit side 5c */ | 122 | spinlock_t wlock; /* lock for transmit side 5c */ |
123 | int *xmit_recursion __percpu; /* xmit recursion detect */ | ||
123 | int mru; /* max receive unit 60 */ | 124 | int mru; /* max receive unit 60 */ |
124 | unsigned int flags; /* control bits 64 */ | 125 | unsigned int flags; /* control bits 64 */ |
125 | unsigned int xstate; /* transmit state bits 68 */ | 126 | unsigned int xstate; /* transmit state bits 68 */ |
@@ -1025,6 +1026,7 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev, | |||
1025 | struct ppp *ppp = netdev_priv(dev); | 1026 | struct ppp *ppp = netdev_priv(dev); |
1026 | int indx; | 1027 | int indx; |
1027 | int err; | 1028 | int err; |
1029 | int cpu; | ||
1028 | 1030 | ||
1029 | ppp->dev = dev; | 1031 | ppp->dev = dev; |
1030 | ppp->ppp_net = src_net; | 1032 | ppp->ppp_net = src_net; |
@@ -1039,6 +1041,15 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev, | |||
1039 | INIT_LIST_HEAD(&ppp->channels); | 1041 | INIT_LIST_HEAD(&ppp->channels); |
1040 | spin_lock_init(&ppp->rlock); | 1042 | spin_lock_init(&ppp->rlock); |
1041 | spin_lock_init(&ppp->wlock); | 1043 | spin_lock_init(&ppp->wlock); |
1044 | |||
1045 | ppp->xmit_recursion = alloc_percpu(int); | ||
1046 | if (!ppp->xmit_recursion) { | ||
1047 | err = -ENOMEM; | ||
1048 | goto err1; | ||
1049 | } | ||
1050 | for_each_possible_cpu(cpu) | ||
1051 | (*per_cpu_ptr(ppp->xmit_recursion, cpu)) = 0; | ||
1052 | |||
1042 | #ifdef CONFIG_PPP_MULTILINK | 1053 | #ifdef CONFIG_PPP_MULTILINK |
1043 | ppp->minseq = -1; | 1054 | ppp->minseq = -1; |
1044 | skb_queue_head_init(&ppp->mrq); | 1055 | skb_queue_head_init(&ppp->mrq); |
@@ -1050,11 +1061,15 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev, | |||
1050 | 1061 | ||
1051 | err = ppp_unit_register(ppp, conf->unit, conf->ifname_is_set); | 1062 | err = ppp_unit_register(ppp, conf->unit, conf->ifname_is_set); |
1052 | if (err < 0) | 1063 | if (err < 0) |
1053 | return err; | 1064 | goto err2; |
1054 | 1065 | ||
1055 | conf->file->private_data = &ppp->file; | 1066 | conf->file->private_data = &ppp->file; |
1056 | 1067 | ||
1057 | return 0; | 1068 | return 0; |
1069 | err2: | ||
1070 | free_percpu(ppp->xmit_recursion); | ||
1071 | err1: | ||
1072 | return err; | ||
1058 | } | 1073 | } |
1059 | 1074 | ||
1060 | static const struct nla_policy ppp_nl_policy[IFLA_PPP_MAX + 1] = { | 1075 | static const struct nla_policy ppp_nl_policy[IFLA_PPP_MAX + 1] = { |
@@ -1400,18 +1415,16 @@ static void __ppp_xmit_process(struct ppp *ppp) | |||
1400 | ppp_xmit_unlock(ppp); | 1415 | ppp_xmit_unlock(ppp); |
1401 | } | 1416 | } |
1402 | 1417 | ||
1403 | static DEFINE_PER_CPU(int, ppp_xmit_recursion); | ||
1404 | |||
1405 | static void ppp_xmit_process(struct ppp *ppp) | 1418 | static void ppp_xmit_process(struct ppp *ppp) |
1406 | { | 1419 | { |
1407 | local_bh_disable(); | 1420 | local_bh_disable(); |
1408 | 1421 | ||
1409 | if (unlikely(__this_cpu_read(ppp_xmit_recursion))) | 1422 | if (unlikely(*this_cpu_ptr(ppp->xmit_recursion))) |
1410 | goto err; | 1423 | goto err; |
1411 | 1424 | ||
1412 | __this_cpu_inc(ppp_xmit_recursion); | 1425 | (*this_cpu_ptr(ppp->xmit_recursion))++; |
1413 | __ppp_xmit_process(ppp); | 1426 | __ppp_xmit_process(ppp); |
1414 | __this_cpu_dec(ppp_xmit_recursion); | 1427 | (*this_cpu_ptr(ppp->xmit_recursion))--; |
1415 | 1428 | ||
1416 | local_bh_enable(); | 1429 | local_bh_enable(); |
1417 | 1430 | ||
@@ -1905,7 +1918,7 @@ static void __ppp_channel_push(struct channel *pch) | |||
1905 | read_lock(&pch->upl); | 1918 | read_lock(&pch->upl); |
1906 | ppp = pch->ppp; | 1919 | ppp = pch->ppp; |
1907 | if (ppp) | 1920 | if (ppp) |
1908 | __ppp_xmit_process(ppp); | 1921 | ppp_xmit_process(ppp); |
1909 | read_unlock(&pch->upl); | 1922 | read_unlock(&pch->upl); |
1910 | } | 1923 | } |
1911 | } | 1924 | } |
@@ -1914,9 +1927,7 @@ static void ppp_channel_push(struct channel *pch) | |||
1914 | { | 1927 | { |
1915 | local_bh_disable(); | 1928 | local_bh_disable(); |
1916 | 1929 | ||
1917 | __this_cpu_inc(ppp_xmit_recursion); | ||
1918 | __ppp_channel_push(pch); | 1930 | __ppp_channel_push(pch); |
1919 | __this_cpu_dec(ppp_xmit_recursion); | ||
1920 | 1931 | ||
1921 | local_bh_enable(); | 1932 | local_bh_enable(); |
1922 | } | 1933 | } |
@@ -3057,6 +3068,7 @@ static void ppp_destroy_interface(struct ppp *ppp) | |||
3057 | #endif /* CONFIG_PPP_FILTER */ | 3068 | #endif /* CONFIG_PPP_FILTER */ |
3058 | 3069 | ||
3059 | kfree_skb(ppp->xmit_pending); | 3070 | kfree_skb(ppp->xmit_pending); |
3071 | free_percpu(ppp->xmit_recursion); | ||
3060 | 3072 | ||
3061 | free_netdev(ppp->dev); | 3073 | free_netdev(ppp->dev); |
3062 | } | 3074 | } |