cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

test_parman.c (11431B)


      1/*
      2 * lib/test_parman.c - Test module for parman
      3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
      4 * Copyright (c) 2017 Jiri Pirko <jiri@mellanox.com>
      5 *
      6 * Redistribution and use in source and binary forms, with or without
      7 * modification, are permitted provided that the following conditions are met:
      8 *
      9 * 1. Redistributions of source code must retain the above copyright
     10 *    notice, this list of conditions and the following disclaimer.
     11 * 2. Redistributions in binary form must reproduce the above copyright
     12 *    notice, this list of conditions and the following disclaimer in the
     13 *    documentation and/or other materials provided with the distribution.
     14 * 3. Neither the names of the copyright holders nor the names of its
     15 *    contributors may be used to endorse or promote products derived from
     16 *    this software without specific prior written permission.
     17 *
     18 * Alternatively, this software may be distributed under the terms of the
     19 * GNU General Public License ("GPL") version 2 as published by the Free
     20 * Software Foundation.
     21 *
     22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     32 * POSSIBILITY OF SUCH DAMAGE.
     33 */
     34
     35#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     36
     37#include <linux/kernel.h>
     38#include <linux/module.h>
     39#include <linux/slab.h>
     40#include <linux/bitops.h>
     41#include <linux/err.h>
     42#include <linux/random.h>
     43#include <linux/parman.h>
     44
     45#define TEST_PARMAN_PRIO_SHIFT 7 /* defines number of prios for testing */
     46#define TEST_PARMAN_PRIO_COUNT BIT(TEST_PARMAN_PRIO_SHIFT)
     47#define TEST_PARMAN_PRIO_MASK (TEST_PARMAN_PRIO_COUNT - 1)
     48
     49#define TEST_PARMAN_ITEM_SHIFT 13 /* defines a total number
     50				   * of items for testing
     51				   */
     52#define TEST_PARMAN_ITEM_COUNT BIT(TEST_PARMAN_ITEM_SHIFT)
     53#define TEST_PARMAN_ITEM_MASK (TEST_PARMAN_ITEM_COUNT - 1)
     54
     55#define TEST_PARMAN_BASE_SHIFT 8
     56#define TEST_PARMAN_BASE_COUNT BIT(TEST_PARMAN_BASE_SHIFT)
     57#define TEST_PARMAN_RESIZE_STEP_SHIFT 7
     58#define TEST_PARMAN_RESIZE_STEP_COUNT BIT(TEST_PARMAN_RESIZE_STEP_SHIFT)
     59
     60#define TEST_PARMAN_BULK_MAX_SHIFT (2 + TEST_PARMAN_RESIZE_STEP_SHIFT)
     61#define TEST_PARMAN_BULK_MAX_COUNT BIT(TEST_PARMAN_BULK_MAX_SHIFT)
     62#define TEST_PARMAN_BULK_MAX_MASK (TEST_PARMAN_BULK_MAX_COUNT - 1)
     63
     64#define TEST_PARMAN_RUN_BUDGET (TEST_PARMAN_ITEM_COUNT * 256)
     65
     66struct test_parman_prio {
     67	struct parman_prio parman_prio;
     68	unsigned long priority;
     69};
     70
     71struct test_parman_item {
     72	struct parman_item parman_item;
     73	struct test_parman_prio *prio;
     74	bool used;
     75};
     76
     77struct test_parman {
     78	struct parman *parman;
     79	struct test_parman_item **prio_array;
     80	unsigned long prio_array_limit;
     81	struct test_parman_prio prios[TEST_PARMAN_PRIO_COUNT];
     82	struct test_parman_item items[TEST_PARMAN_ITEM_COUNT];
     83	struct rnd_state rnd;
     84	unsigned long run_budget;
     85	unsigned long bulk_budget;
     86	bool bulk_noop;
     87	unsigned int used_items;
     88};
     89
     90#define ITEM_PTRS_SIZE(count) (sizeof(struct test_parman_item *) * (count))
     91
     92static int test_parman_resize(void *priv, unsigned long new_count)
     93{
     94	struct test_parman *test_parman = priv;
     95	struct test_parman_item **prio_array;
     96	unsigned long old_count;
     97
     98	prio_array = krealloc(test_parman->prio_array,
     99			      ITEM_PTRS_SIZE(new_count), GFP_KERNEL);
    100	if (new_count == 0)
    101		return 0;
    102	if (!prio_array)
    103		return -ENOMEM;
    104	old_count = test_parman->prio_array_limit;
    105	if (new_count > old_count)
    106		memset(&prio_array[old_count], 0,
    107		       ITEM_PTRS_SIZE(new_count - old_count));
    108	test_parman->prio_array = prio_array;
    109	test_parman->prio_array_limit = new_count;
    110	return 0;
    111}
    112
    113static void test_parman_move(void *priv, unsigned long from_index,
    114			     unsigned long to_index, unsigned long count)
    115{
    116	struct test_parman *test_parman = priv;
    117	struct test_parman_item **prio_array = test_parman->prio_array;
    118
    119	memmove(&prio_array[to_index], &prio_array[from_index],
    120		ITEM_PTRS_SIZE(count));
    121	memset(&prio_array[from_index], 0, ITEM_PTRS_SIZE(count));
    122}
    123
    124static const struct parman_ops test_parman_lsort_ops = {
    125	.base_count	= TEST_PARMAN_BASE_COUNT,
    126	.resize_step	= TEST_PARMAN_RESIZE_STEP_COUNT,
    127	.resize		= test_parman_resize,
    128	.move		= test_parman_move,
    129	.algo		= PARMAN_ALGO_TYPE_LSORT,
    130};
    131
    132static void test_parman_rnd_init(struct test_parman *test_parman)
    133{
    134	prandom_seed_state(&test_parman->rnd, 3141592653589793238ULL);
    135}
    136
    137static u32 test_parman_rnd_get(struct test_parman *test_parman)
    138{
    139	return prandom_u32_state(&test_parman->rnd);
    140}
    141
    142static unsigned long test_parman_priority_gen(struct test_parman *test_parman)
    143{
    144	unsigned long priority;
    145	int i;
    146
    147again:
    148	priority = test_parman_rnd_get(test_parman);
    149	if (priority == 0)
    150		goto again;
    151
    152	for (i = 0; i < TEST_PARMAN_PRIO_COUNT; i++) {
    153		struct test_parman_prio *prio = &test_parman->prios[i];
    154
    155		if (prio->priority == 0)
    156			break;
    157		if (prio->priority == priority)
    158			goto again;
    159	}
    160	return priority;
    161}
    162
    163static void test_parman_prios_init(struct test_parman *test_parman)
    164{
    165	int i;
    166
    167	for (i = 0; i < TEST_PARMAN_PRIO_COUNT; i++) {
    168		struct test_parman_prio *prio = &test_parman->prios[i];
    169
    170		/* Assign random uniqueue priority to each prio structure */
    171		prio->priority = test_parman_priority_gen(test_parman);
    172		parman_prio_init(test_parman->parman, &prio->parman_prio,
    173				 prio->priority);
    174	}
    175}
    176
    177static void test_parman_prios_fini(struct test_parman *test_parman)
    178{
    179	int i;
    180
    181	for (i = 0; i < TEST_PARMAN_PRIO_COUNT; i++) {
    182		struct test_parman_prio *prio = &test_parman->prios[i];
    183
    184		parman_prio_fini(&prio->parman_prio);
    185	}
    186}
    187
    188static void test_parman_items_init(struct test_parman *test_parman)
    189{
    190	int i;
    191
    192	for (i = 0; i < TEST_PARMAN_ITEM_COUNT; i++) {
    193		struct test_parman_item *item = &test_parman->items[i];
    194		unsigned int prio_index = test_parman_rnd_get(test_parman) &
    195					  TEST_PARMAN_PRIO_MASK;
    196
    197		/* Assign random prio to each item structure */
    198		item->prio = &test_parman->prios[prio_index];
    199	}
    200}
    201
    202static void test_parman_items_fini(struct test_parman *test_parman)
    203{
    204	int i;
    205
    206	for (i = 0; i < TEST_PARMAN_ITEM_COUNT; i++) {
    207		struct test_parman_item *item = &test_parman->items[i];
    208
    209		if (!item->used)
    210			continue;
    211		parman_item_remove(test_parman->parman,
    212				   &item->prio->parman_prio,
    213				   &item->parman_item);
    214	}
    215}
    216
    217static struct test_parman *test_parman_create(const struct parman_ops *ops)
    218{
    219	struct test_parman *test_parman;
    220	int err;
    221
    222	test_parman = kzalloc(sizeof(*test_parman), GFP_KERNEL);
    223	if (!test_parman)
    224		return ERR_PTR(-ENOMEM);
    225	err = test_parman_resize(test_parman, TEST_PARMAN_BASE_COUNT);
    226	if (err)
    227		goto err_resize;
    228	test_parman->parman = parman_create(ops, test_parman);
    229	if (!test_parman->parman) {
    230		err = -ENOMEM;
    231		goto err_parman_create;
    232	}
    233	test_parman_rnd_init(test_parman);
    234	test_parman_prios_init(test_parman);
    235	test_parman_items_init(test_parman);
    236	test_parman->run_budget = TEST_PARMAN_RUN_BUDGET;
    237	return test_parman;
    238
    239err_parman_create:
    240	test_parman_resize(test_parman, 0);
    241err_resize:
    242	kfree(test_parman);
    243	return ERR_PTR(err);
    244}
    245
    246static void test_parman_destroy(struct test_parman *test_parman)
    247{
    248	test_parman_items_fini(test_parman);
    249	test_parman_prios_fini(test_parman);
    250	parman_destroy(test_parman->parman);
    251	test_parman_resize(test_parman, 0);
    252	kfree(test_parman);
    253}
    254
    255static bool test_parman_run_check_budgets(struct test_parman *test_parman)
    256{
    257	if (test_parman->run_budget-- == 0)
    258		return false;
    259	if (test_parman->bulk_budget-- != 0)
    260		return true;
    261
    262	test_parman->bulk_budget = test_parman_rnd_get(test_parman) &
    263				   TEST_PARMAN_BULK_MAX_MASK;
    264	test_parman->bulk_noop = test_parman_rnd_get(test_parman) & 1;
    265	return true;
    266}
    267
    268static int test_parman_run(struct test_parman *test_parman)
    269{
    270	unsigned int i = test_parman_rnd_get(test_parman);
    271	int err;
    272
    273	while (test_parman_run_check_budgets(test_parman)) {
    274		unsigned int item_index = i++ & TEST_PARMAN_ITEM_MASK;
    275		struct test_parman_item *item = &test_parman->items[item_index];
    276
    277		if (test_parman->bulk_noop)
    278			continue;
    279
    280		if (!item->used) {
    281			err = parman_item_add(test_parman->parman,
    282					      &item->prio->parman_prio,
    283					      &item->parman_item);
    284			if (err)
    285				return err;
    286			test_parman->prio_array[item->parman_item.index] = item;
    287			test_parman->used_items++;
    288		} else {
    289			test_parman->prio_array[item->parman_item.index] = NULL;
    290			parman_item_remove(test_parman->parman,
    291					   &item->prio->parman_prio,
    292					   &item->parman_item);
    293			test_parman->used_items--;
    294		}
    295		item->used = !item->used;
    296	}
    297	return 0;
    298}
    299
    300static int test_parman_check_array(struct test_parman *test_parman,
    301				   bool gaps_allowed)
    302{
    303	unsigned int last_unused_items = 0;
    304	unsigned long last_priority = 0;
    305	unsigned int used_items = 0;
    306	int i;
    307
    308	if (test_parman->prio_array_limit < TEST_PARMAN_BASE_COUNT) {
    309		pr_err("Array limit is lower than the base count (%lu < %lu)\n",
    310		       test_parman->prio_array_limit, TEST_PARMAN_BASE_COUNT);
    311		return -EINVAL;
    312	}
    313
    314	for (i = 0; i < test_parman->prio_array_limit; i++) {
    315		struct test_parman_item *item = test_parman->prio_array[i];
    316
    317		if (!item) {
    318			last_unused_items++;
    319			continue;
    320		}
    321		if (last_unused_items && !gaps_allowed) {
    322			pr_err("Gap found in array even though they are forbidden\n");
    323			return -EINVAL;
    324		}
    325
    326		last_unused_items = 0;
    327		used_items++;
    328
    329		if (item->prio->priority < last_priority) {
    330			pr_err("Item belongs under higher priority then the last one (current: %lu, previous: %lu)\n",
    331			       item->prio->priority, last_priority);
    332			return -EINVAL;
    333		}
    334		last_priority = item->prio->priority;
    335
    336		if (item->parman_item.index != i) {
    337			pr_err("Item has different index in compare to where it actually is (%lu != %d)\n",
    338			       item->parman_item.index, i);
    339			return -EINVAL;
    340		}
    341	}
    342
    343	if (used_items != test_parman->used_items) {
    344		pr_err("Number of used items in array does not match (%u != %u)\n",
    345		       used_items, test_parman->used_items);
    346		return -EINVAL;
    347	}
    348
    349	if (last_unused_items >= TEST_PARMAN_RESIZE_STEP_COUNT) {
    350		pr_err("Number of unused item at the end of array is bigger than resize step (%u >= %lu)\n",
    351		       last_unused_items, TEST_PARMAN_RESIZE_STEP_COUNT);
    352		return -EINVAL;
    353	}
    354
    355	pr_info("Priority array check successful\n");
    356
    357	return 0;
    358}
    359
    360static int test_parman_lsort(void)
    361{
    362	struct test_parman *test_parman;
    363	int err;
    364
    365	test_parman = test_parman_create(&test_parman_lsort_ops);
    366	if (IS_ERR(test_parman))
    367		return PTR_ERR(test_parman);
    368
    369	err = test_parman_run(test_parman);
    370	if (err)
    371		goto out;
    372
    373	err = test_parman_check_array(test_parman, false);
    374	if (err)
    375		goto out;
    376out:
    377	test_parman_destroy(test_parman);
    378	return err;
    379}
    380
    381static int __init test_parman_init(void)
    382{
    383	return test_parman_lsort();
    384}
    385
    386static void __exit test_parman_exit(void)
    387{
    388}
    389
    390module_init(test_parman_init);
    391module_exit(test_parman_exit);
    392
    393MODULE_LICENSE("Dual BSD/GPL");
    394MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
    395MODULE_DESCRIPTION("Test module for parman");