162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * This program reserves and uses hugetlb memory, supporting a bunch of 462306a36Sopenharmony_ci * scenarios needed by the charged_reserved_hugetlb.sh test. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <err.h> 862306a36Sopenharmony_ci#include <errno.h> 962306a36Sopenharmony_ci#include <signal.h> 1062306a36Sopenharmony_ci#include <stdio.h> 1162306a36Sopenharmony_ci#include <stdlib.h> 1262306a36Sopenharmony_ci#include <string.h> 1362306a36Sopenharmony_ci#include <unistd.h> 1462306a36Sopenharmony_ci#include <fcntl.h> 1562306a36Sopenharmony_ci#include <sys/types.h> 1662306a36Sopenharmony_ci#include <sys/shm.h> 1762306a36Sopenharmony_ci#include <sys/stat.h> 1862306a36Sopenharmony_ci#include <sys/mman.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* Global definitions. */ 2162306a36Sopenharmony_cienum method { 2262306a36Sopenharmony_ci HUGETLBFS, 2362306a36Sopenharmony_ci MMAP_MAP_HUGETLB, 2462306a36Sopenharmony_ci SHM, 2562306a36Sopenharmony_ci MAX_METHOD 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* Global variables. */ 3062306a36Sopenharmony_cistatic const char *self; 3162306a36Sopenharmony_cistatic char *shmaddr; 3262306a36Sopenharmony_cistatic int shmid; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * Show usage and exit. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_cistatic void exit_usage(void) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci printf("Usage: %s -p <path to hugetlbfs file> -s <size to map> " 4062306a36Sopenharmony_ci "[-m <0=hugetlbfs | 1=mmap(MAP_HUGETLB)>] [-l] [-r] " 4162306a36Sopenharmony_ci "[-o] [-w] [-n]\n", 4262306a36Sopenharmony_ci self); 4362306a36Sopenharmony_ci exit(EXIT_FAILURE); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_civoid sig_handler(int signo) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci printf("Received %d.\n", signo); 4962306a36Sopenharmony_ci if (signo == SIGINT) { 5062306a36Sopenharmony_ci printf("Deleting the memory\n"); 5162306a36Sopenharmony_ci if (shmdt((const void *)shmaddr) != 0) { 5262306a36Sopenharmony_ci perror("Detach failure"); 5362306a36Sopenharmony_ci shmctl(shmid, IPC_RMID, NULL); 5462306a36Sopenharmony_ci exit(4); 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci shmctl(shmid, IPC_RMID, NULL); 5862306a36Sopenharmony_ci printf("Done deleting the memory\n"); 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci exit(2); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ciint main(int argc, char **argv) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci int fd = 0; 6662306a36Sopenharmony_ci int key = 0; 6762306a36Sopenharmony_ci int *ptr = NULL; 6862306a36Sopenharmony_ci int c = 0; 6962306a36Sopenharmony_ci int size = 0; 7062306a36Sopenharmony_ci char path[256] = ""; 7162306a36Sopenharmony_ci enum method method = MAX_METHOD; 7262306a36Sopenharmony_ci int want_sleep = 0, private = 0; 7362306a36Sopenharmony_ci int populate = 0; 7462306a36Sopenharmony_ci int write = 0; 7562306a36Sopenharmony_ci int reserve = 1; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (signal(SIGINT, sig_handler) == SIG_ERR) 7862306a36Sopenharmony_ci err(1, "\ncan't catch SIGINT\n"); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* Parse command-line arguments. */ 8162306a36Sopenharmony_ci setvbuf(stdout, NULL, _IONBF, 0); 8262306a36Sopenharmony_ci self = argv[0]; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci while ((c = getopt(argc, argv, "s:p:m:owlrn")) != -1) { 8562306a36Sopenharmony_ci switch (c) { 8662306a36Sopenharmony_ci case 's': 8762306a36Sopenharmony_ci size = atoi(optarg); 8862306a36Sopenharmony_ci break; 8962306a36Sopenharmony_ci case 'p': 9062306a36Sopenharmony_ci strncpy(path, optarg, sizeof(path)); 9162306a36Sopenharmony_ci break; 9262306a36Sopenharmony_ci case 'm': 9362306a36Sopenharmony_ci if (atoi(optarg) >= MAX_METHOD) { 9462306a36Sopenharmony_ci errno = EINVAL; 9562306a36Sopenharmony_ci perror("Invalid -m."); 9662306a36Sopenharmony_ci exit_usage(); 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci method = atoi(optarg); 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci case 'o': 10162306a36Sopenharmony_ci populate = 1; 10262306a36Sopenharmony_ci break; 10362306a36Sopenharmony_ci case 'w': 10462306a36Sopenharmony_ci write = 1; 10562306a36Sopenharmony_ci break; 10662306a36Sopenharmony_ci case 'l': 10762306a36Sopenharmony_ci want_sleep = 1; 10862306a36Sopenharmony_ci break; 10962306a36Sopenharmony_ci case 'r': 11062306a36Sopenharmony_ci private 11162306a36Sopenharmony_ci = 1; 11262306a36Sopenharmony_ci break; 11362306a36Sopenharmony_ci case 'n': 11462306a36Sopenharmony_ci reserve = 0; 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci default: 11762306a36Sopenharmony_ci errno = EINVAL; 11862306a36Sopenharmony_ci perror("Invalid arg"); 11962306a36Sopenharmony_ci exit_usage(); 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (strncmp(path, "", sizeof(path)) != 0) { 12462306a36Sopenharmony_ci printf("Writing to this path: %s\n", path); 12562306a36Sopenharmony_ci } else { 12662306a36Sopenharmony_ci errno = EINVAL; 12762306a36Sopenharmony_ci perror("path not found"); 12862306a36Sopenharmony_ci exit_usage(); 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (size != 0) { 13262306a36Sopenharmony_ci printf("Writing this size: %d\n", size); 13362306a36Sopenharmony_ci } else { 13462306a36Sopenharmony_ci errno = EINVAL; 13562306a36Sopenharmony_ci perror("size not found"); 13662306a36Sopenharmony_ci exit_usage(); 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (!populate) 14062306a36Sopenharmony_ci printf("Not populating.\n"); 14162306a36Sopenharmony_ci else 14262306a36Sopenharmony_ci printf("Populating.\n"); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (!write) 14562306a36Sopenharmony_ci printf("Not writing to memory.\n"); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (method == MAX_METHOD) { 14862306a36Sopenharmony_ci errno = EINVAL; 14962306a36Sopenharmony_ci perror("-m Invalid"); 15062306a36Sopenharmony_ci exit_usage(); 15162306a36Sopenharmony_ci } else 15262306a36Sopenharmony_ci printf("Using method=%d\n", method); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (!private) 15562306a36Sopenharmony_ci printf("Shared mapping.\n"); 15662306a36Sopenharmony_ci else 15762306a36Sopenharmony_ci printf("Private mapping.\n"); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (!reserve) 16062306a36Sopenharmony_ci printf("NO_RESERVE mapping.\n"); 16162306a36Sopenharmony_ci else 16262306a36Sopenharmony_ci printf("RESERVE mapping.\n"); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci switch (method) { 16562306a36Sopenharmony_ci case HUGETLBFS: 16662306a36Sopenharmony_ci printf("Allocating using HUGETLBFS.\n"); 16762306a36Sopenharmony_ci fd = open(path, O_CREAT | O_RDWR, 0777); 16862306a36Sopenharmony_ci if (fd == -1) 16962306a36Sopenharmony_ci err(1, "Failed to open file."); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, 17262306a36Sopenharmony_ci (private ? MAP_PRIVATE : MAP_SHARED) | 17362306a36Sopenharmony_ci (populate ? MAP_POPULATE : 0) | 17462306a36Sopenharmony_ci (reserve ? 0 : MAP_NORESERVE), 17562306a36Sopenharmony_ci fd, 0); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (ptr == MAP_FAILED) { 17862306a36Sopenharmony_ci close(fd); 17962306a36Sopenharmony_ci err(1, "Error mapping the file"); 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci break; 18262306a36Sopenharmony_ci case MMAP_MAP_HUGETLB: 18362306a36Sopenharmony_ci printf("Allocating using MAP_HUGETLB.\n"); 18462306a36Sopenharmony_ci ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, 18562306a36Sopenharmony_ci (private ? (MAP_PRIVATE | MAP_ANONYMOUS) : 18662306a36Sopenharmony_ci MAP_SHARED) | 18762306a36Sopenharmony_ci MAP_HUGETLB | (populate ? MAP_POPULATE : 0) | 18862306a36Sopenharmony_ci (reserve ? 0 : MAP_NORESERVE), 18962306a36Sopenharmony_ci -1, 0); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (ptr == MAP_FAILED) 19262306a36Sopenharmony_ci err(1, "mmap"); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci printf("Returned address is %p\n", ptr); 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci case SHM: 19762306a36Sopenharmony_ci printf("Allocating using SHM.\n"); 19862306a36Sopenharmony_ci shmid = shmget(key, size, 19962306a36Sopenharmony_ci SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W); 20062306a36Sopenharmony_ci if (shmid < 0) { 20162306a36Sopenharmony_ci shmid = shmget(++key, size, 20262306a36Sopenharmony_ci SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W); 20362306a36Sopenharmony_ci if (shmid < 0) 20462306a36Sopenharmony_ci err(1, "shmget"); 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci printf("shmid: 0x%x, shmget key:%d\n", shmid, key); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci ptr = shmat(shmid, NULL, 0); 20962306a36Sopenharmony_ci if (ptr == (int *)-1) { 21062306a36Sopenharmony_ci perror("Shared memory attach failure"); 21162306a36Sopenharmony_ci shmctl(shmid, IPC_RMID, NULL); 21262306a36Sopenharmony_ci exit(2); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci printf("shmaddr: %p\n", ptr); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci break; 21762306a36Sopenharmony_ci default: 21862306a36Sopenharmony_ci errno = EINVAL; 21962306a36Sopenharmony_ci err(1, "Invalid method."); 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (write) { 22362306a36Sopenharmony_ci printf("Writing to memory.\n"); 22462306a36Sopenharmony_ci memset(ptr, 1, size); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (want_sleep) { 22862306a36Sopenharmony_ci /* Signal to caller that we're done. */ 22962306a36Sopenharmony_ci printf("DONE\n"); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* Hold memory until external kill signal is delivered. */ 23262306a36Sopenharmony_ci while (1) 23362306a36Sopenharmony_ci sleep(100); 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (method == HUGETLBFS) 23762306a36Sopenharmony_ci close(fd); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return 0; 24062306a36Sopenharmony_ci} 241