brintos

brintos / linux-shallow public Read only

0
0
Text · 3.6 KiB · 432d5af Raw
130 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * This program tests for hugepage leaks after DIO writes to a file using a4 * hugepage as the user buffer. During DIO, the user buffer is pinned and5 * should be properly unpinned upon completion. This patch verifies that the6 * kernel correctly unpins the buffer at DIO completion for both aligned and7 * unaligned user buffer offsets (w.r.t page boundary), ensuring the hugepage8 * is freed upon unmapping.9 */10 11#define _GNU_SOURCE12#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	/*80	 * If the no. of free hugepages before allocation and after unmap does81	 * not match - that means there could still be a page which is pinned.82	 */83	if (free_hpage_a != free_hpage_b) {84		ksft_print_msg("No. Free pages before allocation : %d\n", free_hpage_b);85		ksft_print_msg("No. Free pages after munmap : %d\n", free_hpage_a);86		ksft_test_result_fail(": Huge pages not freed!\n");87	} else {88		ksft_print_msg("No. Free pages before allocation : %d\n", free_hpage_b);89		ksft_print_msg("No. Free pages after munmap : %d\n", free_hpage_a);90		ksft_test_result_pass(": Huge pages freed successfully !\n");91	}92}93 94int main(void)95{96	size_t pagesize = 0;97	int fd;98 99	ksft_print_header();100 101	/* Open the file to DIO */102	fd = open("/tmp", O_TMPFILE | O_RDWR | O_DIRECT, 0664);103	if (fd < 0)104		ksft_exit_skip("Unable to allocate file: %s\n", strerror(errno));105	close(fd);106 107	/* Check if huge pages are free */108	if (!get_free_hugepages())109		ksft_exit_skip("No free hugepage, exiting\n");110 111	ksft_set_plan(4);112 113	/* Get base page size */114	pagesize  = psize();115 116	/* start and end is aligned to pagesize */117	run_dio_using_hugetlb(0, (pagesize * 3));118 119	/* start is aligned but end is not aligned */120	run_dio_using_hugetlb(0, (pagesize * 3) - (pagesize / 2));121 122	/* start is unaligned and end is aligned */123	run_dio_using_hugetlb(pagesize / 2, (pagesize * 3));124 125	/* both start and end are unaligned */126	run_dio_using_hugetlb(pagesize / 2, (pagesize * 3) + (pagesize / 2));127 128	ksft_finished();129}130