Merge branch 'for-4.2/sg' of git://git.kernel.dk/linux-block
[firefly-linux-kernel-4.4.55.git] / lib / test_rhashtable.c
index 935693ed7ae51e45e85aa40314d36b281cb6beee..c90777eae1f837f84b1b53fd8704b567b9d90835 100644 (file)
@@ -21,8 +21,8 @@
 #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);
@@ -68,6 +68,9 @@ static int __init test_rht_lookup(struct rhashtable *ht)
                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) {
@@ -89,41 +92,43 @@ static int __init test_rht_lookup(struct rhashtable *ht)
        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 ^^^");
@@ -133,7 +138,7 @@ static s64 __init test_rhashtable(struct rhashtable *ht)
 {
        struct test_obj *obj;
        int err;
-       unsigned int i;
+       unsigned int i, insert_fails = 0;
        s64 start, end;
 
        /*
@@ -148,27 +153,36 @@ static s64 __init test_rhashtable(struct rhashtable *ht)
                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();
@@ -215,7 +229,8 @@ static int __init test_rht_init(void)
                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;
 }