Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <e05598c1-3c7c-15c6-7278-ed52ceff0acf@infradead.org>
Date: Sun, 4 Feb 2018 14:19:22 -0800
From: Randy Dunlap <rdunlap@...radead.org>
To: Igor Stoppa <igor.stoppa@...wei.com>, jglisse@...hat.com,
 keescook@...omium.org, mhocko@...nel.org, labbott@...hat.com,
 hch@...radead.org, willy@...radead.org
Cc: cl@...ux.com, linux-security-module@...r.kernel.org, linux-mm@...ck.org,
 linux-kernel@...r.kernel.org, kernel-hardening@...ts.openwall.com
Subject: Re: [PATCH 2/6] genalloc: selftest

On 02/04/2018 08:47 AM, Igor Stoppa wrote:
> Introduce a set of macros for writing concise test cases for genalloc.
> 
> The test cases are meant to provide regression testing, when working on
> new functionality for genalloc.
> 
> Primarily they are meant to confirm that the various allocation strategy
> will continue to work as expected.
> 
> The execution of the self testing is controlled through a Kconfig option.
> 
> Signed-off-by: Igor Stoppa <igor.stoppa@...wei.com>
> ---
>  include/linux/genalloc-selftest.h |  30 +++
>  init/main.c                       |   2 +
>  lib/Kconfig                       |  15 ++
>  lib/Makefile                      |   1 +
>  lib/genalloc-selftest.c           | 402 ++++++++++++++++++++++++++++++++++++++
>  5 files changed, 450 insertions(+)
>  create mode 100644 include/linux/genalloc-selftest.h
>  create mode 100644 lib/genalloc-selftest.c
> 
> diff --git a/include/linux/genalloc-selftest.h b/include/linux/genalloc-selftest.h
> new file mode 100644
> index 000000000000..7af1901e57dc
> --- /dev/null
> +++ b/include/linux/genalloc-selftest.h
> @@ -0,0 +1,30 @@
> +/*
> + * genalloc-selftest.h
> + *
> + * (C) Copyright 2017 Huawei Technologies Co. Ltd.
> + * Author: Igor Stoppa <igor.stoppa@...wei.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; version 2
> + * of the License.
> + */
> +
> +
> +#ifndef __GENALLOC_SELFTEST_H__
> +#define __GENALLOC_SELFTEST_H__

Please use _LINUX_GENALLOC_SELFTEST_H_

> +
> +
> +#ifdef CONFIG_GENERIC_ALLOCATOR_SELFTEST
> +
> +#include <linux/genalloc.h>
> +
> +void genalloc_selftest(void);
> +
> +#else
> +
> +static inline void genalloc_selftest(void){};
> +
> +#endif
> +
> +#endif


> diff --git a/lib/genalloc-selftest.c b/lib/genalloc-selftest.c
> new file mode 100644
> index 000000000000..007a0cfb3d77
> --- /dev/null
> +++ b/lib/genalloc-selftest.c
> @@ -0,0 +1,402 @@
> +/*
> + * genalloc-selftest.c
> + *
> + * (C) Copyright 2017 Huawei Technologies Co. Ltd.
> + * Author: Igor Stoppa <igor.stoppa@...wei.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; version 2
> + * of the License.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/printk.h>
> +#include <linux/init.h>
> +#include <linux/vmalloc.h>
> +#include <asm/set_memory.h>
> +#include <linux/string.h>
> +#include <linux/debugfs.h>
> +#include <linux/atomic.h>
> +#include <linux/genalloc.h>
> +
> +
> +
> +/* Keep the bitmap small, while including case of cross-ulong mapping.
> + * For simplicity, the test cases use only 1 chunk of memory.
> + */
> +#define BITMAP_SIZE_C 16
> +#define ALLOC_ORDER 0
> +
> +#define ULONG_SIZE (sizeof(unsigned long))
> +#define BITMAP_SIZE_UL (BITMAP_SIZE_C / ULONG_SIZE)
> +#define MIN_ALLOC_SIZE (1 << ALLOC_ORDER)
> +#define ENTRIES (BITMAP_SIZE_C * 8)
> +#define CHUNK_SIZE  (MIN_ALLOC_SIZE * ENTRIES)
> +
> +#ifndef CONFIG_GENERIC_ALLOCATOR_SELFTEST_VERBOSE
> +
> +static inline void print_first_chunk_bitmap(struct gen_pool *pool) {}
> +
> +#else
> +
> +static void print_first_chunk_bitmap(struct gen_pool *pool)
> +{
> +	struct gen_pool_chunk *chunk;
> +	char bitmap[BITMAP_SIZE_C * 2 + 1];
> +	unsigned long i;
> +	char *bm = bitmap;
> +	char *entry;
> +
> +	if (unlikely(pool == NULL || pool->chunks.next == NULL))
> +		return;
> +
> +	chunk = container_of(pool->chunks.next, struct gen_pool_chunk,
> +			     next_chunk);
> +	entry = (void *)chunk->entries;
> +	for (i = 1; i <= BITMAP_SIZE_C; i++)
> +		bm += snprintf(bm, 3, "%02hhx", entry[BITMAP_SIZE_C - i]);
> +	*bm = '\0';
> +	pr_notice("chunk: %p    bitmap: 0x%s\n", chunk, bitmap);
> +
> +}
> +
> +#endif
> +
> +enum test_commands {
> +	CMD_ALLOCATOR,
> +	CMD_ALLOCATE,
> +	CMD_FLUSH,
> +	CMD_FREE,
> +	CMD_NUMBER,
> +	CMD_END = CMD_NUMBER,
> +};
> +
> +struct null_struct {
> +	void *null;
> +};
> +
> +struct test_allocator {
> +	genpool_algo_t algo;
> +	union {
> +		struct genpool_data_align align;
> +		struct genpool_data_fixed offset;
> +		struct null_struct null;
> +	} data;
> +};
> +
> +struct test_action {
> +	unsigned int location;
> +	char pattern[BITMAP_SIZE_C];
> +	unsigned int size;
> +};
> +
> +
> +struct test_command {
> +	enum test_commands command;
> +	union {
> +		struct test_allocator allocator;
> +		struct test_action action;
> +	};
> +};
> +
> +
> +/* To pass an array literal as parameter to a macro, it must go through
> + * this one, first.
> + */

Please use kernel multi-line comment style.

> +#define ARR(...) __VA_ARGS__
> +
> +#define SET_DATA(parameter, value)	\
> +	.parameter = {			\
> +		.parameter = value,	\
> +	}				\
> +
> +#define SET_ALLOCATOR(alloc, parameter, value)		\
> +{							\
> +	.command = CMD_ALLOCATOR,			\
> +	.allocator = {					\
> +		.algo = (alloc),			\
> +		.data = {				\
> +			SET_DATA(parameter, value),	\
> +		},					\
> +	}						\
> +}
> +
> +#define ACTION_MEM(act, mem_size, mem_loc, match)	\
> +{							\
> +	.command = act,					\
> +	.action = {					\
> +		.size = (mem_size),			\
> +		.location = (mem_loc),			\
> +		.pattern = match,			\
> +	},						\
> +}
> +
> +#define ALLOCATE_MEM(mem_size, mem_loc, match)	\
> +	ACTION_MEM(CMD_ALLOCATE, mem_size, mem_loc, ARR(match))
> +
> +#define FREE_MEM(mem_size, mem_loc, match)	\
> +	ACTION_MEM(CMD_FREE, mem_size, mem_loc, ARR(match))
> +
> +#define FLUSH_MEM()		\
> +{				\
> +	.command = CMD_FLUSH,	\
> +}
> +
> +#define END()			\
> +{				\
> +	.command = CMD_END,	\
> +}
> +
> +static inline int compare_bitmaps(const struct gen_pool *pool,
> +				   const char *reference)
> +{
> +	struct gen_pool_chunk *chunk;
> +	char *bitmap;
> +	unsigned int i;
> +
> +	chunk = container_of(pool->chunks.next, struct gen_pool_chunk,
> +			     next_chunk);
> +	bitmap = (char *)chunk->entries;
> +
> +	for (i = 0; i < BITMAP_SIZE_C; i++)
> +		if (bitmap[i] != reference[i])
> +			return -1;
> +	return 0;
> +}
> +
> +static void callback_set_allocator(struct gen_pool *pool,
> +				   const struct test_command *cmd,
> +				   unsigned long *locations)
> +{
> +	gen_pool_set_algo(pool, cmd->allocator.algo,
> +			  (void *)&cmd->allocator.data);
> +}
> +
> +static void callback_allocate(struct gen_pool *pool,
> +			      const struct test_command *cmd,
> +			      unsigned long *locations)
> +{
> +	const struct test_action *action = &cmd->action;
> +
> +	locations[action->location] = gen_pool_alloc(pool, action->size);
> +	BUG_ON(!locations[action->location]);
> +	print_first_chunk_bitmap(pool);
> +	BUG_ON(compare_bitmaps(pool, action->pattern));

BUG_ON() seems harsh to me, but some of the other self-tests also do that.

> +}
> +

[snip]

> +
> +/* To make the test work for both 32bit and 64bit ulong sizes,
> + * allocate (8 / 2 * 4 - 1) = 15 bytes bytes, then 16, then 2.
> + * The first allocation prepares for the crossing of the 32bit ulong
> + * threshold. The following crosses the 32bit threshold and prepares for
> + * crossing the 64bit thresholds. The last is large enough (2 bytes) to
> + * cross the 64bit threshold.
> + * Then free the allocations in the order: 2nd, 1st, 3rd.

Fix multi-line comment style.

> + */
> +const struct test_command test_ulong_span[] = {
> +	SET_ALLOCATOR(gen_pool_first_fit, null, NULL),
> +	ALLOCATE_MEM(15, 0, ARR({0xab, 0xaa, 0xaa, 0x2a})),
> +	ALLOCATE_MEM(16, 1, ARR({0xab, 0xaa, 0xaa, 0xea,
> +				0xaa, 0xaa, 0xaa, 0x2a})),
> +	ALLOCATE_MEM(2, 2, ARR({0xab, 0xaa, 0xaa, 0xea,
> +			       0xaa, 0xaa, 0xaa, 0xea,
> +			       0x02})),
> +	FREE_MEM(0, 1, ARR({0xab, 0xaa, 0xaa, 0x2a,
> +			   0x00, 0x00, 0x00, 0xc0,
> +			   0x02})),
> +	FREE_MEM(0, 0, ARR({0x00, 0x00, 0x00, 0x00,
> +			   0x00, 0x00, 0x00, 0xc0,
> +			   0x02})),
> +	FREE_MEM(0, 2, ARR({0x00})),
> +	END(),
> +};
> +
> +/* Create progressively smaller allocations A B C D E.
> + * then free B and D.
> + * Then create new allocation that would fit in both of the gaps left by
> + * B and D. Verify that it uses the gap from B.

Ditto.

> + */
> +const struct test_command test_first_fit_gaps[] = {


-- 
~Randy

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.