19762338dSopenharmony_ci/* 29762338dSopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd. 39762338dSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 49762338dSopenharmony_ci * you may not use this file except in compliance with the License. 59762338dSopenharmony_ci * You may obtain a copy of the License at 69762338dSopenharmony_ci * 79762338dSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 89762338dSopenharmony_ci * 99762338dSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 109762338dSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 119762338dSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 129762338dSopenharmony_ci * See the License for the specific language governing permissions and 139762338dSopenharmony_ci * limitations under the License. 149762338dSopenharmony_ci */ 159762338dSopenharmony_ci 169762338dSopenharmony_ci#include <gtest/gtest.h> 179762338dSopenharmony_ci#include <fcntl.h> 189762338dSopenharmony_ci#include <cinttypes> 199762338dSopenharmony_ci#include <climits> 209762338dSopenharmony_ci#include <cstdio> 219762338dSopenharmony_ci#include <cstdlib> 229762338dSopenharmony_ci#include <unistd.h> 239762338dSopenharmony_ci#include <iomanip> 249762338dSopenharmony_ci#include <iostream> 259762338dSopenharmony_ci#include <string> 269762338dSopenharmony_ci#include <vector> 279762338dSopenharmony_ci#include <sys/mman.h> 289762338dSopenharmony_ci#include <sys/utsname.h> 299762338dSopenharmony_ci#include <string> 309762338dSopenharmony_ci#include <memory.h> 319762338dSopenharmony_ci#include "securec.h" 329762338dSopenharmony_ci 339762338dSopenharmony_ci#define PAGE_SIZE 4096 349762338dSopenharmony_ci#define NR_HUGEPAGES 10U 359762338dSopenharmony_ci#define NR_OVERCOMMIT_HUGEPAGES 20U 369762338dSopenharmony_ci#define HUGETLB_SHIFT 21 379762338dSopenharmony_ci#define OVERCOMMIT_RATIO 1000000000 389762338dSopenharmony_ci#define KB_SHIFT 10U 399762338dSopenharmony_ci#define NUM 1024 409762338dSopenharmony_ciusing namespace testing::ext; 419762338dSopenharmony_ciusing namespace std; 429762338dSopenharmony_ci 439762338dSopenharmony_ciclass MmapVApiTest : public testing::Test { 449762338dSopenharmony_cipublic: 459762338dSopenharmony_ci static void SetUpTestCase(); 469762338dSopenharmony_ci static void TearDownTestCase(); 479762338dSopenharmony_ci void SetUp(); 489762338dSopenharmony_ci void TearDown(); 499762338dSopenharmony_ciprivate: 509762338dSopenharmony_ci}; 519762338dSopenharmony_civoid MmapVApiTest::SetUp() 529762338dSopenharmony_ci{ 539762338dSopenharmony_ci} 549762338dSopenharmony_civoid MmapVApiTest::TearDown() 559762338dSopenharmony_ci{ 569762338dSopenharmony_ci} 579762338dSopenharmony_civoid MmapVApiTest::SetUpTestCase() 589762338dSopenharmony_ci{ 599762338dSopenharmony_ci} 609762338dSopenharmony_civoid MmapVApiTest::TearDownTestCase() 619762338dSopenharmony_ci{ 629762338dSopenharmony_ci} 639762338dSopenharmony_ci 649762338dSopenharmony_ci 659762338dSopenharmony_cienum { 669762338dSopenharmony_ci OVERCOMMIT_GUESS, 679762338dSopenharmony_ci OVERCOMMIT_NEVER, 689762338dSopenharmony_ci}; 699762338dSopenharmony_ci 709762338dSopenharmony_cistatic int g_overcommitPolicy; 719762338dSopenharmony_cistatic int g_overcommitRatio; 729762338dSopenharmony_ci 739762338dSopenharmony_cistatic void SetProc(string entry, int input) 749762338dSopenharmony_ci{ 759762338dSopenharmony_ci FILE *fp = fopen(entry.c_str(), "w"); 769762338dSopenharmony_ci if (fp != nullptr) { 779762338dSopenharmony_ci (void)fprintf(fp, "%d", input); 789762338dSopenharmony_ci (void)fclose(fp); 799762338dSopenharmony_ci } 809762338dSopenharmony_ci} 819762338dSopenharmony_ci 829762338dSopenharmony_cistatic void FetchProc(string entry, int *output) 839762338dSopenharmony_ci{ 849762338dSopenharmony_ci char buffer[NUM]; 859762338dSopenharmony_ci FILE *fp = fopen(entry.c_str(), "r"); 869762338dSopenharmony_ci if (fp != nullptr) { 879762338dSopenharmony_ci int ret = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "%d", *output); 889762338dSopenharmony_ci if (ret == 0) { 899762338dSopenharmony_ci if (fputs(buffer, fp) == EOF) { 909762338dSopenharmony_ci std::cout << "Error fputs .\n" << std::endl; 919762338dSopenharmony_ci } 929762338dSopenharmony_ci } 939762338dSopenharmony_ci } 949762338dSopenharmony_ci} 959762338dSopenharmony_ci 969762338dSopenharmony_cistatic void SetOvercommitMemory(int input) 979762338dSopenharmony_ci{ 989762338dSopenharmony_ci SetProc("/proc/sys/vm/overcommit_memory", input); 999762338dSopenharmony_ci} 1009762338dSopenharmony_ci 1019762338dSopenharmony_cistatic void FetchOvercommitMemory(int *output) 1029762338dSopenharmony_ci{ 1039762338dSopenharmony_ci FetchProc("/proc/sys/vm/overcommit_memory", output); 1049762338dSopenharmony_ci} 1059762338dSopenharmony_ci 1069762338dSopenharmony_cistatic void SetOvercommitRatio(int input) 1079762338dSopenharmony_ci{ 1089762338dSopenharmony_ci SetProc("/proc/sys/vm/overcommit_ratio", input); 1099762338dSopenharmony_ci} 1109762338dSopenharmony_ci 1119762338dSopenharmony_cistatic void FetchOvercommitRatio(int *output) 1129762338dSopenharmony_ci{ 1139762338dSopenharmony_ci FetchProc("/proc/sys/vm/overcommit_ratio", output); 1149762338dSopenharmony_ci} 1159762338dSopenharmony_ci 1169762338dSopenharmony_cistatic int TstSmaps(void *va) 1179762338dSopenharmony_ci{ 1189762338dSopenharmony_ci FILE *fp; 1199762338dSopenharmony_ci char cmd[NUM]; 1209762338dSopenharmony_ci char line[NUM]; 1219762338dSopenharmony_ci char *p; 1229762338dSopenharmony_ci int rss = 0; 1239762338dSopenharmony_ci unsigned long ptr = reinterpret_cast<unsigned long>(va); 1249762338dSopenharmony_ci int ret = snprintf_s(cmd, sizeof(cmd), sizeof(cmd) - 1, 1259762338dSopenharmony_ci "cat /proc/%d/smaps |grep -A 10 '%lx-' |grep 'Rss:'", getpid(), ptr); 1269762338dSopenharmony_ci if (ret < 0) { 1279762338dSopenharmony_ci std::cout << "Error snprintf_s open .\n" << std::endl; 1289762338dSopenharmony_ci return ret; 1299762338dSopenharmony_ci } 1309762338dSopenharmony_ci fp = popen(cmd, "r"); 1319762338dSopenharmony_ci if (fp == nullptr) { 1329762338dSopenharmony_ci std::cout << "Error popen open .\n" << std::endl; 1339762338dSopenharmony_ci return -1; 1349762338dSopenharmony_ci } 1359762338dSopenharmony_ci while (fgets(line, NUM, fp) != nullptr) { 1369762338dSopenharmony_ci p = strstr(line, "Rss:"); 1379762338dSopenharmony_ci if (p != nullptr) { 1389762338dSopenharmony_ci int err = sscanf_s(p, "Rss: %d KB", &rss); 1399762338dSopenharmony_ci if (err < 0) { 1409762338dSopenharmony_ci std::cout << "Error sscanf_s open .\n" << std::endl; 1419762338dSopenharmony_ci return err; 1429762338dSopenharmony_ci } 1439762338dSopenharmony_ci break; 1449762338dSopenharmony_ci } 1459762338dSopenharmony_ci } 1469762338dSopenharmony_ci pclose(fp); 1479762338dSopenharmony_ci return rss; 1489762338dSopenharmony_ci} 1499762338dSopenharmony_ci 1509762338dSopenharmony_cistatic void ForceReclaim(void) 1519762338dSopenharmony_ci{ 1529762338dSopenharmony_ci FILE *fp = fopen("/proc/self/reclaim", "w"); 1539762338dSopenharmony_ci if (fp != nullptr) { 1549762338dSopenharmony_ci fputs("5", fp); 1559762338dSopenharmony_ci fclose(fp); 1569762338dSopenharmony_ci } else { 1579762338dSopenharmony_ci std::cout << "Error ForceReclaim open .\n" << std::endl; 1589762338dSopenharmony_ci ASSERT_TRUE(fp != nullptr); 1599762338dSopenharmony_ci } 1609762338dSopenharmony_ci} 1619762338dSopenharmony_ci 1629762338dSopenharmony_ci/* 1639762338dSopenharmony_ci * @tc.number SUB_KERNEL_MEM_MAP_0600 1649762338dSopenharmony_ci * @tc.name MMAPNoreServe001 1659762338dSopenharmony_ci * @tc.desc mmap use MAP_NORESERVE without OVERCOMMIT_NEVER 1669762338dSopenharmony_ci*/ 1679762338dSopenharmony_ciHWTEST_F(MmapVApiTest, MMAPNoreServe001, Function | MediumTest | Level1) 1689762338dSopenharmony_ci{ 1699762338dSopenharmony_ci FetchOvercommitMemory(&g_overcommitPolicy); 1709762338dSopenharmony_ci ASSERT_TRUE(g_overcommitPolicy >= 0); 1719762338dSopenharmony_ci FetchOvercommitRatio(&g_overcommitRatio); 1729762338dSopenharmony_ci ASSERT_TRUE(g_overcommitRatio >= 0); 1739762338dSopenharmony_ci SetOvercommitRatio(OVERCOMMIT_RATIO); 1749762338dSopenharmony_ci SetOvercommitMemory(OVERCOMMIT_GUESS); 1759762338dSopenharmony_ci void *va = mmap(nullptr, (NR_OVERCOMMIT_HUGEPAGES << HUGETLB_SHIFT), PROT_READ | PROT_WRITE, 1769762338dSopenharmony_ci MAP_ANON | MAP_PRIVATE | MAP_HUGETLB | MAP_NORESERVE, -1, 0); 1779762338dSopenharmony_ci ASSERT_TRUE(va != MAP_FAILED); 1789762338dSopenharmony_ci int ret = munmap(va, (NR_OVERCOMMIT_HUGEPAGES << HUGETLB_SHIFT)); 1799762338dSopenharmony_ci ASSERT_TRUE(ret == 0); 1809762338dSopenharmony_ci va = nullptr; 1819762338dSopenharmony_ci} 1829762338dSopenharmony_ci 1839762338dSopenharmony_ci/* 1849762338dSopenharmony_ci * @tc.number SUB_KERNEL_MEM_MAP_0700 1859762338dSopenharmony_ci * @tc.name MMAPNoreServe002 1869762338dSopenharmony_ci * @tc.desc mmap use MAP_NORESERVE with OVERCOMMIT_NEVER 1879762338dSopenharmony_ci*/ 1889762338dSopenharmony_ciHWTEST_F(MmapVApiTest, MMAPNoreServe002, Function | MediumTest | Level1) 1899762338dSopenharmony_ci{ 1909762338dSopenharmony_ci FetchOvercommitMemory(&g_overcommitPolicy); 1919762338dSopenharmony_ci ASSERT_TRUE(g_overcommitPolicy >= 0); 1929762338dSopenharmony_ci FetchOvercommitRatio(&g_overcommitRatio); 1939762338dSopenharmony_ci ASSERT_TRUE(g_overcommitRatio >= 0); 1949762338dSopenharmony_ci SetOvercommitRatio(OVERCOMMIT_RATIO); 1959762338dSopenharmony_ci SetOvercommitMemory(OVERCOMMIT_NEVER); 1969762338dSopenharmony_ci 1979762338dSopenharmony_ci void *va = mmap(nullptr, (NR_OVERCOMMIT_HUGEPAGES << HUGETLB_SHIFT), PROT_READ | PROT_WRITE, 1989762338dSopenharmony_ci MAP_ANON | MAP_PRIVATE | MAP_HUGETLB | MAP_NORESERVE, -1, 0); 1999762338dSopenharmony_ci ASSERT_TRUE(va != MAP_FAILED); 2009762338dSopenharmony_ci int ret = munmap(va, (NR_OVERCOMMIT_HUGEPAGES << HUGETLB_SHIFT)); 2019762338dSopenharmony_ci ASSERT_TRUE(ret == 0); 2029762338dSopenharmony_ci va = nullptr; 2039762338dSopenharmony_ci} 2049762338dSopenharmony_ci 2059762338dSopenharmony_ci 2069762338dSopenharmony_ci/* 2079762338dSopenharmony_ci * @tc.number SUB_KERNEL_MEM_MAP_1100 2089762338dSopenharmony_ci * @tc.name MMAPNonBlock002 2099762338dSopenharmony_ci * @tc.desc mmap use MAP_NONBLOCK with MAP_POPULATE 2109762338dSopenharmony_ci*/ 2119762338dSopenharmony_ciHWTEST_F(MmapVApiTest, MMAPNonBlock002, Function | MediumTest | Level1) 2129762338dSopenharmony_ci{ 2139762338dSopenharmony_ci void *va = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, 2149762338dSopenharmony_ci MAP_ANON | MAP_PRIVATE | MAP_NONBLOCK | MAP_POPULATE, -1, 0); 2159762338dSopenharmony_ci ASSERT_TRUE(va != MAP_FAILED); 2169762338dSopenharmony_ci int ret = munmap(va, PAGE_SIZE); 2179762338dSopenharmony_ci ASSERT_TRUE(ret == 0); 2189762338dSopenharmony_ci va = nullptr; 2199762338dSopenharmony_ci} 2209762338dSopenharmony_ci 2219762338dSopenharmony_ci/* 2229762338dSopenharmony_ci * @tc.number SUB_KERNEL_MEM_MAP_1200 2239762338dSopenharmony_ci * @tc.name mlockall001 2249762338dSopenharmony_ci * @tc.desc mlockall current pthread 2259762338dSopenharmony_ci*/ 2269762338dSopenharmony_ciHWTEST_F(MmapVApiTest, mlockall001, Function | MediumTest | Level1) 2279762338dSopenharmony_ci{ 2289762338dSopenharmony_ci void *va = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); 2299762338dSopenharmony_ci ASSERT_TRUE(va != MAP_FAILED); 2309762338dSopenharmony_ci int rc = mlockall(MCL_CURRENT | MCL_ONFAULT); 2319762338dSopenharmony_ci ASSERT_TRUE(rc == 0); 2329762338dSopenharmony_ci int64_t rss = TstSmaps(va); 2339762338dSopenharmony_ci ASSERT_TRUE(rss == 0LL); 2349762338dSopenharmony_ci *(char *)va = 1; 2359762338dSopenharmony_ci ForceReclaim(); 2369762338dSopenharmony_ci rss = TstSmaps(va); 2379762338dSopenharmony_ci ASSERT_TRUE(rss == (PAGE_SIZE >> KB_SHIFT)); 2389762338dSopenharmony_ci rc = munlockall(); 2399762338dSopenharmony_ci ASSERT_TRUE(rc == 0); 2409762338dSopenharmony_ci int ret = munmap(va, PAGE_SIZE); 2419762338dSopenharmony_ci ASSERT_TRUE(ret == 0); 2429762338dSopenharmony_ci va = nullptr; 2439762338dSopenharmony_ci} 2449762338dSopenharmony_ci 2459762338dSopenharmony_ci/* 2469762338dSopenharmony_ci * @tc.number SUB_KERNEL_MEM_MAP_1300 2479762338dSopenharmony_ci * @tc.name mlockall002 2489762338dSopenharmony_ci * @tc.desc create vregion after mlockall 2499762338dSopenharmony_ci*/ 2509762338dSopenharmony_ciHWTEST_F(MmapVApiTest, mlockall002, Function | MediumTest | Level1) 2519762338dSopenharmony_ci{ 2529762338dSopenharmony_ci int rc = mlockall(MCL_CURRENT | MCL_ONFAULT); 2539762338dSopenharmony_ci ASSERT_TRUE(rc == 0); 2549762338dSopenharmony_ci void *va = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); 2559762338dSopenharmony_ci ASSERT_TRUE(va != MAP_FAILED); 2569762338dSopenharmony_ci int64_t rss = TstSmaps(va); 2579762338dSopenharmony_ci ASSERT_TRUE(rss == 0LL); 2589762338dSopenharmony_ci *(char *)va = 1; 2599762338dSopenharmony_ci ForceReclaim(); 2609762338dSopenharmony_ci rss = TstSmaps(va); 2619762338dSopenharmony_ci ASSERT_TRUE(rss == (PAGE_SIZE >> KB_SHIFT)); 2629762338dSopenharmony_ci rc = munlockall(); 2639762338dSopenharmony_ci ASSERT_TRUE(rc == 0); 2649762338dSopenharmony_ci int ret = munmap(va, PAGE_SIZE); 2659762338dSopenharmony_ci ASSERT_TRUE(ret == 0); 2669762338dSopenharmony_ci va = nullptr; 2679762338dSopenharmony_ci}