Skip to content

Commit e5dadc6

Browse files
gfreewinddavem330
authored andcommitted
ppp: Fix false xmit recursion detect with two ppp devices
The global percpu variable ppp_xmit_recursion is used to detect the ppp xmit recursion to avoid the deadlock, which is caused by one CPU tries to lock the xmit lock twice. But it would report false recursion when one CPU wants to send the skb from two different PPP devices, like one L2TP on the PPPoE. It is a normal case actually. Now use one percpu member of struct ppp instead of the gloable variable to detect the xmit recursion of one ppp device. Fixes: 55454a5 ("ppp: avoid dealock on recursive xmit") Signed-off-by: Gao Feng <gfree.wind@vip.163.com> Signed-off-by: Liu Jianying <jianying.liu@ikuai8.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent df39a9f commit e5dadc6

File tree

1 file changed

+21
-9
lines changed

1 file changed

+21
-9
lines changed

drivers/net/ppp/ppp_generic.c

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ struct ppp {
120120
int n_channels; /* how many channels are attached 54 */
121121
spinlock_t rlock; /* lock for receive side 58 */
122122
spinlock_t wlock; /* lock for transmit side 5c */
123+
int *xmit_recursion __percpu; /* xmit recursion detect */
123124
int mru; /* max receive unit 60 */
124125
unsigned int flags; /* control bits 64 */
125126
unsigned int xstate; /* transmit state bits 68 */
@@ -1025,6 +1026,7 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
10251026
struct ppp *ppp = netdev_priv(dev);
10261027
int indx;
10271028
int err;
1029+
int cpu;
10281030

10291031
ppp->dev = dev;
10301032
ppp->ppp_net = src_net;
@@ -1039,6 +1041,15 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
10391041
INIT_LIST_HEAD(&ppp->channels);
10401042
spin_lock_init(&ppp->rlock);
10411043
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+
10421053
#ifdef CONFIG_PPP_MULTILINK
10431054
ppp->minseq = -1;
10441055
skb_queue_head_init(&ppp->mrq);
@@ -1050,11 +1061,15 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
10501061

10511062
err = ppp_unit_register(ppp, conf->unit, conf->ifname_is_set);
10521063
if (err < 0)
1053-
return err;
1064+
goto err2;
10541065

10551066
conf->file->private_data = &ppp->file;
10561067

10571068
return 0;
1069+
err2:
1070+
free_percpu(ppp->xmit_recursion);
1071+
err1:
1072+
return err;
10581073
}
10591074

10601075
static const struct nla_policy ppp_nl_policy[IFLA_PPP_MAX + 1] = {
@@ -1400,18 +1415,16 @@ static void __ppp_xmit_process(struct ppp *ppp)
14001415
ppp_xmit_unlock(ppp);
14011416
}
14021417

1403-
static DEFINE_PER_CPU(int, ppp_xmit_recursion);
1404-
14051418
static void ppp_xmit_process(struct ppp *ppp)
14061419
{
14071420
local_bh_disable();
14081421

1409-
if (unlikely(__this_cpu_read(ppp_xmit_recursion)))
1422+
if (unlikely(*this_cpu_ptr(ppp->xmit_recursion)))
14101423
goto err;
14111424

1412-
__this_cpu_inc(ppp_xmit_recursion);
1425+
(*this_cpu_ptr(ppp->xmit_recursion))++;
14131426
__ppp_xmit_process(ppp);
1414-
__this_cpu_dec(ppp_xmit_recursion);
1427+
(*this_cpu_ptr(ppp->xmit_recursion))--;
14151428

14161429
local_bh_enable();
14171430

@@ -1905,7 +1918,7 @@ static void __ppp_channel_push(struct channel *pch)
19051918
read_lock(&pch->upl);
19061919
ppp = pch->ppp;
19071920
if (ppp)
1908-
__ppp_xmit_process(ppp);
1921+
ppp_xmit_process(ppp);
19091922
read_unlock(&pch->upl);
19101923
}
19111924
}
@@ -1914,9 +1927,7 @@ static void ppp_channel_push(struct channel *pch)
19141927
{
19151928
local_bh_disable();
19161929

1917-
__this_cpu_inc(ppp_xmit_recursion);
19181930
__ppp_channel_push(pch);
1919-
__this_cpu_dec(ppp_xmit_recursion);
19201931

19211932
local_bh_enable();
19221933
}
@@ -3057,6 +3068,7 @@ static void ppp_destroy_interface(struct ppp *ppp)
30573068
#endif /* CONFIG_PPP_FILTER */
30583069

30593070
kfree_skb(ppp->xmit_pending);
3071+
free_percpu(ppp->xmit_recursion);
30603072

30613073
free_netdev(ppp->dev);
30623074
}

0 commit comments

Comments
 (0)