1 // SPDX-License-Identifier: GPL-2.0
3 * This program tests for hugepage leaks after DIO writes to a file using a
4 * hugepage as the user buffer. During DIO, the user buffer is pinned and
5 * should be properly unpinned upon completion. This patch verifies that the
6 * kernel correctly unpins the buffer at DIO completion for both aligned and
7 * unaligned user buffer offsets (w.r.t page boundary), ensuring the hugepage
8 * is freed upon unmapping.
21 #include "../kselftest.h"
23 void run_dio_using_hugetlb(unsigned int start_off, unsigned int end_off)
27 char *orig_buffer = NULL;
28 size_t h_pagesize = 0;
32 const int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB;
33 const int mmap_prot = PROT_READ | PROT_WRITE;
35 writesize = end_off - start_off;
37 /* Get the default huge page size */
38 h_pagesize = default_huge_page_size();
40 ksft_exit_fail_msg("Unable to determine huge page size\n");
42 /* Open the file to DIO */
43 fd = open("/tmp", O_TMPFILE | O_RDWR | O_DIRECT, 0664);
45 ksft_exit_fail_perror("Error opening file\n");
47 /* Get the free huge pages before allocation */
48 free_hpage_b = get_free_hugepages();
49 if (free_hpage_b == 0) {
51 ksft_exit_skip("No free hugepage, exiting!\n");
54 /* Allocate a hugetlb page */
55 orig_buffer = mmap(NULL, h_pagesize, mmap_prot, mmap_flags, -1, 0);
56 if (orig_buffer == MAP_FAILED) {
58 ksft_exit_fail_perror("Error mapping memory\n");
63 memset(buffer, 'A', writesize);
65 /* Write the buffer to the file */
66 if (write(fd, buffer, writesize) != (writesize)) {
67 munmap(orig_buffer, h_pagesize);
69 ksft_exit_fail_perror("Error writing to file\n");
72 /* unmap the huge page */
73 munmap(orig_buffer, h_pagesize);
76 /* Get the free huge pages after unmap*/
77 free_hpage_a = get_free_hugepages();
79 ksft_print_msg("No. Free pages before allocation : %d\n", free_hpage_b);
80 ksft_print_msg("No. Free pages after munmap : %d\n", free_hpage_a);
83 * If the no. of free hugepages before allocation and after unmap does
84 * not match - that means there could still be a page which is pinned.
86 ksft_test_result(free_hpage_a == free_hpage_b,
87 "free huge pages from %u-%u\n", start_off, end_off);
97 /* Open the file to DIO */
98 fd = open("/tmp", O_TMPFILE | O_RDWR | O_DIRECT, 0664);
100 ksft_exit_skip("Unable to allocate file: %s\n", strerror(errno));
103 /* Check if huge pages are free */
104 if (!get_free_hugepages())
105 ksft_exit_skip("No free hugepage, exiting\n");
109 /* Get base page size */
112 /* start and end is aligned to pagesize */
113 run_dio_using_hugetlb(0, (pagesize * 3));
115 /* start is aligned but end is not aligned */
116 run_dio_using_hugetlb(0, (pagesize * 3) - (pagesize / 2));
118 /* start is unaligned and end is aligned */
119 run_dio_using_hugetlb(pagesize / 2, (pagesize * 3));
121 /* both start and end are unaligned */
122 run_dio_using_hugetlb(pagesize / 2, (pagesize * 3) + (pagesize / 2));