File Index
Files and directories
Sign in
FILE

hugetlb_dio.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/mm/hugetlb_dio.c 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
 23void 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
 90int 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}
~/ Read-only file preview.