brintos

brintos / linux-shallow public Read only

0
0
Text · 2.8 KiB · 8f122a0 Raw
127 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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_hugepages5 *6 * During setup, the test allocates the only available page, and starts three threads:7 *  - thread1:8 *	* madvise(MADV_DONTNEED) on the allocated huge page9 *  - thread 2:10 *	* Write to the allocated huge page11 *  - 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 SIGBUS17 *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 10031 32size_t mmap_size;33char *huge_ptr;34 35/* Touch the memory while it is being madvised() */36void *touch(void *unused)37{38	for (int i = 0; i < INLOOP_ITER; i++)39		huge_ptr[0] = '.';40 41	return NULL;42}43 44void *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 mapping54 * The other hugepage should be flipping from used <-> reserved, because55 * of madvise(DONTNEED).56 */57void *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 SIGBUG68			 * huge_ptr[0] = '1';69			 */70			return ptr;71		}72	}73 74	return NULL;75}76 77int 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 ~1085	 * interactions86	 */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