Linux Audio

Check our new training course

Loading...
v5.14.15
   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
  12struct tokey {
  13	unsigned int id;
  14};
  15
  16#define NUM_KEYS 32
  17
  18static 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
  29struct 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
  37struct root {
  38	struct tokey key;
  39	char buf[BUF_LEN];
  40};
  41
  42struct delta {
  43	unsigned int key_id_diff;
  44};
  45
  46static 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, &key);
  56	if (IS_ERR(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
  71err_key_id_check:
  72	objagg_obj_put(objagg, objagg_obj);
  73	return ERR_PTR(err);
  74}
  75
  76static 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
  90static 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
  99static 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(-EINVAL);
 109
 110	delta = kzalloc(sizeof(*delta), GFP_KERNEL);
 111	if (!delta)
 112		return ERR_PTR(-ENOMEM);
 113	delta->key_id_diff = diff;
 114	world->delta_count++;
 115	return delta;
 116}
 117
 118static 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(delta);
 125}
 126
 127static 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(sizeof(*root), GFP_KERNEL);
 134	if (!root)
 135		return ERR_PTR(-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
 142static 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(root);
 149}
 150
 151static 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		prandom_bytes(world->next_root_buf,
 161			      sizeof(world->next_root_buf));
 162
 163	objagg_obj = world_obj_get(world, objagg, key_id);
 164	if (IS_ERR(objagg_obj)) {
 165		pr_err("Key %u: Failed to get object.\n", key_id);
 166		return PTR_ERR(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(world->next_root_buf, root->buf, 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
 197err_check_buf:
 198err_check_key_id:
 199err_check_root_count:
 200	objagg_obj_put(objagg, objagg_obj);
 201	return err;
 202}
 203
 204static 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
 226static 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(stats))
 233		return PTR_ERR(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(stats);
 241	return err;
 242}
 243
 244static 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(stats))
 252		return PTR_ERR(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
 275stats_put:
 276	objagg_stats_put(stats);
 277	return err;
 278}
 279
 280static bool delta_check_dummy(void *priv, const void *parent_obj,
 281			      const void *obj)
 282{
 283	return false;
 284}
 285
 286static void *delta_create_dummy(void *priv, void *parent_obj, void *obj)
 287{
 288	return ERR_PTR(-EOPNOTSUPP);
 289}
 290
 291static void delta_destroy_dummy(void *priv, void *delta_priv)
 292{
 293}
 294
 295static 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
 304static int test_nodelta(void)
 305{
 306	struct world world = {};
 307	struct objagg *objagg;
 308	int i;
 309	int err;
 310
 311	objagg = objagg_create(&nodelta_ops, NULL, &world);
 312	if (IS_ERR(objagg))
 313		return PTR_ERR(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, objagg, i, 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, objagg, i, 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, objagg, i, 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, objagg, i, 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
 357err_stats_nodelta:
 358err_obj_first_put:
 359err_obj_second_get:
 360	for (i--; i >= 0; i--)
 361		world_obj_put(&world, objagg, i);
 362
 363	i = NUM_KEYS;
 364err_obj_first_get:
 365err_obj_second_put:
 366	for (i--; i >= 0; i--)
 367		world_obj_put(&world, objagg, i);
 368err_stats_first_zero:
 369err_stats_second_zero:
 370	objagg_destroy(objagg);
 371	return err;
 372}
 373
 374static 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
 383enum action {
 384	ACTION_GET,
 385	ACTION_PUT,
 386};
 387
 388enum expect_delta {
 389	EXPECT_DELTA_SAME,
 390	EXPECT_DELTA_INC,
 391	EXPECT_DELTA_DEC,
 392};
 393
 394enum expect_root {
 395	EXPECT_ROOT_SAME,
 396	EXPECT_ROOT_INC,
 397	EXPECT_ROOT_DEC,
 398};
 399
 400struct expect_stats_info {
 401	struct objagg_obj_stats stats;
 402	bool is_root;
 403	unsigned int key_id;
 404};
 405
 406struct expect_stats {
 407	unsigned int info_count;
 408	struct expect_stats_info info[NUM_KEYS];
 409};
 410
 411struct 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
 431static 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
 561static 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
 626static 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
 640static int
 641check_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
 665static int
 666check_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(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
 679static 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->stats_info[i],
 688					      &expect_stats->info[pos], NULL);
 689		if (err)
 690			break;
 691		err = check_expect_stats_key_id(&stats->stats_info[i],
 692						&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->stats_info[i],
 698					      &expect_stats->info[pos], NULL);
 699		if (err)
 700			break;
 701		err = check_expect_stats_key_id(&stats->stats_info[i],
 702						&expect_stats->info[pos], NULL);
 703		if (!err)
 704			return 0;
 705	}
 706	return -EINVAL;
 707}
 708
 709static 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->stats_info[i],
 723					      &expect_stats->info[i], errmsg);
 724		if (err)
 725			return err;
 726		err = check_expect_stats_key_id(&stats->stats_info[i],
 727						&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, i);
 733			if (err)
 734				return err;
 735		}
 736	}
 737	return 0;
 738}
 739
 740static 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(stats)) {
 749		*errmsg = "objagg_stats_get() failed.";
 750		return PTR_ERR(stats);
 751	}
 752	err = __check_expect_stats(stats, expect_stats, errmsg);
 753	objagg_stats_put(stats);
 754	return err;
 755}
 756
 757static 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(objagg_obj))
 777			return PTR_ERR(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, &action_item->expect_stats, &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
 799errout:
 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, true);
 804	return err;
 805}
 806
 807static int test_delta(void)
 808{
 809	struct world world = {};
 810	struct objagg *objagg;
 811	int i;
 812	int err;
 813
 814	objagg = objagg_create(&delta_ops, NULL, &world);
 815	if (IS_ERR(objagg))
 816		return PTR_ERR(objagg);
 817
 818	for (i = 0; i < ARRAY_SIZE(action_items); i++) {
 819		err = test_delta_action_item(&world, objagg,
 820					     &action_items[i], false);
 821		if (err)
 822			goto err_do_action_item;
 823	}
 824
 825	objagg_destroy(objagg);
 826	return 0;
 827
 828err_do_action_item:
 829	for (i--; i >= 0; i--)
 830		test_delta_action_item(&world, objagg, &action_items[i], true);
 831
 832	objagg_destroy(objagg);
 833	return err;
 834}
 835
 836struct 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
 843static const unsigned int hints_case_key_ids[] = {
 844	1, 7, 3, 5, 3, 1, 30, 8, 8, 5, 6, 8,
 845};
 846
 847static 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
 860static 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
 872static 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(stats))
 878		return;
 879	__pr_debug_stats(stats);
 880	objagg_stats_put(stats);
 881}
 882
 883static 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(stats))
 889		return;
 890	__pr_debug_stats(stats);
 891	objagg_stats_put(stats);
 892}
 893
 894static 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(stats))
 903		return PTR_ERR(stats);
 904	err = __check_expect_stats(stats, expect_stats, errmsg);
 905	objagg_stats_put(stats);
 906	return err;
 907}
 908
 909static 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(&delta_ops, NULL, &world);
 922	if (IS_ERR(objagg))
 923		return PTR_ERR(objagg);
 924
 925	for (i = 0; i < hints_case->key_ids_count; i++) {
 926		objagg_obj = world_obj_get(&world, objagg,
 927					   hints_case->key_ids[i]);
 928		if (IS_ERR(objagg_obj)) {
 929			err = PTR_ERR(objagg_obj);
 930			goto err_world_obj_get;
 931		}
 932	}
 933
 934	pr_debug_stats(objagg);
 935	err = check_expect_stats(objagg, &hints_case->expect_stats, &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, OBJAGG_OPT_ALGO_SIMPLE_GREEDY);
 942	if (IS_ERR(hints)) {
 943		err = PTR_ERR(hints);
 944		goto err_hints_get;
 945	}
 946
 947	pr_debug_hints_stats(hints);
 948	err = check_expect_hints_stats(hints, &hints_case->expect_stats_hints,
 949				       &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(&delta_ops, hints, &world2);
 956	if (IS_ERR(objagg2))
 957		return PTR_ERR(objagg2);
 958
 959	for (i = 0; i < hints_case->key_ids_count; i++) {
 960		objagg_obj = world_obj_get(&world2, objagg2,
 961					   hints_case->key_ids[i]);
 962		if (IS_ERR(objagg_obj)) {
 963			err = PTR_ERR(objagg_obj);
 964			goto err_world2_obj_get;
 965		}
 966	}
 967
 968	pr_debug_stats(objagg2);
 969	err = check_expect_stats(objagg2, &hints_case->expect_stats_hints,
 970				 &errmsg);
 971	if (err) {
 972		pr_err("Stats2: %s\n", errmsg);
 973		goto err_check_expect_stats2;
 974	}
 975
 976	err = 0;
 977
 978err_check_expect_stats2:
 979err_world2_obj_get:
 980	for (i--; i >= 0; i--)
 981		world_obj_put(&world2, objagg, hints_case->key_ids[i]);
 982	i = hints_case->key_ids_count;
 983	objagg_destroy(objagg2);
 984err_check_expect_hints_stats:
 985	objagg_hints_put(hints);
 986err_hints_get:
 987err_check_expect_stats:
 988err_world_obj_get:
 989	for (i--; i >= 0; i--)
 990		world_obj_put(&world, objagg, hints_case->key_ids[i]);
 991
 992	objagg_destroy(objagg);
 993	return err;
 994}
 995static int test_hints(void)
 996{
 997	return test_hints_case(&hints_case);
 998}
 999
1000static 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
1013static void __exit test_objagg_exit(void)
1014{
1015}
1016
1017module_init(test_objagg_init);
1018module_exit(test_objagg_exit);
1019MODULE_LICENSE("Dual BSD/GPL");
1020MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
1021MODULE_DESCRIPTION("Test module for objagg");
v6.13.7
   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
  12struct tokey {
  13	unsigned int id;
  14};
  15
  16#define NUM_KEYS 32
  17
  18static 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
  29struct 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
  37struct root {
  38	struct tokey key;
  39	char buf[BUF_LEN];
  40};
  41
  42struct delta {
  43	unsigned int key_id_diff;
  44};
  45
  46static 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, &key);
  56	if (IS_ERR(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: Got 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
  71err_key_id_check:
  72	objagg_obj_put(objagg, objagg_obj);
  73	return ERR_PTR(err);
  74}
  75
  76static 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
  90static 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
  99static 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(-EINVAL);
 109
 110	delta = kzalloc(sizeof(*delta), GFP_KERNEL);
 111	if (!delta)
 112		return ERR_PTR(-ENOMEM);
 113	delta->key_id_diff = diff;
 114	world->delta_count++;
 115	return delta;
 116}
 117
 118static 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(delta);
 125}
 126
 127static 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(sizeof(*root), GFP_KERNEL);
 134	if (!root)
 135		return ERR_PTR(-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
 142static 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(root);
 149}
 150
 151static 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(world->next_root_buf,
 161			      sizeof(world->next_root_buf));
 162
 163	objagg_obj = world_obj_get(world, objagg, key_id);
 164	if (IS_ERR(objagg_obj)) {
 165		pr_err("Key %u: Failed to get object.\n", key_id);
 166		return PTR_ERR(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(world->next_root_buf, root->buf, 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
 197err_check_buf:
 198err_check_key_id:
 199err_check_root_count:
 200	objagg_obj_put(objagg, objagg_obj);
 201	return err;
 202}
 203
 204static 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
 226static 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(stats))
 233		return PTR_ERR(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(stats);
 241	return err;
 242}
 243
 244static 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(stats))
 252		return PTR_ERR(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
 275stats_put:
 276	objagg_stats_put(stats);
 277	return err;
 278}
 279
 280static bool delta_check_dummy(void *priv, const void *parent_obj,
 281			      const void *obj)
 282{
 283	return false;
 284}
 285
 286static void *delta_create_dummy(void *priv, void *parent_obj, void *obj)
 287{
 288	return ERR_PTR(-EOPNOTSUPP);
 289}
 290
 291static void delta_destroy_dummy(void *priv, void *delta_priv)
 292{
 293}
 294
 295static 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
 304static int test_nodelta(void)
 305{
 306	struct world world = {};
 307	struct objagg *objagg;
 308	int i;
 309	int err;
 310
 311	objagg = objagg_create(&nodelta_ops, NULL, &world);
 312	if (IS_ERR(objagg))
 313		return PTR_ERR(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, objagg, i, 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, objagg, i, 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, objagg, i, 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, objagg, i, 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
 357err_stats_nodelta:
 358err_obj_first_put:
 359err_obj_second_get:
 360	for (i--; i >= 0; i--)
 361		world_obj_put(&world, objagg, i);
 362
 363	i = NUM_KEYS;
 364err_obj_first_get:
 365err_obj_second_put:
 366	for (i--; i >= 0; i--)
 367		world_obj_put(&world, objagg, i);
 368err_stats_first_zero:
 369err_stats_second_zero:
 370	objagg_destroy(objagg);
 371	return err;
 372}
 373
 374static 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
 383enum action {
 384	ACTION_GET,
 385	ACTION_PUT,
 386};
 387
 388enum expect_delta {
 389	EXPECT_DELTA_SAME,
 390	EXPECT_DELTA_INC,
 391	EXPECT_DELTA_DEC,
 392};
 393
 394enum expect_root {
 395	EXPECT_ROOT_SAME,
 396	EXPECT_ROOT_INC,
 397	EXPECT_ROOT_DEC,
 398};
 399
 400struct expect_stats_info {
 401	struct objagg_obj_stats stats;
 402	bool is_root;
 403	unsigned int key_id;
 404};
 405
 406struct expect_stats {
 407	unsigned int info_count;
 408	struct expect_stats_info info[NUM_KEYS];
 409};
 410
 411struct 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
 431static 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
 561static 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
 626static 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
 640static int
 641check_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
 665static int
 666check_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(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
 679static 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->stats_info[i],
 688					      &expect_stats->info[pos], NULL);
 689		if (err)
 690			break;
 691		err = check_expect_stats_key_id(&stats->stats_info[i],
 692						&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->stats_info[i],
 698					      &expect_stats->info[pos], NULL);
 699		if (err)
 700			break;
 701		err = check_expect_stats_key_id(&stats->stats_info[i],
 702						&expect_stats->info[pos], NULL);
 703		if (!err)
 704			return 0;
 705	}
 706	return -EINVAL;
 707}
 708
 709static 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->stats_info[i],
 723					      &expect_stats->info[i], errmsg);
 724		if (err)
 725			return err;
 726		err = check_expect_stats_key_id(&stats->stats_info[i],
 727						&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, i);
 733			if (err)
 734				return err;
 735		}
 736	}
 737	return 0;
 738}
 739
 740static 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(stats)) {
 749		*errmsg = "objagg_stats_get() failed.";
 750		return PTR_ERR(stats);
 751	}
 752	err = __check_expect_stats(stats, expect_stats, errmsg);
 753	objagg_stats_put(stats);
 754	return err;
 755}
 756
 757static 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(objagg_obj))
 777			return PTR_ERR(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, &action_item->expect_stats, &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
 799errout:
 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, true);
 804	return err;
 805}
 806
 807static int test_delta(void)
 808{
 809	struct world world = {};
 810	struct objagg *objagg;
 811	int i;
 812	int err;
 813
 814	objagg = objagg_create(&delta_ops, NULL, &world);
 815	if (IS_ERR(objagg))
 816		return PTR_ERR(objagg);
 817
 818	for (i = 0; i < ARRAY_SIZE(action_items); i++) {
 819		err = test_delta_action_item(&world, objagg,
 820					     &action_items[i], false);
 821		if (err)
 822			goto err_do_action_item;
 823	}
 824
 825	objagg_destroy(objagg);
 826	return 0;
 827
 828err_do_action_item:
 829	for (i--; i >= 0; i--)
 830		test_delta_action_item(&world, objagg, &action_items[i], true);
 831
 832	objagg_destroy(objagg);
 833	return err;
 834}
 835
 836struct 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
 843static const unsigned int hints_case_key_ids[] = {
 844	1, 7, 3, 5, 3, 1, 30, 8, 8, 5, 6, 8,
 845};
 846
 847static 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
 860static 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
 872static 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(stats))
 878		return;
 879	__pr_debug_stats(stats);
 880	objagg_stats_put(stats);
 881}
 882
 883static 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(stats))
 889		return;
 890	__pr_debug_stats(stats);
 891	objagg_stats_put(stats);
 892}
 893
 894static 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(stats))
 903		return PTR_ERR(stats);
 904	err = __check_expect_stats(stats, expect_stats, errmsg);
 905	objagg_stats_put(stats);
 906	return err;
 907}
 908
 909static 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(&delta_ops, NULL, &world);
 922	if (IS_ERR(objagg))
 923		return PTR_ERR(objagg);
 924
 925	for (i = 0; i < hints_case->key_ids_count; i++) {
 926		objagg_obj = world_obj_get(&world, objagg,
 927					   hints_case->key_ids[i]);
 928		if (IS_ERR(objagg_obj)) {
 929			err = PTR_ERR(objagg_obj);
 930			goto err_world_obj_get;
 931		}
 932	}
 933
 934	pr_debug_stats(objagg);
 935	err = check_expect_stats(objagg, &hints_case->expect_stats, &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, OBJAGG_OPT_ALGO_SIMPLE_GREEDY);
 942	if (IS_ERR(hints)) {
 943		err = PTR_ERR(hints);
 944		goto err_hints_get;
 945	}
 946
 947	pr_debug_hints_stats(hints);
 948	err = check_expect_hints_stats(hints, &hints_case->expect_stats_hints,
 949				       &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(&delta_ops, hints, &world2);
 956	if (IS_ERR(objagg2))
 957		return PTR_ERR(objagg2);
 958
 959	for (i = 0; i < hints_case->key_ids_count; i++) {
 960		objagg_obj = world_obj_get(&world2, objagg2,
 961					   hints_case->key_ids[i]);
 962		if (IS_ERR(objagg_obj)) {
 963			err = PTR_ERR(objagg_obj);
 964			goto err_world2_obj_get;
 965		}
 966	}
 967
 968	pr_debug_stats(objagg2);
 969	err = check_expect_stats(objagg2, &hints_case->expect_stats_hints,
 970				 &errmsg);
 971	if (err) {
 972		pr_err("Stats2: %s\n", errmsg);
 973		goto err_check_expect_stats2;
 974	}
 975
 976	err = 0;
 977
 978err_check_expect_stats2:
 979err_world2_obj_get:
 980	for (i--; i >= 0; i--)
 981		world_obj_put(&world2, objagg, hints_case->key_ids[i]);
 982	i = hints_case->key_ids_count;
 983	objagg_destroy(objagg2);
 984err_check_expect_hints_stats:
 985	objagg_hints_put(hints);
 986err_hints_get:
 987err_check_expect_stats:
 988err_world_obj_get:
 989	for (i--; i >= 0; i--)
 990		world_obj_put(&world, objagg, hints_case->key_ids[i]);
 991
 992	objagg_destroy(objagg);
 993	return err;
 994}
 995static int test_hints(void)
 996{
 997	return test_hints_case(&hints_case);
 998}
 999
1000static 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
1013static void __exit test_objagg_exit(void)
1014{
1015}
1016
1017module_init(test_objagg_init);
1018module_exit(test_objagg_exit);
1019MODULE_LICENSE("Dual BSD/GPL");
1020MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
1021MODULE_DESCRIPTION("Test module for objagg");