1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <dirent.h>
5#include <sys/mman.h>
6#include <sys/ipc.h>
7#include <sys/shm.h>
8
9int HPS;
10char hugetlbfsdir[256];
11#ifndef UTILS
12#include "utils.h"
13#endif
14#define errmsg(x) fprintf(stderr, x), exit(1)
15
16/*
17 * Function    : write_hugepage(char *addr, int nr_hugepage, char *avoid_addr)
18 * Parameters  :
19 *     addr            head address of hugepage range
20 *     nr_hugepage     hugepage number from head address
21 *     avoid_addr      the address which avoid to be operated
22 */
23void write_hugepage(char *addr, int nr_hugepage, char *avoid_addr)
24{
25	int i, j;
26	for (i = 0; i < nr_hugepage; i++) {
27		if ((addr + i * HPS) == avoid_addr)
28			continue;
29		for (j = 0; j < HPS; j++) {
30			*(addr + i * HPS + j) = (char)('a' + ((i + j) % 26));
31		}
32	}
33}
34
35/*
36 * Function    : read_hugepage(char *addr, int nr_hugepage, char *avoid_addr)
37 * Parameters  :
38 *     addr            head address of hugepage range
39 *     nr_hugepage     hugepage number from head address
40 *     avoid_addr      the address which avoid to be operated
41 *
42 * return      :
43 *     0               OK
44 *     -1              if buffer content differs from the expected ones
45 */
46int read_hugepage(char *addr, int nr_hugepage, char *avoid_addr)
47{
48	int i, j;
49	int ret = 0;
50
51	for (i = 0; i < nr_hugepage; i++) {
52		if ((addr + i * HPS) == avoid_addr)
53			continue;
54		for (j = 0; j < HPS; j++) {
55			if (*(addr + i * HPS + j) != (char)('a' + ((i + j) % 26))) {
56				printf("Mismatch at %d\n", i + j);
57				ret = -1;
58				break;
59			}
60		}
61	}
62	return ret;
63}
64
65int hugetlbfs_root(char *dir)
66{
67	int found = 0;
68	FILE *f = fopen("/proc/mounts", "r");
69	if (!f) err("open /proc/mounts");
70	char *line = NULL;
71	size_t linelen = 0;
72	char dummy[100];
73	while (getline(&line, &linelen, f) > 0) {
74		if (sscanf(line, "none %s hugetlbfs %[^ ]",
75			   dir, dummy) >= 2) {
76			found = 1;
77			break;
78		}
79	}
80	free(line);
81	fclose(f);
82	if (!found)
83		printf("cannot find hugetlbfs directory in /proc/mounts\n");
84	return found;
85}
86
87/* Assume there is only one types of hugepage size for now. */
88int gethugepagesize(void)
89{
90	int hpagesize = 0;
91	struct dirent *dent;
92	DIR *dir;
93	dir = opendir("/sys/kernel/mm/hugepages");
94	if (!dir) err("open /sys/kernel/mm/hugepages");
95	while ((dent = readdir(dir)) != NULL)
96		if (sscanf(dent->d_name, "hugepages-%dkB", &hpagesize) >= 1)
97			break;
98	closedir(dir);
99	return hpagesize * 1024;
100}
101
102void *alloc_shm_hugepage(int *key, int size)
103{
104	void *addr;
105	int shmid;
106	if ((shmid = shmget(*key, size,
107			    SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W)) < 0) {
108		perror("shmget");
109		return NULL;
110	}
111	addr = shmat(shmid, (void *)0x0UL, 0);
112	if (addr == (char *)-1) {
113		perror("Shared memory attach failure");
114		shmctl(shmid, IPC_RMID, NULL);
115		return NULL;
116	}
117	*key = shmid;
118	return addr;
119}
120
121void *alloc_anonymous_hugepage(int size, int private)
122{
123	void *addr;
124	int mapflag = MAP_ANONYMOUS | 0x40000; /* MAP_HUGETLB */
125	if (private)
126		mapflag |= MAP_PRIVATE;
127	else
128		mapflag |= MAP_SHARED;
129	if ((addr = mmap(0, size,
130			 PROT_READ|PROT_WRITE, mapflag, -1, 0)) == MAP_FAILED) {
131		perror("mmap");
132		return NULL;
133	}
134	return addr;
135}
136
137void *alloc_filebacked_hugepage(char *filepath, int size, int private, int *fd)
138{
139	int mapflag = MAP_SHARED;
140	void *addr;
141	if (private)
142		mapflag = MAP_PRIVATE;
143	if ((*fd = open(filepath, O_CREAT | O_RDWR, 0777)) < 0) {
144		perror("open");
145		return NULL;
146	}
147	if ((addr = mmap(0, size,
148			 PROT_READ|PROT_WRITE, mapflag, *fd, 0)) == MAP_FAILED) {
149		perror("mmap");
150		unlink(filepath);
151		return NULL;
152	}
153	return addr;
154}
155
156int free_shm_hugepage(int key, void *addr)
157{
158	if (shmdt((const void *)addr) != 0) {
159		perror("Detach failure");
160		shmctl(key, IPC_RMID, NULL);
161		return -1;
162	}
163	shmctl(key, IPC_RMID, NULL);
164	return 0;
165}
166
167int free_anonymous_hugepage(void *addr, int size)
168{
169	int ret = 0;
170	if (munmap(addr, size)) {
171		perror("munmap");
172		ret = -1;
173	}
174	return ret;
175}
176
177int free_filebacked_hugepage(void *addr, int size, int fd, char *filepath)
178{
179	int ret = 0;
180	if (munmap(addr, size)) {
181		perror("munmap");
182		ret = -1;
183	}
184	if (close(fd)) {
185		perror("close");
186		ret = -1;
187	}
188	if (filepath) {
189		if (unlink(filepath)) {
190			perror("unlink");
191			ret = -1;
192		}
193	} else {
194		fprintf(stderr, "Filepath not specified.\n");
195		ret = -1;
196	}
197	return ret;
198}
199