aboutsummaryrefslogtreecommitdiff
path: root/testcases/kernel/mem/hugetlb/hugemmap
diff options
context:
space:
mode:
Diffstat (limited to 'testcases/kernel/mem/hugetlb/hugemmap')
-rw-r--r--testcases/kernel/mem/hugetlb/hugemmap/Makefile1
-rw-r--r--testcases/kernel/mem/hugetlb/hugemmap/hugemmap15.c13
-rw-r--r--testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c9
-rw-r--r--testcases/kernel/mem/hugetlb/hugemmap/hugemmap32.c95
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,
+};