aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-11-15 14:56:19 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-11-15 14:56:19 -0500
commit5bbcc0f595fadb4cac0eddc4401035ec0bd95b09 (patch)
tree3b65e490cc36a6c6fecac1fa24d9e0ac9ced4455 /lib
parent892204e06cb9e89fbc4b299a678f9ca358e97cac (diff)
parent50895b9de1d3e0258e015e8e55128d835d9a9f19 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller: "Highlights: 1) Maintain the TCP retransmit queue using an rbtree, with 1GB windows at 100Gb this really has become necessary. From Eric Dumazet. 2) Multi-program support for cgroup+bpf, from Alexei Starovoitov. 3) Perform broadcast flooding in hardware in mv88e6xxx, from Andrew Lunn. 4) Add meter action support to openvswitch, from Andy Zhou. 5) Add a data meta pointer for BPF accessible packets, from Daniel Borkmann. 6) Namespace-ify almost all TCP sysctl knobs, from Eric Dumazet. 7) Turn on Broadcom Tags in b53 driver, from Florian Fainelli. 8) More work to move the RTNL mutex down, from Florian Westphal. 9) Add 'bpftool' utility, to help with bpf program introspection. From Jakub Kicinski. 10) Add new 'cpumap' type for XDP_REDIRECT action, from Jesper Dangaard Brouer. 11) Support 'blocks' of transformations in the packet scheduler which can span multiple network devices, from Jiri Pirko. 12) TC flower offload support in cxgb4, from Kumar Sanghvi. 13) Priority based stream scheduler for SCTP, from Marcelo Ricardo Leitner. 14) Thunderbolt networking driver, from Amir Levy and Mika Westerberg. 15) Add RED qdisc offloadability, and use it in mlxsw driver. From Nogah Frankel. 16) eBPF based device controller for cgroup v2, from Roman Gushchin. 17) Add some fundamental tracepoints for TCP, from Song Liu. 18) Remove garbage collection from ipv6 route layer, this is a significant accomplishment. From Wei Wang. 19) Add multicast route offload support to mlxsw, from Yotam Gigi" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (2177 commits) tcp: highest_sack fix geneve: fix fill_info when link down bpf: fix lockdep splat net: cdc_ncm: GetNtbFormat endian fix openvswitch: meter: fix NULL pointer dereference in ovs_meter_cmd_reply_start netem: remove unnecessary 64 bit modulus netem: use 64 bit divide by rate tcp: Namespace-ify sysctl_tcp_default_congestion_control net: Protect iterations over net::fib_notifier_ops in fib_seq_sum() ipv6: set all.accept_dad to 0 by default uapi: fix linux/tls.h userspace compilation error usbnet: ipheth: prevent TX queue timeouts when device not ready vhost_net: conditionally enable tx polling uapi: fix linux/rxrpc.h userspace compilation errors net: stmmac: fix LPI transitioning for dwmac4 atm: horizon: Fix irq release error net-sysfs: trigger netlink notification on ifalias change via sysfs openvswitch: Using kfree_rcu() to simplify the code openvswitch: Make local function ovs_nsh_key_attr_size() static openvswitch: Fix return value check in ovs_meter_cmd_features() ...
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