diff options
Diffstat (limited to 'testcases/kernel/mem/hugetlb/hugemmap')
-rw-r--r-- | testcases/kernel/mem/hugetlb/hugemmap/Makefile | 1 | ||||
-rw-r--r-- | testcases/kernel/mem/hugetlb/hugemmap/hugemmap15.c | 13 | ||||
-rw-r--r-- | testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c | 9 | ||||
-rw-r--r-- | testcases/kernel/mem/hugetlb/hugemmap/hugemmap32.c | 95 |
4 files changed, 107 insertions, 11 deletions
diff --git a/testcases/kernel/mem/hugetlb/hugemmap/Makefile b/testcases/kernel/mem/hugetlb/hugemmap/Makefile index 6f10807cd..2d651b4aa 100644 --- a/testcases/kernel/mem/hugetlb/hugemmap/Makefile +++ b/testcases/kernel/mem/hugetlb/hugemmap/Makefile @@ -8,5 +8,4 @@ include $(top_srcdir)/include/mk/testcases.mk include $(abs_srcdir)/../Makefile.inc include $(top_srcdir)/include/mk/generic_leaf_target.mk -hugemmap15: CFLAGS+=-O0 hugemmap06: CFLAGS+=-pthread diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap15.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap15.c index 07e65a160..4d1984070 100644 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap15.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap15.c @@ -19,6 +19,10 @@ * remap, or because the icache happens to get flushed in the interim. */ +#if defined(__clang__) + #pragma clang optimize off +#endif + #define _GNU_SOURCE #include "hugetlb.h" @@ -27,16 +31,7 @@ defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64) || \ defined(__i386__) || defined(__x86_64__) || defined(__arm__) -#include <stdio.h> -#include <stdlib.h> #include <setjmp.h> -#include <unistd.h> -#include <signal.h> -#include <sys/mman.h> -#include <ucontext.h> -#include <limits.h> -#include <sys/param.h> -#include <sys/types.h> #define SUCC_JMP 1 #define FAIL_JMP 2 diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c index a465aadec..158a03010 100644 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c @@ -23,7 +23,7 @@ static int fd = -1; static unsigned long slice_boundary; -static long hpage_size, page_size; +static unsigned long hpage_size, page_size; static int init_slice_boundary(int fd) { @@ -44,6 +44,13 @@ static int init_slice_boundary(int fd) heap = malloc(1); free(heap); + /* Avoid underflow on systems with large huge pages. + * The additionally plus heap address is to reduce the possibility + * of MAP_FIXED stomp over existing mappings. + */ + while (slice_boundary + slice_size < (unsigned long)heap + 2*hpage_size) + slice_boundary += slice_size; + /* Find 2 neighbour slices with couple huge pages free * around slice boundary. * 16 is the maximum number of slices (low/high) diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap32.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap32.c new file mode 100644 index 000000000..d27e5b8b2 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap32.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023, IBM Corporation. + * Author: Tarun Sahu + */ + +/*\ + * [Description] + * + * Before kernel version 5.10-rc7, there was a bug that resulted in a "Bad Page + * State" error when freeing gigantic hugepages. This happened because the + * struct page entry compound_nr, which overlapped with page->mapping in the + * first tail page, was not cleared, causing the error. To ensure that this + * issue does not reoccur as struct page keeps changing and some fields are + * managed by folio, this test checks that freeing gigantic hugepages does not + * produce the above-mentioned error. + */ + +#define _GNU_SOURCE +#include <dirent.h> + +#include <stdio.h> + +#include "hugetlb.h" + +#define PATH_HUGEPAGE "/sys/kernel/mm/hugepages" +#define GIGANTIC_MIN_ORDER 10 + +static int org_g_hpages; +static char g_hpage_path[4096]; + +static void run_test(void) +{ + if (FILE_PRINTF(g_hpage_path, "%d", 1)) + tst_brk(TCONF, "Can't update the gigantic hugepages."); + SAFE_FILE_PRINTF(g_hpage_path, "%d", 0); + + if (tst_taint_check()) + tst_res(TFAIL, "Freeing Gigantic pages resulted in Bad Page State bug."); + else + tst_res(TPASS, "Successfully freed the gigantic hugepages"); +} + +static void setup(void) +{ + DIR *dir; + struct dirent *ent; + unsigned long hpage_size; + + if (access(PATH_HUGEPAGE, F_OK)) + tst_brk(TCONF, "hugetlbfs is not supported"); + + dir = SAFE_OPENDIR(PATH_HUGEPAGE); + while ((ent = SAFE_READDIR(dir))) { + if ((sscanf(ent->d_name, "hugepages-%lukB", &hpage_size) == 1) && + is_hugetlb_gigantic(hpage_size * 1024)) { + sprintf(g_hpage_path, "%s/%s/%s", PATH_HUGEPAGE, + ent->d_name, "nr_hugepages"); + break; + } + } + if (!g_hpage_path[0]) + tst_brk(TCONF, "Gigantic hugepages not supported"); + + SAFE_CLOSEDIR(dir); + + SAFE_FILE_PRINTF("/proc/sys/vm/drop_caches", "3"); + SAFE_FILE_PRINTF("/proc/sys/vm/compact_memory", "1"); + + if (tst_available_mem() < (long long)hpage_size) { + g_hpage_path[0] = '\0'; + tst_brk(TCONF, "No enough memory for gigantic hugepage reservation"); + } + + SAFE_FILE_LINES_SCANF(g_hpage_path, "%d", &org_g_hpages); +} + +static void cleanup(void) +{ + if (g_hpage_path[0]) + SAFE_FILE_PRINTF(g_hpage_path, "%d", org_g_hpages); +} + +static struct tst_test test = { + .tags = (struct tst_tag[]) { + {"linux-git", "ba9c1201beaa"}, + {"linux-git", "a01f43901cfb"}, + {} + }, + .needs_root = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .taint_check = TST_TAINT_B, +}; |