Jiri Slaby 8cebe2
From: Gao Feng <gfree.wind@vip.163.com>
Jiri Slaby 8cebe2
Date: Mon, 17 Jul 2017 18:34:42 +0800
Jiri Slaby 8cebe2
Subject: [PATCH] ppp: Fix false xmit recursion detect with two ppp devices
Jiri Slaby 8cebe2
References: bnc#1060662
Thomas Zimmermann 1d81d2
Patch-mainline: v4.12.7
Jiri Slaby 8cebe2
Git-commit: e5dadc65f9e0177eb649bcd9d333f1ebf871223e
Jiri Slaby 8cebe2
Jiri Slaby 8cebe2
[ Upstream commit e5dadc65f9e0177eb649bcd9d333f1ebf871223e ]
Jiri Slaby 8cebe2
Jiri Slaby 8cebe2
The global percpu variable ppp_xmit_recursion is used to detect the ppp
Jiri Slaby 8cebe2
xmit recursion to avoid the deadlock, which is caused by one CPU tries to
Jiri Slaby 8cebe2
lock the xmit lock twice. But it would report false recursion when one CPU
Jiri Slaby 8cebe2
wants to send the skb from two different PPP devices, like one L2TP on the
Jiri Slaby 8cebe2
PPPoE. It is a normal case actually.
Jiri Slaby 8cebe2
Jiri Slaby 8cebe2
Now use one percpu member of struct ppp instead of the gloable variable to
Jiri Slaby 8cebe2
detect the xmit recursion of one ppp device.
Jiri Slaby 8cebe2
Jiri Slaby 8cebe2
Fixes: 55454a565836 ("ppp: avoid dealock on recursive xmit")
Jiri Slaby 8cebe2
Signed-off-by: Gao Feng <gfree.wind@vip.163.com>
Jiri Slaby 8cebe2
Signed-off-by: Liu Jianying <jianying.liu@ikuai8.com>
Jiri Slaby 8cebe2
Signed-off-by: David S. Miller <davem@davemloft.net>
Jiri Slaby 8cebe2
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Jiri Slaby 8cebe2
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Jiri Slaby 8cebe2
---
Jiri Slaby 8cebe2
 drivers/net/ppp/ppp_generic.c | 30 +++++++++++++++++++++---------
Jiri Slaby 8cebe2
 1 file changed, 21 insertions(+), 9 deletions(-)
Jiri Slaby 8cebe2
Jiri Slaby 8cebe2
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
Jiri Slaby 8cebe2
index f9c0e62716ea..0d9f776442cb 100644
Jiri Slaby 8cebe2
--- a/drivers/net/ppp/ppp_generic.c
Jiri Slaby 8cebe2
+++ b/drivers/net/ppp/ppp_generic.c
Jiri Slaby 8cebe2
@@ -120,6 +120,7 @@ struct ppp {
Jiri Slaby 8cebe2
 	int		n_channels;	/* how many channels are attached 54 */
Jiri Slaby 8cebe2
 	spinlock_t	rlock;		/* lock for receive side 58 */
Jiri Slaby 8cebe2
 	spinlock_t	wlock;		/* lock for transmit side 5c */
Jiri Slaby 8cebe2
+	int		*xmit_recursion __percpu; /* xmit recursion detect */
Jiri Slaby 8cebe2
 	int		mru;		/* max receive unit 60 */
Jiri Slaby 8cebe2
 	unsigned int	flags;		/* control bits 64 */
Jiri Slaby 8cebe2
 	unsigned int	xstate;		/* transmit state bits 68 */
Jiri Slaby 8cebe2
@@ -1025,6 +1026,7 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
Jiri Slaby 8cebe2
 	struct ppp *ppp = netdev_priv(dev);
Jiri Slaby 8cebe2
 	int indx;
Jiri Slaby 8cebe2
 	int err;
Jiri Slaby 8cebe2
+	int cpu;
Jiri Slaby 8cebe2
 
Jiri Slaby 8cebe2
 	ppp->dev = dev;
Jiri Slaby 8cebe2
 	ppp->ppp_net = src_net;
Jiri Slaby 8cebe2
@@ -1039,6 +1041,15 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
Jiri Slaby 8cebe2
 	INIT_LIST_HEAD(&ppp->channels);
Jiri Slaby 8cebe2
 	spin_lock_init(&ppp->rlock);
Jiri Slaby 8cebe2
 	spin_lock_init(&ppp->wlock);
Jiri Slaby 8cebe2
+
Jiri Slaby 8cebe2
+	ppp->xmit_recursion = alloc_percpu(int);
Jiri Slaby 8cebe2
+	if (!ppp->xmit_recursion) {
Jiri Slaby 8cebe2
+		err = -ENOMEM;
Jiri Slaby 8cebe2
+		goto err1;
Jiri Slaby 8cebe2
+	}
Jiri Slaby 8cebe2
+	for_each_possible_cpu(cpu)
Jiri Slaby 8cebe2
+		(*per_cpu_ptr(ppp->xmit_recursion, cpu)) = 0;
Jiri Slaby 8cebe2
+
Jiri Slaby 8cebe2
 #ifdef CONFIG_PPP_MULTILINK
Jiri Slaby 8cebe2
 	ppp->minseq = -1;
Jiri Slaby 8cebe2
 	skb_queue_head_init(&ppp->mrq);
Jiri Slaby 8cebe2
@@ -1050,11 +1061,15 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
Jiri Slaby 8cebe2
 
Jiri Slaby 8cebe2
 	err = ppp_unit_register(ppp, conf->unit, conf->ifname_is_set);
Jiri Slaby 8cebe2
 	if (err < 0)
Jiri Slaby 8cebe2
-		return err;
Jiri Slaby 8cebe2
+		goto err2;
Jiri Slaby 8cebe2
 
Jiri Slaby 8cebe2
 	conf->file->private_data = &ppp->file;
Jiri Slaby 8cebe2
 
Jiri Slaby 8cebe2
 	return 0;
Jiri Slaby 8cebe2
+err2:
Jiri Slaby 8cebe2
+	free_percpu(ppp->xmit_recursion);
Jiri Slaby 8cebe2
+err1:
Jiri Slaby 8cebe2
+	return err;
Jiri Slaby 8cebe2
 }
Jiri Slaby 8cebe2
 
Jiri Slaby 8cebe2
 static const struct nla_policy ppp_nl_policy[IFLA_PPP_MAX + 1] = {
Jiri Slaby 8cebe2
@@ -1398,18 +1413,16 @@ static void __ppp_xmit_process(struct ppp *ppp)
Jiri Slaby 8cebe2
 	ppp_xmit_unlock(ppp);
Jiri Slaby 8cebe2
 }
Jiri Slaby 8cebe2
 
Jiri Slaby 8cebe2
-static DEFINE_PER_CPU(int, ppp_xmit_recursion);
Jiri Slaby 8cebe2
-
Jiri Slaby 8cebe2
 static void ppp_xmit_process(struct ppp *ppp)
Jiri Slaby 8cebe2
 {
Jiri Slaby 8cebe2
 	local_bh_disable();
Jiri Slaby 8cebe2
 
Jiri Slaby 8cebe2
-	if (unlikely(__this_cpu_read(ppp_xmit_recursion)))
Jiri Slaby 8cebe2
+	if (unlikely(*this_cpu_ptr(ppp->xmit_recursion)))
Jiri Slaby 8cebe2
 		goto err;
Jiri Slaby 8cebe2
 
Jiri Slaby 8cebe2
-	__this_cpu_inc(ppp_xmit_recursion);
Jiri Slaby 8cebe2
+	(*this_cpu_ptr(ppp->xmit_recursion))++;
Jiri Slaby 8cebe2
 	__ppp_xmit_process(ppp);
Jiri Slaby 8cebe2
-	__this_cpu_dec(ppp_xmit_recursion);
Jiri Slaby 8cebe2
+	(*this_cpu_ptr(ppp->xmit_recursion))--;
Jiri Slaby 8cebe2
 
Jiri Slaby 8cebe2
 	local_bh_enable();
Jiri Slaby 8cebe2
 
Jiri Slaby 8cebe2
@@ -1903,7 +1916,7 @@ static void __ppp_channel_push(struct channel *pch)
Jiri Slaby 8cebe2
 		read_lock_bh(&pch->upl);
Jiri Slaby 8cebe2
 		ppp = pch->ppp;
Jiri Slaby 8cebe2
 		if (ppp)
Jiri Slaby 8cebe2
-			__ppp_xmit_process(ppp);
Jiri Slaby 8cebe2
+			ppp_xmit_process(ppp);
Jiri Slaby 8cebe2
 		read_unlock_bh(&pch->upl);
Jiri Slaby 8cebe2
 	}
Jiri Slaby 8cebe2
 }
Jiri Slaby 8cebe2
@@ -1912,9 +1925,7 @@ static void ppp_channel_push(struct channel *pch)
Jiri Slaby 8cebe2
 {
Jiri Slaby 8cebe2
 	local_bh_disable();
Jiri Slaby 8cebe2
 
Jiri Slaby 8cebe2
-	__this_cpu_inc(ppp_xmit_recursion);
Jiri Slaby 8cebe2
 	__ppp_channel_push(pch);
Jiri Slaby 8cebe2
-	__this_cpu_dec(ppp_xmit_recursion);
Jiri Slaby 8cebe2
 
Jiri Slaby 8cebe2
 	local_bh_enable();
Jiri Slaby 8cebe2
 }
Jiri Slaby 8cebe2
@@ -3055,6 +3066,7 @@ static void ppp_destroy_interface(struct ppp *ppp)
Jiri Slaby 8cebe2
 #endif /* CONFIG_PPP_FILTER */
Jiri Slaby 8cebe2
 
Jiri Slaby 8cebe2
 	kfree_skb(ppp->xmit_pending);
Jiri Slaby 8cebe2
+	free_percpu(ppp->xmit_recursion);
Jiri Slaby 8cebe2
 
Jiri Slaby 8cebe2
 	free_netdev(ppp->dev);
Jiri Slaby 8cebe2
 }
Jiri Slaby 8cebe2
-- 
Jiri Slaby 8cebe2
2.14.2
Jiri Slaby 8cebe2