// 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 #include #include #include #include #include #include #include #include #include #include #include /* 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 -s " "[-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; }