fib: Fix fib zone and its hash leak on namespace stop
authorPavel Emelyanov <xemul@parallels.com>
Thu, 28 Oct 2010 02:00:43 +0000 (02:00 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 28 Oct 2010 17:27:03 +0000 (10:27 -0700)
When we stop a namespace we flush the table and free one, but the
added fn_zone-s (and their hashes if grown) are leaked. Need to free.
Tries releases all its stuff in the flushing code.

Shame on us - this bug exists since the very first make-fib-per-net
patches in 2.6.27 :(

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ip_fib.h
net/ipv4/fib_frontend.c
net/ipv4/fib_hash.c
net/ipv4/fib_trie.c

index ba3666d31766864b354687cc543d9ba3a365193d..07bdb5e9e8ac0b80628400d4b79e7e5041ce8199 100644 (file)
@@ -158,6 +158,8 @@ extern int fib_table_flush(struct fib_table *table);
 extern void fib_table_select_default(struct fib_table *table,
                                     const struct flowi *flp,
                                     struct fib_result *res);
+extern void fib_free_table(struct fib_table *tb);
+
 
 
 #ifndef CONFIG_IP_MULTIPLE_TABLES
index 36e27c2107de9f8286e7848c9b0dfe3560ab2907..eb6f69a8f27aff4db2de494389dd7d9584b93ece 100644 (file)
@@ -1052,7 +1052,7 @@ static void ip_fib_net_exit(struct net *net)
                hlist_for_each_entry_safe(tb, node, tmp, head, tb_hlist) {
                        hlist_del(node);
                        fib_table_flush(tb);
-                       kfree(tb);
+                       fib_free_table(tb);
                }
        }
        kfree(net->ipv4.fib_table_hash);
index b232375a0b75f4f3108284c9bcb4b993b415ebdc..b3acb0417b21f69b754003f76168f30f78b85700 100644 (file)
@@ -716,6 +716,24 @@ int fib_table_flush(struct fib_table *tb)
        return found;
 }
 
+void fib_free_table(struct fib_table *tb)
+{
+       struct fn_hash *table = (struct fn_hash *) tb->tb_data;
+       struct fn_zone *fz, *next;
+
+       next = table->fn_zone_list;
+       while (next != NULL) {
+               fz = next;
+               next = fz->fz_next;
+
+               if (fz->fz_hash != fz->fz_embedded_hash)
+                       fz_hash_free(fz->fz_hash, fz->fz_divisor);
+
+               kfree(fz);
+       }
+
+       kfree(tb);
+}
 
 static inline int
 fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb,
index b14450895102ae385f2c603eb1b591bc3170f994..200eb538fbb3f77101fe9646893dddbd9e83117b 100644 (file)
@@ -1797,6 +1797,11 @@ int fib_table_flush(struct fib_table *tb)
        return found;
 }
 
+void fib_free_table(struct fib_table *tb)
+{
+       kfree(tb);
+}
+
 void fib_table_select_default(struct fib_table *tb,
                              const struct flowi *flp,
                              struct fib_result *res)