]> Git Repo - J-linux.git/blob - tools/testing/selftests/mm/hugetlb_dio.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / testing / selftests / mm / hugetlb_dio.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
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.
9  */
10
11 #define _GNU_SOURCE
12 #include <stdio.h>
13 #include <sys/stat.h>
14 #include <stdlib.h>
15 #include <fcntl.h>
16 #include <stdint.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <sys/mman.h>
20 #include "vm_util.h"
21 #include "../kselftest.h"
22
23 void run_dio_using_hugetlb(unsigned int start_off, unsigned int end_off)
24 {
25         int fd;
26         char *buffer =  NULL;
27         char *orig_buffer = NULL;
28         size_t h_pagesize = 0;
29         size_t writesize;
30         int free_hpage_b = 0;
31         int free_hpage_a = 0;
32         const int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB;
33         const int mmap_prot  = PROT_READ | PROT_WRITE;
34
35         writesize = end_off - start_off;
36
37         /* Get the default huge page size */
38         h_pagesize = default_huge_page_size();
39         if (!h_pagesize)
40                 ksft_exit_fail_msg("Unable to determine huge page size\n");
41
42         /* Open the file to DIO */
43         fd = open("/tmp", O_TMPFILE | O_RDWR | O_DIRECT, 0664);
44         if (fd < 0)
45                 ksft_exit_fail_perror("Error opening file\n");
46
47         /* Get the free huge pages before allocation */
48         free_hpage_b = get_free_hugepages();
49         if (free_hpage_b == 0) {
50                 close(fd);
51                 ksft_exit_skip("No free hugepage, exiting!\n");
52         }
53
54         /* Allocate a hugetlb page */
55         orig_buffer = mmap(NULL, h_pagesize, mmap_prot, mmap_flags, -1, 0);
56         if (orig_buffer == MAP_FAILED) {
57                 close(fd);
58                 ksft_exit_fail_perror("Error mapping memory\n");
59         }
60         buffer = orig_buffer;
61         buffer += start_off;
62
63         memset(buffer, 'A', writesize);
64
65         /* Write the buffer to the file */
66         if (write(fd, buffer, writesize) != (writesize)) {
67                 munmap(orig_buffer, h_pagesize);
68                 close(fd);
69                 ksft_exit_fail_perror("Error writing to file\n");
70         }
71
72         /* unmap the huge page */
73         munmap(orig_buffer, h_pagesize);
74         close(fd);
75
76         /* Get the free huge pages after unmap*/
77         free_hpage_a = get_free_hugepages();
78
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);
81
82         /*
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.
85          */
86         ksft_test_result(free_hpage_a == free_hpage_b,
87                          "free huge pages from %u-%u\n", start_off, end_off);
88 }
89
90 int main(void)
91 {
92         size_t pagesize = 0;
93         int fd;
94
95         ksft_print_header();
96
97         /* Open the file to DIO */
98         fd = open("/tmp", O_TMPFILE | O_RDWR | O_DIRECT, 0664);
99         if (fd < 0)
100                 ksft_exit_skip("Unable to allocate file: %s\n", strerror(errno));
101         close(fd);
102
103         /* Check if huge pages are free */
104         if (!get_free_hugepages())
105                 ksft_exit_skip("No free hugepage, exiting\n");
106
107         ksft_set_plan(4);
108
109         /* Get base page size */
110         pagesize  = psize();
111
112         /* start and end is aligned to pagesize */
113         run_dio_using_hugetlb(0, (pagesize * 3));
114
115         /* start is aligned but end is not aligned */
116         run_dio_using_hugetlb(0, (pagesize * 3) - (pagesize / 2));
117
118         /* start is unaligned and end is aligned */
119         run_dio_using_hugetlb(pagesize / 2, (pagesize * 3));
120
121         /* both start and end are unaligned */
122         run_dio_using_hugetlb(pagesize / 2, (pagesize * 3) + (pagesize / 2));
123
124         ksft_finished();
125 }
This page took 0.032587 seconds and 4 git commands to generate.