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

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/mm/hugetlb_madv_vs_map.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ 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 /*
  3  * A test case that must run on a system with one and only one huge page available.
  4  *      # echo 1 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
  5  *
  6  * During setup, the test allocates the only available page, and starts three threads:
  7  *  - thread1:
  8  *      * madvise(MADV_DONTNEED) on the allocated huge page
  9  *  - thread 2:
 10  *      * Write to the allocated huge page
 11  *  - thread 3:
 12  *      * Try to allocated an extra huge page (which must not available)
 13  *
 14  *  The test fails if thread3 is able to allocate a page.
 15  *
 16  *  Touching the first page after thread3's allocation will raise a SIGBUS
 17  *
 18  *  Author: Breno Leitao <leitao@debian.org>
 19  */
 20 #include <pthread.h>
 21 #include <stdio.h>
 22 #include <stdlib.h>
 23 #include <sys/mman.h>
 24 #include <sys/types.h>
 25 #include <unistd.h>
 26 
 27 #include "vm_util.h"
 28 #include "../kselftest.h"
 29 
 30 #define INLOOP_ITER 100
 31 
 32 size_t mmap_size;
 33 char *huge_ptr;
 34 
 35 /* Touch the memory while it is being madvised() */
 36 void *touch(void *unused)
 37 {
 38         for (int i = 0; i < INLOOP_ITER; i++)
 39                 huge_ptr[0] = '.';
 40 
 41         return NULL;
 42 }
 43 
 44 void *madv(void *unused)
 45 {
 46         for (int i = 0; i < INLOOP_ITER; i++)
 47                 madvise(huge_ptr, mmap_size, MADV_DONTNEED);
 48 
 49         return NULL;
 50 }
 51 
 52 /*
 53  * We got here, and there must be no huge page available for mapping
 54  * The other hugepage should be flipping from used <-> reserved, because
 55  * of madvise(DONTNEED).
 56  */
 57 void *map_extra(void *unused)
 58 {
 59         void *ptr;
 60 
 61         for (int i = 0; i < INLOOP_ITER; i++) {
 62                 ptr = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE,
 63                            MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
 64                            -1, 0);
 65 
 66                 if ((long)ptr != -1) {
 67                         /* Touching the other page now will cause a SIGBUG
 68                          * huge_ptr[0] = '1';
 69                          */
 70                         return ptr;
 71                 }
 72         }
 73 
 74         return NULL;
 75 }
 76 
 77 int main(void)
 78 {
 79         pthread_t thread1, thread2, thread3;
 80         unsigned long free_hugepages;
 81         void *ret;
 82 
 83         /*
 84          * On kernel 6.7, we are able to reproduce the problem with ~10
 85          * interactions
 86          */
 87         int max = 10;
 88 
 89         free_hugepages = get_free_hugepages();
 90 
 91         if (free_hugepages != 1) {
 92                 ksft_exit_skip("This test needs one and only one page to execute. Got %lu\n",
 93                                free_hugepages);
 94         }
 95 
 96         mmap_size = default_huge_page_size();
 97 
 98         while (max--) {
 99                 huge_ptr = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE,
100                                 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
101                                 -1, 0);
102 
103                 if ((unsigned long)huge_ptr == -1) {
104                         ksft_test_result_fail("Failed to allocate huge page\n");
105                         return KSFT_FAIL;
106                 }
107 
108                 pthread_create(&thread1, NULL, madv, NULL);
109                 pthread_create(&thread2, NULL, touch, NULL);
110                 pthread_create(&thread3, NULL, map_extra, NULL);
111 
112                 pthread_join(thread1, NULL);
113                 pthread_join(thread2, NULL);
114                 pthread_join(thread3, &ret);
115 
116                 if (ret) {
117                         ksft_test_result_fail("Unexpected huge page allocation\n");
118                         return KSFT_FAIL;
119                 }
120 
121                 /* Unmap and restart */
122                 munmap(huge_ptr, mmap_size);
123         }
124 
125         return KSFT_PASS;
126 }
127 

~ [ 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