1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2023, IBM Corporation.
4 * Author: Tarun Sahu
5 */
6
7 /*\
8 * [Description]
9 *
10 * Before kernel version 5.10-rc7, there was a bug that resulted in a "Bad Page
11 * State" error when freeing gigantic hugepages. This happened because the
12 * struct page entry compound_nr, which overlapped with page->mapping in the
13 * first tail page, was not cleared, causing the error. To ensure that this
14 * issue does not reoccur as struct page keeps changing and some fields are
15 * managed by folio, this test checks that freeing gigantic hugepages does not
16 * produce the above-mentioned error.
17 */
18
19 #define _GNU_SOURCE
20 #include <dirent.h>
21
22 #include <stdio.h>
23
24 #include "hugetlb.h"
25
26 #define PATH_HUGEPAGE "/sys/kernel/mm/hugepages"
27 #define GIGANTIC_MIN_ORDER 10
28
29 static int org_g_hpages;
30 static char g_hpage_path[4096];
31
run_test(void)32 static void run_test(void)
33 {
34 if (FILE_PRINTF(g_hpage_path, "%d", 1))
35 tst_brk(TCONF, "Can't update the gigantic hugepages.");
36 SAFE_FILE_PRINTF(g_hpage_path, "%d", 0);
37
38 if (tst_taint_check())
39 tst_res(TFAIL, "Freeing Gigantic pages resulted in Bad Page State bug.");
40 else
41 tst_res(TPASS, "Successfully freed the gigantic hugepages");
42 }
43
setup(void)44 static void setup(void)
45 {
46 DIR *dir;
47 struct dirent *ent;
48 unsigned long hpage_size;
49
50 if (access(PATH_HUGEPAGE, F_OK))
51 tst_brk(TCONF, "hugetlbfs is not supported");
52
53 dir = SAFE_OPENDIR(PATH_HUGEPAGE);
54 while ((ent = SAFE_READDIR(dir))) {
55 if ((sscanf(ent->d_name, "hugepages-%lukB", &hpage_size) == 1) &&
56 is_hugetlb_gigantic(hpage_size * 1024)) {
57 sprintf(g_hpage_path, "%s/%s/%s", PATH_HUGEPAGE,
58 ent->d_name, "nr_hugepages");
59 break;
60 }
61 }
62 if (!g_hpage_path[0])
63 tst_brk(TCONF, "Gigantic hugepages not supported");
64
65 SAFE_CLOSEDIR(dir);
66
67 SAFE_FILE_PRINTF("/proc/sys/vm/drop_caches", "3");
68 SAFE_FILE_PRINTF("/proc/sys/vm/compact_memory", "1");
69
70 if (tst_available_mem() < (long long)hpage_size) {
71 g_hpage_path[0] = '\0';
72 tst_brk(TCONF, "No enough memory for gigantic hugepage reservation");
73 }
74
75 SAFE_FILE_LINES_SCANF(g_hpage_path, "%d", &org_g_hpages);
76 }
77
cleanup(void)78 static void cleanup(void)
79 {
80 if (g_hpage_path[0])
81 SAFE_FILE_PRINTF(g_hpage_path, "%d", org_g_hpages);
82 }
83
84 static struct tst_test test = {
85 .tags = (struct tst_tag[]) {
86 {"linux-git", "ba9c1201beaa"},
87 {"linux-git", "a01f43901cfb"},
88 {}
89 },
90 .needs_root = 1,
91 .setup = setup,
92 .cleanup = cleanup,
93 .test_all = run_test,
94 .taint_check = TST_TAINT_B,
95 };
96