[PATCH 10/11] selftests: cgroup: add memcg hugetlb_cma tests
Eric Chanudet <[email protected]>
| Newsgroups | org.kernel.vger.linux-kselftest,org.kernel.vger.cgroups,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel,org.kvack.linux-mm |
|---|---|
| Message-ID | <[email protected]> |
test_hugetlb_cma_charge gets a hugepage by incrementing nr_hugepages, confirms memory.cma.hugetlb0.current increased as expected, then releases it and checks the counter returns to its initial value. test_hugetlb_cma_limit sets memory.cma.hugetlb0.max to 0, tries to allocate a hugepage and verifies it fails. Signed-off-by: Eric Chanudet <[email protected]> --- tools/testing/selftests/cgroup/test_cma_memcg.c | 209 ++++++++++++++++++++++++ 1 file changed, 209 insertions(+) diff --git a/tools/testing/selftests/cgroup/test_cma_memcg.c b/tools/testing/selftests/cgroup/test_cma_memcg.c index b5b5ea140518..9bd41d9a6177 100644 --- a/tools/testing/selftests/cgroup/test_cma_memcg.c +++ b/tools/testing/selftests/cgroup/test_cma_memcg.c @@ -4,7 +4,9 @@ #include <linux/limits.h> #include <sys/mman.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> +#include <dirent.h> #include <fcntl.h> #include <linux/dma-heap.h> #include <sys/ioctl.h> @@ -15,6 +17,10 @@ #define CMA_RESERVED_CURRENT "memory.cma.reserved.current" #define CMA_RESERVED_MAX "memory.cma.reserved.max" +#define HUGETLB_CMA_CURRENT "memory.cma.hugetlb0.current" +#define HUGETLB_CMA_MAX "memory.cma.hugetlb0.max" +#define HUGEPAGES_DIR "/sys/kernel/mm/hugepages" + static int cma_heap_alloc(int heap_fd, size_t size) { struct dma_heap_allocation_data data = { @@ -145,6 +151,207 @@ static int test_cma_limit(const char *root) return rc; } +static long find_largest_hugepage_size_kb(void) +{ + DIR *dir; + struct dirent *entry; + long max_size = 0; + + dir = opendir(HUGEPAGES_DIR); + if (!dir) + return -1; + + while ((entry = readdir(dir)) != NULL) { + long size; + + if (sscanf(entry->d_name, "hugepages-%ldkB", &size) == 1) { + if (size > max_size) + max_size = size; + } + } + closedir(dir); + + return max_size > 0 ? max_size : -1; +} + +static long read_sysfs_long(const char *path) +{ + FILE *f; + long val = -1; + + f = fopen(path, "r"); + if (!f) + return -1; + if (fscanf(f, "%ld", &val) != 1) + val = -1; + fclose(f); + return val; +} + +static int write_sysfs_long(const char *path, long val) +{ + FILE *f; + int rc; + + f = fopen(path, "w"); + if (!f) + return -1; + rc = fprintf(f, "%ld", val); + fclose(f); + return rc < 0 ? -1 : 0; +} + +static int test_hugetlb_cma_charge(const char *root) +{ + int rc = KSFT_SKIP, in_cg = 0; + long hpage_size_kb, hpage_size_bytes; + long orig_nr = -1, new_nr, before, after; + char nr_path[PATH_MAX]; + char *cg; + + hpage_size_kb = find_largest_hugepage_size_kb(); + if (hpage_size_kb < 0) { + ksft_print_msg("no hugepage size found\n"); + return KSFT_SKIP; + } + hpage_size_bytes = hpage_size_kb * 1024; + + snprintf(nr_path, sizeof(nr_path), + HUGEPAGES_DIR "/hugepages-%ldkB/nr_hugepages", hpage_size_kb); + + cg = cg_name(root, "memcg_hugetlb_cma_charge"); + if (!cg) + goto cleanup; + + if (cg_create(cg)) + goto cleanup; + + if (cg_enter_current(cg)) + goto cleanup; + in_cg = 1; + + if (cg_read_long(cg, HUGETLB_CMA_CURRENT) < 0) { + ksft_print_msg("hugetlb CMA counters not available\n"); + goto cleanup; + } + + orig_nr = read_sysfs_long(nr_path); + if (orig_nr < 0) { + ksft_print_msg("cannot read %s\n", nr_path); + goto cleanup; + } + + before = cg_read_long(cg, HUGETLB_CMA_CURRENT); + + if (write_sysfs_long(nr_path, orig_nr + 1)) { + ksft_print_msg("cannot write %s\n", nr_path); + goto cleanup; + } + + new_nr = read_sysfs_long(nr_path); + if (new_nr <= orig_nr) { + ksft_print_msg("failed to allocate a hugepage\n"); + goto cleanup; + } + + rc = KSFT_FAIL; + after = cg_read_long(cg, HUGETLB_CMA_CURRENT); + + if (after - before < hpage_size_bytes) { + ksft_print_msg( + "hugetlb CMA counter not charged: before=%ld after=%ld expected +%ld\n", + before, after, hpage_size_bytes); + goto cleanup; + } + + write_sysfs_long(nr_path, orig_nr); + + after = cg_read_long(cg, HUGETLB_CMA_CURRENT); + if (!values_close(before, after, 3)) { + ksft_print_msg( + "hugetlb CMA counter not uncharged: before=%ld after=%ld\n", + before, after); + goto cleanup; + } + + rc = KSFT_PASS; + +cleanup: + if (orig_nr >= 0) + write_sysfs_long(nr_path, orig_nr); + + if (in_cg) + cg_enter_current(root); + cg_destroy(cg); + free(cg); + + return rc; +} + +static int test_hugetlb_cma_limit(const char *root) +{ + int rc = KSFT_SKIP, in_cg = 0; + long hpage_size_kb; + long orig_nr, new_nr; + char nr_path[PATH_MAX]; + char *cg; + + hpage_size_kb = find_largest_hugepage_size_kb(); + if (hpage_size_kb < 0) { + ksft_print_msg("no hugepage size found\n"); + return KSFT_SKIP; + } + + snprintf(nr_path, sizeof(nr_path), + HUGEPAGES_DIR "/hugepages-%ldkB/nr_hugepages", hpage_size_kb); + + cg = cg_name(root, "memcg_hugetlb_cma_limit"); + if (!cg) + goto cleanup; + + if (cg_create(cg)) + goto cleanup; + + if (cg_enter_current(cg)) + goto cleanup; + in_cg = 1; + + if (cg_read_long(cg, HUGETLB_CMA_MAX) < 0) { + ksft_print_msg("hugetlb CMA counters not available\n"); + goto cleanup; + } + + if (cg_write(cg, HUGETLB_CMA_MAX, "0")) { + ksft_print_msg("cannot set hugetlb CMA limit\n"); + goto cleanup; + } + + orig_nr = read_sysfs_long(nr_path); + if (orig_nr < 0) { + ksft_print_msg("cannot read %s\n", nr_path); + goto cleanup; + } + + write_sysfs_long(nr_path, orig_nr + 1); + new_nr = read_sysfs_long(nr_path); + + rc = KSFT_FAIL; + if (new_nr > orig_nr) { + ksft_print_msg("hugetlb CMA limit not enforced\n"); + write_sysfs_long(nr_path, orig_nr); + } else { + rc = KSFT_PASS; + } + +cleanup: + if (in_cg) + cg_enter_current(root); + cg_destroy(cg); + free(cg); + + return rc; +} + #define T(x) { x, #x } struct cma_memcg_tests { int (*fn)(const char *root); @@ -152,6 +359,8 @@ struct cma_memcg_tests { } tests[] = { T(test_cma_charge), T(test_cma_limit), + T(test_hugetlb_cma_charge), + T(test_hugetlb_cma_limit), }; #undef T -- 2.53.0