diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c index a2396cd03f71..33f2ec84d150 100644 --- a/net/netfilter/nft_set_rbtree.c +++ b/net/netfilter/nft_set_rbtree.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -509,26 +510,44 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, return 0; } +static void nft_rbtree_copy(const struct nft_set *set, struct rb_node *parent, + struct rb_node **pos, struct nft_rbtree_elem *elem) +{ + struct nft_rbtree *priv = nft_set_priv(set); + u8 genbit = nft_rbtree_genbit_copy(priv); + + rb_link_node_rcu(&elem->node[genbit], parent, pos); + rb_set_parent_color(&elem->node[genbit], parent, + rb_color(&elem->node[!genbit])); + + if (elem->node[!genbit].rb_left) + nft_rbtree_copy(set, &elem->node[genbit], + &elem->node[genbit].rb_left, + rb_entry(elem->node[!genbit].rb_left, + struct nft_rbtree_elem, + node[!genbit])); + if (elem->node[!genbit].rb_right) + nft_rbtree_copy(set, &elem->node[genbit], + &elem->node[genbit].rb_right, + rb_entry(elem->node[!genbit].rb_right, + struct nft_rbtree_elem, + node[!genbit])); +} + static void nft_rbtree_maybe_clone(const struct net *net, const struct nft_set *set) { struct nft_rbtree *priv = nft_set_priv(set); u8 genbit = nft_rbtree_genbit_live(priv); - struct nft_rbtree_elem *rbe; - struct rb_node *node, *next; lockdep_assert_held_once(&nft_pernet(net)->commit_mutex); if (priv->cloned) return; - for (node = rb_first(&priv->root[genbit]); node ; node = next) { - next = rb_next(node); - rbe = rb_entry(node, struct nft_rbtree_elem, node[genbit]); - - /* No need to acquire a lock, this is the future tree, not - * exposed to packetpath. - */ - __nft_rbtree_insert_do(set, rbe); + if (priv->root[genbit].rb_node) { + nft_rbtree_copy(set, NULL, &priv->root[!genbit].rb_node, + rb_entry(priv->root[genbit].rb_node, + struct nft_rbtree_elem, node[genbit])); } priv->cloned = true; }