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