| // 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; |
| } |