aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorTom Parkin <tparkin@katalix.com>2013-03-19 02:11:22 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-20 12:10:39 -0400
commit7b7c0719cd7afee725b920d75ec6a500b76107e6 (patch)
tree4ea11a15d2ee815f62d649257a8491870a382504 /net
parentcf2f5c886a209377daefd5d2ba0bcd49c3887813 (diff)
l2tp: avoid deadlock in l2tp stats update
l2tp's u64_stats writers were incorrectly synchronised, making it possible to deadlock a 64bit machine running a 32bit kernel simply by sending the l2tp code netlink commands while passing data through l2tp sessions. Previous discussion on netdev determined that alternative solutions such as spinlock writer synchronisation or per-cpu data would bring unjustified overhead, given that most users interested in high volume traffic will likely be running 64bit kernels on 64bit hardware. As such, this patch replaces l2tp's use of u64_stats with atomic_long_t, thereby avoiding the deadlock. Ref: http://marc.info/?l=linux-netdev&m=134029167910731&w=2 http://marc.info/?l=linux-netdev&m=134079868111131&w=2 Signed-off-by: Tom Parkin <tparkin@katalix.com> Signed-off-by: James Chapman <jchapman@katalix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/l2tp/l2tp_core.c75
-rw-r--r--net/l2tp/l2tp_core.h19
-rw-r--r--net/l2tp/l2tp_debugfs.c28
-rw-r--r--net/l2tp/l2tp_netlink.c72
-rw-r--r--net/l2tp/l2tp_ppp.c46
5 files changed, 93 insertions, 147 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index c00f31b8cc04..97d30ac67c88 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -374,10 +374,8 @@ static void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *sk
374 struct sk_buff *skbp; 374 struct sk_buff *skbp;
375 struct sk_buff *tmp; 375 struct sk_buff *tmp;
376 u32 ns = L2TP_SKB_CB(skb)->ns; 376 u32 ns = L2TP_SKB_CB(skb)->ns;
377 struct l2tp_stats *sstats;
378 377
379 spin_lock_bh(&session->reorder_q.lock); 378 spin_lock_bh(&session->reorder_q.lock);
380 sstats = &session->stats;
381 skb_queue_walk_safe(&session->reorder_q, skbp, tmp) { 379 skb_queue_walk_safe(&session->reorder_q, skbp, tmp) {
382 if (L2TP_SKB_CB(skbp)->ns > ns) { 380 if (L2TP_SKB_CB(skbp)->ns > ns) {
383 __skb_queue_before(&session->reorder_q, skbp, skb); 381 __skb_queue_before(&session->reorder_q, skbp, skb);
@@ -385,9 +383,7 @@ static void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *sk
385 "%s: pkt %hu, inserted before %hu, reorder_q len=%d\n", 383 "%s: pkt %hu, inserted before %hu, reorder_q len=%d\n",
386 session->name, ns, L2TP_SKB_CB(skbp)->ns, 384 session->name, ns, L2TP_SKB_CB(skbp)->ns,
387 skb_queue_len(&session->reorder_q)); 385 skb_queue_len(&session->reorder_q));
388 u64_stats_update_begin(&sstats->syncp); 386 atomic_long_inc(&session->stats.rx_oos_packets);
389 sstats->rx_oos_packets++;
390 u64_stats_update_end(&sstats->syncp);
391 goto out; 387 goto out;
392 } 388 }
393 } 389 }
@@ -404,23 +400,16 @@ static void l2tp_recv_dequeue_skb(struct l2tp_session *session, struct sk_buff *
404{ 400{
405 struct l2tp_tunnel *tunnel = session->tunnel; 401 struct l2tp_tunnel *tunnel = session->tunnel;
406 int length = L2TP_SKB_CB(skb)->length; 402 int length = L2TP_SKB_CB(skb)->length;
407 struct l2tp_stats *tstats, *sstats;
408 403
409 /* We're about to requeue the skb, so return resources 404 /* We're about to requeue the skb, so return resources
410 * to its current owner (a socket receive buffer). 405 * to its current owner (a socket receive buffer).
411 */ 406 */
412 skb_orphan(skb); 407 skb_orphan(skb);
413 408
414 tstats = &tunnel->stats; 409 atomic_long_inc(&tunnel->stats.rx_packets);
415 u64_stats_update_begin(&tstats->syncp); 410 atomic_long_add(length, &tunnel->stats.rx_bytes);
416 sstats = &session->stats; 411 atomic_long_inc(&session->stats.rx_packets);
417 u64_stats_update_begin(&sstats->syncp); 412 atomic_long_add(length, &session->stats.rx_bytes);
418 tstats->rx_packets++;
419 tstats->rx_bytes += length;
420 sstats->rx_packets++;
421 sstats->rx_bytes += length;
422 u64_stats_update_end(&tstats->syncp);
423 u64_stats_update_end(&sstats->syncp);
424 413
425 if (L2TP_SKB_CB(skb)->has_seq) { 414 if (L2TP_SKB_CB(skb)->has_seq) {
426 /* Bump our Nr */ 415 /* Bump our Nr */
@@ -451,7 +440,6 @@ static void l2tp_recv_dequeue(struct l2tp_session *session)
451{ 440{
452 struct sk_buff *skb; 441 struct sk_buff *skb;
453 struct sk_buff *tmp; 442 struct sk_buff *tmp;
454 struct l2tp_stats *sstats;
455 443
456 /* If the pkt at the head of the queue has the nr that we 444 /* If the pkt at the head of the queue has the nr that we
457 * expect to send up next, dequeue it and any other 445 * expect to send up next, dequeue it and any other
@@ -459,13 +447,10 @@ static void l2tp_recv_dequeue(struct l2tp_session *session)
459 */ 447 */
460start: 448start:
461 spin_lock_bh(&session->reorder_q.lock); 449 spin_lock_bh(&session->reorder_q.lock);
462 sstats = &session->stats;
463 skb_queue_walk_safe(&session->reorder_q, skb, tmp) { 450 skb_queue_walk_safe(&session->reorder_q, skb, tmp) {
464 if (time_after(jiffies, L2TP_SKB_CB(skb)->expires)) { 451 if (time_after(jiffies, L2TP_SKB_CB(skb)->expires)) {
465 u64_stats_update_begin(&sstats->syncp); 452 atomic_long_inc(&session->stats.rx_seq_discards);
466 sstats->rx_seq_discards++; 453 atomic_long_inc(&session->stats.rx_errors);
467 sstats->rx_errors++;
468 u64_stats_update_end(&sstats->syncp);
469 l2tp_dbg(session, L2TP_MSG_SEQ, 454 l2tp_dbg(session, L2TP_MSG_SEQ,
470 "%s: oos pkt %u len %d discarded (too old), waiting for %u, reorder_q_len=%d\n", 455 "%s: oos pkt %u len %d discarded (too old), waiting for %u, reorder_q_len=%d\n",
471 session->name, L2TP_SKB_CB(skb)->ns, 456 session->name, L2TP_SKB_CB(skb)->ns,
@@ -624,7 +609,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
624 struct l2tp_tunnel *tunnel = session->tunnel; 609 struct l2tp_tunnel *tunnel = session->tunnel;
625 int offset; 610 int offset;
626 u32 ns, nr; 611 u32 ns, nr;
627 struct l2tp_stats *sstats = &session->stats;
628 612
629 /* The ref count is increased since we now hold a pointer to 613 /* The ref count is increased since we now hold a pointer to
630 * the session. Take care to decrement the refcnt when exiting 614 * the session. Take care to decrement the refcnt when exiting
@@ -641,9 +625,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
641 "%s: cookie mismatch (%u/%u). Discarding.\n", 625 "%s: cookie mismatch (%u/%u). Discarding.\n",
642 tunnel->name, tunnel->tunnel_id, 626 tunnel->name, tunnel->tunnel_id,
643 session->session_id); 627 session->session_id);
644 u64_stats_update_begin(&sstats->syncp); 628 atomic_long_inc(&session->stats.rx_cookie_discards);
645 sstats->rx_cookie_discards++;
646 u64_stats_update_end(&sstats->syncp);
647 goto discard; 629 goto discard;
648 } 630 }
649 ptr += session->peer_cookie_len; 631 ptr += session->peer_cookie_len;
@@ -712,9 +694,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
712 l2tp_warn(session, L2TP_MSG_SEQ, 694 l2tp_warn(session, L2TP_MSG_SEQ,
713 "%s: recv data has no seq numbers when required. Discarding.\n", 695 "%s: recv data has no seq numbers when required. Discarding.\n",
714 session->name); 696 session->name);
715 u64_stats_update_begin(&sstats->syncp); 697 atomic_long_inc(&session->stats.rx_seq_discards);
716 sstats->rx_seq_discards++;
717 u64_stats_update_end(&sstats->syncp);
718 goto discard; 698 goto discard;
719 } 699 }
720 700
@@ -733,9 +713,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
733 l2tp_warn(session, L2TP_MSG_SEQ, 713 l2tp_warn(session, L2TP_MSG_SEQ,
734 "%s: recv data has no seq numbers when required. Discarding.\n", 714 "%s: recv data has no seq numbers when required. Discarding.\n",
735 session->name); 715 session->name);
736 u64_stats_update_begin(&sstats->syncp); 716 atomic_long_inc(&session->stats.rx_seq_discards);
737 sstats->rx_seq_discards++;
738 u64_stats_update_end(&sstats->syncp);
739 goto discard; 717 goto discard;
740 } 718 }
741 } 719 }
@@ -789,9 +767,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
789 * packets 767 * packets
790 */ 768 */
791 if (L2TP_SKB_CB(skb)->ns != session->nr) { 769 if (L2TP_SKB_CB(skb)->ns != session->nr) {
792 u64_stats_update_begin(&sstats->syncp); 770 atomic_long_inc(&session->stats.rx_seq_discards);
793 sstats->rx_seq_discards++;
794 u64_stats_update_end(&sstats->syncp);
795 l2tp_dbg(session, L2TP_MSG_SEQ, 771 l2tp_dbg(session, L2TP_MSG_SEQ,
796 "%s: oos pkt %u len %d discarded, waiting for %u, reorder_q_len=%d\n", 772 "%s: oos pkt %u len %d discarded, waiting for %u, reorder_q_len=%d\n",
797 session->name, L2TP_SKB_CB(skb)->ns, 773 session->name, L2TP_SKB_CB(skb)->ns,
@@ -817,9 +793,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
817 return; 793 return;
818 794
819discard: 795discard:
820 u64_stats_update_begin(&sstats->syncp); 796 atomic_long_inc(&session->stats.rx_errors);
821 sstats->rx_errors++;
822 u64_stats_update_end(&sstats->syncp);
823 kfree_skb(skb); 797 kfree_skb(skb);
824 798
825 if (session->deref) 799 if (session->deref)
@@ -861,7 +835,6 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
861 u32 tunnel_id, session_id; 835 u32 tunnel_id, session_id;
862 u16 version; 836 u16 version;
863 int length; 837 int length;
864 struct l2tp_stats *tstats;
865 838
866 if (tunnel->sock && l2tp_verify_udp_checksum(tunnel->sock, skb)) 839 if (tunnel->sock && l2tp_verify_udp_checksum(tunnel->sock, skb))
867 goto discard_bad_csum; 840 goto discard_bad_csum;
@@ -950,10 +923,7 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
950discard_bad_csum: 923discard_bad_csum:
951 LIMIT_NETDEBUG("%s: UDP: bad checksum\n", tunnel->name); 924 LIMIT_NETDEBUG("%s: UDP: bad checksum\n", tunnel->name);
952 UDP_INC_STATS_USER(tunnel->l2tp_net, UDP_MIB_INERRORS, 0); 925 UDP_INC_STATS_USER(tunnel->l2tp_net, UDP_MIB_INERRORS, 0);
953 tstats = &tunnel->stats; 926 atomic_long_inc(&tunnel->stats.rx_errors);
954 u64_stats_update_begin(&tstats->syncp);
955 tstats->rx_errors++;
956 u64_stats_update_end(&tstats->syncp);
957 kfree_skb(skb); 927 kfree_skb(skb);
958 928
959 return 0; 929 return 0;
@@ -1080,7 +1050,6 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,
1080 struct l2tp_tunnel *tunnel = session->tunnel; 1050 struct l2tp_tunnel *tunnel = session->tunnel;
1081 unsigned int len = skb->len; 1051 unsigned int len = skb->len;
1082 int error; 1052 int error;
1083 struct l2tp_stats *tstats, *sstats;
1084 1053
1085 /* Debug */ 1054 /* Debug */
1086 if (session->send_seq) 1055 if (session->send_seq)
@@ -1109,21 +1078,15 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,
1109 error = ip_queue_xmit(skb, fl); 1078 error = ip_queue_xmit(skb, fl);
1110 1079
1111 /* Update stats */ 1080 /* Update stats */
1112 tstats = &tunnel->stats;
1113 u64_stats_update_begin(&tstats->syncp);
1114 sstats = &session->stats;
1115 u64_stats_update_begin(&sstats->syncp);
1116 if (error >= 0) { 1081 if (error >= 0) {
1117 tstats->tx_packets++; 1082 atomic_long_inc(&tunnel->stats.tx_packets);
1118 tstats->tx_bytes += len; 1083 atomic_long_add(len, &tunnel->stats.tx_bytes);
1119 sstats->tx_packets++; 1084 atomic_long_inc(&session->stats.tx_packets);
1120 sstats->tx_bytes += len; 1085 atomic_long_add(len, &session->stats.tx_bytes);
1121 } else { 1086 } else {
1122 tstats->tx_errors++; 1087 atomic_long_inc(&tunnel->stats.tx_errors);
1123 sstats->tx_errors++; 1088 atomic_long_inc(&session->stats.tx_errors);
1124 } 1089 }
1125 u64_stats_update_end(&tstats->syncp);
1126 u64_stats_update_end(&sstats->syncp);
1127 1090
1128 return 0; 1091 return 0;
1129} 1092}
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index d40713d105fc..519b013f8b31 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -36,16 +36,15 @@ enum {
36struct sk_buff; 36struct sk_buff;
37 37
38struct l2tp_stats { 38struct l2tp_stats {
39 u64 tx_packets; 39 atomic_long_t tx_packets;
40 u64 tx_bytes; 40 atomic_long_t tx_bytes;
41 u64 tx_errors; 41 atomic_long_t tx_errors;
42 u64 rx_packets; 42 atomic_long_t rx_packets;
43 u64 rx_bytes; 43 atomic_long_t rx_bytes;
44 u64 rx_seq_discards; 44 atomic_long_t rx_seq_discards;
45 u64 rx_oos_packets; 45 atomic_long_t rx_oos_packets;
46 u64 rx_errors; 46 atomic_long_t rx_errors;
47 u64 rx_cookie_discards; 47 atomic_long_t rx_cookie_discards;
48 struct u64_stats_sync syncp;
49}; 48};
50 49
51struct l2tp_tunnel; 50struct l2tp_tunnel;
diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c
index c3813bc84552..072d7202e182 100644
--- a/net/l2tp/l2tp_debugfs.c
+++ b/net/l2tp/l2tp_debugfs.c
@@ -146,14 +146,14 @@ static void l2tp_dfs_seq_tunnel_show(struct seq_file *m, void *v)
146 tunnel->sock ? atomic_read(&tunnel->sock->sk_refcnt) : 0, 146 tunnel->sock ? atomic_read(&tunnel->sock->sk_refcnt) : 0,
147 atomic_read(&tunnel->ref_count)); 147 atomic_read(&tunnel->ref_count));
148 148
149 seq_printf(m, " %08x rx %llu/%llu/%llu rx %llu/%llu/%llu\n", 149 seq_printf(m, " %08x rx %ld/%ld/%ld rx %ld/%ld/%ld\n",
150 tunnel->debug, 150 tunnel->debug,
151 (unsigned long long)tunnel->stats.tx_packets, 151 atomic_long_read(&tunnel->stats.tx_packets),
152 (unsigned long long)tunnel->stats.tx_bytes, 152 atomic_long_read(&tunnel->stats.tx_bytes),
153 (unsigned long long)tunnel->stats.tx_errors, 153 atomic_long_read(&tunnel->stats.tx_errors),
154 (unsigned long long)tunnel->stats.rx_packets, 154 atomic_long_read(&tunnel->stats.rx_packets),
155 (unsigned long long)tunnel->stats.rx_bytes, 155 atomic_long_read(&tunnel->stats.rx_bytes),
156 (unsigned long long)tunnel->stats.rx_errors); 156 atomic_long_read(&tunnel->stats.rx_errors));
157 157
158 if (tunnel->show != NULL) 158 if (tunnel->show != NULL)
159 tunnel->show(m, tunnel); 159 tunnel->show(m, tunnel);
@@ -203,14 +203,14 @@ static void l2tp_dfs_seq_session_show(struct seq_file *m, void *v)
203 seq_printf(m, "\n"); 203 seq_printf(m, "\n");
204 } 204 }
205 205
206 seq_printf(m, " %hu/%hu tx %llu/%llu/%llu rx %llu/%llu/%llu\n", 206 seq_printf(m, " %hu/%hu tx %ld/%ld/%ld rx %ld/%ld/%ld\n",
207 session->nr, session->ns, 207 session->nr, session->ns,
208 (unsigned long long)session->stats.tx_packets, 208 atomic_long_read(&session->stats.tx_packets),
209 (unsigned long long)session->stats.tx_bytes, 209 atomic_long_read(&session->stats.tx_bytes),
210 (unsigned long long)session->stats.tx_errors, 210 atomic_long_read(&session->stats.tx_errors),
211 (unsigned long long)session->stats.rx_packets, 211 atomic_long_read(&session->stats.rx_packets),
212 (unsigned long long)session->stats.rx_bytes, 212 atomic_long_read(&session->stats.rx_bytes),
213 (unsigned long long)session->stats.rx_errors); 213 atomic_long_read(&session->stats.rx_errors));
214 214
215 if (session->show != NULL) 215 if (session->show != NULL)
216 session->show(m, session); 216 session->show(m, session);
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index c1bab22db85e..0825ff26e113 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -246,8 +246,6 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla
246#if IS_ENABLED(CONFIG_IPV6) 246#if IS_ENABLED(CONFIG_IPV6)
247 struct ipv6_pinfo *np = NULL; 247 struct ipv6_pinfo *np = NULL;
248#endif 248#endif
249 struct l2tp_stats stats;
250 unsigned int start;
251 249
252 hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags, 250 hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags,
253 L2TP_CMD_TUNNEL_GET); 251 L2TP_CMD_TUNNEL_GET);
@@ -265,28 +263,22 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla
265 if (nest == NULL) 263 if (nest == NULL)
266 goto nla_put_failure; 264 goto nla_put_failure;
267 265
268 do { 266 if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS,
269 start = u64_stats_fetch_begin(&tunnel->stats.syncp); 267 atomic_long_read(&tunnel->stats.tx_packets)) ||
270 stats.tx_packets = tunnel->stats.tx_packets; 268 nla_put_u64(skb, L2TP_ATTR_TX_BYTES,
271 stats.tx_bytes = tunnel->stats.tx_bytes; 269 atomic_long_read(&tunnel->stats.tx_bytes)) ||
272 stats.tx_errors = tunnel->stats.tx_errors; 270 nla_put_u64(skb, L2TP_ATTR_TX_ERRORS,
273 stats.rx_packets = tunnel->stats.rx_packets; 271 atomic_long_read(&tunnel->stats.tx_errors)) ||
274 stats.rx_bytes = tunnel->stats.rx_bytes; 272 nla_put_u64(skb, L2TP_ATTR_RX_PACKETS,
275 stats.rx_errors = tunnel->stats.rx_errors; 273 atomic_long_read(&tunnel->stats.rx_packets)) ||
276 stats.rx_seq_discards = tunnel->stats.rx_seq_discards; 274 nla_put_u64(skb, L2TP_ATTR_RX_BYTES,
277 stats.rx_oos_packets = tunnel->stats.rx_oos_packets; 275 atomic_long_read(&tunnel->stats.rx_bytes)) ||
278 } while (u64_stats_fetch_retry(&tunnel->stats.syncp, start));
279
280 if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, stats.tx_packets) ||
281 nla_put_u64(skb, L2TP_ATTR_TX_BYTES, stats.tx_bytes) ||
282 nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, stats.tx_errors) ||
283 nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, stats.rx_packets) ||
284 nla_put_u64(skb, L2TP_ATTR_RX_BYTES, stats.rx_bytes) ||
285 nla_put_u64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, 276 nla_put_u64(skb, L2TP_ATTR_RX_SEQ_DISCARDS,
286 stats.rx_seq_discards) || 277 atomic_long_read(&tunnel->stats.rx_seq_discards)) ||
287 nla_put_u64(skb, L2TP_ATTR_RX_OOS_PACKETS, 278 nla_put_u64(skb, L2TP_ATTR_RX_OOS_PACKETS,
288 stats.rx_oos_packets) || 279 atomic_long_read(&tunnel->stats.rx_oos_packets)) ||
289 nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, stats.rx_errors)) 280 nla_put_u64(skb, L2TP_ATTR_RX_ERRORS,
281 atomic_long_read(&tunnel->stats.rx_errors)))
290 goto nla_put_failure; 282 goto nla_put_failure;
291 nla_nest_end(skb, nest); 283 nla_nest_end(skb, nest);
292 284
@@ -612,8 +604,6 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl
612 struct nlattr *nest; 604 struct nlattr *nest;
613 struct l2tp_tunnel *tunnel = session->tunnel; 605 struct l2tp_tunnel *tunnel = session->tunnel;
614 struct sock *sk = NULL; 606 struct sock *sk = NULL;
615 struct l2tp_stats stats;
616 unsigned int start;
617 607
618 sk = tunnel->sock; 608 sk = tunnel->sock;
619 609
@@ -656,28 +646,22 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl
656 if (nest == NULL) 646 if (nest == NULL)
657 goto nla_put_failure; 647 goto nla_put_failure;
658 648
659 do { 649 if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS,
660 start = u64_stats_fetch_begin(&session->stats.syncp); 650 atomic_long_read(&session->stats.tx_packets)) ||
661 stats.tx_packets = session->stats.tx_packets; 651 nla_put_u64(skb, L2TP_ATTR_TX_BYTES,
662 stats.tx_bytes = session->stats.tx_bytes; 652 atomic_long_read(&session->stats.tx_bytes)) ||
663 stats.tx_errors = session->stats.tx_errors; 653 nla_put_u64(skb, L2TP_ATTR_TX_ERRORS,
664 stats.rx_packets = session->stats.rx_packets; 654 atomic_long_read(&session->stats.tx_errors)) ||
665 stats.rx_bytes = session->stats.rx_bytes; 655 nla_put_u64(skb, L2TP_ATTR_RX_PACKETS,
666 stats.rx_errors = session->stats.rx_errors; 656 atomic_long_read(&session->stats.rx_packets)) ||
667 stats.rx_seq_discards = session->stats.rx_seq_discards; 657 nla_put_u64(skb, L2TP_ATTR_RX_BYTES,
668 stats.rx_oos_packets = session->stats.rx_oos_packets; 658 atomic_long_read(&session->stats.rx_bytes)) ||
669 } while (u64_stats_fetch_retry(&session->stats.syncp, start));
670
671 if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, stats.tx_packets) ||
672 nla_put_u64(skb, L2TP_ATTR_TX_BYTES, stats.tx_bytes) ||
673 nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, stats.tx_errors) ||
674 nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, stats.rx_packets) ||
675 nla_put_u64(skb, L2TP_ATTR_RX_BYTES, stats.rx_bytes) ||
676 nla_put_u64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, 659 nla_put_u64(skb, L2TP_ATTR_RX_SEQ_DISCARDS,
677 stats.rx_seq_discards) || 660 atomic_long_read(&session->stats.rx_seq_discards)) ||
678 nla_put_u64(skb, L2TP_ATTR_RX_OOS_PACKETS, 661 nla_put_u64(skb, L2TP_ATTR_RX_OOS_PACKETS,
679 stats.rx_oos_packets) || 662 atomic_long_read(&session->stats.rx_oos_packets)) ||
680 nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, stats.rx_errors)) 663 nla_put_u64(skb, L2TP_ATTR_RX_ERRORS,
664 atomic_long_read(&session->stats.rx_errors)))
681 goto nla_put_failure; 665 goto nla_put_failure;
682 nla_nest_end(skb, nest); 666 nla_nest_end(skb, nest);
683 667
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 7e3e16aefcb5..9d0eb8c13530 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -260,7 +260,7 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int
260 session->name); 260 session->name);
261 261
262 /* Not bound. Nothing we can do, so discard. */ 262 /* Not bound. Nothing we can do, so discard. */
263 session->stats.rx_errors++; 263 atomic_long_inc(&session->stats.rx_errors);
264 kfree_skb(skb); 264 kfree_skb(skb);
265 } 265 }
266 266
@@ -992,14 +992,14 @@ end:
992static void pppol2tp_copy_stats(struct pppol2tp_ioc_stats *dest, 992static void pppol2tp_copy_stats(struct pppol2tp_ioc_stats *dest,
993 struct l2tp_stats *stats) 993 struct l2tp_stats *stats)
994{ 994{
995 dest->tx_packets = stats->tx_packets; 995 dest->tx_packets = atomic_long_read(&stats->tx_packets);
996 dest->tx_bytes = stats->tx_bytes; 996 dest->tx_bytes = atomic_long_read(&stats->tx_bytes);
997 dest->tx_errors = stats->tx_errors; 997 dest->tx_errors = atomic_long_read(&stats->tx_errors);
998 dest->rx_packets = stats->rx_packets; 998 dest->rx_packets = atomic_long_read(&stats->rx_packets);
999 dest->rx_bytes = stats->rx_bytes; 999 dest->rx_bytes = atomic_long_read(&stats->rx_bytes);
1000 dest->rx_seq_discards = stats->rx_seq_discards; 1000 dest->rx_seq_discards = atomic_long_read(&stats->rx_seq_discards);
1001 dest->rx_oos_packets = stats->rx_oos_packets; 1001 dest->rx_oos_packets = atomic_long_read(&stats->rx_oos_packets);
1002 dest->rx_errors = stats->rx_errors; 1002 dest->rx_errors = atomic_long_read(&stats->rx_errors);
1003} 1003}
1004 1004
1005/* Session ioctl helper. 1005/* Session ioctl helper.
@@ -1633,14 +1633,14 @@ static void pppol2tp_seq_tunnel_show(struct seq_file *m, void *v)
1633 tunnel->name, 1633 tunnel->name,
1634 (tunnel == tunnel->sock->sk_user_data) ? 'Y' : 'N', 1634 (tunnel == tunnel->sock->sk_user_data) ? 'Y' : 'N',
1635 atomic_read(&tunnel->ref_count) - 1); 1635 atomic_read(&tunnel->ref_count) - 1);
1636 seq_printf(m, " %08x %llu/%llu/%llu %llu/%llu/%llu\n", 1636 seq_printf(m, " %08x %ld/%ld/%ld %ld/%ld/%ld\n",
1637 tunnel->debug, 1637 tunnel->debug,
1638 (unsigned long long)tunnel->stats.tx_packets, 1638 atomic_long_read(&tunnel->stats.tx_packets),
1639 (unsigned long long)tunnel->stats.tx_bytes, 1639 atomic_long_read(&tunnel->stats.tx_bytes),
1640 (unsigned long long)tunnel->stats.tx_errors, 1640 atomic_long_read(&tunnel->stats.tx_errors),
1641 (unsigned long long)tunnel->stats.rx_packets, 1641 atomic_long_read(&tunnel->stats.rx_packets),
1642 (unsigned long long)tunnel->stats.rx_bytes, 1642 atomic_long_read(&tunnel->stats.rx_bytes),
1643 (unsigned long long)tunnel->stats.rx_errors); 1643 atomic_long_read(&tunnel->stats.rx_errors));
1644} 1644}
1645 1645
1646static void pppol2tp_seq_session_show(struct seq_file *m, void *v) 1646static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
@@ -1675,14 +1675,14 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
1675 session->lns_mode ? "LNS" : "LAC", 1675 session->lns_mode ? "LNS" : "LAC",
1676 session->debug, 1676 session->debug,
1677 jiffies_to_msecs(session->reorder_timeout)); 1677 jiffies_to_msecs(session->reorder_timeout));
1678 seq_printf(m, " %hu/%hu %llu/%llu/%llu %llu/%llu/%llu\n", 1678 seq_printf(m, " %hu/%hu %ld/%ld/%ld %ld/%ld/%ld\n",
1679 session->nr, session->ns, 1679 session->nr, session->ns,
1680 (unsigned long long)session->stats.tx_packets, 1680 atomic_long_read(&session->stats.tx_packets),
1681 (unsigned long long)session->stats.tx_bytes, 1681 atomic_long_read(&session->stats.tx_bytes),
1682 (unsigned long long)session->stats.tx_errors, 1682 atomic_long_read(&session->stats.tx_errors),
1683 (unsigned long long)session->stats.rx_packets, 1683 atomic_long_read(&session->stats.rx_packets),
1684 (unsigned long long)session->stats.rx_bytes, 1684 atomic_long_read(&session->stats.rx_bytes),
1685 (unsigned long long)session->stats.rx_errors); 1685 atomic_long_read(&session->stats.rx_errors));
1686 1686
1687 if (po) 1687 if (po)
1688 seq_printf(m, " interface %s\n", ppp_dev_name(&po->chan)); 1688 seq_printf(m, " interface %s\n", ppp_dev_name(&po->chan));