summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/dst.h5
-rw-r--r--net/bridge/br_netfilter.c2
-rw-r--r--net/core/dst.c26
-rw-r--r--net/core/pktgen.c2
-rw-r--r--net/ipv4/fib_semantics.c4
-rw-r--r--net/ipv6/ip6_fib.c2
-rw-r--r--net/ipv6/route.c2
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,
};