3.16.50-rc1 review patch.  If anyone has any objections, please let me know.

------------------

From: Ben Hutchings <b...@decadent.org.uk>

For the backport of "ipv4: add reference counting to metrics", we will
need a third flag on metrics pointers.  This was not needed upstream
as the DST_METRICS_FORCE_OVERWRITE flag has been eliminated there.
In order to use three flag bits we need to increase the alignment of
metrics from 4 to 8 bytes.

Signed-off-by: Ben Hutchings <b...@decadent.org.uk>
---
--- 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)
--- 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,
 };
 
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -149,7 +149,7 @@ int dst_discard_sk(struct sock *sk, stru
 }
 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_
                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(struc
        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_not
 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);
 }
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -2502,7 +2502,7 @@ static void mod_cur_headers(struct pktge
 
 
 #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 */
 };
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -213,7 +213,7 @@ static void free_fib_info_rcu(struct rcu
 
        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
                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
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -247,7 +247,7 @@ static struct dst_ops ip6_dst_blackhole_
        .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,
 };
 
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -643,7 +643,7 @@ static int fib6_commit_metrics(struct ds
        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);

Reply via email to