aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@openvz.org>2008-03-31 19:42:16 -0700
committerDavid S. Miller <davem@davemloft.net>2008-03-31 19:42:16 -0700
commit70ee115942be6ce52ff10e5e813fb4da82cdb25a (patch)
treeaa3a22dfece765ead70df8f07974e398766b0104
parentc29a0bc4dfc4d833eb702b1929cec96a3eeb9f7a (diff)
[SOCK][NETNS]: Add the percpu prot_inuse counter in the struct net.
Such an accounting would cost us two more dereferences to get the percpu variable from the struct net, so I make sock_prot_inuse_get and _add calls work differently depending on CONFIG_NET_NS - without it old optimized routines are used. The per-cpu counter for init_net is prepared in core_initcall, so that even af_inet, that starts as fs_initcall, will already have the init_net prepared. Signed-off-by: Pavel Emelyanov <xemul@openvz.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/netns/core.h3
-rw-r--r--net/core/sock.c48
2 files changed, 51 insertions, 0 deletions
diff --git a/include/net/netns/core.h b/include/net/netns/core.h
index 0e8c0f8435d..24d4be76bbd 100644
--- a/include/net/netns/core.h
+++ b/include/net/netns/core.h
@@ -2,12 +2,15 @@
#define __NETNS_CORE_H__
struct ctl_table_header;
+struct prot_inuse;
struct netns_core {
/* core sysctls */
struct ctl_table_header *sysctl_hdr;
int sysctl_somaxconn;
+
+ struct prot_inuse *inuse;
};
#endif
diff --git a/net/core/sock.c b/net/core/sock.c
index 6f36ab91bb5..83e11f7260f 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1947,6 +1947,53 @@ struct prot_inuse {
};
static DECLARE_BITMAP(proto_inuse_idx, PROTO_INUSE_NR);
+
+#ifdef CONFIG_NET_NS
+void sock_prot_inuse_add(struct net *net, struct proto *prot, int val)
+{
+ int cpu = smp_processor_id();
+ per_cpu_ptr(net->core.inuse, cpu)->val[prot->inuse_idx] += val;
+}
+EXPORT_SYMBOL_GPL(sock_prot_inuse_add);
+
+int sock_prot_inuse_get(struct net *net, struct proto *prot)
+{
+ int cpu, idx = prot->inuse_idx;
+ int res = 0;
+
+ for_each_possible_cpu(cpu)
+ res += per_cpu_ptr(net->core.inuse, cpu)->val[idx];
+
+ return res >= 0 ? res : 0;
+}
+EXPORT_SYMBOL_GPL(sock_prot_inuse_get);
+
+static int sock_inuse_init_net(struct net *net)
+{
+ net->core.inuse = alloc_percpu(struct prot_inuse);
+ return net->core.inuse ? 0 : -ENOMEM;
+}
+
+static void sock_inuse_exit_net(struct net *net)
+{
+ free_percpu(net->core.inuse);
+}
+
+static struct pernet_operations net_inuse_ops = {
+ .init = sock_inuse_init_net,
+ .exit = sock_inuse_exit_net,
+};
+
+static __init int net_inuse_init(void)
+{
+ if (register_pernet_subsys(&net_inuse_ops))
+ panic("Cannot initialize net inuse counters");
+
+ return 0;
+}
+
+core_initcall(net_inuse_init);
+#else
static DEFINE_PER_CPU(struct prot_inuse, prot_inuse);
void sock_prot_inuse_add(struct net *net, struct proto *prot, int val)
@@ -1966,6 +2013,7 @@ int sock_prot_inuse_get(struct net *net, struct proto *prot)
return res >= 0 ? res : 0;
}
EXPORT_SYMBOL_GPL(sock_prot_inuse_get);
+#endif
static void assign_proto_idx(struct proto *prot)
{