@@ -541,8 +541,9 @@ mtype_resize(struct ip_set *set, bool retried)
u8 htable_bits = orig->htable_bits;
#ifdef IP_SET_HASH_WITH_NETS
u8 flags;
+ u8 _data[set->dsize];
#endif
- struct mtype_elem *data;
+ struct mtype_elem *data, *hdata;
struct mtype_elem *d;
struct hbucket *n, *m;
u32 i, j;
@@ -581,15 +582,15 @@ retry:
for (j = 0; j < n->pos; j++) {
data = ahash_data(n, j, set->dsize);
#ifdef IP_SET_HASH_WITH_NETS
+ hdata = memcpy(_data, data, set->dsize);
flags = 0;
- mtype_data_reset_flags(data, &flags);
+ mtype_data_reset_flags(hdata, &flags);
+#else
+ hdata = data;
#endif
- m = hbucket(t, HKEY(data, h->initval, htable_bits));
+ m = hbucket(t, HKEY(hdata, h->initval, htable_bits));
ret = hbucket_elem_add(m, AHASH_MAX(h), set->dsize);
if (ret < 0) {
-#ifdef IP_SET_HASH_WITH_NETS
- mtype_data_reset_flags(data, &flags);
-#endif
read_unlock_bh(&set->lock);
mtype_ahash_destroy(set, t, false);
if (ret == -EAGAIN)
@@ -598,9 +599,6 @@ retry:
}
d = ahash_data(m, m->pos++, set->dsize);
memcpy(d, data, set->dsize);
-#ifdef IP_SET_HASH_WITH_NETS
- mtype_data_reset_flags(d, &flags);
-#endif
}
}
Set resizing takes read lock on the hash table, so we should not modify any data in the original hash table, as this would disrupt concurrent readers. Furthermore set resizing could fail, leaving original set data in inconsistent state: flags (nomatch currently) would be cleared on all, but the last, where reallocation fails, set elements. Fix this by taking private copy of original set entry for sets, where it is necessary. Signed-off-by: Sergey Popovich <popovich_sergei@mail.ua> --- net/netfilter/ipset/ip_set_hash_gen.h | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-)