~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/mm/soft-dirty.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <stdbool.h>
  5 #include <fcntl.h>
  6 #include <stdint.h>
  7 #include <malloc.h>
  8 #include <sys/mman.h>
  9 #include "../kselftest.h"
 10 #include "vm_util.h"
 11 
 12 #define PAGEMAP_FILE_PATH "/proc/self/pagemap"
 13 #define TEST_ITERATIONS 10000
 14 
 15 static void test_simple(int pagemap_fd, int pagesize)
 16 {
 17         int i;
 18         char *map;
 19 
 20         map = aligned_alloc(pagesize, pagesize);
 21         if (!map)
 22                 ksft_exit_fail_msg("mmap failed\n");
 23 
 24         clear_softdirty();
 25 
 26         for (i = 0 ; i < TEST_ITERATIONS; i++) {
 27                 if (pagemap_is_softdirty(pagemap_fd, map) == 1) {
 28                         ksft_print_msg("dirty bit was 1, but should be 0 (i=%d)\n", i);
 29                         break;
 30                 }
 31 
 32                 clear_softdirty();
 33                 // Write something to the page to get the dirty bit enabled on the page
 34                 map[0]++;
 35 
 36                 if (pagemap_is_softdirty(pagemap_fd, map) == 0) {
 37                         ksft_print_msg("dirty bit was 0, but should be 1 (i=%d)\n", i);
 38                         break;
 39                 }
 40 
 41                 clear_softdirty();
 42         }
 43         free(map);
 44 
 45         ksft_test_result(i == TEST_ITERATIONS, "Test %s\n", __func__);
 46 }
 47 
 48 static void test_vma_reuse(int pagemap_fd, int pagesize)
 49 {
 50         char *map, *map2;
 51 
 52         map = mmap(NULL, pagesize, (PROT_READ | PROT_WRITE), (MAP_PRIVATE | MAP_ANON), -1, 0);
 53         if (map == MAP_FAILED)
 54                 ksft_exit_fail_msg("mmap failed");
 55 
 56         // The kernel always marks new regions as soft dirty
 57         ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 1,
 58                          "Test %s dirty bit of allocated page\n", __func__);
 59 
 60         clear_softdirty();
 61         munmap(map, pagesize);
 62 
 63         map2 = mmap(NULL, pagesize, (PROT_READ | PROT_WRITE), (MAP_PRIVATE | MAP_ANON), -1, 0);
 64         if (map2 == MAP_FAILED)
 65                 ksft_exit_fail_msg("mmap failed");
 66 
 67         // Dirty bit is set for new regions even if they are reused
 68         if (map == map2)
 69                 ksft_test_result(pagemap_is_softdirty(pagemap_fd, map2) == 1,
 70                                  "Test %s dirty bit of reused address page\n", __func__);
 71         else
 72                 ksft_test_result_skip("Test %s dirty bit of reused address page\n", __func__);
 73 
 74         munmap(map2, pagesize);
 75 }
 76 
 77 static void test_hugepage(int pagemap_fd, int pagesize)
 78 {
 79         char *map;
 80         int i, ret;
 81         size_t hpage_len = read_pmd_pagesize();
 82 
 83         if (!hpage_len)
 84                 ksft_exit_fail_msg("Reading PMD pagesize failed");
 85 
 86         map = memalign(hpage_len, hpage_len);
 87         if (!map)
 88                 ksft_exit_fail_msg("memalign failed\n");
 89 
 90         ret = madvise(map, hpage_len, MADV_HUGEPAGE);
 91         if (ret)
 92                 ksft_exit_fail_msg("madvise failed %d\n", ret);
 93 
 94         for (i = 0; i < hpage_len; i++)
 95                 map[i] = (char)i;
 96 
 97         if (check_huge_anon(map, 1, hpage_len)) {
 98                 ksft_test_result_pass("Test %s huge page allocation\n", __func__);
 99 
100                 clear_softdirty();
101                 for (i = 0 ; i < TEST_ITERATIONS ; i++) {
102                         if (pagemap_is_softdirty(pagemap_fd, map) == 1) {
103                                 ksft_print_msg("dirty bit was 1, but should be 0 (i=%d)\n", i);
104                                 break;
105                         }
106 
107                         clear_softdirty();
108                         // Write something to the page to get the dirty bit enabled on the page
109                         map[0]++;
110 
111                         if (pagemap_is_softdirty(pagemap_fd, map) == 0) {
112                                 ksft_print_msg("dirty bit was 0, but should be 1 (i=%d)\n", i);
113                                 break;
114                         }
115                         clear_softdirty();
116                 }
117 
118                 ksft_test_result(i == TEST_ITERATIONS, "Test %s huge page dirty bit\n", __func__);
119         } else {
120                 // hugepage allocation failed. skip these tests
121                 ksft_test_result_skip("Test %s huge page allocation\n", __func__);
122                 ksft_test_result_skip("Test %s huge page dirty bit\n", __func__);
123         }
124         free(map);
125 }
126 
127 static void test_mprotect(int pagemap_fd, int pagesize, bool anon)
128 {
129         const char *type[] = {"file", "anon"};
130         const char *fname = "./soft-dirty-test-file";
131         int test_fd;
132         char *map;
133 
134         if (anon) {
135                 map = mmap(NULL, pagesize, PROT_READ|PROT_WRITE,
136                            MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
137                 if (!map)
138                         ksft_exit_fail_msg("anon mmap failed\n");
139         } else {
140                 test_fd = open(fname, O_RDWR | O_CREAT, 0664);
141                 if (test_fd < 0) {
142                         ksft_test_result_skip("Test %s open() file failed\n", __func__);
143                         return;
144                 }
145                 unlink(fname);
146                 ftruncate(test_fd, pagesize);
147                 map = mmap(NULL, pagesize, PROT_READ|PROT_WRITE,
148                            MAP_SHARED, test_fd, 0);
149                 if (!map)
150                         ksft_exit_fail_msg("file mmap failed\n");
151         }
152 
153         *map = 1;
154         ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 1,
155                          "Test %s-%s dirty bit of new written page\n",
156                          __func__, type[anon]);
157         clear_softdirty();
158         ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 0,
159                          "Test %s-%s soft-dirty clear after clear_refs\n",
160                          __func__, type[anon]);
161         mprotect(map, pagesize, PROT_READ);
162         ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 0,
163                          "Test %s-%s soft-dirty clear after marking RO\n",
164                          __func__, type[anon]);
165         mprotect(map, pagesize, PROT_READ|PROT_WRITE);
166         ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 0,
167                          "Test %s-%s soft-dirty clear after marking RW\n",
168                          __func__, type[anon]);
169         *map = 2;
170         ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 1,
171                          "Test %s-%s soft-dirty after rewritten\n",
172                          __func__, type[anon]);
173 
174         munmap(map, pagesize);
175 
176         if (!anon)
177                 close(test_fd);
178 }
179 
180 static void test_mprotect_anon(int pagemap_fd, int pagesize)
181 {
182         test_mprotect(pagemap_fd, pagesize, true);
183 }
184 
185 static void test_mprotect_file(int pagemap_fd, int pagesize)
186 {
187         test_mprotect(pagemap_fd, pagesize, false);
188 }
189 
190 int main(int argc, char **argv)
191 {
192         int pagemap_fd;
193         int pagesize;
194 
195         ksft_print_header();
196         ksft_set_plan(15);
197 
198         pagemap_fd = open(PAGEMAP_FILE_PATH, O_RDONLY);
199         if (pagemap_fd < 0)
200                 ksft_exit_fail_msg("Failed to open %s\n", PAGEMAP_FILE_PATH);
201 
202         pagesize = getpagesize();
203 
204         test_simple(pagemap_fd, pagesize);
205         test_vma_reuse(pagemap_fd, pagesize);
206         test_hugepage(pagemap_fd, pagesize);
207         test_mprotect_anon(pagemap_fd, pagesize);
208         test_mprotect_file(pagemap_fd, pagesize);
209 
210         close(pagemap_fd);
211 
212         ksft_finished();
213 }
214 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php