1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ |
3 | |
4 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
5 | |
6 | #include <linux/kernel.h> |
7 | #include <linux/module.h> |
8 | #include <linux/slab.h> |
9 | #include <linux/random.h> |
10 | #include <linux/objagg.h> |
11 | |
12 | struct tokey { |
13 | unsigned int id; |
14 | }; |
15 | |
16 | #define NUM_KEYS 32 |
17 | |
18 | static int key_id_index(unsigned int key_id) |
19 | { |
20 | if (key_id >= NUM_KEYS) { |
21 | WARN_ON(1); |
22 | return 0; |
23 | } |
24 | return key_id; |
25 | } |
26 | |
27 | #define BUF_LEN 128 |
28 | |
29 | struct world { |
30 | unsigned int root_count; |
31 | unsigned int delta_count; |
32 | char next_root_buf[BUF_LEN]; |
33 | struct objagg_obj *objagg_objs[NUM_KEYS]; |
34 | unsigned int key_refs[NUM_KEYS]; |
35 | }; |
36 | |
37 | struct root { |
38 | struct tokey key; |
39 | char buf[BUF_LEN]; |
40 | }; |
41 | |
42 | struct delta { |
43 | unsigned int key_id_diff; |
44 | }; |
45 | |
46 | static struct objagg_obj *world_obj_get(struct world *world, |
47 | struct objagg *objagg, |
48 | unsigned int key_id) |
49 | { |
50 | struct objagg_obj *objagg_obj; |
51 | struct tokey key; |
52 | int err; |
53 | |
54 | key.id = key_id; |
55 | objagg_obj = objagg_obj_get(objagg, obj: &key); |
56 | if (IS_ERR(ptr: objagg_obj)) { |
57 | pr_err("Key %u: Failed to get object.\n" , key_id); |
58 | return objagg_obj; |
59 | } |
60 | if (!world->key_refs[key_id_index(key_id)]) { |
61 | world->objagg_objs[key_id_index(key_id)] = objagg_obj; |
62 | } else if (world->objagg_objs[key_id_index(key_id)] != objagg_obj) { |
63 | pr_err("Key %u: God another object for the same key.\n" , |
64 | key_id); |
65 | err = -EINVAL; |
66 | goto err_key_id_check; |
67 | } |
68 | world->key_refs[key_id_index(key_id)]++; |
69 | return objagg_obj; |
70 | |
71 | err_key_id_check: |
72 | objagg_obj_put(objagg, objagg_obj); |
73 | return ERR_PTR(error: err); |
74 | } |
75 | |
76 | static void world_obj_put(struct world *world, struct objagg *objagg, |
77 | unsigned int key_id) |
78 | { |
79 | struct objagg_obj *objagg_obj; |
80 | |
81 | if (!world->key_refs[key_id_index(key_id)]) |
82 | return; |
83 | objagg_obj = world->objagg_objs[key_id_index(key_id)]; |
84 | objagg_obj_put(objagg, objagg_obj); |
85 | world->key_refs[key_id_index(key_id)]--; |
86 | } |
87 | |
88 | #define MAX_KEY_ID_DIFF 5 |
89 | |
90 | static bool delta_check(void *priv, const void *parent_obj, const void *obj) |
91 | { |
92 | const struct tokey *parent_key = parent_obj; |
93 | const struct tokey *key = obj; |
94 | int diff = key->id - parent_key->id; |
95 | |
96 | return diff >= 0 && diff <= MAX_KEY_ID_DIFF; |
97 | } |
98 | |
99 | static void *delta_create(void *priv, void *parent_obj, void *obj) |
100 | { |
101 | struct tokey *parent_key = parent_obj; |
102 | struct world *world = priv; |
103 | struct tokey *key = obj; |
104 | int diff = key->id - parent_key->id; |
105 | struct delta *delta; |
106 | |
107 | if (!delta_check(priv, parent_obj, obj)) |
108 | return ERR_PTR(error: -EINVAL); |
109 | |
110 | delta = kzalloc(size: sizeof(*delta), GFP_KERNEL); |
111 | if (!delta) |
112 | return ERR_PTR(error: -ENOMEM); |
113 | delta->key_id_diff = diff; |
114 | world->delta_count++; |
115 | return delta; |
116 | } |
117 | |
118 | static void delta_destroy(void *priv, void *delta_priv) |
119 | { |
120 | struct delta *delta = delta_priv; |
121 | struct world *world = priv; |
122 | |
123 | world->delta_count--; |
124 | kfree(objp: delta); |
125 | } |
126 | |
127 | static void *root_create(void *priv, void *obj, unsigned int id) |
128 | { |
129 | struct world *world = priv; |
130 | struct tokey *key = obj; |
131 | struct root *root; |
132 | |
133 | root = kzalloc(size: sizeof(*root), GFP_KERNEL); |
134 | if (!root) |
135 | return ERR_PTR(error: -ENOMEM); |
136 | memcpy(&root->key, key, sizeof(root->key)); |
137 | memcpy(root->buf, world->next_root_buf, sizeof(root->buf)); |
138 | world->root_count++; |
139 | return root; |
140 | } |
141 | |
142 | static void root_destroy(void *priv, void *root_priv) |
143 | { |
144 | struct root *root = root_priv; |
145 | struct world *world = priv; |
146 | |
147 | world->root_count--; |
148 | kfree(objp: root); |
149 | } |
150 | |
151 | static int test_nodelta_obj_get(struct world *world, struct objagg *objagg, |
152 | unsigned int key_id, bool should_create_root) |
153 | { |
154 | unsigned int orig_root_count = world->root_count; |
155 | struct objagg_obj *objagg_obj; |
156 | const struct root *root; |
157 | int err; |
158 | |
159 | if (should_create_root) |
160 | get_random_bytes(buf: world->next_root_buf, |
161 | len: sizeof(world->next_root_buf)); |
162 | |
163 | objagg_obj = world_obj_get(world, objagg, key_id); |
164 | if (IS_ERR(ptr: objagg_obj)) { |
165 | pr_err("Key %u: Failed to get object.\n" , key_id); |
166 | return PTR_ERR(ptr: objagg_obj); |
167 | } |
168 | if (should_create_root) { |
169 | if (world->root_count != orig_root_count + 1) { |
170 | pr_err("Key %u: Root was not created\n" , key_id); |
171 | err = -EINVAL; |
172 | goto err_check_root_count; |
173 | } |
174 | } else { |
175 | if (world->root_count != orig_root_count) { |
176 | pr_err("Key %u: Root was incorrectly created\n" , |
177 | key_id); |
178 | err = -EINVAL; |
179 | goto err_check_root_count; |
180 | } |
181 | } |
182 | root = objagg_obj_root_priv(objagg_obj); |
183 | if (root->key.id != key_id) { |
184 | pr_err("Key %u: Root has unexpected key id\n" , key_id); |
185 | err = -EINVAL; |
186 | goto err_check_key_id; |
187 | } |
188 | if (should_create_root && |
189 | memcmp(p: world->next_root_buf, q: root->buf, size: sizeof(root->buf))) { |
190 | pr_err("Key %u: Buffer does not match the expected content\n" , |
191 | key_id); |
192 | err = -EINVAL; |
193 | goto err_check_buf; |
194 | } |
195 | return 0; |
196 | |
197 | err_check_buf: |
198 | err_check_key_id: |
199 | err_check_root_count: |
200 | objagg_obj_put(objagg, objagg_obj); |
201 | return err; |
202 | } |
203 | |
204 | static int test_nodelta_obj_put(struct world *world, struct objagg *objagg, |
205 | unsigned int key_id, bool should_destroy_root) |
206 | { |
207 | unsigned int orig_root_count = world->root_count; |
208 | |
209 | world_obj_put(world, objagg, key_id); |
210 | |
211 | if (should_destroy_root) { |
212 | if (world->root_count != orig_root_count - 1) { |
213 | pr_err("Key %u: Root was not destroyed\n" , key_id); |
214 | return -EINVAL; |
215 | } |
216 | } else { |
217 | if (world->root_count != orig_root_count) { |
218 | pr_err("Key %u: Root was incorrectly destroyed\n" , |
219 | key_id); |
220 | return -EINVAL; |
221 | } |
222 | } |
223 | return 0; |
224 | } |
225 | |
226 | static int check_stats_zero(struct objagg *objagg) |
227 | { |
228 | const struct objagg_stats *stats; |
229 | int err = 0; |
230 | |
231 | stats = objagg_stats_get(objagg); |
232 | if (IS_ERR(ptr: stats)) |
233 | return PTR_ERR(ptr: stats); |
234 | |
235 | if (stats->stats_info_count != 0) { |
236 | pr_err("Stats: Object count is not zero while it should be\n" ); |
237 | err = -EINVAL; |
238 | } |
239 | |
240 | objagg_stats_put(objagg_stats: stats); |
241 | return err; |
242 | } |
243 | |
244 | static int check_stats_nodelta(struct objagg *objagg) |
245 | { |
246 | const struct objagg_stats *stats; |
247 | int i; |
248 | int err; |
249 | |
250 | stats = objagg_stats_get(objagg); |
251 | if (IS_ERR(ptr: stats)) |
252 | return PTR_ERR(ptr: stats); |
253 | |
254 | if (stats->stats_info_count != NUM_KEYS) { |
255 | pr_err("Stats: Unexpected object count (%u expected, %u returned)\n" , |
256 | NUM_KEYS, stats->stats_info_count); |
257 | err = -EINVAL; |
258 | goto stats_put; |
259 | } |
260 | |
261 | for (i = 0; i < stats->stats_info_count; i++) { |
262 | if (stats->stats_info[i].stats.user_count != 2) { |
263 | pr_err("Stats: incorrect user count\n" ); |
264 | err = -EINVAL; |
265 | goto stats_put; |
266 | } |
267 | if (stats->stats_info[i].stats.delta_user_count != 2) { |
268 | pr_err("Stats: incorrect delta user count\n" ); |
269 | err = -EINVAL; |
270 | goto stats_put; |
271 | } |
272 | } |
273 | err = 0; |
274 | |
275 | stats_put: |
276 | objagg_stats_put(objagg_stats: stats); |
277 | return err; |
278 | } |
279 | |
280 | static bool delta_check_dummy(void *priv, const void *parent_obj, |
281 | const void *obj) |
282 | { |
283 | return false; |
284 | } |
285 | |
286 | static void *delta_create_dummy(void *priv, void *parent_obj, void *obj) |
287 | { |
288 | return ERR_PTR(error: -EOPNOTSUPP); |
289 | } |
290 | |
291 | static void delta_destroy_dummy(void *priv, void *delta_priv) |
292 | { |
293 | } |
294 | |
295 | static const struct objagg_ops nodelta_ops = { |
296 | .obj_size = sizeof(struct tokey), |
297 | .delta_check = delta_check_dummy, |
298 | .delta_create = delta_create_dummy, |
299 | .delta_destroy = delta_destroy_dummy, |
300 | .root_create = root_create, |
301 | .root_destroy = root_destroy, |
302 | }; |
303 | |
304 | static int test_nodelta(void) |
305 | { |
306 | struct world world = {}; |
307 | struct objagg *objagg; |
308 | int i; |
309 | int err; |
310 | |
311 | objagg = objagg_create(ops: &nodelta_ops, NULL, priv: &world); |
312 | if (IS_ERR(ptr: objagg)) |
313 | return PTR_ERR(ptr: objagg); |
314 | |
315 | err = check_stats_zero(objagg); |
316 | if (err) |
317 | goto err_stats_first_zero; |
318 | |
319 | /* First round of gets, the root objects should be created */ |
320 | for (i = 0; i < NUM_KEYS; i++) { |
321 | err = test_nodelta_obj_get(world: &world, objagg, key_id: i, should_create_root: true); |
322 | if (err) |
323 | goto err_obj_first_get; |
324 | } |
325 | |
326 | /* Do the second round of gets, all roots are already created, |
327 | * make sure that no new root is created |
328 | */ |
329 | for (i = 0; i < NUM_KEYS; i++) { |
330 | err = test_nodelta_obj_get(world: &world, objagg, key_id: i, should_create_root: false); |
331 | if (err) |
332 | goto err_obj_second_get; |
333 | } |
334 | |
335 | err = check_stats_nodelta(objagg); |
336 | if (err) |
337 | goto err_stats_nodelta; |
338 | |
339 | for (i = NUM_KEYS - 1; i >= 0; i--) { |
340 | err = test_nodelta_obj_put(world: &world, objagg, key_id: i, should_destroy_root: false); |
341 | if (err) |
342 | goto err_obj_first_put; |
343 | } |
344 | for (i = NUM_KEYS - 1; i >= 0; i--) { |
345 | err = test_nodelta_obj_put(world: &world, objagg, key_id: i, should_destroy_root: true); |
346 | if (err) |
347 | goto err_obj_second_put; |
348 | } |
349 | |
350 | err = check_stats_zero(objagg); |
351 | if (err) |
352 | goto err_stats_second_zero; |
353 | |
354 | objagg_destroy(objagg); |
355 | return 0; |
356 | |
357 | err_stats_nodelta: |
358 | err_obj_first_put: |
359 | err_obj_second_get: |
360 | for (i--; i >= 0; i--) |
361 | world_obj_put(world: &world, objagg, key_id: i); |
362 | |
363 | i = NUM_KEYS; |
364 | err_obj_first_get: |
365 | err_obj_second_put: |
366 | for (i--; i >= 0; i--) |
367 | world_obj_put(world: &world, objagg, key_id: i); |
368 | err_stats_first_zero: |
369 | err_stats_second_zero: |
370 | objagg_destroy(objagg); |
371 | return err; |
372 | } |
373 | |
374 | static const struct objagg_ops delta_ops = { |
375 | .obj_size = sizeof(struct tokey), |
376 | .delta_check = delta_check, |
377 | .delta_create = delta_create, |
378 | .delta_destroy = delta_destroy, |
379 | .root_create = root_create, |
380 | .root_destroy = root_destroy, |
381 | }; |
382 | |
383 | enum action { |
384 | ACTION_GET, |
385 | ACTION_PUT, |
386 | }; |
387 | |
388 | enum expect_delta { |
389 | EXPECT_DELTA_SAME, |
390 | EXPECT_DELTA_INC, |
391 | EXPECT_DELTA_DEC, |
392 | }; |
393 | |
394 | enum expect_root { |
395 | EXPECT_ROOT_SAME, |
396 | EXPECT_ROOT_INC, |
397 | EXPECT_ROOT_DEC, |
398 | }; |
399 | |
400 | struct expect_stats_info { |
401 | struct objagg_obj_stats stats; |
402 | bool is_root; |
403 | unsigned int key_id; |
404 | }; |
405 | |
406 | struct expect_stats { |
407 | unsigned int info_count; |
408 | struct expect_stats_info info[NUM_KEYS]; |
409 | }; |
410 | |
411 | struct action_item { |
412 | unsigned int key_id; |
413 | enum action action; |
414 | enum expect_delta expect_delta; |
415 | enum expect_root expect_root; |
416 | struct expect_stats expect_stats; |
417 | }; |
418 | |
419 | #define EXPECT_STATS(count, ...) \ |
420 | { \ |
421 | .info_count = count, \ |
422 | .info = { __VA_ARGS__ } \ |
423 | } |
424 | |
425 | #define ROOT(key_id, user_count, delta_user_count) \ |
426 | {{user_count, delta_user_count}, true, key_id} |
427 | |
428 | #define DELTA(key_id, user_count) \ |
429 | {{user_count, user_count}, false, key_id} |
430 | |
431 | static const struct action_item action_items[] = { |
432 | { |
433 | 1, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_INC, |
434 | EXPECT_STATS(1, ROOT(1, 1, 1)), |
435 | }, /* r: 1 d: */ |
436 | { |
437 | 7, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_INC, |
438 | EXPECT_STATS(2, ROOT(1, 1, 1), ROOT(7, 1, 1)), |
439 | }, /* r: 1, 7 d: */ |
440 | { |
441 | 3, ACTION_GET, EXPECT_DELTA_INC, EXPECT_ROOT_SAME, |
442 | EXPECT_STATS(3, ROOT(1, 1, 2), ROOT(7, 1, 1), |
443 | DELTA(3, 1)), |
444 | }, /* r: 1, 7 d: 3^1 */ |
445 | { |
446 | 5, ACTION_GET, EXPECT_DELTA_INC, EXPECT_ROOT_SAME, |
447 | EXPECT_STATS(4, ROOT(1, 1, 3), ROOT(7, 1, 1), |
448 | DELTA(3, 1), DELTA(5, 1)), |
449 | }, /* r: 1, 7 d: 3^1, 5^1 */ |
450 | { |
451 | 3, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME, |
452 | EXPECT_STATS(4, ROOT(1, 1, 4), ROOT(7, 1, 1), |
453 | DELTA(3, 2), DELTA(5, 1)), |
454 | }, /* r: 1, 7 d: 3^1, 3^1, 5^1 */ |
455 | { |
456 | 1, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME, |
457 | EXPECT_STATS(4, ROOT(1, 2, 5), ROOT(7, 1, 1), |
458 | DELTA(3, 2), DELTA(5, 1)), |
459 | }, /* r: 1, 1, 7 d: 3^1, 3^1, 5^1 */ |
460 | { |
461 | 30, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_INC, |
462 | EXPECT_STATS(5, ROOT(1, 2, 5), ROOT(7, 1, 1), ROOT(30, 1, 1), |
463 | DELTA(3, 2), DELTA(5, 1)), |
464 | }, /* r: 1, 1, 7, 30 d: 3^1, 3^1, 5^1 */ |
465 | { |
466 | 8, ACTION_GET, EXPECT_DELTA_INC, EXPECT_ROOT_SAME, |
467 | EXPECT_STATS(6, ROOT(1, 2, 5), ROOT(7, 1, 2), ROOT(30, 1, 1), |
468 | DELTA(3, 2), DELTA(5, 1), DELTA(8, 1)), |
469 | }, /* r: 1, 1, 7, 30 d: 3^1, 3^1, 5^1, 8^7 */ |
470 | { |
471 | 8, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME, |
472 | EXPECT_STATS(6, ROOT(1, 2, 5), ROOT(7, 1, 3), ROOT(30, 1, 1), |
473 | DELTA(3, 2), DELTA(8, 2), DELTA(5, 1)), |
474 | }, /* r: 1, 1, 7, 30 d: 3^1, 3^1, 5^1, 8^7, 8^7 */ |
475 | { |
476 | 3, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME, |
477 | EXPECT_STATS(6, ROOT(1, 2, 4), ROOT(7, 1, 3), ROOT(30, 1, 1), |
478 | DELTA(8, 2), DELTA(3, 1), DELTA(5, 1)), |
479 | }, /* r: 1, 1, 7, 30 d: 3^1, 5^1, 8^7, 8^7 */ |
480 | { |
481 | 3, ACTION_PUT, EXPECT_DELTA_DEC, EXPECT_ROOT_SAME, |
482 | EXPECT_STATS(5, ROOT(1, 2, 3), ROOT(7, 1, 3), ROOT(30, 1, 1), |
483 | DELTA(8, 2), DELTA(5, 1)), |
484 | }, /* r: 1, 1, 7, 30 d: 5^1, 8^7, 8^7 */ |
485 | { |
486 | 1, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME, |
487 | EXPECT_STATS(5, ROOT(7, 1, 3), ROOT(1, 1, 2), ROOT(30, 1, 1), |
488 | DELTA(8, 2), DELTA(5, 1)), |
489 | }, /* r: 1, 7, 30 d: 5^1, 8^7, 8^7 */ |
490 | { |
491 | 1, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME, |
492 | EXPECT_STATS(5, ROOT(7, 1, 3), ROOT(30, 1, 1), ROOT(1, 0, 1), |
493 | DELTA(8, 2), DELTA(5, 1)), |
494 | }, /* r: 7, 30 d: 5^1, 8^7, 8^7 */ |
495 | { |
496 | 5, ACTION_PUT, EXPECT_DELTA_DEC, EXPECT_ROOT_DEC, |
497 | EXPECT_STATS(3, ROOT(7, 1, 3), ROOT(30, 1, 1), |
498 | DELTA(8, 2)), |
499 | }, /* r: 7, 30 d: 8^7, 8^7 */ |
500 | { |
501 | 5, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_INC, |
502 | EXPECT_STATS(4, ROOT(7, 1, 3), ROOT(30, 1, 1), ROOT(5, 1, 1), |
503 | DELTA(8, 2)), |
504 | }, /* r: 7, 30, 5 d: 8^7, 8^7 */ |
505 | { |
506 | 6, ACTION_GET, EXPECT_DELTA_INC, EXPECT_ROOT_SAME, |
507 | EXPECT_STATS(5, ROOT(7, 1, 3), ROOT(5, 1, 2), ROOT(30, 1, 1), |
508 | DELTA(8, 2), DELTA(6, 1)), |
509 | }, /* r: 7, 30, 5 d: 8^7, 8^7, 6^5 */ |
510 | { |
511 | 8, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME, |
512 | EXPECT_STATS(5, ROOT(7, 1, 4), ROOT(5, 1, 2), ROOT(30, 1, 1), |
513 | DELTA(8, 3), DELTA(6, 1)), |
514 | }, /* r: 7, 30, 5 d: 8^7, 8^7, 8^7, 6^5 */ |
515 | { |
516 | 8, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME, |
517 | EXPECT_STATS(5, ROOT(7, 1, 3), ROOT(5, 1, 2), ROOT(30, 1, 1), |
518 | DELTA(8, 2), DELTA(6, 1)), |
519 | }, /* r: 7, 30, 5 d: 8^7, 8^7, 6^5 */ |
520 | { |
521 | 8, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME, |
522 | EXPECT_STATS(5, ROOT(7, 1, 2), ROOT(5, 1, 2), ROOT(30, 1, 1), |
523 | DELTA(8, 1), DELTA(6, 1)), |
524 | }, /* r: 7, 30, 5 d: 8^7, 6^5 */ |
525 | { |
526 | 8, ACTION_PUT, EXPECT_DELTA_DEC, EXPECT_ROOT_SAME, |
527 | EXPECT_STATS(4, ROOT(5, 1, 2), ROOT(7, 1, 1), ROOT(30, 1, 1), |
528 | DELTA(6, 1)), |
529 | }, /* r: 7, 30, 5 d: 6^5 */ |
530 | { |
531 | 8, ACTION_GET, EXPECT_DELTA_INC, EXPECT_ROOT_SAME, |
532 | EXPECT_STATS(5, ROOT(5, 1, 3), ROOT(7, 1, 1), ROOT(30, 1, 1), |
533 | DELTA(6, 1), DELTA(8, 1)), |
534 | }, /* r: 7, 30, 5 d: 6^5, 8^5 */ |
535 | { |
536 | 7, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_DEC, |
537 | EXPECT_STATS(4, ROOT(5, 1, 3), ROOT(30, 1, 1), |
538 | DELTA(6, 1), DELTA(8, 1)), |
539 | }, /* r: 30, 5 d: 6^5, 8^5 */ |
540 | { |
541 | 30, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_DEC, |
542 | EXPECT_STATS(3, ROOT(5, 1, 3), |
543 | DELTA(6, 1), DELTA(8, 1)), |
544 | }, /* r: 5 d: 6^5, 8^5 */ |
545 | { |
546 | 5, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME, |
547 | EXPECT_STATS(3, ROOT(5, 0, 2), |
548 | DELTA(6, 1), DELTA(8, 1)), |
549 | }, /* r: d: 6^5, 8^5 */ |
550 | { |
551 | 6, ACTION_PUT, EXPECT_DELTA_DEC, EXPECT_ROOT_SAME, |
552 | EXPECT_STATS(2, ROOT(5, 0, 1), |
553 | DELTA(8, 1)), |
554 | }, /* r: d: 6^5 */ |
555 | { |
556 | 8, ACTION_PUT, EXPECT_DELTA_DEC, EXPECT_ROOT_DEC, |
557 | EXPECT_STATS(0, ), |
558 | }, /* r: d: */ |
559 | }; |
560 | |
561 | static int check_expect(struct world *world, |
562 | const struct action_item *action_item, |
563 | unsigned int orig_delta_count, |
564 | unsigned int orig_root_count) |
565 | { |
566 | unsigned int key_id = action_item->key_id; |
567 | |
568 | switch (action_item->expect_delta) { |
569 | case EXPECT_DELTA_SAME: |
570 | if (orig_delta_count != world->delta_count) { |
571 | pr_err("Key %u: Delta count changed while expected to remain the same.\n" , |
572 | key_id); |
573 | return -EINVAL; |
574 | } |
575 | break; |
576 | case EXPECT_DELTA_INC: |
577 | if (WARN_ON(action_item->action == ACTION_PUT)) |
578 | return -EINVAL; |
579 | if (orig_delta_count + 1 != world->delta_count) { |
580 | pr_err("Key %u: Delta count was not incremented.\n" , |
581 | key_id); |
582 | return -EINVAL; |
583 | } |
584 | break; |
585 | case EXPECT_DELTA_DEC: |
586 | if (WARN_ON(action_item->action == ACTION_GET)) |
587 | return -EINVAL; |
588 | if (orig_delta_count - 1 != world->delta_count) { |
589 | pr_err("Key %u: Delta count was not decremented.\n" , |
590 | key_id); |
591 | return -EINVAL; |
592 | } |
593 | break; |
594 | } |
595 | |
596 | switch (action_item->expect_root) { |
597 | case EXPECT_ROOT_SAME: |
598 | if (orig_root_count != world->root_count) { |
599 | pr_err("Key %u: Root count changed while expected to remain the same.\n" , |
600 | key_id); |
601 | return -EINVAL; |
602 | } |
603 | break; |
604 | case EXPECT_ROOT_INC: |
605 | if (WARN_ON(action_item->action == ACTION_PUT)) |
606 | return -EINVAL; |
607 | if (orig_root_count + 1 != world->root_count) { |
608 | pr_err("Key %u: Root count was not incremented.\n" , |
609 | key_id); |
610 | return -EINVAL; |
611 | } |
612 | break; |
613 | case EXPECT_ROOT_DEC: |
614 | if (WARN_ON(action_item->action == ACTION_GET)) |
615 | return -EINVAL; |
616 | if (orig_root_count - 1 != world->root_count) { |
617 | pr_err("Key %u: Root count was not decremented.\n" , |
618 | key_id); |
619 | return -EINVAL; |
620 | } |
621 | } |
622 | |
623 | return 0; |
624 | } |
625 | |
626 | static unsigned int obj_to_key_id(struct objagg_obj *objagg_obj) |
627 | { |
628 | const struct tokey *root_key; |
629 | const struct delta *delta; |
630 | unsigned int key_id; |
631 | |
632 | root_key = objagg_obj_root_priv(objagg_obj); |
633 | key_id = root_key->id; |
634 | delta = objagg_obj_delta_priv(objagg_obj); |
635 | if (delta) |
636 | key_id += delta->key_id_diff; |
637 | return key_id; |
638 | } |
639 | |
640 | static int |
641 | check_expect_stats_nums(const struct objagg_obj_stats_info *stats_info, |
642 | const struct expect_stats_info *expect_stats_info, |
643 | const char **errmsg) |
644 | { |
645 | if (stats_info->is_root != expect_stats_info->is_root) { |
646 | if (errmsg) |
647 | *errmsg = "Incorrect root/delta indication" ; |
648 | return -EINVAL; |
649 | } |
650 | if (stats_info->stats.user_count != |
651 | expect_stats_info->stats.user_count) { |
652 | if (errmsg) |
653 | *errmsg = "Incorrect user count" ; |
654 | return -EINVAL; |
655 | } |
656 | if (stats_info->stats.delta_user_count != |
657 | expect_stats_info->stats.delta_user_count) { |
658 | if (errmsg) |
659 | *errmsg = "Incorrect delta user count" ; |
660 | return -EINVAL; |
661 | } |
662 | return 0; |
663 | } |
664 | |
665 | static int |
666 | check_expect_stats_key_id(const struct objagg_obj_stats_info *stats_info, |
667 | const struct expect_stats_info *expect_stats_info, |
668 | const char **errmsg) |
669 | { |
670 | if (obj_to_key_id(objagg_obj: stats_info->objagg_obj) != |
671 | expect_stats_info->key_id) { |
672 | if (errmsg) |
673 | *errmsg = "incorrect key id" ; |
674 | return -EINVAL; |
675 | } |
676 | return 0; |
677 | } |
678 | |
679 | static int check_expect_stats_neigh(const struct objagg_stats *stats, |
680 | const struct expect_stats *expect_stats, |
681 | int pos) |
682 | { |
683 | int i; |
684 | int err; |
685 | |
686 | for (i = pos - 1; i >= 0; i--) { |
687 | err = check_expect_stats_nums(stats_info: &stats->stats_info[i], |
688 | expect_stats_info: &expect_stats->info[pos], NULL); |
689 | if (err) |
690 | break; |
691 | err = check_expect_stats_key_id(stats_info: &stats->stats_info[i], |
692 | expect_stats_info: &expect_stats->info[pos], NULL); |
693 | if (!err) |
694 | return 0; |
695 | } |
696 | for (i = pos + 1; i < stats->stats_info_count; i++) { |
697 | err = check_expect_stats_nums(stats_info: &stats->stats_info[i], |
698 | expect_stats_info: &expect_stats->info[pos], NULL); |
699 | if (err) |
700 | break; |
701 | err = check_expect_stats_key_id(stats_info: &stats->stats_info[i], |
702 | expect_stats_info: &expect_stats->info[pos], NULL); |
703 | if (!err) |
704 | return 0; |
705 | } |
706 | return -EINVAL; |
707 | } |
708 | |
709 | static int __check_expect_stats(const struct objagg_stats *stats, |
710 | const struct expect_stats *expect_stats, |
711 | const char **errmsg) |
712 | { |
713 | int i; |
714 | int err; |
715 | |
716 | if (stats->stats_info_count != expect_stats->info_count) { |
717 | *errmsg = "Unexpected object count" ; |
718 | return -EINVAL; |
719 | } |
720 | |
721 | for (i = 0; i < stats->stats_info_count; i++) { |
722 | err = check_expect_stats_nums(stats_info: &stats->stats_info[i], |
723 | expect_stats_info: &expect_stats->info[i], errmsg); |
724 | if (err) |
725 | return err; |
726 | err = check_expect_stats_key_id(stats_info: &stats->stats_info[i], |
727 | expect_stats_info: &expect_stats->info[i], errmsg); |
728 | if (err) { |
729 | /* It is possible that one of the neighbor stats with |
730 | * same numbers have the correct key id, so check it |
731 | */ |
732 | err = check_expect_stats_neigh(stats, expect_stats, pos: i); |
733 | if (err) |
734 | return err; |
735 | } |
736 | } |
737 | return 0; |
738 | } |
739 | |
740 | static int check_expect_stats(struct objagg *objagg, |
741 | const struct expect_stats *expect_stats, |
742 | const char **errmsg) |
743 | { |
744 | const struct objagg_stats *stats; |
745 | int err; |
746 | |
747 | stats = objagg_stats_get(objagg); |
748 | if (IS_ERR(ptr: stats)) { |
749 | *errmsg = "objagg_stats_get() failed." ; |
750 | return PTR_ERR(ptr: stats); |
751 | } |
752 | err = __check_expect_stats(stats, expect_stats, errmsg); |
753 | objagg_stats_put(objagg_stats: stats); |
754 | return err; |
755 | } |
756 | |
757 | static int test_delta_action_item(struct world *world, |
758 | struct objagg *objagg, |
759 | const struct action_item *action_item, |
760 | bool inverse) |
761 | { |
762 | unsigned int orig_delta_count = world->delta_count; |
763 | unsigned int orig_root_count = world->root_count; |
764 | unsigned int key_id = action_item->key_id; |
765 | enum action action = action_item->action; |
766 | struct objagg_obj *objagg_obj; |
767 | const char *errmsg; |
768 | int err; |
769 | |
770 | if (inverse) |
771 | action = action == ACTION_GET ? ACTION_PUT : ACTION_GET; |
772 | |
773 | switch (action) { |
774 | case ACTION_GET: |
775 | objagg_obj = world_obj_get(world, objagg, key_id); |
776 | if (IS_ERR(ptr: objagg_obj)) |
777 | return PTR_ERR(ptr: objagg_obj); |
778 | break; |
779 | case ACTION_PUT: |
780 | world_obj_put(world, objagg, key_id); |
781 | break; |
782 | } |
783 | |
784 | if (inverse) |
785 | return 0; |
786 | err = check_expect(world, action_item, |
787 | orig_delta_count, orig_root_count); |
788 | if (err) |
789 | goto errout; |
790 | |
791 | err = check_expect_stats(objagg, expect_stats: &action_item->expect_stats, errmsg: &errmsg); |
792 | if (err) { |
793 | pr_err("Key %u: Stats: %s\n" , action_item->key_id, errmsg); |
794 | goto errout; |
795 | } |
796 | |
797 | return 0; |
798 | |
799 | errout: |
800 | /* This can only happen when action is not inversed. |
801 | * So in case of an error, cleanup by doing inverse action. |
802 | */ |
803 | test_delta_action_item(world, objagg, action_item, inverse: true); |
804 | return err; |
805 | } |
806 | |
807 | static int test_delta(void) |
808 | { |
809 | struct world world = {}; |
810 | struct objagg *objagg; |
811 | int i; |
812 | int err; |
813 | |
814 | objagg = objagg_create(ops: &delta_ops, NULL, priv: &world); |
815 | if (IS_ERR(ptr: objagg)) |
816 | return PTR_ERR(ptr: objagg); |
817 | |
818 | for (i = 0; i < ARRAY_SIZE(action_items); i++) { |
819 | err = test_delta_action_item(world: &world, objagg, |
820 | action_item: &action_items[i], inverse: false); |
821 | if (err) |
822 | goto err_do_action_item; |
823 | } |
824 | |
825 | objagg_destroy(objagg); |
826 | return 0; |
827 | |
828 | err_do_action_item: |
829 | for (i--; i >= 0; i--) |
830 | test_delta_action_item(world: &world, objagg, action_item: &action_items[i], inverse: true); |
831 | |
832 | objagg_destroy(objagg); |
833 | return err; |
834 | } |
835 | |
836 | struct hints_case { |
837 | const unsigned int *key_ids; |
838 | size_t key_ids_count; |
839 | struct expect_stats expect_stats; |
840 | struct expect_stats expect_stats_hints; |
841 | }; |
842 | |
843 | static const unsigned int hints_case_key_ids[] = { |
844 | 1, 7, 3, 5, 3, 1, 30, 8, 8, 5, 6, 8, |
845 | }; |
846 | |
847 | static const struct hints_case hints_case = { |
848 | .key_ids = hints_case_key_ids, |
849 | .key_ids_count = ARRAY_SIZE(hints_case_key_ids), |
850 | .expect_stats = |
851 | EXPECT_STATS(7, ROOT(1, 2, 7), ROOT(7, 1, 4), ROOT(30, 1, 1), |
852 | DELTA(8, 3), DELTA(3, 2), |
853 | DELTA(5, 2), DELTA(6, 1)), |
854 | .expect_stats_hints = |
855 | EXPECT_STATS(7, ROOT(3, 2, 9), ROOT(1, 2, 2), ROOT(30, 1, 1), |
856 | DELTA(8, 3), DELTA(5, 2), |
857 | DELTA(6, 1), DELTA(7, 1)), |
858 | }; |
859 | |
860 | static void __pr_debug_stats(const struct objagg_stats *stats) |
861 | { |
862 | int i; |
863 | |
864 | for (i = 0; i < stats->stats_info_count; i++) |
865 | pr_debug("Stat index %d key %u: u %d, d %d, %s\n" , i, |
866 | obj_to_key_id(stats->stats_info[i].objagg_obj), |
867 | stats->stats_info[i].stats.user_count, |
868 | stats->stats_info[i].stats.delta_user_count, |
869 | stats->stats_info[i].is_root ? "root" : "noroot" ); |
870 | } |
871 | |
872 | static void pr_debug_stats(struct objagg *objagg) |
873 | { |
874 | const struct objagg_stats *stats; |
875 | |
876 | stats = objagg_stats_get(objagg); |
877 | if (IS_ERR(ptr: stats)) |
878 | return; |
879 | __pr_debug_stats(stats); |
880 | objagg_stats_put(objagg_stats: stats); |
881 | } |
882 | |
883 | static void pr_debug_hints_stats(struct objagg_hints *objagg_hints) |
884 | { |
885 | const struct objagg_stats *stats; |
886 | |
887 | stats = objagg_hints_stats_get(objagg_hints); |
888 | if (IS_ERR(ptr: stats)) |
889 | return; |
890 | __pr_debug_stats(stats); |
891 | objagg_stats_put(objagg_stats: stats); |
892 | } |
893 | |
894 | static int check_expect_hints_stats(struct objagg_hints *objagg_hints, |
895 | const struct expect_stats *expect_stats, |
896 | const char **errmsg) |
897 | { |
898 | const struct objagg_stats *stats; |
899 | int err; |
900 | |
901 | stats = objagg_hints_stats_get(objagg_hints); |
902 | if (IS_ERR(ptr: stats)) |
903 | return PTR_ERR(ptr: stats); |
904 | err = __check_expect_stats(stats, expect_stats, errmsg); |
905 | objagg_stats_put(objagg_stats: stats); |
906 | return err; |
907 | } |
908 | |
909 | static int test_hints_case(const struct hints_case *hints_case) |
910 | { |
911 | struct objagg_obj *objagg_obj; |
912 | struct objagg_hints *hints; |
913 | struct world world2 = {}; |
914 | struct world world = {}; |
915 | struct objagg *objagg2; |
916 | struct objagg *objagg; |
917 | const char *errmsg; |
918 | int i; |
919 | int err; |
920 | |
921 | objagg = objagg_create(ops: &delta_ops, NULL, priv: &world); |
922 | if (IS_ERR(ptr: objagg)) |
923 | return PTR_ERR(ptr: objagg); |
924 | |
925 | for (i = 0; i < hints_case->key_ids_count; i++) { |
926 | objagg_obj = world_obj_get(world: &world, objagg, |
927 | key_id: hints_case->key_ids[i]); |
928 | if (IS_ERR(ptr: objagg_obj)) { |
929 | err = PTR_ERR(ptr: objagg_obj); |
930 | goto err_world_obj_get; |
931 | } |
932 | } |
933 | |
934 | pr_debug_stats(objagg); |
935 | err = check_expect_stats(objagg, expect_stats: &hints_case->expect_stats, errmsg: &errmsg); |
936 | if (err) { |
937 | pr_err("Stats: %s\n" , errmsg); |
938 | goto err_check_expect_stats; |
939 | } |
940 | |
941 | hints = objagg_hints_get(objagg, opt_algo_type: OBJAGG_OPT_ALGO_SIMPLE_GREEDY); |
942 | if (IS_ERR(ptr: hints)) { |
943 | err = PTR_ERR(ptr: hints); |
944 | goto err_hints_get; |
945 | } |
946 | |
947 | pr_debug_hints_stats(objagg_hints: hints); |
948 | err = check_expect_hints_stats(objagg_hints: hints, expect_stats: &hints_case->expect_stats_hints, |
949 | errmsg: &errmsg); |
950 | if (err) { |
951 | pr_err("Hints stats: %s\n" , errmsg); |
952 | goto err_check_expect_hints_stats; |
953 | } |
954 | |
955 | objagg2 = objagg_create(ops: &delta_ops, hints, priv: &world2); |
956 | if (IS_ERR(ptr: objagg2)) |
957 | return PTR_ERR(ptr: objagg2); |
958 | |
959 | for (i = 0; i < hints_case->key_ids_count; i++) { |
960 | objagg_obj = world_obj_get(world: &world2, objagg: objagg2, |
961 | key_id: hints_case->key_ids[i]); |
962 | if (IS_ERR(ptr: objagg_obj)) { |
963 | err = PTR_ERR(ptr: objagg_obj); |
964 | goto err_world2_obj_get; |
965 | } |
966 | } |
967 | |
968 | pr_debug_stats(objagg: objagg2); |
969 | err = check_expect_stats(objagg: objagg2, expect_stats: &hints_case->expect_stats_hints, |
970 | errmsg: &errmsg); |
971 | if (err) { |
972 | pr_err("Stats2: %s\n" , errmsg); |
973 | goto err_check_expect_stats2; |
974 | } |
975 | |
976 | err = 0; |
977 | |
978 | err_check_expect_stats2: |
979 | err_world2_obj_get: |
980 | for (i--; i >= 0; i--) |
981 | world_obj_put(world: &world2, objagg, key_id: hints_case->key_ids[i]); |
982 | i = hints_case->key_ids_count; |
983 | objagg_destroy(objagg: objagg2); |
984 | err_check_expect_hints_stats: |
985 | objagg_hints_put(objagg_hints: hints); |
986 | err_hints_get: |
987 | err_check_expect_stats: |
988 | err_world_obj_get: |
989 | for (i--; i >= 0; i--) |
990 | world_obj_put(world: &world, objagg, key_id: hints_case->key_ids[i]); |
991 | |
992 | objagg_destroy(objagg); |
993 | return err; |
994 | } |
995 | static int test_hints(void) |
996 | { |
997 | return test_hints_case(hints_case: &hints_case); |
998 | } |
999 | |
1000 | static int __init test_objagg_init(void) |
1001 | { |
1002 | int err; |
1003 | |
1004 | err = test_nodelta(); |
1005 | if (err) |
1006 | return err; |
1007 | err = test_delta(); |
1008 | if (err) |
1009 | return err; |
1010 | return test_hints(); |
1011 | } |
1012 | |
1013 | static void __exit test_objagg_exit(void) |
1014 | { |
1015 | } |
1016 | |
1017 | module_init(test_objagg_init); |
1018 | module_exit(test_objagg_exit); |
1019 | MODULE_LICENSE("Dual BSD/GPL" ); |
1020 | MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>" ); |
1021 | MODULE_DESCRIPTION("Test module for objagg" ); |
1022 | |