xref: /openbmc/linux/lib/test_objagg.c (revision 197173db)
10a020d41SJiri Pirko // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
20a020d41SJiri Pirko /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
30a020d41SJiri Pirko 
40a020d41SJiri Pirko #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
50a020d41SJiri Pirko 
60a020d41SJiri Pirko #include <linux/kernel.h>
70a020d41SJiri Pirko #include <linux/module.h>
80a020d41SJiri Pirko #include <linux/slab.h>
90a020d41SJiri Pirko #include <linux/random.h>
100a020d41SJiri Pirko #include <linux/objagg.h>
110a020d41SJiri Pirko 
120a020d41SJiri Pirko struct tokey {
130a020d41SJiri Pirko 	unsigned int id;
140a020d41SJiri Pirko };
150a020d41SJiri Pirko 
160a020d41SJiri Pirko #define NUM_KEYS 32
170a020d41SJiri Pirko 
key_id_index(unsigned int key_id)180a020d41SJiri Pirko static int key_id_index(unsigned int key_id)
190a020d41SJiri Pirko {
200a020d41SJiri Pirko 	if (key_id >= NUM_KEYS) {
210a020d41SJiri Pirko 		WARN_ON(1);
220a020d41SJiri Pirko 		return 0;
230a020d41SJiri Pirko 	}
240a020d41SJiri Pirko 	return key_id;
250a020d41SJiri Pirko }
260a020d41SJiri Pirko 
270a020d41SJiri Pirko #define BUF_LEN 128
280a020d41SJiri Pirko 
290a020d41SJiri Pirko struct world {
300a020d41SJiri Pirko 	unsigned int root_count;
310a020d41SJiri Pirko 	unsigned int delta_count;
320a020d41SJiri Pirko 	char next_root_buf[BUF_LEN];
330a020d41SJiri Pirko 	struct objagg_obj *objagg_objs[NUM_KEYS];
340a020d41SJiri Pirko 	unsigned int key_refs[NUM_KEYS];
350a020d41SJiri Pirko };
360a020d41SJiri Pirko 
370a020d41SJiri Pirko struct root {
380a020d41SJiri Pirko 	struct tokey key;
390a020d41SJiri Pirko 	char buf[BUF_LEN];
400a020d41SJiri Pirko };
410a020d41SJiri Pirko 
420a020d41SJiri Pirko struct delta {
430a020d41SJiri Pirko 	unsigned int key_id_diff;
440a020d41SJiri Pirko };
450a020d41SJiri Pirko 
world_obj_get(struct world * world,struct objagg * objagg,unsigned int key_id)460a020d41SJiri Pirko static struct objagg_obj *world_obj_get(struct world *world,
470a020d41SJiri Pirko 					struct objagg *objagg,
480a020d41SJiri Pirko 					unsigned int key_id)
490a020d41SJiri Pirko {
500a020d41SJiri Pirko 	struct objagg_obj *objagg_obj;
510a020d41SJiri Pirko 	struct tokey key;
520a020d41SJiri Pirko 	int err;
530a020d41SJiri Pirko 
540a020d41SJiri Pirko 	key.id = key_id;
550a020d41SJiri Pirko 	objagg_obj = objagg_obj_get(objagg, &key);
560a020d41SJiri Pirko 	if (IS_ERR(objagg_obj)) {
570a020d41SJiri Pirko 		pr_err("Key %u: Failed to get object.\n", key_id);
580a020d41SJiri Pirko 		return objagg_obj;
590a020d41SJiri Pirko 	}
600a020d41SJiri Pirko 	if (!world->key_refs[key_id_index(key_id)]) {
610a020d41SJiri Pirko 		world->objagg_objs[key_id_index(key_id)] = objagg_obj;
620a020d41SJiri Pirko 	} else if (world->objagg_objs[key_id_index(key_id)] != objagg_obj) {
630a020d41SJiri Pirko 		pr_err("Key %u: God another object for the same key.\n",
640a020d41SJiri Pirko 		       key_id);
650a020d41SJiri Pirko 		err = -EINVAL;
660a020d41SJiri Pirko 		goto err_key_id_check;
670a020d41SJiri Pirko 	}
680a020d41SJiri Pirko 	world->key_refs[key_id_index(key_id)]++;
690a020d41SJiri Pirko 	return objagg_obj;
700a020d41SJiri Pirko 
710a020d41SJiri Pirko err_key_id_check:
720a020d41SJiri Pirko 	objagg_obj_put(objagg, objagg_obj);
730a020d41SJiri Pirko 	return ERR_PTR(err);
740a020d41SJiri Pirko }
750a020d41SJiri Pirko 
world_obj_put(struct world * world,struct objagg * objagg,unsigned int key_id)760a020d41SJiri Pirko static void world_obj_put(struct world *world, struct objagg *objagg,
770a020d41SJiri Pirko 			  unsigned int key_id)
780a020d41SJiri Pirko {
790a020d41SJiri Pirko 	struct objagg_obj *objagg_obj;
800a020d41SJiri Pirko 
810a020d41SJiri Pirko 	if (!world->key_refs[key_id_index(key_id)])
820a020d41SJiri Pirko 		return;
830a020d41SJiri Pirko 	objagg_obj = world->objagg_objs[key_id_index(key_id)];
840a020d41SJiri Pirko 	objagg_obj_put(objagg, objagg_obj);
850a020d41SJiri Pirko 	world->key_refs[key_id_index(key_id)]--;
860a020d41SJiri Pirko }
870a020d41SJiri Pirko 
880a020d41SJiri Pirko #define MAX_KEY_ID_DIFF 5
890a020d41SJiri Pirko 
delta_check(void * priv,const void * parent_obj,const void * obj)909069a381SJiri Pirko static bool delta_check(void *priv, const void *parent_obj, const void *obj)
919069a381SJiri Pirko {
929069a381SJiri Pirko 	const struct tokey *parent_key = parent_obj;
939069a381SJiri Pirko 	const struct tokey *key = obj;
949069a381SJiri Pirko 	int diff = key->id - parent_key->id;
959069a381SJiri Pirko 
969069a381SJiri Pirko 	return diff >= 0 && diff <= MAX_KEY_ID_DIFF;
979069a381SJiri Pirko }
989069a381SJiri Pirko 
delta_create(void * priv,void * parent_obj,void * obj)990a020d41SJiri Pirko static void *delta_create(void *priv, void *parent_obj, void *obj)
1000a020d41SJiri Pirko {
1010a020d41SJiri Pirko 	struct tokey *parent_key = parent_obj;
1020a020d41SJiri Pirko 	struct world *world = priv;
1030a020d41SJiri Pirko 	struct tokey *key = obj;
1040a020d41SJiri Pirko 	int diff = key->id - parent_key->id;
1050a020d41SJiri Pirko 	struct delta *delta;
1060a020d41SJiri Pirko 
1079069a381SJiri Pirko 	if (!delta_check(priv, parent_obj, obj))
1080a020d41SJiri Pirko 		return ERR_PTR(-EINVAL);
1090a020d41SJiri Pirko 
1100a020d41SJiri Pirko 	delta = kzalloc(sizeof(*delta), GFP_KERNEL);
1110a020d41SJiri Pirko 	if (!delta)
1120a020d41SJiri Pirko 		return ERR_PTR(-ENOMEM);
1130a020d41SJiri Pirko 	delta->key_id_diff = diff;
1140a020d41SJiri Pirko 	world->delta_count++;
1150a020d41SJiri Pirko 	return delta;
1160a020d41SJiri Pirko }
1170a020d41SJiri Pirko 
delta_destroy(void * priv,void * delta_priv)1180a020d41SJiri Pirko static void delta_destroy(void *priv, void *delta_priv)
1190a020d41SJiri Pirko {
1200a020d41SJiri Pirko 	struct delta *delta = delta_priv;
1210a020d41SJiri Pirko 	struct world *world = priv;
1220a020d41SJiri Pirko 
1230a020d41SJiri Pirko 	world->delta_count--;
1240a020d41SJiri Pirko 	kfree(delta);
1250a020d41SJiri Pirko }
1260a020d41SJiri Pirko 
root_create(void * priv,void * obj,unsigned int id)1279069a381SJiri Pirko static void *root_create(void *priv, void *obj, unsigned int id)
1280a020d41SJiri Pirko {
1290a020d41SJiri Pirko 	struct world *world = priv;
1300a020d41SJiri Pirko 	struct tokey *key = obj;
1310a020d41SJiri Pirko 	struct root *root;
1320a020d41SJiri Pirko 
1330a020d41SJiri Pirko 	root = kzalloc(sizeof(*root), GFP_KERNEL);
1340a020d41SJiri Pirko 	if (!root)
1350a020d41SJiri Pirko 		return ERR_PTR(-ENOMEM);
1360a020d41SJiri Pirko 	memcpy(&root->key, key, sizeof(root->key));
1370a020d41SJiri Pirko 	memcpy(root->buf, world->next_root_buf, sizeof(root->buf));
1380a020d41SJiri Pirko 	world->root_count++;
1390a020d41SJiri Pirko 	return root;
1400a020d41SJiri Pirko }
1410a020d41SJiri Pirko 
root_destroy(void * priv,void * root_priv)1420a020d41SJiri Pirko static void root_destroy(void *priv, void *root_priv)
1430a020d41SJiri Pirko {
1440a020d41SJiri Pirko 	struct root *root = root_priv;
1450a020d41SJiri Pirko 	struct world *world = priv;
1460a020d41SJiri Pirko 
1470a020d41SJiri Pirko 	world->root_count--;
1480a020d41SJiri Pirko 	kfree(root);
1490a020d41SJiri Pirko }
1500a020d41SJiri Pirko 
test_nodelta_obj_get(struct world * world,struct objagg * objagg,unsigned int key_id,bool should_create_root)1510a020d41SJiri Pirko static int test_nodelta_obj_get(struct world *world, struct objagg *objagg,
1520a020d41SJiri Pirko 				unsigned int key_id, bool should_create_root)
1530a020d41SJiri Pirko {
1540a020d41SJiri Pirko 	unsigned int orig_root_count = world->root_count;
1550a020d41SJiri Pirko 	struct objagg_obj *objagg_obj;
1560a020d41SJiri Pirko 	const struct root *root;
1570a020d41SJiri Pirko 	int err;
1580a020d41SJiri Pirko 
1590a020d41SJiri Pirko 	if (should_create_root)
160*197173dbSJason A. Donenfeld 		get_random_bytes(world->next_root_buf,
1610a020d41SJiri Pirko 			      sizeof(world->next_root_buf));
1620a020d41SJiri Pirko 
1630a020d41SJiri Pirko 	objagg_obj = world_obj_get(world, objagg, key_id);
1640a020d41SJiri Pirko 	if (IS_ERR(objagg_obj)) {
1650a020d41SJiri Pirko 		pr_err("Key %u: Failed to get object.\n", key_id);
1660a020d41SJiri Pirko 		return PTR_ERR(objagg_obj);
1670a020d41SJiri Pirko 	}
1680a020d41SJiri Pirko 	if (should_create_root) {
1690a020d41SJiri Pirko 		if (world->root_count != orig_root_count + 1) {
1700a020d41SJiri Pirko 			pr_err("Key %u: Root was not created\n", key_id);
1710a020d41SJiri Pirko 			err = -EINVAL;
1720a020d41SJiri Pirko 			goto err_check_root_count;
1730a020d41SJiri Pirko 		}
1740a020d41SJiri Pirko 	} else {
1750a020d41SJiri Pirko 		if (world->root_count != orig_root_count) {
1760a020d41SJiri Pirko 			pr_err("Key %u: Root was incorrectly created\n",
1770a020d41SJiri Pirko 			       key_id);
1780a020d41SJiri Pirko 			err = -EINVAL;
1790a020d41SJiri Pirko 			goto err_check_root_count;
1800a020d41SJiri Pirko 		}
1810a020d41SJiri Pirko 	}
1820a020d41SJiri Pirko 	root = objagg_obj_root_priv(objagg_obj);
1830a020d41SJiri Pirko 	if (root->key.id != key_id) {
1840a020d41SJiri Pirko 		pr_err("Key %u: Root has unexpected key id\n", key_id);
1850a020d41SJiri Pirko 		err = -EINVAL;
1860a020d41SJiri Pirko 		goto err_check_key_id;
1870a020d41SJiri Pirko 	}
1880a020d41SJiri Pirko 	if (should_create_root &&
1890a020d41SJiri Pirko 	    memcmp(world->next_root_buf, root->buf, sizeof(root->buf))) {
1900a020d41SJiri Pirko 		pr_err("Key %u: Buffer does not match the expected content\n",
1910a020d41SJiri Pirko 		       key_id);
1920a020d41SJiri Pirko 		err = -EINVAL;
1930a020d41SJiri Pirko 		goto err_check_buf;
1940a020d41SJiri Pirko 	}
1950a020d41SJiri Pirko 	return 0;
1960a020d41SJiri Pirko 
1970a020d41SJiri Pirko err_check_buf:
1980a020d41SJiri Pirko err_check_key_id:
1990a020d41SJiri Pirko err_check_root_count:
2000a020d41SJiri Pirko 	objagg_obj_put(objagg, objagg_obj);
2010a020d41SJiri Pirko 	return err;
2020a020d41SJiri Pirko }
2030a020d41SJiri Pirko 
test_nodelta_obj_put(struct world * world,struct objagg * objagg,unsigned int key_id,bool should_destroy_root)2040a020d41SJiri Pirko static int test_nodelta_obj_put(struct world *world, struct objagg *objagg,
2050a020d41SJiri Pirko 				unsigned int key_id, bool should_destroy_root)
2060a020d41SJiri Pirko {
2070a020d41SJiri Pirko 	unsigned int orig_root_count = world->root_count;
2080a020d41SJiri Pirko 
2090a020d41SJiri Pirko 	world_obj_put(world, objagg, key_id);
2100a020d41SJiri Pirko 
2110a020d41SJiri Pirko 	if (should_destroy_root) {
2120a020d41SJiri Pirko 		if (world->root_count != orig_root_count - 1) {
2130a020d41SJiri Pirko 			pr_err("Key %u: Root was not destroyed\n", key_id);
2140a020d41SJiri Pirko 			return -EINVAL;
2150a020d41SJiri Pirko 		}
2160a020d41SJiri Pirko 	} else {
2170a020d41SJiri Pirko 		if (world->root_count != orig_root_count) {
2180a020d41SJiri Pirko 			pr_err("Key %u: Root was incorrectly destroyed\n",
2190a020d41SJiri Pirko 			       key_id);
2200a020d41SJiri Pirko 			return -EINVAL;
2210a020d41SJiri Pirko 		}
2220a020d41SJiri Pirko 	}
2230a020d41SJiri Pirko 	return 0;
2240a020d41SJiri Pirko }
2250a020d41SJiri Pirko 
check_stats_zero(struct objagg * objagg)2260a020d41SJiri Pirko static int check_stats_zero(struct objagg *objagg)
2270a020d41SJiri Pirko {
2280a020d41SJiri Pirko 	const struct objagg_stats *stats;
2290a020d41SJiri Pirko 	int err = 0;
2300a020d41SJiri Pirko 
2310a020d41SJiri Pirko 	stats = objagg_stats_get(objagg);
2320a020d41SJiri Pirko 	if (IS_ERR(stats))
2330a020d41SJiri Pirko 		return PTR_ERR(stats);
2340a020d41SJiri Pirko 
2350a020d41SJiri Pirko 	if (stats->stats_info_count != 0) {
2360a020d41SJiri Pirko 		pr_err("Stats: Object count is not zero while it should be\n");
2370a020d41SJiri Pirko 		err = -EINVAL;
2380a020d41SJiri Pirko 	}
2390a020d41SJiri Pirko 
2400a020d41SJiri Pirko 	objagg_stats_put(stats);
2410a020d41SJiri Pirko 	return err;
2420a020d41SJiri Pirko }
2430a020d41SJiri Pirko 
check_stats_nodelta(struct objagg * objagg)2440a020d41SJiri Pirko static int check_stats_nodelta(struct objagg *objagg)
2450a020d41SJiri Pirko {
2460a020d41SJiri Pirko 	const struct objagg_stats *stats;
2470a020d41SJiri Pirko 	int i;
2480a020d41SJiri Pirko 	int err;
2490a020d41SJiri Pirko 
2500a020d41SJiri Pirko 	stats = objagg_stats_get(objagg);
2510a020d41SJiri Pirko 	if (IS_ERR(stats))
2520a020d41SJiri Pirko 		return PTR_ERR(stats);
2530a020d41SJiri Pirko 
2540a020d41SJiri Pirko 	if (stats->stats_info_count != NUM_KEYS) {
2550a020d41SJiri Pirko 		pr_err("Stats: Unexpected object count (%u expected, %u returned)\n",
2560a020d41SJiri Pirko 		       NUM_KEYS, stats->stats_info_count);
2570a020d41SJiri Pirko 		err = -EINVAL;
2580a020d41SJiri Pirko 		goto stats_put;
2590a020d41SJiri Pirko 	}
2600a020d41SJiri Pirko 
2610a020d41SJiri Pirko 	for (i = 0; i < stats->stats_info_count; i++) {
2620a020d41SJiri Pirko 		if (stats->stats_info[i].stats.user_count != 2) {
2630a020d41SJiri Pirko 			pr_err("Stats: incorrect user count\n");
2640a020d41SJiri Pirko 			err = -EINVAL;
2650a020d41SJiri Pirko 			goto stats_put;
2660a020d41SJiri Pirko 		}
2670a020d41SJiri Pirko 		if (stats->stats_info[i].stats.delta_user_count != 2) {
2680a020d41SJiri Pirko 			pr_err("Stats: incorrect delta user count\n");
2690a020d41SJiri Pirko 			err = -EINVAL;
2700a020d41SJiri Pirko 			goto stats_put;
2710a020d41SJiri Pirko 		}
2720a020d41SJiri Pirko 	}
2730a020d41SJiri Pirko 	err = 0;
2740a020d41SJiri Pirko 
2750a020d41SJiri Pirko stats_put:
2760a020d41SJiri Pirko 	objagg_stats_put(stats);
2770a020d41SJiri Pirko 	return err;
2780a020d41SJiri Pirko }
2790a020d41SJiri Pirko 
delta_check_dummy(void * priv,const void * parent_obj,const void * obj)2809069a381SJiri Pirko static bool delta_check_dummy(void *priv, const void *parent_obj,
2819069a381SJiri Pirko 			      const void *obj)
2829069a381SJiri Pirko {
2839069a381SJiri Pirko 	return false;
2849069a381SJiri Pirko }
2859069a381SJiri Pirko 
delta_create_dummy(void * priv,void * parent_obj,void * obj)2860a020d41SJiri Pirko static void *delta_create_dummy(void *priv, void *parent_obj, void *obj)
2870a020d41SJiri Pirko {
2880a020d41SJiri Pirko 	return ERR_PTR(-EOPNOTSUPP);
2890a020d41SJiri Pirko }
2900a020d41SJiri Pirko 
delta_destroy_dummy(void * priv,void * delta_priv)2910a020d41SJiri Pirko static void delta_destroy_dummy(void *priv, void *delta_priv)
2920a020d41SJiri Pirko {
2930a020d41SJiri Pirko }
2940a020d41SJiri Pirko 
2950a020d41SJiri Pirko static const struct objagg_ops nodelta_ops = {
2960a020d41SJiri Pirko 	.obj_size = sizeof(struct tokey),
2979069a381SJiri Pirko 	.delta_check = delta_check_dummy,
2980a020d41SJiri Pirko 	.delta_create = delta_create_dummy,
2990a020d41SJiri Pirko 	.delta_destroy = delta_destroy_dummy,
3000a020d41SJiri Pirko 	.root_create = root_create,
3010a020d41SJiri Pirko 	.root_destroy = root_destroy,
3020a020d41SJiri Pirko };
3030a020d41SJiri Pirko 
test_nodelta(void)3040a020d41SJiri Pirko static int test_nodelta(void)
3050a020d41SJiri Pirko {
3060a020d41SJiri Pirko 	struct world world = {};
3070a020d41SJiri Pirko 	struct objagg *objagg;
3080a020d41SJiri Pirko 	int i;
3090a020d41SJiri Pirko 	int err;
3100a020d41SJiri Pirko 
3119069a381SJiri Pirko 	objagg = objagg_create(&nodelta_ops, NULL, &world);
3120a020d41SJiri Pirko 	if (IS_ERR(objagg))
3130a020d41SJiri Pirko 		return PTR_ERR(objagg);
3140a020d41SJiri Pirko 
3150a020d41SJiri Pirko 	err = check_stats_zero(objagg);
3160a020d41SJiri Pirko 	if (err)
3170a020d41SJiri Pirko 		goto err_stats_first_zero;
3180a020d41SJiri Pirko 
3190a020d41SJiri Pirko 	/* First round of gets, the root objects should be created */
3200a020d41SJiri Pirko 	for (i = 0; i < NUM_KEYS; i++) {
3210a020d41SJiri Pirko 		err = test_nodelta_obj_get(&world, objagg, i, true);
3220a020d41SJiri Pirko 		if (err)
3230a020d41SJiri Pirko 			goto err_obj_first_get;
3240a020d41SJiri Pirko 	}
3250a020d41SJiri Pirko 
3260a020d41SJiri Pirko 	/* Do the second round of gets, all roots are already created,
3270a020d41SJiri Pirko 	 * make sure that no new root is created
3280a020d41SJiri Pirko 	 */
3290a020d41SJiri Pirko 	for (i = 0; i < NUM_KEYS; i++) {
3300a020d41SJiri Pirko 		err = test_nodelta_obj_get(&world, objagg, i, false);
3310a020d41SJiri Pirko 		if (err)
3320a020d41SJiri Pirko 			goto err_obj_second_get;
3330a020d41SJiri Pirko 	}
3340a020d41SJiri Pirko 
3350a020d41SJiri Pirko 	err = check_stats_nodelta(objagg);
3360a020d41SJiri Pirko 	if (err)
3370a020d41SJiri Pirko 		goto err_stats_nodelta;
3380a020d41SJiri Pirko 
3390a020d41SJiri Pirko 	for (i = NUM_KEYS - 1; i >= 0; i--) {
3400a020d41SJiri Pirko 		err = test_nodelta_obj_put(&world, objagg, i, false);
3410a020d41SJiri Pirko 		if (err)
3420a020d41SJiri Pirko 			goto err_obj_first_put;
3430a020d41SJiri Pirko 	}
3440a020d41SJiri Pirko 	for (i = NUM_KEYS - 1; i >= 0; i--) {
3450a020d41SJiri Pirko 		err = test_nodelta_obj_put(&world, objagg, i, true);
3460a020d41SJiri Pirko 		if (err)
3470a020d41SJiri Pirko 			goto err_obj_second_put;
3480a020d41SJiri Pirko 	}
3490a020d41SJiri Pirko 
3500a020d41SJiri Pirko 	err = check_stats_zero(objagg);
3510a020d41SJiri Pirko 	if (err)
3520a020d41SJiri Pirko 		goto err_stats_second_zero;
3530a020d41SJiri Pirko 
3540a020d41SJiri Pirko 	objagg_destroy(objagg);
3550a020d41SJiri Pirko 	return 0;
3560a020d41SJiri Pirko 
3570a020d41SJiri Pirko err_stats_nodelta:
3580a020d41SJiri Pirko err_obj_first_put:
3590a020d41SJiri Pirko err_obj_second_get:
3600a020d41SJiri Pirko 	for (i--; i >= 0; i--)
3610a020d41SJiri Pirko 		world_obj_put(&world, objagg, i);
3620a020d41SJiri Pirko 
3630a020d41SJiri Pirko 	i = NUM_KEYS;
3640a020d41SJiri Pirko err_obj_first_get:
3650a020d41SJiri Pirko err_obj_second_put:
3660a020d41SJiri Pirko 	for (i--; i >= 0; i--)
3670a020d41SJiri Pirko 		world_obj_put(&world, objagg, i);
3680a020d41SJiri Pirko err_stats_first_zero:
3690a020d41SJiri Pirko err_stats_second_zero:
3700a020d41SJiri Pirko 	objagg_destroy(objagg);
3710a020d41SJiri Pirko 	return err;
3720a020d41SJiri Pirko }
3730a020d41SJiri Pirko 
3740a020d41SJiri Pirko static const struct objagg_ops delta_ops = {
3750a020d41SJiri Pirko 	.obj_size = sizeof(struct tokey),
3769069a381SJiri Pirko 	.delta_check = delta_check,
3770a020d41SJiri Pirko 	.delta_create = delta_create,
3780a020d41SJiri Pirko 	.delta_destroy = delta_destroy,
3790a020d41SJiri Pirko 	.root_create = root_create,
3800a020d41SJiri Pirko 	.root_destroy = root_destroy,
3810a020d41SJiri Pirko };
3820a020d41SJiri Pirko 
3830a020d41SJiri Pirko enum action {
3840a020d41SJiri Pirko 	ACTION_GET,
3850a020d41SJiri Pirko 	ACTION_PUT,
3860a020d41SJiri Pirko };
3870a020d41SJiri Pirko 
3880a020d41SJiri Pirko enum expect_delta {
3890a020d41SJiri Pirko 	EXPECT_DELTA_SAME,
3900a020d41SJiri Pirko 	EXPECT_DELTA_INC,
3910a020d41SJiri Pirko 	EXPECT_DELTA_DEC,
3920a020d41SJiri Pirko };
3930a020d41SJiri Pirko 
3940a020d41SJiri Pirko enum expect_root {
3950a020d41SJiri Pirko 	EXPECT_ROOT_SAME,
3960a020d41SJiri Pirko 	EXPECT_ROOT_INC,
3970a020d41SJiri Pirko 	EXPECT_ROOT_DEC,
3980a020d41SJiri Pirko };
3990a020d41SJiri Pirko 
4000a020d41SJiri Pirko struct expect_stats_info {
4010a020d41SJiri Pirko 	struct objagg_obj_stats stats;
4020a020d41SJiri Pirko 	bool is_root;
4030a020d41SJiri Pirko 	unsigned int key_id;
4040a020d41SJiri Pirko };
4050a020d41SJiri Pirko 
4060a020d41SJiri Pirko struct expect_stats {
4070a020d41SJiri Pirko 	unsigned int info_count;
4080a020d41SJiri Pirko 	struct expect_stats_info info[NUM_KEYS];
4090a020d41SJiri Pirko };
4100a020d41SJiri Pirko 
4110a020d41SJiri Pirko struct action_item {
4120a020d41SJiri Pirko 	unsigned int key_id;
4130a020d41SJiri Pirko 	enum action action;
4140a020d41SJiri Pirko 	enum expect_delta expect_delta;
4150a020d41SJiri Pirko 	enum expect_root expect_root;
4160a020d41SJiri Pirko 	struct expect_stats expect_stats;
4170a020d41SJiri Pirko };
4180a020d41SJiri Pirko 
4190a020d41SJiri Pirko #define EXPECT_STATS(count, ...)		\
4200a020d41SJiri Pirko {						\
4210a020d41SJiri Pirko 	.info_count = count,			\
4220a020d41SJiri Pirko 	.info = { __VA_ARGS__ }			\
4230a020d41SJiri Pirko }
4240a020d41SJiri Pirko 
4250a020d41SJiri Pirko #define ROOT(key_id, user_count, delta_user_count)	\
4260a020d41SJiri Pirko 	{{user_count, delta_user_count}, true, key_id}
4270a020d41SJiri Pirko 
4280a020d41SJiri Pirko #define DELTA(key_id, user_count)			\
4290a020d41SJiri Pirko 	{{user_count, user_count}, false, key_id}
4300a020d41SJiri Pirko 
4310a020d41SJiri Pirko static const struct action_item action_items[] = {
4320a020d41SJiri Pirko 	{
4330a020d41SJiri Pirko 		1, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_INC,
4340a020d41SJiri Pirko 		EXPECT_STATS(1, ROOT(1, 1, 1)),
4350a020d41SJiri Pirko 	},	/* r: 1			d: */
4360a020d41SJiri Pirko 	{
4370a020d41SJiri Pirko 		7, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_INC,
4380a020d41SJiri Pirko 		EXPECT_STATS(2, ROOT(1, 1, 1), ROOT(7, 1, 1)),
4390a020d41SJiri Pirko 	},	/* r: 1, 7		d: */
4400a020d41SJiri Pirko 	{
4410a020d41SJiri Pirko 		3, ACTION_GET, EXPECT_DELTA_INC, EXPECT_ROOT_SAME,
4420a020d41SJiri Pirko 		EXPECT_STATS(3, ROOT(1, 1, 2), ROOT(7, 1, 1),
4430a020d41SJiri Pirko 				DELTA(3, 1)),
4440a020d41SJiri Pirko 	},	/* r: 1, 7		d: 3^1 */
4450a020d41SJiri Pirko 	{
4460a020d41SJiri Pirko 		5, ACTION_GET, EXPECT_DELTA_INC, EXPECT_ROOT_SAME,
4470a020d41SJiri Pirko 		EXPECT_STATS(4, ROOT(1, 1, 3), ROOT(7, 1, 1),
4480a020d41SJiri Pirko 				DELTA(3, 1), DELTA(5, 1)),
4490a020d41SJiri Pirko 	},	/* r: 1, 7		d: 3^1, 5^1 */
4500a020d41SJiri Pirko 	{
4510a020d41SJiri Pirko 		3, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME,
4520a020d41SJiri Pirko 		EXPECT_STATS(4, ROOT(1, 1, 4), ROOT(7, 1, 1),
4530a020d41SJiri Pirko 				DELTA(3, 2), DELTA(5, 1)),
4540a020d41SJiri Pirko 	},	/* r: 1, 7		d: 3^1, 3^1, 5^1 */
4550a020d41SJiri Pirko 	{
4560a020d41SJiri Pirko 		1, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME,
4570a020d41SJiri Pirko 		EXPECT_STATS(4, ROOT(1, 2, 5), ROOT(7, 1, 1),
4580a020d41SJiri Pirko 				DELTA(3, 2), DELTA(5, 1)),
4590a020d41SJiri Pirko 	},	/* r: 1, 1, 7		d: 3^1, 3^1, 5^1 */
4600a020d41SJiri Pirko 	{
4610a020d41SJiri Pirko 		30, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_INC,
4620a020d41SJiri Pirko 		EXPECT_STATS(5, ROOT(1, 2, 5), ROOT(7, 1, 1), ROOT(30, 1, 1),
4630a020d41SJiri Pirko 				DELTA(3, 2), DELTA(5, 1)),
4640a020d41SJiri Pirko 	},	/* r: 1, 1, 7, 30	d: 3^1, 3^1, 5^1 */
4650a020d41SJiri Pirko 	{
4660a020d41SJiri Pirko 		8, ACTION_GET, EXPECT_DELTA_INC, EXPECT_ROOT_SAME,
4670a020d41SJiri Pirko 		EXPECT_STATS(6, ROOT(1, 2, 5), ROOT(7, 1, 2), ROOT(30, 1, 1),
4680a020d41SJiri Pirko 				DELTA(3, 2), DELTA(5, 1), DELTA(8, 1)),
4690a020d41SJiri Pirko 	},	/* r: 1, 1, 7, 30	d: 3^1, 3^1, 5^1, 8^7 */
4700a020d41SJiri Pirko 	{
4710a020d41SJiri Pirko 		8, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME,
4720a020d41SJiri Pirko 		EXPECT_STATS(6, ROOT(1, 2, 5), ROOT(7, 1, 3), ROOT(30, 1, 1),
4730a020d41SJiri Pirko 				DELTA(3, 2), DELTA(8, 2), DELTA(5, 1)),
4740a020d41SJiri Pirko 	},	/* r: 1, 1, 7, 30	d: 3^1, 3^1, 5^1, 8^7, 8^7 */
4750a020d41SJiri Pirko 	{
4760a020d41SJiri Pirko 		3, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME,
4770a020d41SJiri Pirko 		EXPECT_STATS(6, ROOT(1, 2, 4), ROOT(7, 1, 3), ROOT(30, 1, 1),
4780a020d41SJiri Pirko 				DELTA(8, 2), DELTA(3, 1), DELTA(5, 1)),
4790a020d41SJiri Pirko 	},	/* r: 1, 1, 7, 30	d: 3^1, 5^1, 8^7, 8^7 */
4800a020d41SJiri Pirko 	{
4810a020d41SJiri Pirko 		3, ACTION_PUT, EXPECT_DELTA_DEC, EXPECT_ROOT_SAME,
4820a020d41SJiri Pirko 		EXPECT_STATS(5, ROOT(1, 2, 3), ROOT(7, 1, 3), ROOT(30, 1, 1),
4830a020d41SJiri Pirko 				DELTA(8, 2), DELTA(5, 1)),
4840a020d41SJiri Pirko 	},	/* r: 1, 1, 7, 30	d: 5^1, 8^7, 8^7 */
4850a020d41SJiri Pirko 	{
4860a020d41SJiri Pirko 		1, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME,
4870a020d41SJiri Pirko 		EXPECT_STATS(5, ROOT(7, 1, 3), ROOT(1, 1, 2), ROOT(30, 1, 1),
4880a020d41SJiri Pirko 				DELTA(8, 2), DELTA(5, 1)),
4890a020d41SJiri Pirko 	},	/* r: 1, 7, 30		d: 5^1, 8^7, 8^7 */
4900a020d41SJiri Pirko 	{
4910a020d41SJiri Pirko 		1, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME,
4920a020d41SJiri Pirko 		EXPECT_STATS(5, ROOT(7, 1, 3), ROOT(30, 1, 1), ROOT(1, 0, 1),
4930a020d41SJiri Pirko 				DELTA(8, 2), DELTA(5, 1)),
4940a020d41SJiri Pirko 	},	/* r: 7, 30		d: 5^1, 8^7, 8^7 */
4950a020d41SJiri Pirko 	{
4960a020d41SJiri Pirko 		5, ACTION_PUT, EXPECT_DELTA_DEC, EXPECT_ROOT_DEC,
4970a020d41SJiri Pirko 		EXPECT_STATS(3, ROOT(7, 1, 3), ROOT(30, 1, 1),
4980a020d41SJiri Pirko 				DELTA(8, 2)),
4990a020d41SJiri Pirko 	},	/* r: 7, 30		d: 8^7, 8^7 */
5000a020d41SJiri Pirko 	{
5010a020d41SJiri Pirko 		5, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_INC,
5020a020d41SJiri Pirko 		EXPECT_STATS(4, ROOT(7, 1, 3), ROOT(30, 1, 1), ROOT(5, 1, 1),
5030a020d41SJiri Pirko 				DELTA(8, 2)),
5040a020d41SJiri Pirko 	},	/* r: 7, 30, 5		d: 8^7, 8^7 */
5050a020d41SJiri Pirko 	{
5060a020d41SJiri Pirko 		6, ACTION_GET, EXPECT_DELTA_INC, EXPECT_ROOT_SAME,
5070a020d41SJiri Pirko 		EXPECT_STATS(5, ROOT(7, 1, 3), ROOT(5, 1, 2), ROOT(30, 1, 1),
5080a020d41SJiri Pirko 				DELTA(8, 2), DELTA(6, 1)),
5090a020d41SJiri Pirko 	},	/* r: 7, 30, 5		d: 8^7, 8^7, 6^5 */
5100a020d41SJiri Pirko 	{
5110a020d41SJiri Pirko 		8, ACTION_GET, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME,
5120a020d41SJiri Pirko 		EXPECT_STATS(5, ROOT(7, 1, 4), ROOT(5, 1, 2), ROOT(30, 1, 1),
5130a020d41SJiri Pirko 				DELTA(8, 3), DELTA(6, 1)),
5140a020d41SJiri Pirko 	},	/* r: 7, 30, 5		d: 8^7, 8^7, 8^7, 6^5 */
5150a020d41SJiri Pirko 	{
5160a020d41SJiri Pirko 		8, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME,
5170a020d41SJiri Pirko 		EXPECT_STATS(5, ROOT(7, 1, 3), ROOT(5, 1, 2), ROOT(30, 1, 1),
5180a020d41SJiri Pirko 				DELTA(8, 2), DELTA(6, 1)),
5190a020d41SJiri Pirko 	},	/* r: 7, 30, 5		d: 8^7, 8^7, 6^5 */
5200a020d41SJiri Pirko 	{
5210a020d41SJiri Pirko 		8, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME,
5220a020d41SJiri Pirko 		EXPECT_STATS(5, ROOT(7, 1, 2), ROOT(5, 1, 2), ROOT(30, 1, 1),
5230a020d41SJiri Pirko 				DELTA(8, 1), DELTA(6, 1)),
5240a020d41SJiri Pirko 	},	/* r: 7, 30, 5		d: 8^7, 6^5 */
5250a020d41SJiri Pirko 	{
5260a020d41SJiri Pirko 		8, ACTION_PUT, EXPECT_DELTA_DEC, EXPECT_ROOT_SAME,
5270a020d41SJiri Pirko 		EXPECT_STATS(4, ROOT(5, 1, 2), ROOT(7, 1, 1), ROOT(30, 1, 1),
5280a020d41SJiri Pirko 				DELTA(6, 1)),
5290a020d41SJiri Pirko 	},	/* r: 7, 30, 5		d: 6^5 */
5300a020d41SJiri Pirko 	{
5310a020d41SJiri Pirko 		8, ACTION_GET, EXPECT_DELTA_INC, EXPECT_ROOT_SAME,
5320a020d41SJiri Pirko 		EXPECT_STATS(5, ROOT(5, 1, 3), ROOT(7, 1, 1), ROOT(30, 1, 1),
5330a020d41SJiri Pirko 				DELTA(6, 1), DELTA(8, 1)),
5340a020d41SJiri Pirko 	},	/* r: 7, 30, 5		d: 6^5, 8^5 */
5350a020d41SJiri Pirko 	{
5360a020d41SJiri Pirko 		7, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_DEC,
5370a020d41SJiri Pirko 		EXPECT_STATS(4, ROOT(5, 1, 3), ROOT(30, 1, 1),
5380a020d41SJiri Pirko 				DELTA(6, 1), DELTA(8, 1)),
5390a020d41SJiri Pirko 	},	/* r: 30, 5		d: 6^5, 8^5 */
5400a020d41SJiri Pirko 	{
5410a020d41SJiri Pirko 		30, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_DEC,
5420a020d41SJiri Pirko 		EXPECT_STATS(3, ROOT(5, 1, 3),
5430a020d41SJiri Pirko 				DELTA(6, 1), DELTA(8, 1)),
5440a020d41SJiri Pirko 	},	/* r: 5			d: 6^5, 8^5 */
5450a020d41SJiri Pirko 	{
5460a020d41SJiri Pirko 		5, ACTION_PUT, EXPECT_DELTA_SAME, EXPECT_ROOT_SAME,
5470a020d41SJiri Pirko 		EXPECT_STATS(3, ROOT(5, 0, 2),
5480a020d41SJiri Pirko 				DELTA(6, 1), DELTA(8, 1)),
5490a020d41SJiri Pirko 	},	/* r:			d: 6^5, 8^5 */
5500a020d41SJiri Pirko 	{
5510a020d41SJiri Pirko 		6, ACTION_PUT, EXPECT_DELTA_DEC, EXPECT_ROOT_SAME,
5520a020d41SJiri Pirko 		EXPECT_STATS(2, ROOT(5, 0, 1),
5530a020d41SJiri Pirko 				DELTA(8, 1)),
5540a020d41SJiri Pirko 	},	/* r:			d: 6^5 */
5550a020d41SJiri Pirko 	{
5560a020d41SJiri Pirko 		8, ACTION_PUT, EXPECT_DELTA_DEC, EXPECT_ROOT_DEC,
5570a020d41SJiri Pirko 		EXPECT_STATS(0, ),
5580a020d41SJiri Pirko 	},	/* r:			d: */
5590a020d41SJiri Pirko };
5600a020d41SJiri Pirko 
check_expect(struct world * world,const struct action_item * action_item,unsigned int orig_delta_count,unsigned int orig_root_count)5610a020d41SJiri Pirko static int check_expect(struct world *world,
5620a020d41SJiri Pirko 			const struct action_item *action_item,
5630a020d41SJiri Pirko 			unsigned int orig_delta_count,
5640a020d41SJiri Pirko 			unsigned int orig_root_count)
5650a020d41SJiri Pirko {
5660a020d41SJiri Pirko 	unsigned int key_id = action_item->key_id;
5670a020d41SJiri Pirko 
5680a020d41SJiri Pirko 	switch (action_item->expect_delta) {
5690a020d41SJiri Pirko 	case EXPECT_DELTA_SAME:
5700a020d41SJiri Pirko 		if (orig_delta_count != world->delta_count) {
5710a020d41SJiri Pirko 			pr_err("Key %u: Delta count changed while expected to remain the same.\n",
5720a020d41SJiri Pirko 			       key_id);
5730a020d41SJiri Pirko 			return -EINVAL;
5740a020d41SJiri Pirko 		}
5750a020d41SJiri Pirko 		break;
5760a020d41SJiri Pirko 	case EXPECT_DELTA_INC:
5770a020d41SJiri Pirko 		if (WARN_ON(action_item->action == ACTION_PUT))
5780a020d41SJiri Pirko 			return -EINVAL;
5790a020d41SJiri Pirko 		if (orig_delta_count + 1 != world->delta_count) {
5800a020d41SJiri Pirko 			pr_err("Key %u: Delta count was not incremented.\n",
5810a020d41SJiri Pirko 			       key_id);
5820a020d41SJiri Pirko 			return -EINVAL;
5830a020d41SJiri Pirko 		}
5840a020d41SJiri Pirko 		break;
5850a020d41SJiri Pirko 	case EXPECT_DELTA_DEC:
5860a020d41SJiri Pirko 		if (WARN_ON(action_item->action == ACTION_GET))
5870a020d41SJiri Pirko 			return -EINVAL;
5880a020d41SJiri Pirko 		if (orig_delta_count - 1 != world->delta_count) {
5890a020d41SJiri Pirko 			pr_err("Key %u: Delta count was not decremented.\n",
5900a020d41SJiri Pirko 			       key_id);
5910a020d41SJiri Pirko 			return -EINVAL;
5920a020d41SJiri Pirko 		}
5930a020d41SJiri Pirko 		break;
5940a020d41SJiri Pirko 	}
5950a020d41SJiri Pirko 
5960a020d41SJiri Pirko 	switch (action_item->expect_root) {
5970a020d41SJiri Pirko 	case EXPECT_ROOT_SAME:
5980a020d41SJiri Pirko 		if (orig_root_count != world->root_count) {
5990a020d41SJiri Pirko 			pr_err("Key %u: Root count changed while expected to remain the same.\n",
6000a020d41SJiri Pirko 			       key_id);
6010a020d41SJiri Pirko 			return -EINVAL;
6020a020d41SJiri Pirko 		}
6030a020d41SJiri Pirko 		break;
6040a020d41SJiri Pirko 	case EXPECT_ROOT_INC:
6050a020d41SJiri Pirko 		if (WARN_ON(action_item->action == ACTION_PUT))
6060a020d41SJiri Pirko 			return -EINVAL;
6070a020d41SJiri Pirko 		if (orig_root_count + 1 != world->root_count) {
6080a020d41SJiri Pirko 			pr_err("Key %u: Root count was not incremented.\n",
6090a020d41SJiri Pirko 			       key_id);
6100a020d41SJiri Pirko 			return -EINVAL;
6110a020d41SJiri Pirko 		}
6120a020d41SJiri Pirko 		break;
6130a020d41SJiri Pirko 	case EXPECT_ROOT_DEC:
6140a020d41SJiri Pirko 		if (WARN_ON(action_item->action == ACTION_GET))
6150a020d41SJiri Pirko 			return -EINVAL;
6160a020d41SJiri Pirko 		if (orig_root_count - 1 != world->root_count) {
6170a020d41SJiri Pirko 			pr_err("Key %u: Root count was not decremented.\n",
6180a020d41SJiri Pirko 			       key_id);
6190a020d41SJiri Pirko 			return -EINVAL;
6200a020d41SJiri Pirko 		}
6210a020d41SJiri Pirko 	}
6220a020d41SJiri Pirko 
6230a020d41SJiri Pirko 	return 0;
6240a020d41SJiri Pirko }
6250a020d41SJiri Pirko 
obj_to_key_id(struct objagg_obj * objagg_obj)6260a020d41SJiri Pirko static unsigned int obj_to_key_id(struct objagg_obj *objagg_obj)
6270a020d41SJiri Pirko {
6280a020d41SJiri Pirko 	const struct tokey *root_key;
6290a020d41SJiri Pirko 	const struct delta *delta;
6300a020d41SJiri Pirko 	unsigned int key_id;
6310a020d41SJiri Pirko 
6320a020d41SJiri Pirko 	root_key = objagg_obj_root_priv(objagg_obj);
6330a020d41SJiri Pirko 	key_id = root_key->id;
6340a020d41SJiri Pirko 	delta = objagg_obj_delta_priv(objagg_obj);
6350a020d41SJiri Pirko 	if (delta)
6360a020d41SJiri Pirko 		key_id += delta->key_id_diff;
6370a020d41SJiri Pirko 	return key_id;
6380a020d41SJiri Pirko }
6390a020d41SJiri Pirko 
6400a020d41SJiri Pirko static int
check_expect_stats_nums(const struct objagg_obj_stats_info * stats_info,const struct expect_stats_info * expect_stats_info,const char ** errmsg)6410a020d41SJiri Pirko check_expect_stats_nums(const struct objagg_obj_stats_info *stats_info,
6420a020d41SJiri Pirko 			const struct expect_stats_info *expect_stats_info,
6430a020d41SJiri Pirko 			const char **errmsg)
6440a020d41SJiri Pirko {
6450a020d41SJiri Pirko 	if (stats_info->is_root != expect_stats_info->is_root) {
6460a020d41SJiri Pirko 		if (errmsg)
6470a020d41SJiri Pirko 			*errmsg = "Incorrect root/delta indication";
6480a020d41SJiri Pirko 		return -EINVAL;
6490a020d41SJiri Pirko 	}
6500a020d41SJiri Pirko 	if (stats_info->stats.user_count !=
6510a020d41SJiri Pirko 	    expect_stats_info->stats.user_count) {
6520a020d41SJiri Pirko 		if (errmsg)
6530a020d41SJiri Pirko 			*errmsg = "Incorrect user count";
6540a020d41SJiri Pirko 		return -EINVAL;
6550a020d41SJiri Pirko 	}
6560a020d41SJiri Pirko 	if (stats_info->stats.delta_user_count !=
6570a020d41SJiri Pirko 	    expect_stats_info->stats.delta_user_count) {
6580a020d41SJiri Pirko 		if (errmsg)
6590a020d41SJiri Pirko 			*errmsg = "Incorrect delta user count";
6600a020d41SJiri Pirko 		return -EINVAL;
6610a020d41SJiri Pirko 	}
6620a020d41SJiri Pirko 	return 0;
6630a020d41SJiri Pirko }
6640a020d41SJiri Pirko 
6650a020d41SJiri Pirko static int
check_expect_stats_key_id(const struct objagg_obj_stats_info * stats_info,const struct expect_stats_info * expect_stats_info,const char ** errmsg)6660a020d41SJiri Pirko check_expect_stats_key_id(const struct objagg_obj_stats_info *stats_info,
6670a020d41SJiri Pirko 			  const struct expect_stats_info *expect_stats_info,
6680a020d41SJiri Pirko 			  const char **errmsg)
6690a020d41SJiri Pirko {
6700a020d41SJiri Pirko 	if (obj_to_key_id(stats_info->objagg_obj) !=
6710a020d41SJiri Pirko 	    expect_stats_info->key_id) {
6720a020d41SJiri Pirko 		if (errmsg)
6730a020d41SJiri Pirko 			*errmsg = "incorrect key id";
6740a020d41SJiri Pirko 		return -EINVAL;
6750a020d41SJiri Pirko 	}
6760a020d41SJiri Pirko 	return 0;
6770a020d41SJiri Pirko }
6780a020d41SJiri Pirko 
check_expect_stats_neigh(const struct objagg_stats * stats,const struct expect_stats * expect_stats,int pos)6790a020d41SJiri Pirko static int check_expect_stats_neigh(const struct objagg_stats *stats,
6800a020d41SJiri Pirko 				    const struct expect_stats *expect_stats,
6810a020d41SJiri Pirko 				    int pos)
6820a020d41SJiri Pirko {
6830a020d41SJiri Pirko 	int i;
6840a020d41SJiri Pirko 	int err;
6850a020d41SJiri Pirko 
6860a020d41SJiri Pirko 	for (i = pos - 1; i >= 0; i--) {
6870a020d41SJiri Pirko 		err = check_expect_stats_nums(&stats->stats_info[i],
6880a020d41SJiri Pirko 					      &expect_stats->info[pos], NULL);
6890a020d41SJiri Pirko 		if (err)
6900a020d41SJiri Pirko 			break;
6910a020d41SJiri Pirko 		err = check_expect_stats_key_id(&stats->stats_info[i],
6920a020d41SJiri Pirko 						&expect_stats->info[pos], NULL);
6930a020d41SJiri Pirko 		if (!err)
6940a020d41SJiri Pirko 			return 0;
6950a020d41SJiri Pirko 	}
6960a020d41SJiri Pirko 	for (i = pos + 1; i < stats->stats_info_count; i++) {
6970a020d41SJiri Pirko 		err = check_expect_stats_nums(&stats->stats_info[i],
6980a020d41SJiri Pirko 					      &expect_stats->info[pos], NULL);
6990a020d41SJiri Pirko 		if (err)
7000a020d41SJiri Pirko 			break;
7010a020d41SJiri Pirko 		err = check_expect_stats_key_id(&stats->stats_info[i],
7020a020d41SJiri Pirko 						&expect_stats->info[pos], NULL);
7030a020d41SJiri Pirko 		if (!err)
7040a020d41SJiri Pirko 			return 0;
7050a020d41SJiri Pirko 	}
7060a020d41SJiri Pirko 	return -EINVAL;
7070a020d41SJiri Pirko }
7080a020d41SJiri Pirko 
__check_expect_stats(const struct objagg_stats * stats,const struct expect_stats * expect_stats,const char ** errmsg)7090a020d41SJiri Pirko static int __check_expect_stats(const struct objagg_stats *stats,
7100a020d41SJiri Pirko 				const struct expect_stats *expect_stats,
7110a020d41SJiri Pirko 				const char **errmsg)
7120a020d41SJiri Pirko {
7130a020d41SJiri Pirko 	int i;
7140a020d41SJiri Pirko 	int err;
7150a020d41SJiri Pirko 
7160a020d41SJiri Pirko 	if (stats->stats_info_count != expect_stats->info_count) {
7170a020d41SJiri Pirko 		*errmsg = "Unexpected object count";
7180a020d41SJiri Pirko 		return -EINVAL;
7190a020d41SJiri Pirko 	}
7200a020d41SJiri Pirko 
7210a020d41SJiri Pirko 	for (i = 0; i < stats->stats_info_count; i++) {
7220a020d41SJiri Pirko 		err = check_expect_stats_nums(&stats->stats_info[i],
7230a020d41SJiri Pirko 					      &expect_stats->info[i], errmsg);
7240a020d41SJiri Pirko 		if (err)
7250a020d41SJiri Pirko 			return err;
7260a020d41SJiri Pirko 		err = check_expect_stats_key_id(&stats->stats_info[i],
7270a020d41SJiri Pirko 						&expect_stats->info[i], errmsg);
7280a020d41SJiri Pirko 		if (err) {
7290a020d41SJiri Pirko 			/* It is possible that one of the neighbor stats with
7300a020d41SJiri Pirko 			 * same numbers have the correct key id, so check it
7310a020d41SJiri Pirko 			 */
7320a020d41SJiri Pirko 			err = check_expect_stats_neigh(stats, expect_stats, i);
7330a020d41SJiri Pirko 			if (err)
7340a020d41SJiri Pirko 				return err;
7350a020d41SJiri Pirko 		}
7360a020d41SJiri Pirko 	}
7370a020d41SJiri Pirko 	return 0;
7380a020d41SJiri Pirko }
7390a020d41SJiri Pirko 
check_expect_stats(struct objagg * objagg,const struct expect_stats * expect_stats,const char ** errmsg)7400a020d41SJiri Pirko static int check_expect_stats(struct objagg *objagg,
7410a020d41SJiri Pirko 			      const struct expect_stats *expect_stats,
7420a020d41SJiri Pirko 			      const char **errmsg)
7430a020d41SJiri Pirko {
7440a020d41SJiri Pirko 	const struct objagg_stats *stats;
7450a020d41SJiri Pirko 	int err;
7460a020d41SJiri Pirko 
7470a020d41SJiri Pirko 	stats = objagg_stats_get(objagg);
748e7c2e3b5SDan Carpenter 	if (IS_ERR(stats)) {
749e7c2e3b5SDan Carpenter 		*errmsg = "objagg_stats_get() failed.";
7500a020d41SJiri Pirko 		return PTR_ERR(stats);
751e7c2e3b5SDan Carpenter 	}
7520a020d41SJiri Pirko 	err = __check_expect_stats(stats, expect_stats, errmsg);
7530a020d41SJiri Pirko 	objagg_stats_put(stats);
7540a020d41SJiri Pirko 	return err;
7550a020d41SJiri Pirko }
7560a020d41SJiri Pirko 
test_delta_action_item(struct world * world,struct objagg * objagg,const struct action_item * action_item,bool inverse)7570a020d41SJiri Pirko static int test_delta_action_item(struct world *world,
7580a020d41SJiri Pirko 				  struct objagg *objagg,
7590a020d41SJiri Pirko 				  const struct action_item *action_item,
7600a020d41SJiri Pirko 				  bool inverse)
7610a020d41SJiri Pirko {
7620a020d41SJiri Pirko 	unsigned int orig_delta_count = world->delta_count;
7630a020d41SJiri Pirko 	unsigned int orig_root_count = world->root_count;
7640a020d41SJiri Pirko 	unsigned int key_id = action_item->key_id;
7650a020d41SJiri Pirko 	enum action action = action_item->action;
7660a020d41SJiri Pirko 	struct objagg_obj *objagg_obj;
7670a020d41SJiri Pirko 	const char *errmsg;
7680a020d41SJiri Pirko 	int err;
7690a020d41SJiri Pirko 
7700a020d41SJiri Pirko 	if (inverse)
7710a020d41SJiri Pirko 		action = action == ACTION_GET ? ACTION_PUT : ACTION_GET;
7720a020d41SJiri Pirko 
7730a020d41SJiri Pirko 	switch (action) {
7740a020d41SJiri Pirko 	case ACTION_GET:
7750a020d41SJiri Pirko 		objagg_obj = world_obj_get(world, objagg, key_id);
7760a020d41SJiri Pirko 		if (IS_ERR(objagg_obj))
7770a020d41SJiri Pirko 			return PTR_ERR(objagg_obj);
7780a020d41SJiri Pirko 		break;
7790a020d41SJiri Pirko 	case ACTION_PUT:
7800a020d41SJiri Pirko 		world_obj_put(world, objagg, key_id);
7810a020d41SJiri Pirko 		break;
7820a020d41SJiri Pirko 	}
7830a020d41SJiri Pirko 
7840a020d41SJiri Pirko 	if (inverse)
7850a020d41SJiri Pirko 		return 0;
7860a020d41SJiri Pirko 	err = check_expect(world, action_item,
7870a020d41SJiri Pirko 			   orig_delta_count, orig_root_count);
7880a020d41SJiri Pirko 	if (err)
7890a020d41SJiri Pirko 		goto errout;
7900a020d41SJiri Pirko 
7910a020d41SJiri Pirko 	err = check_expect_stats(objagg, &action_item->expect_stats, &errmsg);
7920a020d41SJiri Pirko 	if (err) {
7930a020d41SJiri Pirko 		pr_err("Key %u: Stats: %s\n", action_item->key_id, errmsg);
7940a020d41SJiri Pirko 		goto errout;
7950a020d41SJiri Pirko 	}
7960a020d41SJiri Pirko 
7970a020d41SJiri Pirko 	return 0;
7980a020d41SJiri Pirko 
7990a020d41SJiri Pirko errout:
8000a020d41SJiri Pirko 	/* This can only happen when action is not inversed.
8010a020d41SJiri Pirko 	 * So in case of an error, cleanup by doing inverse action.
8020a020d41SJiri Pirko 	 */
8030a020d41SJiri Pirko 	test_delta_action_item(world, objagg, action_item, true);
8040a020d41SJiri Pirko 	return err;
8050a020d41SJiri Pirko }
8060a020d41SJiri Pirko 
test_delta(void)8070a020d41SJiri Pirko static int test_delta(void)
8080a020d41SJiri Pirko {
8090a020d41SJiri Pirko 	struct world world = {};
8100a020d41SJiri Pirko 	struct objagg *objagg;
8110a020d41SJiri Pirko 	int i;
8120a020d41SJiri Pirko 	int err;
8130a020d41SJiri Pirko 
8149069a381SJiri Pirko 	objagg = objagg_create(&delta_ops, NULL, &world);
8150a020d41SJiri Pirko 	if (IS_ERR(objagg))
8160a020d41SJiri Pirko 		return PTR_ERR(objagg);
8170a020d41SJiri Pirko 
8180a020d41SJiri Pirko 	for (i = 0; i < ARRAY_SIZE(action_items); i++) {
8190a020d41SJiri Pirko 		err = test_delta_action_item(&world, objagg,
8200a020d41SJiri Pirko 					     &action_items[i], false);
8210a020d41SJiri Pirko 		if (err)
8220a020d41SJiri Pirko 			goto err_do_action_item;
8230a020d41SJiri Pirko 	}
8240a020d41SJiri Pirko 
8250a020d41SJiri Pirko 	objagg_destroy(objagg);
8260a020d41SJiri Pirko 	return 0;
8270a020d41SJiri Pirko 
8280a020d41SJiri Pirko err_do_action_item:
8290a020d41SJiri Pirko 	for (i--; i >= 0; i--)
8300a020d41SJiri Pirko 		test_delta_action_item(&world, objagg, &action_items[i], true);
8310a020d41SJiri Pirko 
8320a020d41SJiri Pirko 	objagg_destroy(objagg);
8330a020d41SJiri Pirko 	return err;
8340a020d41SJiri Pirko }
8350a020d41SJiri Pirko 
8369069a381SJiri Pirko struct hints_case {
8379069a381SJiri Pirko 	const unsigned int *key_ids;
8389069a381SJiri Pirko 	size_t key_ids_count;
8399069a381SJiri Pirko 	struct expect_stats expect_stats;
8409069a381SJiri Pirko 	struct expect_stats expect_stats_hints;
8419069a381SJiri Pirko };
8429069a381SJiri Pirko 
8439069a381SJiri Pirko static const unsigned int hints_case_key_ids[] = {
8449069a381SJiri Pirko 	1, 7, 3, 5, 3, 1, 30, 8, 8, 5, 6, 8,
8459069a381SJiri Pirko };
8469069a381SJiri Pirko 
8479069a381SJiri Pirko static const struct hints_case hints_case = {
8489069a381SJiri Pirko 	.key_ids = hints_case_key_ids,
8499069a381SJiri Pirko 	.key_ids_count = ARRAY_SIZE(hints_case_key_ids),
8509069a381SJiri Pirko 	.expect_stats =
8519069a381SJiri Pirko 		EXPECT_STATS(7, ROOT(1, 2, 7), ROOT(7, 1, 4), ROOT(30, 1, 1),
8529069a381SJiri Pirko 				DELTA(8, 3), DELTA(3, 2),
8539069a381SJiri Pirko 				DELTA(5, 2), DELTA(6, 1)),
8549069a381SJiri Pirko 	.expect_stats_hints =
8559069a381SJiri Pirko 		EXPECT_STATS(7, ROOT(3, 2, 9), ROOT(1, 2, 2), ROOT(30, 1, 1),
8569069a381SJiri Pirko 				DELTA(8, 3), DELTA(5, 2),
8579069a381SJiri Pirko 				DELTA(6, 1), DELTA(7, 1)),
8589069a381SJiri Pirko };
8599069a381SJiri Pirko 
__pr_debug_stats(const struct objagg_stats * stats)8609069a381SJiri Pirko static void __pr_debug_stats(const struct objagg_stats *stats)
8619069a381SJiri Pirko {
8629069a381SJiri Pirko 	int i;
8639069a381SJiri Pirko 
8649069a381SJiri Pirko 	for (i = 0; i < stats->stats_info_count; i++)
8659069a381SJiri Pirko 		pr_debug("Stat index %d key %u: u %d, d %d, %s\n", i,
8669069a381SJiri Pirko 			 obj_to_key_id(stats->stats_info[i].objagg_obj),
8679069a381SJiri Pirko 			 stats->stats_info[i].stats.user_count,
8689069a381SJiri Pirko 			 stats->stats_info[i].stats.delta_user_count,
8699069a381SJiri Pirko 			 stats->stats_info[i].is_root ? "root" : "noroot");
8709069a381SJiri Pirko }
8719069a381SJiri Pirko 
pr_debug_stats(struct objagg * objagg)8729069a381SJiri Pirko static void pr_debug_stats(struct objagg *objagg)
8739069a381SJiri Pirko {
8749069a381SJiri Pirko 	const struct objagg_stats *stats;
8759069a381SJiri Pirko 
8769069a381SJiri Pirko 	stats = objagg_stats_get(objagg);
8779069a381SJiri Pirko 	if (IS_ERR(stats))
8789069a381SJiri Pirko 		return;
8799069a381SJiri Pirko 	__pr_debug_stats(stats);
8809069a381SJiri Pirko 	objagg_stats_put(stats);
8819069a381SJiri Pirko }
8829069a381SJiri Pirko 
pr_debug_hints_stats(struct objagg_hints * objagg_hints)8839069a381SJiri Pirko static void pr_debug_hints_stats(struct objagg_hints *objagg_hints)
8849069a381SJiri Pirko {
8859069a381SJiri Pirko 	const struct objagg_stats *stats;
8869069a381SJiri Pirko 
8879069a381SJiri Pirko 	stats = objagg_hints_stats_get(objagg_hints);
8889069a381SJiri Pirko 	if (IS_ERR(stats))
8899069a381SJiri Pirko 		return;
8909069a381SJiri Pirko 	__pr_debug_stats(stats);
8919069a381SJiri Pirko 	objagg_stats_put(stats);
8929069a381SJiri Pirko }
8939069a381SJiri Pirko 
check_expect_hints_stats(struct objagg_hints * objagg_hints,const struct expect_stats * expect_stats,const char ** errmsg)8949069a381SJiri Pirko static int check_expect_hints_stats(struct objagg_hints *objagg_hints,
8959069a381SJiri Pirko 				    const struct expect_stats *expect_stats,
8969069a381SJiri Pirko 				    const char **errmsg)
8979069a381SJiri Pirko {
8989069a381SJiri Pirko 	const struct objagg_stats *stats;
8999069a381SJiri Pirko 	int err;
9009069a381SJiri Pirko 
9019069a381SJiri Pirko 	stats = objagg_hints_stats_get(objagg_hints);
9029069a381SJiri Pirko 	if (IS_ERR(stats))
9039069a381SJiri Pirko 		return PTR_ERR(stats);
9049069a381SJiri Pirko 	err = __check_expect_stats(stats, expect_stats, errmsg);
9059069a381SJiri Pirko 	objagg_stats_put(stats);
9069069a381SJiri Pirko 	return err;
9079069a381SJiri Pirko }
9089069a381SJiri Pirko 
test_hints_case(const struct hints_case * hints_case)9099069a381SJiri Pirko static int test_hints_case(const struct hints_case *hints_case)
9109069a381SJiri Pirko {
9119069a381SJiri Pirko 	struct objagg_obj *objagg_obj;
9129069a381SJiri Pirko 	struct objagg_hints *hints;
9139069a381SJiri Pirko 	struct world world2 = {};
9149069a381SJiri Pirko 	struct world world = {};
9159069a381SJiri Pirko 	struct objagg *objagg2;
9169069a381SJiri Pirko 	struct objagg *objagg;
9179069a381SJiri Pirko 	const char *errmsg;
9189069a381SJiri Pirko 	int i;
9199069a381SJiri Pirko 	int err;
9209069a381SJiri Pirko 
9219069a381SJiri Pirko 	objagg = objagg_create(&delta_ops, NULL, &world);
9229069a381SJiri Pirko 	if (IS_ERR(objagg))
9239069a381SJiri Pirko 		return PTR_ERR(objagg);
9249069a381SJiri Pirko 
9259069a381SJiri Pirko 	for (i = 0; i < hints_case->key_ids_count; i++) {
9269069a381SJiri Pirko 		objagg_obj = world_obj_get(&world, objagg,
9279069a381SJiri Pirko 					   hints_case->key_ids[i]);
9289069a381SJiri Pirko 		if (IS_ERR(objagg_obj)) {
9299069a381SJiri Pirko 			err = PTR_ERR(objagg_obj);
9309069a381SJiri Pirko 			goto err_world_obj_get;
9319069a381SJiri Pirko 		}
9329069a381SJiri Pirko 	}
9339069a381SJiri Pirko 
9349069a381SJiri Pirko 	pr_debug_stats(objagg);
9359069a381SJiri Pirko 	err = check_expect_stats(objagg, &hints_case->expect_stats, &errmsg);
9369069a381SJiri Pirko 	if (err) {
9379069a381SJiri Pirko 		pr_err("Stats: %s\n", errmsg);
9389069a381SJiri Pirko 		goto err_check_expect_stats;
9399069a381SJiri Pirko 	}
9409069a381SJiri Pirko 
9419069a381SJiri Pirko 	hints = objagg_hints_get(objagg, OBJAGG_OPT_ALGO_SIMPLE_GREEDY);
9429069a381SJiri Pirko 	if (IS_ERR(hints)) {
9439069a381SJiri Pirko 		err = PTR_ERR(hints);
9449069a381SJiri Pirko 		goto err_hints_get;
9459069a381SJiri Pirko 	}
9469069a381SJiri Pirko 
9479069a381SJiri Pirko 	pr_debug_hints_stats(hints);
9489069a381SJiri Pirko 	err = check_expect_hints_stats(hints, &hints_case->expect_stats_hints,
9499069a381SJiri Pirko 				       &errmsg);
9509069a381SJiri Pirko 	if (err) {
9519069a381SJiri Pirko 		pr_err("Hints stats: %s\n", errmsg);
9529069a381SJiri Pirko 		goto err_check_expect_hints_stats;
9539069a381SJiri Pirko 	}
9549069a381SJiri Pirko 
9559069a381SJiri Pirko 	objagg2 = objagg_create(&delta_ops, hints, &world2);
956951d3d6fSDan Carpenter 	if (IS_ERR(objagg2))
957951d3d6fSDan Carpenter 		return PTR_ERR(objagg2);
9589069a381SJiri Pirko 
9599069a381SJiri Pirko 	for (i = 0; i < hints_case->key_ids_count; i++) {
9609069a381SJiri Pirko 		objagg_obj = world_obj_get(&world2, objagg2,
9619069a381SJiri Pirko 					   hints_case->key_ids[i]);
9629069a381SJiri Pirko 		if (IS_ERR(objagg_obj)) {
9639069a381SJiri Pirko 			err = PTR_ERR(objagg_obj);
9649069a381SJiri Pirko 			goto err_world2_obj_get;
9659069a381SJiri Pirko 		}
9669069a381SJiri Pirko 	}
9679069a381SJiri Pirko 
9689069a381SJiri Pirko 	pr_debug_stats(objagg2);
9699069a381SJiri Pirko 	err = check_expect_stats(objagg2, &hints_case->expect_stats_hints,
9709069a381SJiri Pirko 				 &errmsg);
9719069a381SJiri Pirko 	if (err) {
9729069a381SJiri Pirko 		pr_err("Stats2: %s\n", errmsg);
9739069a381SJiri Pirko 		goto err_check_expect_stats2;
9749069a381SJiri Pirko 	}
9759069a381SJiri Pirko 
9769069a381SJiri Pirko 	err = 0;
9779069a381SJiri Pirko 
9789069a381SJiri Pirko err_check_expect_stats2:
9799069a381SJiri Pirko err_world2_obj_get:
9809069a381SJiri Pirko 	for (i--; i >= 0; i--)
9819069a381SJiri Pirko 		world_obj_put(&world2, objagg, hints_case->key_ids[i]);
9829069a381SJiri Pirko 	i = hints_case->key_ids_count;
983a6379f0aSAditya Pakki 	objagg_destroy(objagg2);
9849069a381SJiri Pirko err_check_expect_hints_stats:
985a6379f0aSAditya Pakki 	objagg_hints_put(hints);
9869069a381SJiri Pirko err_hints_get:
9879069a381SJiri Pirko err_check_expect_stats:
9889069a381SJiri Pirko err_world_obj_get:
9899069a381SJiri Pirko 	for (i--; i >= 0; i--)
9909069a381SJiri Pirko 		world_obj_put(&world, objagg, hints_case->key_ids[i]);
9919069a381SJiri Pirko 
9929069a381SJiri Pirko 	objagg_destroy(objagg);
9939069a381SJiri Pirko 	return err;
9949069a381SJiri Pirko }
test_hints(void)9959069a381SJiri Pirko static int test_hints(void)
9969069a381SJiri Pirko {
9979069a381SJiri Pirko 	return test_hints_case(&hints_case);
9989069a381SJiri Pirko }
9999069a381SJiri Pirko 
test_objagg_init(void)10000a020d41SJiri Pirko static int __init test_objagg_init(void)
10010a020d41SJiri Pirko {
10020a020d41SJiri Pirko 	int err;
10030a020d41SJiri Pirko 
10040a020d41SJiri Pirko 	err = test_nodelta();
10050a020d41SJiri Pirko 	if (err)
10060a020d41SJiri Pirko 		return err;
10079069a381SJiri Pirko 	err = test_delta();
10089069a381SJiri Pirko 	if (err)
10099069a381SJiri Pirko 		return err;
10109069a381SJiri Pirko 	return test_hints();
10110a020d41SJiri Pirko }
10120a020d41SJiri Pirko 
test_objagg_exit(void)10130a020d41SJiri Pirko static void __exit test_objagg_exit(void)
10140a020d41SJiri Pirko {
10150a020d41SJiri Pirko }
10160a020d41SJiri Pirko 
10170a020d41SJiri Pirko module_init(test_objagg_init);
10180a020d41SJiri Pirko module_exit(test_objagg_exit);
10190a020d41SJiri Pirko MODULE_LICENSE("Dual BSD/GPL");
10200a020d41SJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
10210a020d41SJiri Pirko MODULE_DESCRIPTION("Test module for objagg");
1022