Path: blob/master/tools/testing/selftests/cgroup/test_hugetlb_memcg.c
26285 views
// SPDX-License-Identifier: GPL-2.01#define _GNU_SOURCE23#include <linux/limits.h>4#include <sys/mman.h>5#include <stdio.h>6#include <stdlib.h>7#include <string.h>8#include <fcntl.h>9#include "../kselftest.h"10#include "cgroup_util.h"1112#define ADDR ((void *)(0x0UL))13#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)14/* mapping 8 MBs == 4 hugepages */15#define LENGTH (8UL*1024*1024)16#define PROTECTION (PROT_READ | PROT_WRITE)1718/* borrowed from mm/hmm-tests.c */19static long get_hugepage_size(void)20{21int fd;22char buf[2048];23int len;24char *p, *q, *path = "/proc/meminfo", *tag = "Hugepagesize:";25long val;2627fd = open(path, O_RDONLY);28if (fd < 0) {29/* Error opening the file */30return -1;31}3233len = read(fd, buf, sizeof(buf));34close(fd);35if (len < 0) {36/* Error in reading the file */37return -1;38}39if (len == sizeof(buf)) {40/* Error file is too large */41return -1;42}43buf[len] = '\0';4445/* Search for a tag if provided */46if (tag) {47p = strstr(buf, tag);48if (!p)49return -1; /* looks like the line we want isn't there */50p += strlen(tag);51} else52p = buf;5354val = strtol(p, &q, 0);55if (*q != ' ') {56/* Error parsing the file */57return -1;58}5960return val;61}6263static int set_file(const char *path, long value)64{65FILE *file;66int ret;6768file = fopen(path, "w");69if (!file)70return -1;71ret = fprintf(file, "%ld\n", value);72fclose(file);73return ret;74}7576static int set_nr_hugepages(long value)77{78return set_file("/proc/sys/vm/nr_hugepages", value);79}8081static unsigned int check_first(char *addr)82{83return *(unsigned int *)addr;84}8586static void write_data(char *addr)87{88unsigned long i;8990for (i = 0; i < LENGTH; i++)91*(addr + i) = (char)i;92}9394static int hugetlb_test_program(const char *cgroup, void *arg)95{96char *test_group = (char *)arg;97void *addr;98long old_current, expected_current, current;99int ret = EXIT_FAILURE;100101old_current = cg_read_long(test_group, "memory.current");102set_nr_hugepages(20);103current = cg_read_long(test_group, "memory.current");104if (current - old_current >= MB(2)) {105ksft_print_msg(106"setting nr_hugepages should not increase hugepage usage.\n");107ksft_print_msg("before: %ld, after: %ld\n", old_current, current);108return EXIT_FAILURE;109}110111addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0);112if (addr == MAP_FAILED) {113ksft_print_msg("fail to mmap.\n");114return EXIT_FAILURE;115}116current = cg_read_long(test_group, "memory.current");117if (current - old_current >= MB(2)) {118ksft_print_msg("mmap should not increase hugepage usage.\n");119ksft_print_msg("before: %ld, after: %ld\n", old_current, current);120goto out_failed_munmap;121}122old_current = current;123124/* read the first page */125check_first(addr);126expected_current = old_current + MB(2);127current = cg_read_long(test_group, "memory.current");128if (!values_close(expected_current, current, 5)) {129ksft_print_msg("memory usage should increase by around 2MB.\n");130ksft_print_msg(131"expected memory: %ld, actual memory: %ld\n",132expected_current, current);133goto out_failed_munmap;134}135136/* write to the whole range */137write_data(addr);138current = cg_read_long(test_group, "memory.current");139expected_current = old_current + MB(8);140if (!values_close(expected_current, current, 5)) {141ksft_print_msg("memory usage should increase by around 8MB.\n");142ksft_print_msg(143"expected memory: %ld, actual memory: %ld\n",144expected_current, current);145goto out_failed_munmap;146}147148/* unmap the whole range */149munmap(addr, LENGTH);150current = cg_read_long(test_group, "memory.current");151expected_current = old_current;152if (!values_close(expected_current, current, 5)) {153ksft_print_msg("memory usage should go back down.\n");154ksft_print_msg(155"expected memory: %ld, actual memory: %ld\n",156expected_current, current);157return ret;158}159160ret = EXIT_SUCCESS;161return ret;162163out_failed_munmap:164munmap(addr, LENGTH);165return ret;166}167168static int test_hugetlb_memcg(char *root)169{170int ret = KSFT_FAIL;171char *test_group;172173test_group = cg_name(root, "hugetlb_memcg_test");174if (!test_group || cg_create(test_group)) {175ksft_print_msg("fail to create cgroup.\n");176goto out;177}178179if (cg_write(test_group, "memory.max", "100M")) {180ksft_print_msg("fail to set cgroup memory limit.\n");181goto out;182}183184/* disable swap */185if (cg_write(test_group, "memory.swap.max", "0")) {186ksft_print_msg("fail to disable swap.\n");187goto out;188}189190if (!cg_run(test_group, hugetlb_test_program, (void *)test_group))191ret = KSFT_PASS;192out:193cg_destroy(test_group);194free(test_group);195return ret;196}197198int main(int argc, char **argv)199{200char root[PATH_MAX];201int ret = EXIT_SUCCESS, has_memory_hugetlb_acc;202203has_memory_hugetlb_acc = proc_mount_contains("memory_hugetlb_accounting");204if (has_memory_hugetlb_acc < 0)205ksft_exit_skip("Failed to query cgroup mount option\n");206else if (!has_memory_hugetlb_acc)207ksft_exit_skip("memory hugetlb accounting is disabled\n");208209/* Unit is kB! */210if (get_hugepage_size() != 2048) {211ksft_print_msg("test_hugetlb_memcg requires 2MB hugepages\n");212ksft_test_result_skip("test_hugetlb_memcg\n");213return ret;214}215216if (cg_find_unified_root(root, sizeof(root), NULL))217ksft_exit_skip("cgroup v2 isn't mounted\n");218219switch (test_hugetlb_memcg(root)) {220case KSFT_PASS:221ksft_test_result_pass("test_hugetlb_memcg\n");222break;223case KSFT_SKIP:224ksft_test_result_skip("test_hugetlb_memcg\n");225break;226default:227ret = EXIT_FAILURE;228ksft_test_result_fail("test_hugetlb_memcg\n");229break;230}231232return ret;233}234235236