Skip to content

Commit 9903bd7

Browse files
mjkravetztorvalds
authored andcommitted
userfaultfd: hugetlbfs: add userfaultfd_hugetlb test
Test userfaultfd hugetlb functionality by using the existing testing method (in userfaultfd.c). Instead of an anonymous memeory, a hugetlbfs file is mmap'ed private. In this way fallocate hole punch can be used to release pages. This is because madvise(MADV_DONTNEED) is not supported for huge pages. Use the same file, but create wrappers for allocating ranges and releasing pages. Compile userfaultfd.c with HUGETLB_TEST defined to produce an executable to test userfaultfd hugetlb functionality. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Mike Kravetz <[email protected]> Signed-off-by: Andrea Arcangeli <[email protected]> Cc: "Dr. David Alan Gilbert" <[email protected]> Cc: Hillf Danton <[email protected]> Cc: Michael Rapoport <[email protected]> Cc: Mike Rapoport <[email protected]> Cc: Pavel Emelyanov <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent cab350a commit 9903bd7

File tree

3 files changed

+161
-17
lines changed

3 files changed

+161
-17
lines changed

tools/testing/selftests/vm/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ BINARIES += on-fault-limit
1010
BINARIES += thuge-gen
1111
BINARIES += transhuge-stress
1212
BINARIES += userfaultfd
13+
BINARIES += userfaultfd_hugetlb
1314
BINARIES += mlock-random-test
1415

1516
all: $(BINARIES)
@@ -18,6 +19,9 @@ all: $(BINARIES)
1819
userfaultfd: userfaultfd.c ../../../../usr/include/linux/kernel.h
1920
$(CC) $(CFLAGS) -O2 -o $@ $< -lpthread
2021

22+
userfaultfd_hugetlb: userfaultfd.c ../../../../usr/include/linux/kernel.h
23+
$(CC) $(CFLAGS) -DHUGETLB_TEST -O2 -o $@ $< -lpthread
24+
2125
mlock-random-test: mlock-random-test.c
2226
$(CC) $(CFLAGS) -o $@ $< -lcap
2327

tools/testing/selftests/vm/run_vmtests

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,19 @@ else
103103
echo "[PASS]"
104104
fi
105105

106+
echo "----------------------------"
107+
echo "running userfaultfd_hugetlb"
108+
echo "----------------------------"
109+
# 258MB total huge pages == 128MB src and 128MB dst
110+
./userfaultfd_hugetlb 128 32 $mnt/ufd_test_file
111+
if [ $? -ne 0 ]; then
112+
echo "[FAIL]"
113+
exitcode=1
114+
else
115+
echo "[PASS]"
116+
fi
117+
rm -f $mnt/ufd_test_file
118+
106119
#cleanup
107120
umount $mnt
108121
rm -rf $mnt

tools/testing/selftests/vm/userfaultfd.c

Lines changed: 144 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ static unsigned long nr_cpus, nr_pages, nr_pages_per_cpu, page_size;
7676
#define BOUNCE_POLL (1<<3)
7777
static int bounces;
7878

79+
#ifdef HUGETLB_TEST
80+
static int huge_fd;
81+
static char *huge_fd_off0;
82+
#endif
7983
static unsigned long long *count_verify;
8084
static int uffd, finished, *pipefd;
8185
static char *area_src, *area_dst;
@@ -97,6 +101,69 @@ pthread_attr_t attr;
97101
~(unsigned long)(sizeof(unsigned long long) \
98102
- 1)))
99103

104+
#ifndef HUGETLB_TEST
105+
106+
#define EXPECTED_IOCTLS ((1 << _UFFDIO_WAKE) | \
107+
(1 << _UFFDIO_COPY) | \
108+
(1 << _UFFDIO_ZEROPAGE))
109+
110+
static int release_pages(char *rel_area)
111+
{
112+
int ret = 0;
113+
114+
if (madvise(rel_area, nr_pages * page_size, MADV_DONTNEED)) {
115+
perror("madvise");
116+
ret = 1;
117+
}
118+
119+
return ret;
120+
}
121+
122+
static void allocate_area(void **alloc_area)
123+
{
124+
if (posix_memalign(alloc_area, page_size, nr_pages * page_size)) {
125+
fprintf(stderr, "out of memory\n");
126+
*alloc_area = NULL;
127+
}
128+
}
129+
130+
#else /* HUGETLB_TEST */
131+
132+
#define EXPECTED_IOCTLS UFFD_API_RANGE_IOCTLS_HPAGE
133+
134+
static int release_pages(char *rel_area)
135+
{
136+
int ret = 0;
137+
138+
if (fallocate(huge_fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
139+
rel_area == huge_fd_off0 ? 0 :
140+
nr_pages * page_size,
141+
nr_pages * page_size)) {
142+
perror("fallocate");
143+
ret = 1;
144+
}
145+
146+
return ret;
147+
}
148+
149+
150+
static void allocate_area(void **alloc_area)
151+
{
152+
*alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE,
153+
MAP_PRIVATE | MAP_HUGETLB, huge_fd,
154+
*alloc_area == area_src ? 0 :
155+
nr_pages * page_size);
156+
if (*alloc_area == MAP_FAILED) {
157+
fprintf(stderr, "mmap of hugetlbfs file failed\n");
158+
*alloc_area = NULL;
159+
}
160+
161+
if (*alloc_area == area_src)
162+
huge_fd_off0 = *alloc_area;
163+
}
164+
165+
#endif /* HUGETLB_TEST */
166+
100167
static int my_bcmp(char *str1, char *str2, size_t n)
101168
{
102169
unsigned long i;
@@ -384,10 +451,8 @@ static int stress(unsigned long *userfaults)
384451
* UFFDIO_COPY without writing zero pages into area_dst
385452
* because the background threads already completed).
386453
*/
387-
if (madvise(area_src, nr_pages * page_size, MADV_DONTNEED)) {
388-
perror("madvise");
454+
if (release_pages(area_src))
389455
return 1;
390-
}
391456

392457
for (cpu = 0; cpu < nr_cpus; cpu++) {
393458
char c;
@@ -425,16 +490,12 @@ static int userfaultfd_stress(void)
425490
int uffd_flags, err;
426491
unsigned long userfaults[nr_cpus];
427492

428-
if (posix_memalign(&area, page_size, nr_pages * page_size)) {
429-
fprintf(stderr, "out of memory\n");
493+
allocate_area((void **)&area_src);
494+
if (!area_src)
430495
return 1;
431-
}
432-
area_src = area;
433-
if (posix_memalign(&area, page_size, nr_pages * page_size)) {
434-
fprintf(stderr, "out of memory\n");
496+
allocate_area((void **)&area_dst);
497+
if (!area_dst)
435498
return 1;
436-
}
437-
area_dst = area;
438499

439500
uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
440501
if (uffd < 0) {
@@ -528,9 +589,7 @@ static int userfaultfd_stress(void)
528589
fprintf(stderr, "register failure\n");
529590
return 1;
530591
}
531-
expected_ioctls = (1 << _UFFDIO_WAKE) |
532-
(1 << _UFFDIO_COPY) |
533-
(1 << _UFFDIO_ZEROPAGE);
592+
expected_ioctls = EXPECTED_IOCTLS;
534593
if ((uffdio_register.ioctls & expected_ioctls) !=
535594
expected_ioctls) {
536595
fprintf(stderr,
@@ -562,10 +621,8 @@ static int userfaultfd_stress(void)
562621
* MADV_DONTNEED only after the UFFDIO_REGISTER, so it's
563622
* required to MADV_DONTNEED here.
564623
*/
565-
if (madvise(area_dst, nr_pages * page_size, MADV_DONTNEED)) {
566-
perror("madvise 2");
624+
if (release_pages(area_dst))
567625
return 1;
568-
}
569626

570627
/* bounce pass */
571628
if (stress(userfaults))
@@ -606,6 +663,8 @@ static int userfaultfd_stress(void)
606663
return err;
607664
}
608665

666+
#ifndef HUGETLB_TEST
667+
609668
int main(int argc, char **argv)
610669
{
611670
if (argc < 3)
@@ -632,6 +691,74 @@ int main(int argc, char **argv)
632691
return userfaultfd_stress();
633692
}
634693

694+
#else /* HUGETLB_TEST */
695+
696+
/*
697+
* Copied from mlock2-tests.c
698+
*/
699+
unsigned long default_huge_page_size(void)
700+
{
701+
unsigned long hps = 0;
702+
char *line = NULL;
703+
size_t linelen = 0;
704+
FILE *f = fopen("/proc/meminfo", "r");
705+
706+
if (!f)
707+
return 0;
708+
while (getline(&line, &linelen, f) > 0) {
709+
if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) {
710+
hps <<= 10;
711+
break;
712+
}
713+
}
714+
715+
free(line);
716+
fclose(f);
717+
return hps;
718+
}
719+
720+
int main(int argc, char **argv)
721+
{
722+
if (argc < 4)
723+
fprintf(stderr, "Usage: <MiB> <bounces> <hugetlbfs_file>\n"),
724+
exit(1);
725+
nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
726+
page_size = default_huge_page_size();
727+
if (!page_size)
728+
fprintf(stderr, "Unable to determine huge page size\n"),
729+
exit(2);
730+
if ((unsigned long) area_count(NULL, 0) + sizeof(unsigned long long) * 2
731+
> page_size)
732+
fprintf(stderr, "Impossible to run this test\n"), exit(2);
733+
nr_pages_per_cpu = atol(argv[1]) * 1024*1024 / page_size /
734+
nr_cpus;
735+
if (!nr_pages_per_cpu) {
736+
fprintf(stderr, "invalid MiB\n");
737+
fprintf(stderr, "Usage: <MiB> <bounces>\n"), exit(1);
738+
}
739+
bounces = atoi(argv[2]);
740+
if (bounces <= 0) {
741+
fprintf(stderr, "invalid bounces\n");
742+
fprintf(stderr, "Usage: <MiB> <bounces>\n"), exit(1);
743+
}
744+
nr_pages = nr_pages_per_cpu * nr_cpus;
745+
huge_fd = open(argv[3], O_CREAT | O_RDWR, 0755);
746+
if (huge_fd < 0) {
747+
fprintf(stderr, "Open of %s failed", argv[3]);
748+
perror("open");
749+
exit(1);
750+
}
751+
if (ftruncate(huge_fd, 0)) {
752+
fprintf(stderr, "ftruncate %s to size 0 failed", argv[3]);
753+
perror("ftruncate");
754+
exit(1);
755+
}
756+
printf("nr_pages: %lu, nr_pages_per_cpu: %lu\n",
757+
nr_pages, nr_pages_per_cpu);
758+
return userfaultfd_stress();
759+
}
760+
761+
#endif
635762
#else /* __NR_userfaultfd */
636763

637764
#warning "missing __NR_userfaultfd definition"

0 commit comments

Comments
 (0)