diff options
author | Eric Dumazet <edumazet@google.com> | 2012-06-25 01:35:45 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-06-26 19:42:33 -0400 |
commit | a2842a1e66329798d66563b52faec1a299ec4f73 (patch) | |
tree | 8c9cb11089d4f9d1b75b83e494d15e43caaef99f /net/l2tp | |
parent | 8a8e28b8e2c27362f24cf06513c05d5e3a304e03 (diff) |
net: l2tp_eth: use LLTX to avoid LOCKDEP splats
Denys Fedoryshchenko reported a LOCKDEP issue with l2tp code.
[ 8683.927442] ======================================================
[ 8683.927555] [ INFO: possible circular locking dependency detected ]
[ 8683.927672] 3.4.1-build-0061 #14 Not tainted
[ 8683.927782] -------------------------------------------------------
[ 8683.927895] swapper/0/0 is trying to acquire lock:
[ 8683.928007] (slock-AF_INET){+.-...}, at: [<e0fc73ec>]
l2tp_xmit_skb+0x173/0x47e [l2tp_core]
[ 8683.928121]
[ 8683.928121] but task is already holding lock:
[ 8683.928121] (_xmit_ETHER#2){+.-...}, at: [<c02f062d>]
sch_direct_xmit+0x36/0x119
[ 8683.928121]
[ 8683.928121] which lock already depends on the new lock.
[ 8683.928121]
[ 8683.928121]
[ 8683.928121] the existing dependency chain (in reverse order) is:
[ 8683.928121]
[ 8683.928121] -> #1 (_xmit_ETHER#2){+.-...}:
[ 8683.928121] [<c015a561>] lock_acquire+0x71/0x85
[ 8683.928121] [<c034da2d>] _raw_spin_lock+0x33/0x40
[ 8683.928121] [<c0304e0c>] ip_send_reply+0xf2/0x1ce
[ 8683.928121] [<c0317dbc>] tcp_v4_send_reset+0x153/0x16f
[ 8683.928121] [<c0317f4a>] tcp_v4_do_rcv+0x172/0x194
[ 8683.928121] [<c031929b>] tcp_v4_rcv+0x387/0x5a0
[ 8683.928121] [<c03001d0>] ip_local_deliver_finish+0x13a/0x1e9
[ 8683.928121] [<c0300645>] NF_HOOK.clone.11+0x46/0x4d
[ 8683.928121] [<c030075b>] ip_local_deliver+0x41/0x45
[ 8683.928121] [<c03005dd>] ip_rcv_finish+0x31a/0x33c
[ 8683.928121] [<c0300645>] NF_HOOK.clone.11+0x46/0x4d
[ 8683.928121] [<c0300960>] ip_rcv+0x201/0x23d
[ 8683.928121] [<c02de91b>] __netif_receive_skb+0x329/0x378
[ 8683.928121] [<c02deae8>] netif_receive_skb+0x4e/0x7d
[ 8683.928121] [<e08d5ef3>] rtl8139_poll+0x243/0x33d [8139too]
[ 8683.928121] [<c02df103>] net_rx_action+0x90/0x15d
[ 8683.928121] [<c012b2b5>] __do_softirq+0x7b/0x118
[ 8683.928121]
[ 8683.928121] -> #0 (slock-AF_INET){+.-...}:
[ 8683.928121] [<c0159f1b>] __lock_acquire+0x9a3/0xc27
[ 8683.928121] [<c015a561>] lock_acquire+0x71/0x85
[ 8683.928121] [<c034da2d>] _raw_spin_lock+0x33/0x40
[ 8683.928121] [<e0fc73ec>] l2tp_xmit_skb+0x173/0x47e
[l2tp_core]
[ 8683.928121] [<e0fe31fb>] l2tp_eth_dev_xmit+0x1a/0x2f
[l2tp_eth]
[ 8683.928121] [<c02e01e7>] dev_hard_start_xmit+0x333/0x3f2
[ 8683.928121] [<c02f064c>] sch_direct_xmit+0x55/0x119
[ 8683.928121] [<c02e0528>] dev_queue_xmit+0x282/0x418
[ 8683.928121] [<c031f4fb>] NF_HOOK.clone.19+0x45/0x4c
[ 8683.928121] [<c031f524>] arp_xmit+0x22/0x24
[ 8683.928121] [<c031f567>] arp_send+0x41/0x48
[ 8683.928121] [<c031fa7d>] arp_process+0x289/0x491
[ 8683.928121] [<c031f4fb>] NF_HOOK.clone.19+0x45/0x4c
[ 8683.928121] [<c031f7a0>] arp_rcv+0xb1/0xc3
[ 8683.928121] [<c02de91b>] __netif_receive_skb+0x329/0x378
[ 8683.928121] [<c02de9d3>] process_backlog+0x69/0x130
[ 8683.928121] [<c02df103>] net_rx_action+0x90/0x15d
[ 8683.928121] [<c012b2b5>] __do_softirq+0x7b/0x118
[ 8683.928121]
[ 8683.928121] other info that might help us debug this:
[ 8683.928121]
[ 8683.928121] Possible unsafe locking scenario:
[ 8683.928121]
[ 8683.928121] CPU0 CPU1
[ 8683.928121] ---- ----
[ 8683.928121] lock(_xmit_ETHER#2);
[ 8683.928121] lock(slock-AF_INET);
[ 8683.928121] lock(_xmit_ETHER#2);
[ 8683.928121] lock(slock-AF_INET);
[ 8683.928121]
[ 8683.928121] *** DEADLOCK ***
[ 8683.928121]
[ 8683.928121] 3 locks held by swapper/0/0:
[ 8683.928121] #0: (rcu_read_lock){.+.+..}, at: [<c02dbc10>]
rcu_lock_acquire+0x0/0x30
[ 8683.928121] #1: (rcu_read_lock_bh){.+....}, at: [<c02dbc10>]
rcu_lock_acquire+0x0/0x30
[ 8683.928121] #2: (_xmit_ETHER#2){+.-...}, at: [<c02f062d>]
sch_direct_xmit+0x36/0x119
[ 8683.928121]
[ 8683.928121] stack backtrace:
[ 8683.928121] Pid: 0, comm: swapper/0 Not tainted 3.4.1-build-0061 #14
[ 8683.928121] Call Trace:
[ 8683.928121] [<c034bdd2>] ? printk+0x18/0x1a
[ 8683.928121] [<c0158904>] print_circular_bug+0x1ac/0x1b6
[ 8683.928121] [<c0159f1b>] __lock_acquire+0x9a3/0xc27
[ 8683.928121] [<c015a561>] lock_acquire+0x71/0x85
[ 8683.928121] [<e0fc73ec>] ? l2tp_xmit_skb+0x173/0x47e [l2tp_core]
[ 8683.928121] [<c034da2d>] _raw_spin_lock+0x33/0x40
[ 8683.928121] [<e0fc73ec>] ? l2tp_xmit_skb+0x173/0x47e [l2tp_core]
[ 8683.928121] [<e0fc73ec>] l2tp_xmit_skb+0x173/0x47e [l2tp_core]
[ 8683.928121] [<e0fe31fb>] l2tp_eth_dev_xmit+0x1a/0x2f [l2tp_eth]
[ 8683.928121] [<c02e01e7>] dev_hard_start_xmit+0x333/0x3f2
[ 8683.928121] [<c02f064c>] sch_direct_xmit+0x55/0x119
[ 8683.928121] [<c02e0528>] dev_queue_xmit+0x282/0x418
[ 8683.928121] [<c02e02a6>] ? dev_hard_start_xmit+0x3f2/0x3f2
[ 8683.928121] [<c031f4fb>] NF_HOOK.clone.19+0x45/0x4c
[ 8683.928121] [<c031f524>] arp_xmit+0x22/0x24
[ 8683.928121] [<c02e02a6>] ? dev_hard_start_xmit+0x3f2/0x3f2
[ 8683.928121] [<c031f567>] arp_send+0x41/0x48
[ 8683.928121] [<c031fa7d>] arp_process+0x289/0x491
[ 8683.928121] [<c031f7f4>] ? __neigh_lookup.clone.20+0x42/0x42
[ 8683.928121] [<c031f4fb>] NF_HOOK.clone.19+0x45/0x4c
[ 8683.928121] [<c031f7a0>] arp_rcv+0xb1/0xc3
[ 8683.928121] [<c031f7f4>] ? __neigh_lookup.clone.20+0x42/0x42
[ 8683.928121] [<c02de91b>] __netif_receive_skb+0x329/0x378
[ 8683.928121] [<c02de9d3>] process_backlog+0x69/0x130
[ 8683.928121] [<c02df103>] net_rx_action+0x90/0x15d
[ 8683.928121] [<c012b2b5>] __do_softirq+0x7b/0x118
[ 8683.928121] [<c012b23a>] ? local_bh_enable+0xd/0xd
[ 8683.928121] <IRQ> [<c012b4d0>] ? irq_exit+0x41/0x91
[ 8683.928121] [<c0103c6f>] ? do_IRQ+0x79/0x8d
[ 8683.928121] [<c0157ea1>] ? trace_hardirqs_off_caller+0x2e/0x86
[ 8683.928121] [<c034ef6e>] ? common_interrupt+0x2e/0x34
[ 8683.928121] [<c0108a33>] ? default_idle+0x23/0x38
[ 8683.928121] [<c01091a8>] ? cpu_idle+0x55/0x6f
[ 8683.928121] [<c033df25>] ? rest_init+0xa1/0xa7
[ 8683.928121] [<c033de84>] ? __read_lock_failed+0x14/0x14
[ 8683.928121] [<c0498745>] ? start_kernel+0x303/0x30a
[ 8683.928121] [<c0498209>] ? repair_env_string+0x51/0x51
[ 8683.928121] [<c04980a8>] ? i386_start_kernel+0xa8/0xaf
It appears that like most virtual devices, l2tp should be converted to
LLTX mode.
This patch takes care of statistics using atomic_long in both RX and TX
paths, and fix a bug in l2tp_eth_dev_recv(), which was caching skb->data
before a pskb_may_pull() call.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Denys Fedoryshchenko <denys@visp.net.lb>
Cc: James Chapman <jchapman@katalix.com>
Cc: Hong zhi guo <honkiko@gmail.com>
Cc: Francois Romieu <romieu@fr.zoreil.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/l2tp')
-rw-r--r-- | net/l2tp/l2tp_eth.c | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index c3738f49646a..47b259fccd27 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c | |||
@@ -42,6 +42,11 @@ struct l2tp_eth { | |||
42 | struct sock *tunnel_sock; | 42 | struct sock *tunnel_sock; |
43 | struct l2tp_session *session; | 43 | struct l2tp_session *session; |
44 | struct list_head list; | 44 | struct list_head list; |
45 | atomic_long_t tx_bytes; | ||
46 | atomic_long_t tx_packets; | ||
47 | atomic_long_t rx_bytes; | ||
48 | atomic_long_t rx_packets; | ||
49 | atomic_long_t rx_errors; | ||
45 | }; | 50 | }; |
46 | 51 | ||
47 | /* via l2tp_session_priv() */ | 52 | /* via l2tp_session_priv() */ |
@@ -88,24 +93,40 @@ static int l2tp_eth_dev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
88 | struct l2tp_eth *priv = netdev_priv(dev); | 93 | struct l2tp_eth *priv = netdev_priv(dev); |
89 | struct l2tp_session *session = priv->session; | 94 | struct l2tp_session *session = priv->session; |
90 | 95 | ||
91 | dev->stats.tx_bytes += skb->len; | 96 | atomic_long_add(skb->len, &priv->tx_bytes); |
92 | dev->stats.tx_packets++; | 97 | atomic_long_inc(&priv->tx_packets); |
93 | 98 | ||
94 | l2tp_xmit_skb(session, skb, session->hdr_len); | 99 | l2tp_xmit_skb(session, skb, session->hdr_len); |
95 | 100 | ||
96 | return NETDEV_TX_OK; | 101 | return NETDEV_TX_OK; |
97 | } | 102 | } |
98 | 103 | ||
104 | static struct rtnl_link_stats64 *l2tp_eth_get_stats64(struct net_device *dev, | ||
105 | struct rtnl_link_stats64 *stats) | ||
106 | { | ||
107 | struct l2tp_eth *priv = netdev_priv(dev); | ||
108 | |||
109 | stats->tx_bytes = atomic_long_read(&priv->tx_bytes); | ||
110 | stats->tx_packets = atomic_long_read(&priv->tx_packets); | ||
111 | stats->rx_bytes = atomic_long_read(&priv->rx_bytes); | ||
112 | stats->rx_packets = atomic_long_read(&priv->rx_packets); | ||
113 | stats->rx_errors = atomic_long_read(&priv->rx_errors); | ||
114 | return stats; | ||
115 | } | ||
116 | |||
117 | |||
99 | static struct net_device_ops l2tp_eth_netdev_ops = { | 118 | static struct net_device_ops l2tp_eth_netdev_ops = { |
100 | .ndo_init = l2tp_eth_dev_init, | 119 | .ndo_init = l2tp_eth_dev_init, |
101 | .ndo_uninit = l2tp_eth_dev_uninit, | 120 | .ndo_uninit = l2tp_eth_dev_uninit, |
102 | .ndo_start_xmit = l2tp_eth_dev_xmit, | 121 | .ndo_start_xmit = l2tp_eth_dev_xmit, |
122 | .ndo_get_stats64 = l2tp_eth_get_stats64, | ||
103 | }; | 123 | }; |
104 | 124 | ||
105 | static void l2tp_eth_dev_setup(struct net_device *dev) | 125 | static void l2tp_eth_dev_setup(struct net_device *dev) |
106 | { | 126 | { |
107 | ether_setup(dev); | 127 | ether_setup(dev); |
108 | dev->priv_flags &= ~IFF_TX_SKB_SHARING; | 128 | dev->priv_flags &= ~IFF_TX_SKB_SHARING; |
129 | dev->features |= NETIF_F_LLTX; | ||
109 | dev->netdev_ops = &l2tp_eth_netdev_ops; | 130 | dev->netdev_ops = &l2tp_eth_netdev_ops; |
110 | dev->destructor = free_netdev; | 131 | dev->destructor = free_netdev; |
111 | } | 132 | } |
@@ -114,17 +135,17 @@ static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb, | |||
114 | { | 135 | { |
115 | struct l2tp_eth_sess *spriv = l2tp_session_priv(session); | 136 | struct l2tp_eth_sess *spriv = l2tp_session_priv(session); |
116 | struct net_device *dev = spriv->dev; | 137 | struct net_device *dev = spriv->dev; |
138 | struct l2tp_eth *priv = netdev_priv(dev); | ||
117 | 139 | ||
118 | if (session->debug & L2TP_MSG_DATA) { | 140 | if (session->debug & L2TP_MSG_DATA) { |
119 | unsigned int length; | 141 | unsigned int length; |
120 | u8 *ptr = skb->data; | ||
121 | 142 | ||
122 | length = min(32u, skb->len); | 143 | length = min(32u, skb->len); |
123 | if (!pskb_may_pull(skb, length)) | 144 | if (!pskb_may_pull(skb, length)) |
124 | goto error; | 145 | goto error; |
125 | 146 | ||
126 | pr_debug("%s: eth recv\n", session->name); | 147 | pr_debug("%s: eth recv\n", session->name); |
127 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ptr, length); | 148 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, skb->data, length); |
128 | } | 149 | } |
129 | 150 | ||
130 | if (!pskb_may_pull(skb, sizeof(ETH_HLEN))) | 151 | if (!pskb_may_pull(skb, sizeof(ETH_HLEN))) |
@@ -139,15 +160,15 @@ static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb, | |||
139 | nf_reset(skb); | 160 | nf_reset(skb); |
140 | 161 | ||
141 | if (dev_forward_skb(dev, skb) == NET_RX_SUCCESS) { | 162 | if (dev_forward_skb(dev, skb) == NET_RX_SUCCESS) { |
142 | dev->stats.rx_packets++; | 163 | atomic_long_inc(&priv->rx_packets); |
143 | dev->stats.rx_bytes += data_len; | 164 | atomic_long_add(data_len, &priv->rx_bytes); |
144 | } else | 165 | } else { |
145 | dev->stats.rx_errors++; | 166 | atomic_long_inc(&priv->rx_errors); |
146 | 167 | } | |
147 | return; | 168 | return; |
148 | 169 | ||
149 | error: | 170 | error: |
150 | dev->stats.rx_errors++; | 171 | atomic_long_inc(&priv->rx_errors); |
151 | kfree_skb(skb); | 172 | kfree_skb(skb); |
152 | } | 173 | } |
153 | 174 | ||