diff options
-rw-r--r-- | include/net/dst.h | 5 | ||||
-rw-r--r-- | net/bridge/br_netfilter.c | 2 | ||||
-rw-r--r-- | net/core/dst.c | 26 | ||||
-rw-r--r-- | net/core/pktgen.c | 2 | ||||
-rw-r--r-- | net/ipv4/fib_semantics.c | 4 | ||||
-rw-r--r-- | net/ipv6/ip6_fib.c | 2 | ||||
-rw-r--r-- | net/ipv6/route.c | 2 |
7 files changed, 32 insertions, 11 deletions
diff --git a/include/net/dst.h b/include/net/dst.h index 0fb99a26e973..f285de9d567a 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -105,12 +105,15 @@ struct dst_entry { }; }; +void *dst_alloc_metrics(gfp_t flags); +void dst_free_metrics(void *metrics); u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old); extern const u32 dst_default_metrics[]; #define DST_METRICS_READ_ONLY 0x1UL #define DST_METRICS_FORCE_OVERWRITE 0x2UL -#define DST_METRICS_FLAGS 0x3UL +#define DST_METRICS_FLAGS 0x7UL +#define DST_METRICS_ALIGNMENT 0x8UL #define __DST_METRICS_PTR(Y) \ ((u32 *)((Y) & ~DST_METRICS_FLAGS)) #define DST_METRICS_PTR(X) __DST_METRICS_PTR((X)->_metrics) diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index a615264cf01a..2cf4e30ac41a 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -155,7 +155,7 @@ static struct dst_ops fake_dst_ops = { * ipt_REJECT needs it. Future netfilter modules might * require us to fill additional fields. */ -static const u32 br_dst_default_metrics[RTAX_MAX] = { +static const u32 br_dst_default_metrics[RTAX_MAX] __aligned(DST_METRICS_ALIGNMENT) = { [RTAX_MTU - 1] = 1500, }; diff --git a/net/core/dst.c b/net/core/dst.c index 57746a18c957..7fa4d03c38a3 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -149,7 +149,7 @@ int dst_discard_sk(struct sock *sk, struct sk_buff *skb) } EXPORT_SYMBOL(dst_discard_sk); -const u32 dst_default_metrics[RTAX_MAX + 1] = { +const u32 dst_default_metrics[RTAX_MAX + 1] __aligned(DST_METRICS_ALIGNMENT) = { /* This initializer is needed to force linker to place this variable * into const section. Otherwise it might end into bss section. * We really want to avoid false sharing on this variable, and catch @@ -292,9 +292,23 @@ void dst_release(struct dst_entry *dst) } EXPORT_SYMBOL(dst_release); +static struct kmem_cache *metrics_cache; + +void *dst_alloc_metrics(gfp_t flags) +{ + return kmem_cache_alloc(metrics_cache, flags); +} +EXPORT_SYMBOL(dst_alloc_metrics); + +void dst_free_metrics(void *metrics) +{ + kmem_cache_free(metrics_cache, metrics); +} +EXPORT_SYMBOL(dst_free_metrics); + u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old) { - u32 *p = kmalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC); + u32 *p = dst_alloc_metrics(GFP_ATOMIC); if (p) { u32 *old_p = __DST_METRICS_PTR(old); @@ -306,7 +320,7 @@ u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old) prev = cmpxchg(&dst->_metrics, old, new); if (prev != old) { - kfree(p); + dst_free_metrics(p); p = __DST_METRICS_PTR(prev); if (prev & DST_METRICS_READ_ONLY) p = NULL; @@ -324,7 +338,7 @@ void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old) new = ((unsigned long) dst_default_metrics) | DST_METRICS_READ_ONLY; prev = cmpxchg(&dst->_metrics, old, new); if (prev == old) - kfree(__DST_METRICS_PTR(old)); + dst_free_metrics(__DST_METRICS_PTR(old)); } EXPORT_SYMBOL(__dst_destroy_metrics_generic); @@ -419,4 +433,8 @@ static struct notifier_block dst_dev_notifier = { void __init dst_init(void) { register_netdevice_notifier(&dst_dev_notifier); + metrics_cache = kmem_cache_create("dst_metrics", + sizeof(u32) * RTAX_MAX, + DST_METRICS_ALIGNMENT, + SLAB_PANIC, NULL); } diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 0234ae038a62..d585bc9109b4 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2502,7 +2502,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) #ifdef CONFIG_XFRM -static u32 pktgen_dst_metrics[RTAX_MAX + 1] = { +static u32 pktgen_dst_metrics[RTAX_MAX + 1] __aligned(DST_METRICS_ALIGNMENT) = { [RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */ }; diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index b77a181cd450..fe53b9122b8b 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -213,7 +213,7 @@ static void free_fib_info_rcu(struct rcu_head *head) release_net(fi->fib_net); if (fi->fib_metrics != (u32 *) dst_default_metrics) - kfree(fi->fib_metrics); + dst_free_metrics(fi->fib_metrics); kfree(fi); } @@ -823,7 +823,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) goto failure; fib_info_cnt++; if (cfg->fc_mx) { - fi->fib_metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL); + fi->fib_metrics = dst_alloc_metrics(GFP_KERNEL | __GFP_ZERO); if (!fi->fib_metrics) goto failure; } else diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 36aadaeb7f44..7b7e955ca14e 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -643,7 +643,7 @@ static int fib6_commit_metrics(struct dst_entry *dst, if (dst->flags & DST_HOST) { mp = dst_metrics_write_ptr(dst); } else { - mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC); + mp = dst_alloc_metrics(GFP_ATOMIC | __GFP_ZERO); if (!mp) return -ENOMEM; dst_init_metrics(dst, mp, 0); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a66142e53216..90e59ea3adbc 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -247,7 +247,7 @@ static struct dst_ops ip6_dst_blackhole_ops = { .neigh_lookup = ip6_neigh_lookup, }; -static const u32 ip6_template_metrics[RTAX_MAX] = { +static const u32 ip6_template_metrics[RTAX_MAX] __aligned(DST_METRICS_ALIGNMENT) = { [RTAX_HOPLIMIT - 1] = 0, }; |