Commit 9d4f8e54 authored by Herbert Xu's avatar Herbert Xu
Browse files

rhashtable: Fix rhashtable_try_insert test



The test on whether rhashtable_insert_one did an insertion relies
on the value returned by rhashtable_lookup_one.  Unfortunately that
value is overwritten after rhashtable_insert_one returns.  Fix this
by moving the test before data gets overwritten.

Simplify the test as only data == NULL matters.

Finally move atomic_inc back within the lock as otherwise it may
be reordered with the atomic_dec on the removal side, potentially
leading to an underflow.

Reported-by: default avatarMichael Kelley <mhklinux@outlook.com>
Fixes: e1d3422c ("rhashtable: Fix potential deadlock by moving schedule_work outside lock")
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Tested-by: default avatarMichael Kelley <mhklinux@outlook.com>
Reviewed-by: default avatarBreno Leitao <leitao@debian.org>
Tested-by: default avatarMikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 076d9119
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -611,22 +611,24 @@ static void *rhashtable_try_insert(struct rhashtable *ht, const void *key,
			new_tbl = rht_dereference_rcu(tbl->future_tbl, ht);
			data = ERR_PTR(-EAGAIN);
		} else {
			bool inserted;

			flags = rht_lock(tbl, bkt);
			data = rhashtable_lookup_one(ht, bkt, tbl,
						     hash, key, obj);
			new_tbl = rhashtable_insert_one(ht, bkt, tbl,
							hash, obj, data);
			inserted = data && !new_tbl;
			if (inserted)
				atomic_inc(&ht->nelems);
			if (PTR_ERR(new_tbl) != -EEXIST)
				data = ERR_CAST(new_tbl);

			rht_unlock(tbl, bkt, flags);

			if (PTR_ERR(data) == -ENOENT && !new_tbl) {
				atomic_inc(&ht->nelems);
				if (rht_grow_above_75(ht, tbl))
			if (inserted && rht_grow_above_75(ht, tbl))
				schedule_work(&ht->run_work);
		}
		}
	} while (!IS_ERR_OR_NULL(new_tbl));

	if (PTR_ERR(data) == -EAGAIN)