209 lines · 4.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later#include "tests/common.h"#include <string.h>#include <getopt.h>#include <linux/memory_hotplug.h>#include <linux/build_bug.h> #define PREFIXES_MAX				15#define DELIM					": "#define BASIS					10000 static struct test_memory memory_block;static const char __maybe_unused *prefixes[PREFIXES_MAX];static int __maybe_unused nr_prefixes; static const char *short_opts = "hmv";static const struct option long_opts[] = {	{"help", 0, NULL, 'h'},	{"movable-node", 0, NULL, 'm'},	{"verbose", 0, NULL, 'v'},	{NULL, 0, NULL, 0}}; static const char * const help_opts[] = {	"display this help message and exit",	"disallow allocations from regions marked as hotplugged\n\t\t\t"		"by simulating enabling the \"movable_node\" kernel\n\t\t\t"		"parameter",	"enable verbose output, which includes the name of the\n\t\t\t"		"memblock function being tested, the name of the test,\n\t\t\t"		"and whether the test passed or failed."}; static int verbose; /* sets global variable returned by movable_node_is_enabled() stub */bool movable_node_enabled; void reset_memblock_regions(void){	memset(memblock.memory.regions, 0,	       memblock.memory.cnt * sizeof(struct memblock_region));	memblock.memory.cnt     = 0;	memblock.memory.max	= INIT_MEMBLOCK_REGIONS;	memblock.memory.total_size = 0; 	memset(memblock.reserved.regions, 0,	       memblock.reserved.cnt * sizeof(struct memblock_region));	memblock.reserved.cnt   = 0;	memblock.reserved.max	= INIT_MEMBLOCK_RESERVED_REGIONS;	memblock.reserved.total_size = 0;} void reset_memblock_attributes(void){	memblock.memory.name	= "memory";	memblock.reserved.name	= "reserved";	memblock.bottom_up	= false;	memblock.current_limit	= MEMBLOCK_ALLOC_ANYWHERE;} static inline void fill_memblock(void){	memset(memory_block.base, 1, PHYS_MEM_SIZE);} void setup_memblock(void){	reset_memblock_regions();	memblock_add((phys_addr_t)memory_block.base, MEM_SIZE);	fill_memblock();} /** * setup_numa_memblock: * Set up a memory layout with multiple NUMA nodes in a previously allocated * dummy physical memory. * @node_fracs: an array representing the fraction of MEM_SIZE contained in *              each node in basis point units (one hundredth of 1% or 1/10000). *              For example, if node 0 should contain 1/8 of MEM_SIZE, *              node_fracs[0] = 1250. * * The nids will be set to 0 through NUMA_NODES - 1. */void setup_numa_memblock(const unsigned int node_fracs[]){	phys_addr_t base;	int flags; 	reset_memblock_regions();	base = (phys_addr_t)memory_block.base;	flags = (movable_node_is_enabled()) ? MEMBLOCK_NONE : MEMBLOCK_HOTPLUG; 	for (int i = 0; i < NUMA_NODES; i++) {		assert(node_fracs[i] <= BASIS);		phys_addr_t size = MEM_SIZE * node_fracs[i] / BASIS; 		memblock_add_node(base, size, i, flags);		base += size;	}	fill_memblock();} void dummy_physical_memory_init(void){	memory_block.base = malloc(PHYS_MEM_SIZE);	assert(memory_block.base);	fill_memblock();} void dummy_physical_memory_cleanup(void){	free(memory_block.base);} phys_addr_t dummy_physical_memory_base(void){	return (phys_addr_t)memory_block.base;} static void usage(const char *prog){	BUILD_BUG_ON(ARRAY_SIZE(help_opts) != ARRAY_SIZE(long_opts) - 1); 	printf("Usage: %s [-%s]\n", prog, short_opts); 	for (int i = 0; long_opts[i].name; i++) {		printf("  -%c, --%-12s\t%s\n", long_opts[i].val,		       long_opts[i].name, help_opts[i]);	} 	exit(1);} void parse_args(int argc, char **argv){	int c; 	while ((c = getopt_long_only(argc, argv, short_opts, long_opts,				     NULL)) != -1) {		switch (c) {		case 'm':			movable_node_enabled = true;			break;		case 'v':			verbose = 1;			break;		default:			usage(argv[0]);		}	}} void print_prefixes(const char *postfix){	for (int i = 0; i < nr_prefixes; i++)		test_print("%s%s", prefixes[i], DELIM);	test_print(postfix);} void test_fail(void){	if (verbose) {		ksft_test_result_fail(": ");		print_prefixes("failed\n");	}} void test_pass(void){	if (verbose) {		ksft_test_result_pass(": ");		print_prefixes("passed\n");	}} void test_print(const char *fmt, ...){	if (verbose) {		int saved_errno = errno;		va_list args; 		va_start(args, fmt);		errno = saved_errno;		vprintf(fmt, args);		va_end(args);	}} void prefix_reset(void){	memset(prefixes, 0, PREFIXES_MAX * sizeof(char *));	nr_prefixes = 0;} void prefix_push(const char *prefix){	assert(nr_prefixes < PREFIXES_MAX);	prefixes[nr_prefixes] = prefix;	nr_prefixes++;} void prefix_pop(void){	if (nr_prefixes > 0) {		prefixes[nr_prefixes - 1] = 0;		nr_prefixes--;	}}