brintos

brintos / linux-shallow public Read only

0
0
Text · 5.4 KiB · 856f950 Raw
235 lines · c
1// SPDX-License-Identifier: GPL-2.02#define _GNU_SOURCE3 4#include <linux/limits.h>5#include <sys/mman.h>6#include <stdio.h>7#include <stdlib.h>8#include <string.h>9#include <fcntl.h>10#include "../kselftest.h"11#include "cgroup_util.h"12 13#define ADDR ((void *)(0x0UL))14#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)15/* mapping 8 MBs == 4 hugepages */16#define LENGTH (8UL*1024*1024)17#define PROTECTION (PROT_READ | PROT_WRITE)18 19/* borrowed from mm/hmm-tests.c */20static long get_hugepage_size(void)21{22	int fd;23	char buf[2048];24	int len;25	char *p, *q, *path = "/proc/meminfo", *tag = "Hugepagesize:";26	long val;27 28	fd = open(path, O_RDONLY);29	if (fd < 0) {30		/* Error opening the file */31		return -1;32	}33 34	len = read(fd, buf, sizeof(buf));35	close(fd);36	if (len < 0) {37		/* Error in reading the file */38		return -1;39	}40	if (len == sizeof(buf)) {41		/* Error file is too large */42		return -1;43	}44	buf[len] = '\0';45 46	/* Search for a tag if provided */47	if (tag) {48		p = strstr(buf, tag);49		if (!p)50			return -1; /* looks like the line we want isn't there */51		p += strlen(tag);52	} else53		p = buf;54 55	val = strtol(p, &q, 0);56	if (*q != ' ') {57		/* Error parsing the file */58		return -1;59	}60 61	return val;62}63 64static int set_file(const char *path, long value)65{66	FILE *file;67	int ret;68 69	file = fopen(path, "w");70	if (!file)71		return -1;72	ret = fprintf(file, "%ld\n", value);73	fclose(file);74	return ret;75}76 77static int set_nr_hugepages(long value)78{79	return set_file("/proc/sys/vm/nr_hugepages", value);80}81 82static unsigned int check_first(char *addr)83{84	return *(unsigned int *)addr;85}86 87static void write_data(char *addr)88{89	unsigned long i;90 91	for (i = 0; i < LENGTH; i++)92		*(addr + i) = (char)i;93}94 95static int hugetlb_test_program(const char *cgroup, void *arg)96{97	char *test_group = (char *)arg;98	void *addr;99	long old_current, expected_current, current;100	int ret = EXIT_FAILURE;101 102	old_current = cg_read_long(test_group, "memory.current");103	set_nr_hugepages(20);104	current = cg_read_long(test_group, "memory.current");105	if (current - old_current >= MB(2)) {106		ksft_print_msg(107			"setting nr_hugepages should not increase hugepage usage.\n");108		ksft_print_msg("before: %ld, after: %ld\n", old_current, current);109		return EXIT_FAILURE;110	}111 112	addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0);113	if (addr == MAP_FAILED) {114		ksft_print_msg("fail to mmap.\n");115		return EXIT_FAILURE;116	}117	current = cg_read_long(test_group, "memory.current");118	if (current - old_current >= MB(2)) {119		ksft_print_msg("mmap should not increase hugepage usage.\n");120		ksft_print_msg("before: %ld, after: %ld\n", old_current, current);121		goto out_failed_munmap;122	}123	old_current = current;124 125	/* read the first page */126	check_first(addr);127	expected_current = old_current + MB(2);128	current = cg_read_long(test_group, "memory.current");129	if (!values_close(expected_current, current, 5)) {130		ksft_print_msg("memory usage should increase by around 2MB.\n");131		ksft_print_msg(132			"expected memory: %ld, actual memory: %ld\n",133			expected_current, current);134		goto out_failed_munmap;135	}136 137	/* write to the whole range */138	write_data(addr);139	current = cg_read_long(test_group, "memory.current");140	expected_current = old_current + MB(8);141	if (!values_close(expected_current, current, 5)) {142		ksft_print_msg("memory usage should increase by around 8MB.\n");143		ksft_print_msg(144			"expected memory: %ld, actual memory: %ld\n",145			expected_current, current);146		goto out_failed_munmap;147	}148 149	/* unmap the whole range */150	munmap(addr, LENGTH);151	current = cg_read_long(test_group, "memory.current");152	expected_current = old_current;153	if (!values_close(expected_current, current, 5)) {154		ksft_print_msg("memory usage should go back down.\n");155		ksft_print_msg(156			"expected memory: %ld, actual memory: %ld\n",157			expected_current, current);158		return ret;159	}160 161	ret = EXIT_SUCCESS;162	return ret;163 164out_failed_munmap:165	munmap(addr, LENGTH);166	return ret;167}168 169static int test_hugetlb_memcg(char *root)170{171	int ret = KSFT_FAIL;172	char *test_group;173 174	test_group = cg_name(root, "hugetlb_memcg_test");175	if (!test_group || cg_create(test_group)) {176		ksft_print_msg("fail to create cgroup.\n");177		goto out;178	}179 180	if (cg_write(test_group, "memory.max", "100M")) {181		ksft_print_msg("fail to set cgroup memory limit.\n");182		goto out;183	}184 185	/* disable swap */186	if (cg_write(test_group, "memory.swap.max", "0")) {187		ksft_print_msg("fail to disable swap.\n");188		goto out;189	}190 191	if (!cg_run(test_group, hugetlb_test_program, (void *)test_group))192		ret = KSFT_PASS;193out:194	cg_destroy(test_group);195	free(test_group);196	return ret;197}198 199int main(int argc, char **argv)200{201	char root[PATH_MAX];202	int ret = EXIT_SUCCESS, has_memory_hugetlb_acc;203 204	has_memory_hugetlb_acc = proc_mount_contains("memory_hugetlb_accounting");205	if (has_memory_hugetlb_acc < 0)206		ksft_exit_skip("Failed to query cgroup mount option\n");207	else if (!has_memory_hugetlb_acc)208		ksft_exit_skip("memory hugetlb accounting is disabled\n");209 210	/* Unit is kB! */211	if (get_hugepage_size() != 2048) {212		ksft_print_msg("test_hugetlb_memcg requires 2MB hugepages\n");213		ksft_test_result_skip("test_hugetlb_memcg\n");214		return ret;215	}216 217	if (cg_find_unified_root(root, sizeof(root), NULL))218		ksft_exit_skip("cgroup v2 isn't mounted\n");219 220	switch (test_hugetlb_memcg(root)) {221	case KSFT_PASS:222		ksft_test_result_pass("test_hugetlb_memcg\n");223		break;224	case KSFT_SKIP:225		ksft_test_result_skip("test_hugetlb_memcg\n");226		break;227	default:228		ret = EXIT_FAILURE;229		ksft_test_result_fail("test_hugetlb_memcg\n");230		break;231	}232 233	return ret;234}235