#include <linux/rhashtable.h>
#include <linux/slab.h>
-
#define MAX_ENTRIES 1000000
+#define TEST_INSERT_FAIL INT_MAX
static int entries = 50000;
module_param(entries, int, 0);
bool expected = !(i % 2);
u32 key = i;
+ if (array[i / 2].value == TEST_INSERT_FAIL)
+ expected = false;
+
obj = rhashtable_lookup_fast(ht, &key, test_rht_params);
if (expected && !obj) {
return 0;
}
-static void test_bucket_stats(struct rhashtable *ht, bool quiet)
+static void test_bucket_stats(struct rhashtable *ht)
{
- unsigned int cnt, rcu_cnt, i, total = 0;
+ unsigned int err, total = 0, chain_len = 0;
+ struct rhashtable_iter hti;
struct rhash_head *pos;
- struct test_obj *obj;
- struct bucket_table *tbl;
- tbl = rht_dereference_rcu(ht->tbl, ht);
- for (i = 0; i < tbl->size; i++) {
- rcu_cnt = cnt = 0;
+ err = rhashtable_walk_init(ht, &hti);
+ if (err) {
+ pr_warn("Test failed: allocation error");
+ return;
+ }
- if (!quiet)
- pr_info(" [%#4x/%u]", i, tbl->size);
+ err = rhashtable_walk_start(&hti);
+ if (err && err != -EAGAIN) {
+ pr_warn("Test failed: iterator failed: %d\n", err);
+ return;
+ }
- rht_for_each_entry_rcu(obj, pos, tbl, i, node) {
- cnt++;
- total++;
- if (!quiet)
- pr_cont(" [%p],", obj);
+ while ((pos = rhashtable_walk_next(&hti))) {
+ if (PTR_ERR(pos) == -EAGAIN) {
+ pr_info("Info: encountered resize\n");
+ chain_len++;
+ continue;
+ } else if (IS_ERR(pos)) {
+ pr_warn("Test failed: rhashtable_walk_next() error: %ld\n",
+ PTR_ERR(pos));
+ break;
}
- rht_for_each_entry_rcu(obj, pos, tbl, i, node)
- rcu_cnt++;
-
- if (rcu_cnt != cnt)
- pr_warn("Test failed: Chain count mismach %d != %d",
- cnt, rcu_cnt);
-
- if (!quiet)
- pr_cont("\n [%#x] first element: %p, chain length: %u\n",
- i, tbl->buckets[i], cnt);
+ total++;
}
- pr_info(" Traversal complete: counted=%u, nelems=%u, entries=%d\n",
- total, atomic_read(&ht->nelems), entries);
+ rhashtable_walk_stop(&hti);
+ rhashtable_walk_exit(&hti);
+
+ pr_info(" Traversal complete: counted=%u, nelems=%u, entries=%d, table-jumps=%u\n",
+ total, atomic_read(&ht->nelems), entries, chain_len);
if (total != atomic_read(&ht->nelems) || total != entries)
pr_warn("Test failed: Total count mismatch ^^^");
{
struct test_obj *obj;
int err;
- unsigned int i;
+ unsigned int i, insert_fails = 0;
s64 start, end;
/*
obj->value = i * 2;
err = rhashtable_insert_fast(ht, &obj->node, test_rht_params);
- if (err)
+ if (err == -ENOMEM || err == -EBUSY) {
+ /* Mark failed inserts but continue */
+ obj->value = TEST_INSERT_FAIL;
+ insert_fails++;
+ } else if (err) {
return err;
+ }
}
+ if (insert_fails)
+ pr_info(" %u insertions failed due to memory pressure\n",
+ insert_fails);
+
+ test_bucket_stats(ht);
rcu_read_lock();
- test_bucket_stats(ht, true);
test_rht_lookup(ht);
rcu_read_unlock();
- rcu_read_lock();
- test_bucket_stats(ht, true);
- rcu_read_unlock();
+ test_bucket_stats(ht);
pr_info(" Deleting %d keys\n", entries);
for (i = 0; i < entries; i++) {
u32 key = i * 2;
- obj = rhashtable_lookup_fast(ht, &key, test_rht_params);
- BUG_ON(!obj);
+ if (array[i].value != TEST_INSERT_FAIL) {
+ obj = rhashtable_lookup_fast(ht, &key, test_rht_params);
+ BUG_ON(!obj);
- rhashtable_remove_fast(ht, &obj->node, test_rht_params);
+ rhashtable_remove_fast(ht, &obj->node, test_rht_params);
+ }
}
end = ktime_get_ns();
total_time += time;
}
- pr_info("Average test time: %llu\n", total_time / runs);
+ do_div(total_time, runs);
+ pr_info("Average test time: %llu\n", total_time);
return 0;
}