diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/af_inet.c | 36 | ||||
-rw-r--r-- | net/ipv4/proc.c | 15 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 18 | ||||
-rw-r--r-- | net/ipv6/proc.c | 17 |
4 files changed, 76 insertions, 10 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 640db9b90330..3ceb025b16f2 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -1427,6 +1427,42 @@ unsigned long snmp_fold_field(void __percpu *mib[], int offt) | |||
1427 | } | 1427 | } |
1428 | EXPORT_SYMBOL_GPL(snmp_fold_field); | 1428 | EXPORT_SYMBOL_GPL(snmp_fold_field); |
1429 | 1429 | ||
1430 | #if BITS_PER_LONG==32 | ||
1431 | |||
1432 | u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_offset) | ||
1433 | { | ||
1434 | u64 res = 0; | ||
1435 | int cpu; | ||
1436 | |||
1437 | for_each_possible_cpu(cpu) { | ||
1438 | void *bhptr, *userptr; | ||
1439 | struct u64_stats_sync *syncp; | ||
1440 | u64 v_bh, v_user; | ||
1441 | unsigned int start; | ||
1442 | |||
1443 | /* first mib used by softirq context, we must use _bh() accessors */ | ||
1444 | bhptr = per_cpu_ptr(SNMP_STAT_BHPTR(mib), cpu); | ||
1445 | syncp = (struct u64_stats_sync *)(bhptr + syncp_offset); | ||
1446 | do { | ||
1447 | start = u64_stats_fetch_begin_bh(syncp); | ||
1448 | v_bh = *(((u64 *) bhptr) + offt); | ||
1449 | } while (u64_stats_fetch_retry_bh(syncp, start)); | ||
1450 | |||
1451 | /* second mib used in USER context */ | ||
1452 | userptr = per_cpu_ptr(SNMP_STAT_USRPTR(mib), cpu); | ||
1453 | syncp = (struct u64_stats_sync *)(userptr + syncp_offset); | ||
1454 | do { | ||
1455 | start = u64_stats_fetch_begin(syncp); | ||
1456 | v_user = *(((u64 *) userptr) + offt); | ||
1457 | } while (u64_stats_fetch_retry(syncp, start)); | ||
1458 | |||
1459 | res += v_bh + v_user; | ||
1460 | } | ||
1461 | return res; | ||
1462 | } | ||
1463 | EXPORT_SYMBOL_GPL(snmp_fold_field64); | ||
1464 | #endif | ||
1465 | |||
1430 | int snmp_mib_init(void __percpu *ptr[2], size_t mibsize, size_t align) | 1466 | int snmp_mib_init(void __percpu *ptr[2], size_t mibsize, size_t align) |
1431 | { | 1467 | { |
1432 | BUG_ON(ptr == NULL); | 1468 | BUG_ON(ptr == NULL); |
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index e320ca6b3ef3..4ae1f203f7cb 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c | |||
@@ -343,10 +343,12 @@ static int snmp_seq_show(struct seq_file *seq, void *v) | |||
343 | IPV4_DEVCONF_ALL(net, FORWARDING) ? 1 : 2, | 343 | IPV4_DEVCONF_ALL(net, FORWARDING) ? 1 : 2, |
344 | sysctl_ip_default_ttl); | 344 | sysctl_ip_default_ttl); |
345 | 345 | ||
346 | BUILD_BUG_ON(offsetof(struct ipstats_mib, mibs) != 0); | ||
346 | for (i = 0; snmp4_ipstats_list[i].name != NULL; i++) | 347 | for (i = 0; snmp4_ipstats_list[i].name != NULL; i++) |
347 | seq_printf(seq, " %lu", | 348 | seq_printf(seq, " %llu", |
348 | snmp_fold_field((void __percpu **)net->mib.ip_statistics, | 349 | snmp_fold_field64((void __percpu **)net->mib.ip_statistics, |
349 | snmp4_ipstats_list[i].entry)); | 350 | snmp4_ipstats_list[i].entry, |
351 | offsetof(struct ipstats_mib, syncp))); | ||
350 | 352 | ||
351 | icmp_put(seq); /* RFC 2011 compatibility */ | 353 | icmp_put(seq); /* RFC 2011 compatibility */ |
352 | icmpmsg_put(seq); | 354 | icmpmsg_put(seq); |
@@ -432,9 +434,10 @@ static int netstat_seq_show(struct seq_file *seq, void *v) | |||
432 | 434 | ||
433 | seq_puts(seq, "\nIpExt:"); | 435 | seq_puts(seq, "\nIpExt:"); |
434 | for (i = 0; snmp4_ipextstats_list[i].name != NULL; i++) | 436 | for (i = 0; snmp4_ipextstats_list[i].name != NULL; i++) |
435 | seq_printf(seq, " %lu", | 437 | seq_printf(seq, " %llu", |
436 | snmp_fold_field((void __percpu **)net->mib.ip_statistics, | 438 | snmp_fold_field64((void __percpu **)net->mib.ip_statistics, |
437 | snmp4_ipextstats_list[i].entry)); | 439 | snmp4_ipextstats_list[i].entry, |
440 | offsetof(struct ipstats_mib, syncp))); | ||
438 | 441 | ||
439 | seq_putc(seq, '\n'); | 442 | seq_putc(seq, '\n'); |
440 | return 0; | 443 | return 0; |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 2514adf5251e..e81155d2f251 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -3862,12 +3862,28 @@ static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, | |||
3862 | memset(&stats[items], 0, pad); | 3862 | memset(&stats[items], 0, pad); |
3863 | } | 3863 | } |
3864 | 3864 | ||
3865 | static inline void __snmp6_fill_stats64(u64 *stats, void __percpu **mib, | ||
3866 | int items, int bytes, size_t syncpoff) | ||
3867 | { | ||
3868 | int i; | ||
3869 | int pad = bytes - sizeof(u64) * items; | ||
3870 | BUG_ON(pad < 0); | ||
3871 | |||
3872 | /* Use put_unaligned() because stats may not be aligned for u64. */ | ||
3873 | put_unaligned(items, &stats[0]); | ||
3874 | for (i = 1; i < items; i++) | ||
3875 | put_unaligned(snmp_fold_field64(mib, i, syncpoff), &stats[i]); | ||
3876 | |||
3877 | memset(&stats[items], 0, pad); | ||
3878 | } | ||
3879 | |||
3865 | static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, | 3880 | static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, |
3866 | int bytes) | 3881 | int bytes) |
3867 | { | 3882 | { |
3868 | switch (attrtype) { | 3883 | switch (attrtype) { |
3869 | case IFLA_INET6_STATS: | 3884 | case IFLA_INET6_STATS: |
3870 | __snmp6_fill_stats(stats, (void __percpu **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes); | 3885 | __snmp6_fill_stats64(stats, (void __percpu **)idev->stats.ipv6, |
3886 | IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp)); | ||
3871 | break; | 3887 | break; |
3872 | case IFLA_INET6_ICMP6STATS: | 3888 | case IFLA_INET6_ICMP6STATS: |
3873 | __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); | 3889 | __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); |
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 566798d69f37..d082eaeefa25 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c | |||
@@ -174,17 +174,28 @@ static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **mib, | |||
174 | const struct snmp_mib *itemlist) | 174 | const struct snmp_mib *itemlist) |
175 | { | 175 | { |
176 | int i; | 176 | int i; |
177 | for (i=0; itemlist[i].name; i++) | 177 | |
178 | for (i = 0; itemlist[i].name; i++) | ||
178 | seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name, | 179 | seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name, |
179 | snmp_fold_field(mib, itemlist[i].entry)); | 180 | snmp_fold_field(mib, itemlist[i].entry)); |
180 | } | 181 | } |
181 | 182 | ||
183 | static void snmp6_seq_show_item64(struct seq_file *seq, void __percpu **mib, | ||
184 | const struct snmp_mib *itemlist, size_t syncpoff) | ||
185 | { | ||
186 | int i; | ||
187 | |||
188 | for (i = 0; itemlist[i].name; i++) | ||
189 | seq_printf(seq, "%-32s\t%llu\n", itemlist[i].name, | ||
190 | snmp_fold_field64(mib, itemlist[i].entry, syncpoff)); | ||
191 | } | ||
192 | |||
182 | static int snmp6_seq_show(struct seq_file *seq, void *v) | 193 | static int snmp6_seq_show(struct seq_file *seq, void *v) |
183 | { | 194 | { |
184 | struct net *net = (struct net *)seq->private; | 195 | struct net *net = (struct net *)seq->private; |
185 | 196 | ||
186 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.ipv6_statistics, | 197 | snmp6_seq_show_item64(seq, (void __percpu **)net->mib.ipv6_statistics, |
187 | snmp6_ipstats_list); | 198 | snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp)); |
188 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics, | 199 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics, |
189 | snmp6_icmp6_list); | 200 | snmp6_icmp6_list); |
190 | snmp6_seq_show_icmpv6msg(seq, | 201 | snmp6_seq_show_icmpv6msg(seq, |