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}