same rationale as previous patch, however, this time we cannot add lockdep assertion in ip_set_ext_destroy(). At this time the function has too many call sites where set->lock is held (e.g. during set destruction). Signed-off-by: Florian Westphal --- include/linux/netfilter/ipset/ip_set.h | 24 ++++++++++++++++++++---- net/netfilter/ipset/ip_set_bitmap_gen.h | 2 ++ net/netfilter/ipset/ip_set_hash_gen.h | 8 ++++---- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index 50cd719bc270..f9003ec21259 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h @@ -282,17 +282,33 @@ struct ip_set { void *data; }; +static inline void +__ip_set_destroy_comment(struct ip_set *set, void *data) +{ + struct ip_set_comment *c = ext_comment(data, set); + + ip_set_extensions[IPSET_EXT_ID_COMMENT].destroy(set, c); +} + static inline void ip_set_ext_destroy(struct ip_set *set, void *data) { /* Check that the extension is enabled for the set and * call it's destroy function for its extension part in data. */ - if (SET_WITH_COMMENT(set)) { - struct ip_set_comment *c = ext_comment(data, set); + if (SET_WITH_COMMENT(set)) + __ip_set_destroy_comment(set, data); +} - ip_set_extensions[IPSET_EXT_ID_COMMENT].destroy(set, c); - } +static inline void +ip_set_ext_destroy_slow(struct ip_set *set, void *data) +{ + if (!SET_WITH_COMMENT(set)) + return; + + spin_lock_bh(&set->lock); + __ip_set_destroy_comment(set, data); + spin_unlock_bh(&set->lock); } int ip_set_put_flags(struct sk_buff *skb, struct ip_set *set); diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h index b13cde902c17..ca68b6e51214 100644 --- a/net/netfilter/ipset/ip_set_bitmap_gen.h +++ b/net/netfilter/ipset/ip_set_bitmap_gen.h @@ -182,6 +182,8 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, const struct mtype_adt_elem *e = value; void *x = get_ext(set, map, e->id); + lockdep_assert_held(&set->lock); + if (mtype_do_del(e, map)) return -IPSET_ERR_EXIST; diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h index c3dda56d786c..1eff2c065bb3 100644 --- a/net/netfilter/ipset/ip_set_hash_gen.h +++ b/net/netfilter/ipset/ip_set_hash_gen.h @@ -443,7 +443,7 @@ mtype_ext_cleanup(struct ip_set *set, struct hbucket *n) for (i = 0; i < pos; i++) if (test_bit(i, n->used)) - ip_set_ext_destroy(set, ahash_data(n, i, set->dsize)); + ip_set_ext_destroy_slow(set, ahash_data(n, i, set->dsize)); } /* Flush a hash type of set: destroy all elements */ @@ -587,7 +587,7 @@ mtype_gc_do(struct ip_set *set, struct htype *h, struct htable *t, u32 r) smp_mb__after_atomic(); mtype_del_cidr_all(set, h, data); t->hregion[r].elements--; - ip_set_ext_destroy(set, data); + ip_set_ext_destroy_slow(set, data); d++; } if (d >= AHASH_INIT_SIZE) { @@ -1012,7 +1012,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, data = ahash_data(n, j, set->dsize); if (!deleted) { mtype_del_cidr_all(set, h, data); - ip_set_ext_destroy(set, data); + ip_set_ext_destroy_slow(set, data); t->hregion[r].elements--; } goto copy_data; @@ -1167,7 +1167,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, smp_store_release(&n->pos, --pos); t->hregion[r].elements--; mtype_del_cidr_all(set, h, d); - ip_set_ext_destroy(set, data); + ip_set_ext_destroy_slow(set, data); if (t->resizing && ext && ext->target) { /* Resize is in process and kernel side del, -- 2.54.0