Skip to content

Instantly share code, notes, and snippets.

@48ca
Last active December 4, 2023 17:16
Show Gist options
  • Save 48ca/11d1e466deee032cb35aa8c2280f93b0 to your computer and use it in GitHub Desktop.
Save 48ca/11d1e466deee032cb35aa8c2280f93b0 to your computer and use it in GitHub Desktop.
HugeTLB contiguous PTE page fault loop reproducer
// SPDX-License-Identifier: GPL-2.0
/*
* Reproducer for contiguous PTE breakage.
*
* This test assumes 4KiB base pages, and that 64KiB hugepages are implemented
* with contiguous PTEs.
*
* aarch64-linux-gnu-gcc -Wall hugetlb-cont.c -o hugetlb-cont
* echo 1 > /sys/kernel/mm/hugepages/hugepages-64kB/nr_hugepages
*/
#define _GNU_SOURCE
#include <fcntl.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <linux/magic.h>
#include <sys/mman.h>
#include <sys/statfs.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define PAGE_SIZE 4096
#define PAGE_MASK ~(PAGE_SIZE - 1)
#define PREFIX " ... "
#define ERROR_PREFIX " !!! "
int run_repro(int fd, size_t len)
{
char *map;
map = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (map == MAP_FAILED) {
perror(ERROR_PREFIX "mmap for primary mapping failed");
return -1;
}
/*
* Fault in page.
* vma flags = VM_SHARED | VM_READ | VM_WRITE
* vma pgprot = PTE_RDONLY | PTE_WRITE
* pte pgprot = PTE_DIRTY | PTE_WRITE (dirtied by hugetlb)
*/
*(volatile char *)map;
/*
* vma flags = VM_SHARED
* vma pgprot = PTE_RDONLY
* pte pgprot = PTE_DIRTY | PTE_RDONLY (sw-dirty bit is not touched)
*/
if (mprotect(map, len, PROT_NONE)) {
perror("mprotect RW failed");
goto out;
}
/*
* vma flags = VM_SHARED | VM_READ | VM_WRITE
* vma pgprot = PTE_RDONLY | PTE_WRITE
* pte pgprot = PTE_DIRTY | PTE_WRITE | PTE_RDONLY (PTE assumed clean)
*/
if (mprotect(map, len, PROT_READ | PROT_WRITE)) {
perror("mprotect RW failed");
goto out;
}
printf("attempting read: %p\n", map);
*(volatile char *)map;
/* stuck on the following write if the bug is present */
printf("attempting write: %p\n", map);
*(volatile char *)map = 0;
printf("success\n");
out:
munmap(map, len);
return 0;
}
#ifndef MFD_HUGE_64KB
#define MFD_HUGE_64KB 0x40000000
#endif
int main(void)
{
int fd;
struct statfs file_stat;
size_t hugepagesize;
size_t len;
int ret = 0;
fd = memfd_create("hugetlb_tmp", MFD_HUGETLB | MFD_HUGE_64KB);
if (fd < 0) {
perror(ERROR_PREFIX "could not open hugetlbfs file");
return -1;
}
memset(&file_stat, 0, sizeof(file_stat));
if (fstatfs(fd, &file_stat)) {
perror(ERROR_PREFIX "fstatfs failed");
goto close;
}
if (file_stat.f_type != HUGETLBFS_MAGIC) {
printf(ERROR_PREFIX "not hugetlbfs file\n");
goto close;
}
hugepagesize = file_stat.f_bsize;
len = hugepagesize;
if (ftruncate(fd, len) < 0) {
perror(ERROR_PREFIX "ftruncate failed");
goto close;
}
run_repro(fd, len);
if (ftruncate(fd, 0) < 0)
perror(ERROR_PREFIX "ftruncate back to 0 failed");
close:
close(fd);
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment