aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/af_inet.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-06-10 15:45:51 -0400
committerDavid S. Miller <davem@davemloft.net>2011-06-11 19:23:59 -0400
commit8f0ea0fe3a036a47767f9c80e81b13e379a1f43b (patch)
tree6f4079c8da32f3e1ac4860ac9f90b26e9df86e3b /net/ipv4/af_inet.c
parent830a9c75514b477994fd3847f72654d3dbdfa5ca (diff)
snmp: reduce percpu needs by 50%
SNMP mibs use two percpu arrays, one used in BH context, another in USER context. With increasing number of cpus in machines, and fact that ipv6 uses per network device ipstats_mib, this is consuming a lot of memory if many network devices are registered. commit be281e554e2a (ipv6: reduce per device ICMP mib sizes) shrinked percpu needs for ipv6, but we can reduce memory use a bit more. With recent percpu infrastructure (irqsafe_cpu_inc() ...), we no longer need this BH/USER separation since we can update counters in a single x86 instruction, regardless of the BH/USER context. Other arches than x86 might need to disable irq in their irqsafe_cpu_inc() implementation : If this happens to be a problem, we can make SNMP_ARRAY_SZ arch dependent, but a previous poll ( https://lkml.org/lkml/2011/3/17/174 ) to arch maintainers did not raise strong opposition. Only on 32bit arches, we need to disable BH for 64bit counters updates done from USER context (currently used for IP MIB) This also reduces vmlinux size : 1) x86_64 build $ size vmlinux.before vmlinux.after text data bss dec hex filename 7853650 1293772 1896448 11043870 a8841e vmlinux.before 7850578 1293772 1896448 11040798 a8781e vmlinux.after 2) i386 build $ size vmlinux.before vmlinux.afterpatch text data bss dec hex filename 6039335 635076 3670016 10344427 9dd7eb vmlinux.before 6037342 635076 3670016 10342434 9dd022 vmlinux.afterpatch Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> CC: Andi Kleen <andi@firstfloor.org> CC: Ingo Molnar <mingo@elte.hu> CC: Tejun Heo <tj@kernel.org> CC: Christoph Lameter <cl@linux-foundation.org> CC: Benjamin Herrenschmidt <benh@kernel.crashing.org CC: linux-arch@vger.kernel.org Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/af_inet.c')
-rw-r--r--net/ipv4/af_inet.c52
1 files changed, 23 insertions, 29 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 9c1926027a26..83673d23d4dd 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1437,11 +1437,11 @@ EXPORT_SYMBOL_GPL(inet_ctl_sock_create);
1437unsigned long snmp_fold_field(void __percpu *mib[], int offt) 1437unsigned long snmp_fold_field(void __percpu *mib[], int offt)
1438{ 1438{
1439 unsigned long res = 0; 1439 unsigned long res = 0;
1440 int i; 1440 int i, j;
1441 1441
1442 for_each_possible_cpu(i) { 1442 for_each_possible_cpu(i) {
1443 res += *(((unsigned long *) per_cpu_ptr(mib[0], i)) + offt); 1443 for (j = 0; j < SNMP_ARRAY_SZ; j++)
1444 res += *(((unsigned long *) per_cpu_ptr(mib[1], i)) + offt); 1444 res += *(((unsigned long *) per_cpu_ptr(mib[j], i)) + offt);
1445 } 1445 }
1446 return res; 1446 return res;
1447} 1447}
@@ -1455,28 +1455,19 @@ u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_offset)
1455 int cpu; 1455 int cpu;
1456 1456
1457 for_each_possible_cpu(cpu) { 1457 for_each_possible_cpu(cpu) {
1458 void *bhptr, *userptr; 1458 void *bhptr;
1459 struct u64_stats_sync *syncp; 1459 struct u64_stats_sync *syncp;
1460 u64 v_bh, v_user; 1460 u64 v;
1461 unsigned int start; 1461 unsigned int start;
1462 1462
1463 /* first mib used by softirq context, we must use _bh() accessors */ 1463 bhptr = per_cpu_ptr(mib[0], cpu);
1464 bhptr = per_cpu_ptr(SNMP_STAT_BHPTR(mib), cpu);
1465 syncp = (struct u64_stats_sync *)(bhptr + syncp_offset); 1464 syncp = (struct u64_stats_sync *)(bhptr + syncp_offset);
1466 do { 1465 do {
1467 start = u64_stats_fetch_begin_bh(syncp); 1466 start = u64_stats_fetch_begin_bh(syncp);
1468 v_bh = *(((u64 *) bhptr) + offt); 1467 v = *(((u64 *) bhptr) + offt);
1469 } while (u64_stats_fetch_retry_bh(syncp, start)); 1468 } while (u64_stats_fetch_retry_bh(syncp, start));
1470 1469
1471 /* second mib used in USER context */ 1470 res += v;
1472 userptr = per_cpu_ptr(SNMP_STAT_USRPTR(mib), cpu);
1473 syncp = (struct u64_stats_sync *)(userptr + syncp_offset);
1474 do {
1475 start = u64_stats_fetch_begin(syncp);
1476 v_user = *(((u64 *) userptr) + offt);
1477 } while (u64_stats_fetch_retry(syncp, start));
1478
1479 res += v_bh + v_user;
1480 } 1471 }
1481 return res; 1472 return res;
1482} 1473}
@@ -1488,25 +1479,28 @@ int snmp_mib_init(void __percpu *ptr[2], size_t mibsize, size_t align)
1488 BUG_ON(ptr == NULL); 1479 BUG_ON(ptr == NULL);
1489 ptr[0] = __alloc_percpu(mibsize, align); 1480 ptr[0] = __alloc_percpu(mibsize, align);
1490 if (!ptr[0]) 1481 if (!ptr[0])
1491 goto err0; 1482 return -ENOMEM;
1483#if SNMP_ARRAY_SZ == 2
1492 ptr[1] = __alloc_percpu(mibsize, align); 1484 ptr[1] = __alloc_percpu(mibsize, align);
1493 if (!ptr[1]) 1485 if (!ptr[1]) {
1494 goto err1; 1486 free_percpu(ptr[0]);
1487 ptr[0] = NULL;
1488 return -ENOMEM;
1489 }
1490#endif
1495 return 0; 1491 return 0;
1496err1:
1497 free_percpu(ptr[0]);
1498 ptr[0] = NULL;
1499err0:
1500 return -ENOMEM;
1501} 1492}
1502EXPORT_SYMBOL_GPL(snmp_mib_init); 1493EXPORT_SYMBOL_GPL(snmp_mib_init);
1503 1494
1504void snmp_mib_free(void __percpu *ptr[2]) 1495void snmp_mib_free(void __percpu *ptr[SNMP_ARRAY_SZ])
1505{ 1496{
1497 int i;
1498
1506 BUG_ON(ptr == NULL); 1499 BUG_ON(ptr == NULL);
1507 free_percpu(ptr[0]); 1500 for (i = 0; i < SNMP_ARRAY_SZ; i++) {
1508 free_percpu(ptr[1]); 1501 free_percpu(ptr[i]);
1509 ptr[0] = ptr[1] = NULL; 1502 ptr[i] = NULL;
1503 }
1510} 1504}
1511EXPORT_SYMBOL_GPL(snmp_mib_free); 1505EXPORT_SYMBOL_GPL(snmp_mib_free);
1512 1506