// 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 #include #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, };