diff options
Diffstat (limited to 'tools/testing/selftests/mm/write_to_hugetlbfs.c')
| -rw-r--r-- | tools/testing/selftests/mm/write_to_hugetlbfs.c | 240 | 
1 files changed, 240 insertions, 0 deletions
diff --git a/tools/testing/selftests/mm/write_to_hugetlbfs.c b/tools/testing/selftests/mm/write_to_hugetlbfs.c new file mode 100644 index 000000000000..6a2caba19ee1 --- /dev/null +++ b/tools/testing/selftests/mm/write_to_hugetlbfs.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This program reserves and uses hugetlb memory, supporting a bunch of + * scenarios needed by the charged_reserved_hugetlb.sh test. + */ + +#include <err.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/shm.h> +#include <sys/stat.h> +#include <sys/mman.h> + +/* Global definitions. */ +enum method { +	HUGETLBFS, +	MMAP_MAP_HUGETLB, +	SHM, +	MAX_METHOD +}; + + +/* Global variables. */ +static const char *self; +static char *shmaddr; +static int shmid; + +/* + * Show usage and exit. + */ +static void exit_usage(void) +{ +	printf("Usage: %s -p <path to hugetlbfs file> -s <size to map> " +	       "[-m <0=hugetlbfs | 1=mmap(MAP_HUGETLB)>] [-l] [-r] " +	       "[-o] [-w] [-n]\n", +	       self); +	exit(EXIT_FAILURE); +} + +void sig_handler(int signo) +{ +	printf("Received %d.\n", signo); +	if (signo == SIGINT) { +		printf("Deleting the memory\n"); +		if (shmdt((const void *)shmaddr) != 0) { +			perror("Detach failure"); +			shmctl(shmid, IPC_RMID, NULL); +			exit(4); +		} + +		shmctl(shmid, IPC_RMID, NULL); +		printf("Done deleting the memory\n"); +	} +	exit(2); +} + +int main(int argc, char **argv) +{ +	int fd = 0; +	int key = 0; +	int *ptr = NULL; +	int c = 0; +	int size = 0; +	char path[256] = ""; +	enum method method = MAX_METHOD; +	int want_sleep = 0, private = 0; +	int populate = 0; +	int write = 0; +	int reserve = 1; + +	if (signal(SIGINT, sig_handler) == SIG_ERR) +		err(1, "\ncan't catch SIGINT\n"); + +	/* Parse command-line arguments. */ +	setvbuf(stdout, NULL, _IONBF, 0); +	self = argv[0]; + +	while ((c = getopt(argc, argv, "s:p:m:owlrn")) != -1) { +		switch (c) { +		case 's': +			size = atoi(optarg); +			break; +		case 'p': +			strncpy(path, optarg, sizeof(path)); +			break; +		case 'm': +			if (atoi(optarg) >= MAX_METHOD) { +				errno = EINVAL; +				perror("Invalid -m."); +				exit_usage(); +			} +			method = atoi(optarg); +			break; +		case 'o': +			populate = 1; +			break; +		case 'w': +			write = 1; +			break; +		case 'l': +			want_sleep = 1; +			break; +		case 'r': +		    private +			= 1; +			break; +		case 'n': +			reserve = 0; +			break; +		default: +			errno = EINVAL; +			perror("Invalid arg"); +			exit_usage(); +		} +	} + +	if (strncmp(path, "", sizeof(path)) != 0) { +		printf("Writing to this path: %s\n", path); +	} else { +		errno = EINVAL; +		perror("path not found"); +		exit_usage(); +	} + +	if (size != 0) { +		printf("Writing this size: %d\n", size); +	} else { +		errno = EINVAL; +		perror("size not found"); +		exit_usage(); +	} + +	if (!populate) +		printf("Not populating.\n"); +	else +		printf("Populating.\n"); + +	if (!write) +		printf("Not writing to memory.\n"); + +	if (method == MAX_METHOD) { +		errno = EINVAL; +		perror("-m Invalid"); +		exit_usage(); +	} else +		printf("Using method=%d\n", method); + +	if (!private) +		printf("Shared mapping.\n"); +	else +		printf("Private mapping.\n"); + +	if (!reserve) +		printf("NO_RESERVE mapping.\n"); +	else +		printf("RESERVE mapping.\n"); + +	switch (method) { +	case HUGETLBFS: +		printf("Allocating using HUGETLBFS.\n"); +		fd = open(path, O_CREAT | O_RDWR, 0777); +		if (fd == -1) +			err(1, "Failed to open file."); + +		ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, +			   (private ? MAP_PRIVATE : MAP_SHARED) | +				   (populate ? MAP_POPULATE : 0) | +				   (reserve ? 0 : MAP_NORESERVE), +			   fd, 0); + +		if (ptr == MAP_FAILED) { +			close(fd); +			err(1, "Error mapping the file"); +		} +		break; +	case MMAP_MAP_HUGETLB: +		printf("Allocating using MAP_HUGETLB.\n"); +		ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, +			   (private ? (MAP_PRIVATE | MAP_ANONYMOUS) : +				      MAP_SHARED) | +				   MAP_HUGETLB | (populate ? MAP_POPULATE : 0) | +				   (reserve ? 0 : MAP_NORESERVE), +			   -1, 0); + +		if (ptr == MAP_FAILED) +			err(1, "mmap"); + +		printf("Returned address is %p\n", ptr); +		break; +	case SHM: +		printf("Allocating using SHM.\n"); +		shmid = shmget(key, size, +			       SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W); +		if (shmid < 0) { +			shmid = shmget(++key, size, +				       SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W); +			if (shmid < 0) +				err(1, "shmget"); +		} +		printf("shmid: 0x%x, shmget key:%d\n", shmid, key); + +		ptr = shmat(shmid, NULL, 0); +		if (ptr == (int *)-1) { +			perror("Shared memory attach failure"); +			shmctl(shmid, IPC_RMID, NULL); +			exit(2); +		} +		printf("shmaddr: %p\n", ptr); + +		break; +	default: +		errno = EINVAL; +		err(1, "Invalid method."); +	} + +	if (write) { +		printf("Writing to memory.\n"); +		memset(ptr, 1, size); +	} + +	if (want_sleep) { +		/* Signal to caller that we're done. */ +		printf("DONE\n"); + +		/* Hold memory until external kill signal is delivered. */ +		while (1) +			sleep(100); +	} + +	if (method == HUGETLBFS) +		close(fd); + +	return 0; +}  |