aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/dynamic_queue_limits.c3
-rw-r--r--lib/kobject_uevent.c94
-rw-r--r--lib/nlattr.c19
-rw-r--r--lib/once.c8
-rw-r--r--lib/test_rhashtable.c293
5 files changed, 342 insertions, 75 deletions
diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c
index da4672a50a54..e659a027036e 100644
--- a/lib/dynamic_queue_limits.c
+++ b/lib/dynamic_queue_limits.c
@@ -128,12 +128,11 @@ void dql_reset(struct dql *dql)
128} 128}
129EXPORT_SYMBOL(dql_reset); 129EXPORT_SYMBOL(dql_reset);
130 130
131int dql_init(struct dql *dql, unsigned hold_time) 131void dql_init(struct dql *dql, unsigned int hold_time)
132{ 132{
133 dql->max_limit = DQL_MAX_LIMIT; 133 dql->max_limit = DQL_MAX_LIMIT;
134 dql->min_limit = 0; 134 dql->min_limit = 0;
135 dql->slack_hold_time = hold_time; 135 dql->slack_hold_time = hold_time;
136 dql_reset(dql); 136 dql_reset(dql);
137 return 0;
138} 137}
139EXPORT_SYMBOL(dql_init); 138EXPORT_SYMBOL(dql_init);
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index f237a09a5862..c3e84edc47c9 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -294,6 +294,55 @@ static void cleanup_uevent_env(struct subprocess_info *info)
294} 294}
295#endif 295#endif
296 296
297static int kobject_uevent_net_broadcast(struct kobject *kobj,
298 struct kobj_uevent_env *env,
299 const char *action_string,
300 const char *devpath)
301{
302 int retval = 0;
303#if defined(CONFIG_NET)
304 struct sk_buff *skb = NULL;
305 struct uevent_sock *ue_sk;
306
307 /* send netlink message */
308 list_for_each_entry(ue_sk, &uevent_sock_list, list) {
309 struct sock *uevent_sock = ue_sk->sk;
310
311 if (!netlink_has_listeners(uevent_sock, 1))
312 continue;
313
314 if (!skb) {
315 /* allocate message with the maximum possible size */
316 size_t len = strlen(action_string) + strlen(devpath) + 2;
317 char *scratch;
318
319 retval = -ENOMEM;
320 skb = alloc_skb(len + env->buflen, GFP_KERNEL);
321 if (!skb)
322 continue;
323
324 /* add header */
325 scratch = skb_put(skb, len);
326 sprintf(scratch, "%s@%s", action_string, devpath);
327
328 skb_put_data(skb, env->buf, env->buflen);
329
330 NETLINK_CB(skb).dst_group = 1;
331 }
332
333 retval = netlink_broadcast_filtered(uevent_sock, skb_get(skb),
334 0, 1, GFP_KERNEL,
335 kobj_bcast_filter,
336 kobj);
337 /* ENOBUFS should be handled in userspace */
338 if (retval == -ENOBUFS || retval == -ESRCH)
339 retval = 0;
340 }
341 consume_skb(skb);
342#endif
343 return retval;
344}
345
297static void zap_modalias_env(struct kobj_uevent_env *env) 346static void zap_modalias_env(struct kobj_uevent_env *env)
298{ 347{
299 static const char modalias_prefix[] = "MODALIAS="; 348 static const char modalias_prefix[] = "MODALIAS=";
@@ -336,9 +385,6 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
336 const struct kset_uevent_ops *uevent_ops; 385 const struct kset_uevent_ops *uevent_ops;
337 int i = 0; 386 int i = 0;
338 int retval = 0; 387 int retval = 0;
339#ifdef CONFIG_NET
340 struct uevent_sock *ue_sk;
341#endif
342 388
343 pr_debug("kobject: '%s' (%p): %s\n", 389 pr_debug("kobject: '%s' (%p): %s\n",
344 kobject_name(kobj), kobj, __func__); 390 kobject_name(kobj), kobj, __func__);
@@ -460,46 +506,8 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
460 mutex_unlock(&uevent_sock_mutex); 506 mutex_unlock(&uevent_sock_mutex);
461 goto exit; 507 goto exit;
462 } 508 }
463 509 retval = kobject_uevent_net_broadcast(kobj, env, action_string,
464#if defined(CONFIG_NET) 510 devpath);
465 /* send netlink message */
466 list_for_each_entry(ue_sk, &uevent_sock_list, list) {
467 struct sock *uevent_sock = ue_sk->sk;
468 struct sk_buff *skb;
469 size_t len;
470
471 if (!netlink_has_listeners(uevent_sock, 1))
472 continue;
473
474 /* allocate message with the maximum possible size */
475 len = strlen(action_string) + strlen(devpath) + 2;
476 skb = alloc_skb(len + env->buflen, GFP_KERNEL);
477 if (skb) {
478 char *scratch;
479
480 /* add header */
481 scratch = skb_put(skb, len);
482 sprintf(scratch, "%s@%s", action_string, devpath);
483
484 /* copy keys to our continuous event payload buffer */
485 for (i = 0; i < env->envp_idx; i++) {
486 len = strlen(env->envp[i]) + 1;
487 scratch = skb_put(skb, len);
488 strcpy(scratch, env->envp[i]);
489 }
490
491 NETLINK_CB(skb).dst_group = 1;
492 retval = netlink_broadcast_filtered(uevent_sock, skb,
493 0, 1, GFP_KERNEL,
494 kobj_bcast_filter,
495 kobj);
496 /* ENOBUFS should be handled in userspace */
497 if (retval == -ENOBUFS || retval == -ESRCH)
498 retval = 0;
499 } else
500 retval = -ENOMEM;
501 }
502#endif
503 mutex_unlock(&uevent_sock_mutex); 511 mutex_unlock(&uevent_sock_mutex);
504 512
505#ifdef CONFIG_UEVENT_HELPER 513#ifdef CONFIG_UEVENT_HELPER
diff --git a/lib/nlattr.c b/lib/nlattr.c
index 3d8295c85505..8bf78b4b78f0 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -15,19 +15,23 @@
15#include <linux/types.h> 15#include <linux/types.h>
16#include <net/netlink.h> 16#include <net/netlink.h>
17 17
18static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = { 18/* for these data types attribute length must be exactly given size */
19static const u8 nla_attr_len[NLA_TYPE_MAX+1] = {
19 [NLA_U8] = sizeof(u8), 20 [NLA_U8] = sizeof(u8),
20 [NLA_U16] = sizeof(u16), 21 [NLA_U16] = sizeof(u16),
21 [NLA_U32] = sizeof(u32), 22 [NLA_U32] = sizeof(u32),
22 [NLA_U64] = sizeof(u64), 23 [NLA_U64] = sizeof(u64),
23 [NLA_MSECS] = sizeof(u64),
24 [NLA_NESTED] = NLA_HDRLEN,
25 [NLA_S8] = sizeof(s8), 24 [NLA_S8] = sizeof(s8),
26 [NLA_S16] = sizeof(s16), 25 [NLA_S16] = sizeof(s16),
27 [NLA_S32] = sizeof(s32), 26 [NLA_S32] = sizeof(s32),
28 [NLA_S64] = sizeof(s64), 27 [NLA_S64] = sizeof(s64),
29}; 28};
30 29
30static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
31 [NLA_MSECS] = sizeof(u64),
32 [NLA_NESTED] = NLA_HDRLEN,
33};
34
31static int validate_nla_bitfield32(const struct nlattr *nla, 35static int validate_nla_bitfield32(const struct nlattr *nla,
32 u32 *valid_flags_allowed) 36 u32 *valid_flags_allowed)
33{ 37{
@@ -65,6 +69,13 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
65 69
66 BUG_ON(pt->type > NLA_TYPE_MAX); 70 BUG_ON(pt->type > NLA_TYPE_MAX);
67 71
72 /* for data types NLA_U* and NLA_S* require exact length */
73 if (nla_attr_len[pt->type]) {
74 if (attrlen != nla_attr_len[pt->type])
75 return -ERANGE;
76 return 0;
77 }
78
68 switch (pt->type) { 79 switch (pt->type) {
69 case NLA_FLAG: 80 case NLA_FLAG:
70 if (attrlen > 0) 81 if (attrlen > 0)
@@ -191,6 +202,8 @@ nla_policy_len(const struct nla_policy *p, int n)
191 for (i = 0; i < n; i++, p++) { 202 for (i = 0; i < n; i++, p++) {
192 if (p->len) 203 if (p->len)
193 len += nla_total_size(p->len); 204 len += nla_total_size(p->len);
205 else if (nla_attr_len[p->type])
206 len += nla_total_size(nla_attr_len[p->type]);
194 else if (nla_attr_minlen[p->type]) 207 else if (nla_attr_minlen[p->type])
195 len += nla_total_size(nla_attr_minlen[p->type]); 208 len += nla_total_size(nla_attr_minlen[p->type]);
196 } 209 }
diff --git a/lib/once.c b/lib/once.c
index bfb7420d0de3..8b7d6235217e 100644
--- a/lib/once.c
+++ b/lib/once.c
@@ -6,7 +6,7 @@
6 6
7struct once_work { 7struct once_work {
8 struct work_struct work; 8 struct work_struct work;
9 struct static_key *key; 9 struct static_key_true *key;
10}; 10};
11 11
12static void once_deferred(struct work_struct *w) 12static void once_deferred(struct work_struct *w)
@@ -15,11 +15,11 @@ static void once_deferred(struct work_struct *w)
15 15
16 work = container_of(w, struct once_work, work); 16 work = container_of(w, struct once_work, work);
17 BUG_ON(!static_key_enabled(work->key)); 17 BUG_ON(!static_key_enabled(work->key));
18 static_key_slow_dec(work->key); 18 static_branch_disable(work->key);
19 kfree(work); 19 kfree(work);
20} 20}
21 21
22static void once_disable_jump(struct static_key *key) 22static void once_disable_jump(struct static_key_true *key)
23{ 23{
24 struct once_work *w; 24 struct once_work *w;
25 25
@@ -52,7 +52,7 @@ bool __do_once_start(bool *done, unsigned long *flags)
52} 52}
53EXPORT_SYMBOL(__do_once_start); 53EXPORT_SYMBOL(__do_once_start);
54 54
55void __do_once_done(bool *done, struct static_key *once_key, 55void __do_once_done(bool *done, struct static_key_true *once_key,
56 unsigned long *flags) 56 unsigned long *flags)
57 __releases(once_lock) 57 __releases(once_lock)
58{ 58{
diff --git a/lib/test_rhashtable.c b/lib/test_rhashtable.c
index 0ffca990a833..8e83cbdc049c 100644
--- a/lib/test_rhashtable.c
+++ b/lib/test_rhashtable.c
@@ -23,14 +23,15 @@
23#include <linux/semaphore.h> 23#include <linux/semaphore.h>
24#include <linux/slab.h> 24#include <linux/slab.h>
25#include <linux/sched.h> 25#include <linux/sched.h>
26#include <linux/random.h>
26#include <linux/vmalloc.h> 27#include <linux/vmalloc.h>
27 28
28#define MAX_ENTRIES 1000000 29#define MAX_ENTRIES 1000000
29#define TEST_INSERT_FAIL INT_MAX 30#define TEST_INSERT_FAIL INT_MAX
30 31
31static int entries = 50000; 32static int parm_entries = 50000;
32module_param(entries, int, 0); 33module_param(parm_entries, int, 0);
33MODULE_PARM_DESC(entries, "Number of entries to add (default: 50000)"); 34MODULE_PARM_DESC(parm_entries, "Number of entries to add (default: 50000)");
34 35
35static int runs = 4; 36static int runs = 4;
36module_param(runs, int, 0); 37module_param(runs, int, 0);
@@ -66,14 +67,18 @@ struct test_obj {
66 struct rhash_head node; 67 struct rhash_head node;
67}; 68};
68 69
70struct test_obj_rhl {
71 struct test_obj_val value;
72 struct rhlist_head list_node;
73};
74
69struct thread_data { 75struct thread_data {
76 unsigned int entries;
70 int id; 77 int id;
71 struct task_struct *task; 78 struct task_struct *task;
72 struct test_obj *objs; 79 struct test_obj *objs;
73}; 80};
74 81
75static struct test_obj array[MAX_ENTRIES];
76
77static struct rhashtable_params test_rht_params = { 82static struct rhashtable_params test_rht_params = {
78 .head_offset = offsetof(struct test_obj, node), 83 .head_offset = offsetof(struct test_obj, node),
79 .key_offset = offsetof(struct test_obj, value), 84 .key_offset = offsetof(struct test_obj, value),
@@ -85,7 +90,7 @@ static struct rhashtable_params test_rht_params = {
85static struct semaphore prestart_sem; 90static struct semaphore prestart_sem;
86static struct semaphore startup_sem = __SEMAPHORE_INITIALIZER(startup_sem, 0); 91static struct semaphore startup_sem = __SEMAPHORE_INITIALIZER(startup_sem, 0);
87 92
88static int insert_retry(struct rhashtable *ht, struct rhash_head *obj, 93static int insert_retry(struct rhashtable *ht, struct test_obj *obj,
89 const struct rhashtable_params params) 94 const struct rhashtable_params params)
90{ 95{
91 int err, retries = -1, enomem_retries = 0; 96 int err, retries = -1, enomem_retries = 0;
@@ -93,7 +98,7 @@ static int insert_retry(struct rhashtable *ht, struct rhash_head *obj,
93 do { 98 do {
94 retries++; 99 retries++;
95 cond_resched(); 100 cond_resched();
96 err = rhashtable_insert_fast(ht, obj, params); 101 err = rhashtable_insert_fast(ht, &obj->node, params);
97 if (err == -ENOMEM && enomem_retry) { 102 if (err == -ENOMEM && enomem_retry) {
98 enomem_retries++; 103 enomem_retries++;
99 err = -EBUSY; 104 err = -EBUSY;
@@ -107,11 +112,12 @@ static int insert_retry(struct rhashtable *ht, struct rhash_head *obj,
107 return err ? : retries; 112 return err ? : retries;
108} 113}
109 114
110static int __init test_rht_lookup(struct rhashtable *ht) 115static int __init test_rht_lookup(struct rhashtable *ht, struct test_obj *array,
116 unsigned int entries)
111{ 117{
112 unsigned int i; 118 unsigned int i;
113 119
114 for (i = 0; i < entries * 2; i++) { 120 for (i = 0; i < entries; i++) {
115 struct test_obj *obj; 121 struct test_obj *obj;
116 bool expected = !(i % 2); 122 bool expected = !(i % 2);
117 struct test_obj_val key = { 123 struct test_obj_val key = {
@@ -144,7 +150,7 @@ static int __init test_rht_lookup(struct rhashtable *ht)
144 return 0; 150 return 0;
145} 151}
146 152
147static void test_bucket_stats(struct rhashtable *ht) 153static void test_bucket_stats(struct rhashtable *ht, unsigned int entries)
148{ 154{
149 unsigned int err, total = 0, chain_len = 0; 155 unsigned int err, total = 0, chain_len = 0;
150 struct rhashtable_iter hti; 156 struct rhashtable_iter hti;
@@ -186,7 +192,8 @@ static void test_bucket_stats(struct rhashtable *ht)
186 pr_warn("Test failed: Total count mismatch ^^^"); 192 pr_warn("Test failed: Total count mismatch ^^^");
187} 193}
188 194
189static s64 __init test_rhashtable(struct rhashtable *ht) 195static s64 __init test_rhashtable(struct rhashtable *ht, struct test_obj *array,
196 unsigned int entries)
190{ 197{
191 struct test_obj *obj; 198 struct test_obj *obj;
192 int err; 199 int err;
@@ -203,7 +210,7 @@ static s64 __init test_rhashtable(struct rhashtable *ht)
203 struct test_obj *obj = &array[i]; 210 struct test_obj *obj = &array[i];
204 211
205 obj->value.id = i * 2; 212 obj->value.id = i * 2;
206 err = insert_retry(ht, &obj->node, test_rht_params); 213 err = insert_retry(ht, obj, test_rht_params);
207 if (err > 0) 214 if (err > 0)
208 insert_retries += err; 215 insert_retries += err;
209 else if (err) 216 else if (err)
@@ -214,12 +221,12 @@ static s64 __init test_rhashtable(struct rhashtable *ht)
214 pr_info(" %u insertions retried due to memory pressure\n", 221 pr_info(" %u insertions retried due to memory pressure\n",
215 insert_retries); 222 insert_retries);
216 223
217 test_bucket_stats(ht); 224 test_bucket_stats(ht, entries);
218 rcu_read_lock(); 225 rcu_read_lock();
219 test_rht_lookup(ht); 226 test_rht_lookup(ht, array, entries);
220 rcu_read_unlock(); 227 rcu_read_unlock();
221 228
222 test_bucket_stats(ht); 229 test_bucket_stats(ht, entries);
223 230
224 pr_info(" Deleting %d keys\n", entries); 231 pr_info(" Deleting %d keys\n", entries);
225 for (i = 0; i < entries; i++) { 232 for (i = 0; i < entries; i++) {
@@ -244,9 +251,227 @@ static s64 __init test_rhashtable(struct rhashtable *ht)
244} 251}
245 252
246static struct rhashtable ht; 253static struct rhashtable ht;
254static struct rhltable rhlt;
255
256static int __init test_rhltable(unsigned int entries)
257{
258 struct test_obj_rhl *rhl_test_objects;
259 unsigned long *obj_in_table;
260 unsigned int i, j, k;
261 int ret, err;
262
263 if (entries == 0)
264 entries = 1;
265
266 rhl_test_objects = vzalloc(sizeof(*rhl_test_objects) * entries);
267 if (!rhl_test_objects)
268 return -ENOMEM;
269
270 ret = -ENOMEM;
271 obj_in_table = vzalloc(BITS_TO_LONGS(entries) * sizeof(unsigned long));
272 if (!obj_in_table)
273 goto out_free;
274
275 /* nulls_base not supported in rhlist interface */
276 test_rht_params.nulls_base = 0;
277 err = rhltable_init(&rhlt, &test_rht_params);
278 if (WARN_ON(err))
279 goto out_free;
280
281 k = prandom_u32();
282 ret = 0;
283 for (i = 0; i < entries; i++) {
284 rhl_test_objects[i].value.id = k;
285 err = rhltable_insert(&rhlt, &rhl_test_objects[i].list_node,
286 test_rht_params);
287 if (WARN(err, "error %d on element %d\n", err, i))
288 break;
289 if (err == 0)
290 set_bit(i, obj_in_table);
291 }
292
293 if (err)
294 ret = err;
295
296 pr_info("test %d add/delete pairs into rhlist\n", entries);
297 for (i = 0; i < entries; i++) {
298 struct rhlist_head *h, *pos;
299 struct test_obj_rhl *obj;
300 struct test_obj_val key = {
301 .id = k,
302 };
303 bool found;
304
305 rcu_read_lock();
306 h = rhltable_lookup(&rhlt, &key, test_rht_params);
307 if (WARN(!h, "key not found during iteration %d of %d", i, entries)) {
308 rcu_read_unlock();
309 break;
310 }
311
312 if (i) {
313 j = i - 1;
314 rhl_for_each_entry_rcu(obj, pos, h, list_node) {
315 if (WARN(pos == &rhl_test_objects[j].list_node, "old element found, should be gone"))
316 break;
317 }
318 }
319
320 cond_resched_rcu();
321
322 found = false;
323
324 rhl_for_each_entry_rcu(obj, pos, h, list_node) {
325 if (pos == &rhl_test_objects[i].list_node) {
326 found = true;
327 break;
328 }
329 }
330
331 rcu_read_unlock();
332
333 if (WARN(!found, "element %d not found", i))
334 break;
335
336 err = rhltable_remove(&rhlt, &rhl_test_objects[i].list_node, test_rht_params);
337 WARN(err, "rhltable_remove: err %d for iteration %d\n", err, i);
338 if (err == 0)
339 clear_bit(i, obj_in_table);
340 }
341
342 if (ret == 0 && err)
343 ret = err;
344
345 for (i = 0; i < entries; i++) {
346 WARN(test_bit(i, obj_in_table), "elem %d allegedly still present", i);
347
348 err = rhltable_insert(&rhlt, &rhl_test_objects[i].list_node,
349 test_rht_params);
350 if (WARN(err, "error %d on element %d\n", err, i))
351 break;
352 if (err == 0)
353 set_bit(i, obj_in_table);
354 }
355
356 pr_info("test %d random rhlist add/delete operations\n", entries);
357 for (j = 0; j < entries; j++) {
358 u32 i = prandom_u32_max(entries);
359 u32 prand = prandom_u32();
360
361 cond_resched();
362
363 if (prand == 0)
364 prand = prandom_u32();
365
366 if (prand & 1) {
367 prand >>= 1;
368 continue;
369 }
370
371 err = rhltable_remove(&rhlt, &rhl_test_objects[i].list_node, test_rht_params);
372 if (test_bit(i, obj_in_table)) {
373 clear_bit(i, obj_in_table);
374 if (WARN(err, "cannot remove element at slot %d", i))
375 continue;
376 } else {
377 if (WARN(err != -ENOENT, "removed non-existant element %d, error %d not %d",
378 i, err, -ENOENT))
379 continue;
380 }
381
382 if (prand & 1) {
383 prand >>= 1;
384 continue;
385 }
386
387 err = rhltable_insert(&rhlt, &rhl_test_objects[i].list_node, test_rht_params);
388 if (err == 0) {
389 if (WARN(test_and_set_bit(i, obj_in_table), "succeeded to insert same object %d", i))
390 continue;
391 } else {
392 if (WARN(!test_bit(i, obj_in_table), "failed to insert object %d", i))
393 continue;
394 }
395
396 if (prand & 1) {
397 prand >>= 1;
398 continue;
399 }
400
401 i = prandom_u32_max(entries);
402 if (test_bit(i, obj_in_table)) {
403 err = rhltable_remove(&rhlt, &rhl_test_objects[i].list_node, test_rht_params);
404 WARN(err, "cannot remove element at slot %d", i);
405 if (err == 0)
406 clear_bit(i, obj_in_table);
407 } else {
408 err = rhltable_insert(&rhlt, &rhl_test_objects[i].list_node, test_rht_params);
409 WARN(err, "failed to insert object %d", i);
410 if (err == 0)
411 set_bit(i, obj_in_table);
412 }
413 }
414
415 for (i = 0; i < entries; i++) {
416 cond_resched();
417 err = rhltable_remove(&rhlt, &rhl_test_objects[i].list_node, test_rht_params);
418 if (test_bit(i, obj_in_table)) {
419 if (WARN(err, "cannot remove element at slot %d", i))
420 continue;
421 } else {
422 if (WARN(err != -ENOENT, "removed non-existant element, error %d not %d",
423 err, -ENOENT))
424 continue;
425 }
426 }
427
428 rhltable_destroy(&rhlt);
429out_free:
430 vfree(rhl_test_objects);
431 vfree(obj_in_table);
432 return ret;
433}
434
435static int __init test_rhashtable_max(struct test_obj *array,
436 unsigned int entries)
437{
438 unsigned int i, insert_retries = 0;
439 int err;
440
441 test_rht_params.max_size = roundup_pow_of_two(entries / 8);
442 err = rhashtable_init(&ht, &test_rht_params);
443 if (err)
444 return err;
445
446 for (i = 0; i < ht.max_elems; i++) {
447 struct test_obj *obj = &array[i];
448
449 obj->value.id = i * 2;
450 err = insert_retry(&ht, obj, test_rht_params);
451 if (err > 0)
452 insert_retries += err;
453 else if (err)
454 return err;
455 }
456
457 err = insert_retry(&ht, &array[ht.max_elems], test_rht_params);
458 if (err == -E2BIG) {
459 err = 0;
460 } else {
461 pr_info("insert element %u should have failed with %d, got %d\n",
462 ht.max_elems, -E2BIG, err);
463 if (err == 0)
464 err = -1;
465 }
466
467 rhashtable_destroy(&ht);
468
469 return err;
470}
247 471
248static int thread_lookup_test(struct thread_data *tdata) 472static int thread_lookup_test(struct thread_data *tdata)
249{ 473{
474 unsigned int entries = tdata->entries;
250 int i, err = 0; 475 int i, err = 0;
251 476
252 for (i = 0; i < entries; i++) { 477 for (i = 0; i < entries; i++) {
@@ -283,10 +508,10 @@ static int threadfunc(void *data)
283 if (down_interruptible(&startup_sem)) 508 if (down_interruptible(&startup_sem))
284 pr_err(" thread[%d]: down_interruptible failed\n", tdata->id); 509 pr_err(" thread[%d]: down_interruptible failed\n", tdata->id);
285 510
286 for (i = 0; i < entries; i++) { 511 for (i = 0; i < tdata->entries; i++) {
287 tdata->objs[i].value.id = i; 512 tdata->objs[i].value.id = i;
288 tdata->objs[i].value.tid = tdata->id; 513 tdata->objs[i].value.tid = tdata->id;
289 err = insert_retry(&ht, &tdata->objs[i].node, test_rht_params); 514 err = insert_retry(&ht, &tdata->objs[i], test_rht_params);
290 if (err > 0) { 515 if (err > 0) {
291 insert_retries += err; 516 insert_retries += err;
292 } else if (err) { 517 } else if (err) {
@@ -307,7 +532,7 @@ static int threadfunc(void *data)
307 } 532 }
308 533
309 for (step = 10; step > 0; step--) { 534 for (step = 10; step > 0; step--) {
310 for (i = 0; i < entries; i += step) { 535 for (i = 0; i < tdata->entries; i += step) {
311 if (tdata->objs[i].value.id == TEST_INSERT_FAIL) 536 if (tdata->objs[i].value.id == TEST_INSERT_FAIL)
312 continue; 537 continue;
313 err = rhashtable_remove_fast(&ht, &tdata->objs[i].node, 538 err = rhashtable_remove_fast(&ht, &tdata->objs[i].node,
@@ -338,17 +563,25 @@ out:
338 563
339static int __init test_rht_init(void) 564static int __init test_rht_init(void)
340{ 565{
566 unsigned int entries;
341 int i, err, started_threads = 0, failed_threads = 0; 567 int i, err, started_threads = 0, failed_threads = 0;
342 u64 total_time = 0; 568 u64 total_time = 0;
343 struct thread_data *tdata; 569 struct thread_data *tdata;
344 struct test_obj *objs; 570 struct test_obj *objs;
345 571
346 entries = min(entries, MAX_ENTRIES); 572 if (parm_entries < 0)
573 parm_entries = 1;
574
575 entries = min(parm_entries, MAX_ENTRIES);
347 576
348 test_rht_params.automatic_shrinking = shrinking; 577 test_rht_params.automatic_shrinking = shrinking;
349 test_rht_params.max_size = max_size ? : roundup_pow_of_two(entries); 578 test_rht_params.max_size = max_size ? : roundup_pow_of_two(entries);
350 test_rht_params.nelem_hint = size; 579 test_rht_params.nelem_hint = size;
351 580
581 objs = vzalloc((test_rht_params.max_size + 1) * sizeof(struct test_obj));
582 if (!objs)
583 return -ENOMEM;
584
352 pr_info("Running rhashtable test nelem=%d, max_size=%d, shrinking=%d\n", 585 pr_info("Running rhashtable test nelem=%d, max_size=%d, shrinking=%d\n",
353 size, max_size, shrinking); 586 size, max_size, shrinking);
354 587
@@ -356,7 +589,8 @@ static int __init test_rht_init(void)
356 s64 time; 589 s64 time;
357 590
358 pr_info("Test %02d:\n", i); 591 pr_info("Test %02d:\n", i);
359 memset(&array, 0, sizeof(array)); 592 memset(objs, 0, test_rht_params.max_size * sizeof(struct test_obj));
593
360 err = rhashtable_init(&ht, &test_rht_params); 594 err = rhashtable_init(&ht, &test_rht_params);
361 if (err < 0) { 595 if (err < 0) {
362 pr_warn("Test failed: Unable to initialize hashtable: %d\n", 596 pr_warn("Test failed: Unable to initialize hashtable: %d\n",
@@ -364,9 +598,10 @@ static int __init test_rht_init(void)
364 continue; 598 continue;
365 } 599 }
366 600
367 time = test_rhashtable(&ht); 601 time = test_rhashtable(&ht, objs, entries);
368 rhashtable_destroy(&ht); 602 rhashtable_destroy(&ht);
369 if (time < 0) { 603 if (time < 0) {
604 vfree(objs);
370 pr_warn("Test failed: return code %lld\n", time); 605 pr_warn("Test failed: return code %lld\n", time);
371 return -EINVAL; 606 return -EINVAL;
372 } 607 }
@@ -374,6 +609,11 @@ static int __init test_rht_init(void)
374 total_time += time; 609 total_time += time;
375 } 610 }
376 611
612 pr_info("test if its possible to exceed max_size %d: %s\n",
613 test_rht_params.max_size, test_rhashtable_max(objs, entries) == 0 ?
614 "no, ok" : "YES, failed");
615 vfree(objs);
616
377 do_div(total_time, runs); 617 do_div(total_time, runs);
378 pr_info("Average test time: %llu\n", total_time); 618 pr_info("Average test time: %llu\n", total_time);
379 619
@@ -404,6 +644,7 @@ static int __init test_rht_init(void)
404 } 644 }
405 for (i = 0; i < tcount; i++) { 645 for (i = 0; i < tcount; i++) {
406 tdata[i].id = i; 646 tdata[i].id = i;
647 tdata[i].entries = entries;
407 tdata[i].objs = objs + i * entries; 648 tdata[i].objs = objs + i * entries;
408 tdata[i].task = kthread_run(threadfunc, &tdata[i], 649 tdata[i].task = kthread_run(threadfunc, &tdata[i],
409 "rhashtable_thrad[%d]", i); 650 "rhashtable_thrad[%d]", i);
@@ -425,11 +666,17 @@ static int __init test_rht_init(void)
425 failed_threads++; 666 failed_threads++;
426 } 667 }
427 } 668 }
428 pr_info("Started %d threads, %d failed\n",
429 started_threads, failed_threads);
430 rhashtable_destroy(&ht); 669 rhashtable_destroy(&ht);
431 vfree(tdata); 670 vfree(tdata);
432 vfree(objs); 671 vfree(objs);
672
673 /*
674 * rhltable_remove is very expensive, default values can cause test
675 * to run for 2 minutes or more, use a smaller number instead.
676 */
677 err = test_rhltable(entries / 16);
678 pr_info("Started %d threads, %d failed, rhltable test returns %d\n",
679 started_threads, failed_threads, err);
433 return 0; 680 return 0;
434} 681}
435 682