Since there is no serialization mechanism (e.g. the RTNL lock) between
llist_add() in net_complete_free() and llist_del_all() in
net_complete_free(), it is possible that net_complete_free() finds 'struct
net' as soon as net_complete_free() added it to the defer_free_list.
Fixes: 0f6ede9fbc74 ("net: defer final 'struct net' free in netns dismantle")
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
net/core/net_namespace.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index d9dafe24f57e..6e9a0c29a9a0 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -514,14 +514,10 @@ static struct net *net_alloc(void)
static LLIST_HEAD(defer_free_list);
-static void net_complete_free(void)
+static void net_complete_free(struct llist_node *kill_list)
{
- struct llist_node *kill_list;
struct net *net, *next;
- /* Get the list of namespaces to free from last round. */
- kill_list = llist_del_all(&defer_free_list);
-
llist_for_each_entry_safe(net, next, kill_list, defer_free_list)
kmem_cache_free(net_cachep, net);
@@ -703,12 +699,15 @@ static void cleanup_net(struct work_struct *work)
up_read(&pernet_ops_rwsem);
+ /* Get the list of namespaces to free from last round. */
+ net_kill_list = llist_del_all(&defer_free_list);
+
/* Ensure there are no outstanding rcu callbacks using this
* network namespace.
*/
rcu_barrier();
- net_complete_free();
+ net_complete_free(net_kill_list);
/* Finally it is safe to free my network namespace structure */
list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {--
2.55.0