This patch removes nfnl_acct_list from struct net, making it possible to compile nfacct module out of tree and reducing the default memory footprint for the netns structure. Signed-off-by: Miao Wang <shankerwangmiao@xxxxxxxxx> --- include/net/net_namespace.h | 3 --- net/netfilter/nfnetlink_acct.c | 38 ++++++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 22bc07f4b043..dc20a47e3828 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -151,9 +151,6 @@ struct net { #endif struct sock *nfnl; struct sock *nfnl_stash; -#if IS_ENABLED(CONFIG_NETFILTER_NETLINK_ACCT) - struct list_head nfnl_acct_list; -#endif #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) struct list_head nfct_timeout_list; #endif diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c index 5bfec829c12f..dbc2fc8940c8 100644 --- a/net/netfilter/nfnetlink_acct.c +++ b/net/netfilter/nfnetlink_acct.c @@ -16,6 +16,7 @@ #include <linux/errno.h> #include <net/netlink.h> #include <net/sock.h> +#include <net/netns/generic.h> #include <linux/netfilter.h> #include <linux/netfilter/nfnetlink.h> @@ -41,6 +42,17 @@ struct nfacct_filter { u32 mask; }; +struct nfnl_acct_net { + struct list_head nfnl_acct_list; +}; + +static unsigned int nfnl_acct_net_id __read_mostly; + +static inline struct nfnl_acct_net *nfnl_acct_pernet(struct net *net) +{ + return net_generic(net, nfnl_acct_net_id); +} + #define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES) #define NFACCT_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */ @@ -49,6 +61,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl, const struct nlattr * const tb[], struct netlink_ext_ack *extack) { + struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net); struct nf_acct *nfacct, *matching = NULL; char *acct_name; unsigned int size = 0; @@ -61,7 +74,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl, if (strlen(acct_name) == 0) return -EINVAL; - list_for_each_entry(nfacct, &net->nfnl_acct_list, head) { + list_for_each_entry(nfacct, &nfnl_acct_net->nfnl_acct_list, head) { if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0) continue; @@ -123,7 +136,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl, be64_to_cpu(nla_get_be64(tb[NFACCT_PKTS]))); } refcount_set(&nfacct->refcnt, 1); - list_add_tail_rcu(&nfacct->head, &net->nfnl_acct_list); + list_add_tail_rcu(&nfacct->head, &nfnl_acct_net->nfnl_acct_list); return 0; } @@ -188,6 +201,7 @@ static int nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); + struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net); struct nf_acct *cur, *last; const struct nfacct_filter *filter = cb->data; @@ -199,7 +213,7 @@ nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb) cb->args[1] = 0; rcu_read_lock(); - list_for_each_entry_rcu(cur, &net->nfnl_acct_list, head) { + list_for_each_entry_rcu(cur, &nfnl_acct_net->nfnl_acct_list, head) { if (last) { if (cur != last) continue; @@ -269,6 +283,7 @@ static int nfnl_acct_get(struct net *net, struct sock *nfnl, const struct nlattr * const tb[], struct netlink_ext_ack *extack) { + struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net); int ret = -ENOENT; struct nf_acct *cur; char *acct_name; @@ -288,7 +303,7 @@ static int nfnl_acct_get(struct net *net, struct sock *nfnl, return -EINVAL; acct_name = nla_data(tb[NFACCT_NAME]); - list_for_each_entry(cur, &net->nfnl_acct_list, head) { + list_for_each_entry(cur, &nfnl_acct_net->nfnl_acct_list, head) { struct sk_buff *skb2; if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX)!= 0) @@ -342,19 +357,20 @@ static int nfnl_acct_del(struct net *net, struct sock *nfnl, const struct nlattr * const tb[], struct netlink_ext_ack *extack) { + struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net); struct nf_acct *cur, *tmp; int ret = -ENOENT; char *acct_name; if (!tb[NFACCT_NAME]) { - list_for_each_entry_safe(cur, tmp, &net->nfnl_acct_list, head) + list_for_each_entry_safe(cur, tmp, &nfnl_acct_net->nfnl_acct_list, head) nfnl_acct_try_del(cur); return 0; } acct_name = nla_data(tb[NFACCT_NAME]); - list_for_each_entry(cur, &net->nfnl_acct_list, head) { + list_for_each_entry(cur, &nfnl_acct_net->nfnl_acct_list, head) { if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX) != 0) continue; @@ -402,10 +418,11 @@ MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ACCT); struct nf_acct *nfnl_acct_find_get(struct net *net, const char *acct_name) { + struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net); struct nf_acct *cur, *acct = NULL; rcu_read_lock(); - list_for_each_entry_rcu(cur, &net->nfnl_acct_list, head) { + list_for_each_entry_rcu(cur, &nfnl_acct_net->nfnl_acct_list, head) { if (strncmp(cur->name, acct_name, NFACCT_NAME_MAX)!= 0) continue; @@ -488,16 +505,17 @@ EXPORT_SYMBOL_GPL(nfnl_acct_overquota); static int __net_init nfnl_acct_net_init(struct net *net) { - INIT_LIST_HEAD(&net->nfnl_acct_list); + INIT_LIST_HEAD(&nfnl_acct_pernet(net)->nfnl_acct_list); return 0; } static void __net_exit nfnl_acct_net_exit(struct net *net) { + struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net); struct nf_acct *cur, *tmp; - list_for_each_entry_safe(cur, tmp, &net->nfnl_acct_list, head) { + list_for_each_entry_safe(cur, tmp, &nfnl_acct_net->nfnl_acct_list, head) { list_del_rcu(&cur->head); if (refcount_dec_and_test(&cur->refcnt)) @@ -508,6 +526,8 @@ static void __net_exit nfnl_acct_net_exit(struct net *net) static struct pernet_operations nfnl_acct_ops = { .init = nfnl_acct_net_init, .exit = nfnl_acct_net_exit, + .id = &nfnl_acct_net_id, + .size = sizeof(struct nfnl_acct_net), }; static int __init nfnl_acct_init(void) -- 2.20.1