* Copyright (c) 2023-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <fcntl.h>
#include <cinttypes>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
#include <sys/mman.h>
#include <sys/utsname.h>
#include <string>
#include <memory.h>
#include "securec.h"
#define PAGE_SIZE 4096
#define NR_HUGEPAGES 10U
#define NR_OVERCOMMIT_HUGEPAGES 20U
#define HUGETLB_SHIFT 21
#define OVERCOMMIT_RATIO 1000000000
#define KB_SHIFT 10U
#define NUM 1024
using namespace testing::ext;
using namespace std;
class MmapVApiTest : public testing::Test {
public:
static void SetUpTestCase();
static void TearDownTestCase();
void SetUp();
void TearDown();
private:
};
void MmapVApiTest::SetUp()
{
}
void MmapVApiTest::TearDown()
{
}
void MmapVApiTest::SetUpTestCase()
{
}
void MmapVApiTest::TearDownTestCase()
{
}
enum {
OVERCOMMIT_GUESS,
OVERCOMMIT_NEVER,
};
static int g_overcommitPolicy;
static int g_overcommitRatio;
static void SetProc(string entry, int input)
{
FILE *fp = fopen(entry.c_str(), "w");
if (fp != nullptr) {
(void)fprintf(fp, "%d", input);
(void)fclose(fp);
}
}
static void FetchProc(string entry, int *output)
{
char buffer[NUM];
FILE *fp = fopen(entry.c_str(), "r");
if (fp != nullptr) {
int ret = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "%d", *output);
if (ret == 0) {
if (fputs(buffer, fp) == EOF) {
std::cout << "Error fputs .\n" << std::endl;
}
}
}
}
static void SetOvercommitMemory(int input)
{
SetProc("/proc/sys/vm/overcommit_memory", input);
}
static void FetchOvercommitMemory(int *output)
{
FetchProc("/proc/sys/vm/overcommit_memory", output);
}
static void SetOvercommitRatio(int input)
{
SetProc("/proc/sys/vm/overcommit_ratio", input);
}
static void FetchOvercommitRatio(int *output)
{
FetchProc("/proc/sys/vm/overcommit_ratio", output);
}
static int TstSmaps(void *va)
{
FILE *fp;
char cmd[NUM];
char line[NUM];
char *p;
int rss = 0;
unsigned long ptr = reinterpret_cast<unsigned long>(va);
int ret = snprintf_s(cmd, sizeof(cmd), sizeof(cmd) - 1,
"cat /proc/%d/smaps |grep -A 10 '%lx-' |grep 'Rss:'", getpid(), ptr);
if (ret < 0) {
std::cout << "Error snprintf_s open .\n" << std::endl;
return ret;
}
fp = popen(cmd, "r");
if (fp == nullptr) {
std::cout << "Error popen open .\n" << std::endl;
return -1;
}
while (fgets(line, NUM, fp) != nullptr) {
p = strstr(line, "Rss:");
if (p != nullptr) {
int err = sscanf_s(p, "Rss: %d KB", &rss);
if (err < 0) {
std::cout << "Error sscanf_s open .\n" << std::endl;
return err;
}
break;
}
}
pclose(fp);
return rss;
}
static void ForceReclaim(void)
{
FILE *fp = fopen("/proc/self/reclaim", "w");
if (fp != nullptr) {
fputs("3", fp);
fclose(fp);
} else {
std::cout << "Error ForceReclaim open .\n" << std::endl;
ASSERT_TRUE(fp != nullptr);
}
}
* @tc.number SUB_KERNEL_MEM_MAP_0600
* @tc.name MMAPNoreServe001
* @tc.desc mmap use MAP_NORESERVE without OVERCOMMIT_NEVER
*/
HWTEST_F(MmapVApiTest, MMAPNoreServe001, Function | MediumTest | Level1)
{
FetchOvercommitMemory(&g_overcommitPolicy);
ASSERT_TRUE(g_overcommitPolicy >= 0);
FetchOvercommitRatio(&g_overcommitRatio);
ASSERT_TRUE(g_overcommitRatio >= 0);
SetOvercommitRatio(OVERCOMMIT_RATIO);
SetOvercommitMemory(OVERCOMMIT_GUESS);
void *va = mmap(nullptr, (NR_OVERCOMMIT_HUGEPAGES << HUGETLB_SHIFT), PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE | MAP_HUGETLB | MAP_NORESERVE, -1, 0);
ASSERT_TRUE(va != MAP_FAILED);
int ret = munmap(va, (NR_OVERCOMMIT_HUGEPAGES << HUGETLB_SHIFT));
ASSERT_TRUE(ret == 0);
va = nullptr;
}
* @tc.number SUB_KERNEL_MEM_MAP_0700
* @tc.name MMAPNoreServe002
* @tc.desc mmap use MAP_NORESERVE with OVERCOMMIT_NEVER
*/
HWTEST_F(MmapVApiTest, MMAPNoreServe002, Function | MediumTest | Level1)
{
FetchOvercommitMemory(&g_overcommitPolicy);
ASSERT_TRUE(g_overcommitPolicy >= 0);
FetchOvercommitRatio(&g_overcommitRatio);
ASSERT_TRUE(g_overcommitRatio >= 0);
SetOvercommitRatio(OVERCOMMIT_RATIO);
SetOvercommitMemory(OVERCOMMIT_NEVER);
void *va = mmap(nullptr, (NR_OVERCOMMIT_HUGEPAGES << HUGETLB_SHIFT), PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE | MAP_HUGETLB | MAP_NORESERVE, -1, 0);
ASSERT_TRUE(va != MAP_FAILED);
int ret = munmap(va, (NR_OVERCOMMIT_HUGEPAGES << HUGETLB_SHIFT));
ASSERT_TRUE(ret == 0);
va = nullptr;
}
* @tc.number SUB_KERNEL_MEM_MAP_1100
* @tc.name MMAPNonBlock002
* @tc.desc mmap use MAP_NONBLOCK with MAP_POPULATE
*/
HWTEST_F(MmapVApiTest, MMAPNonBlock002, Function | MediumTest | Level1)
{
void *va = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE | MAP_NONBLOCK | MAP_POPULATE, -1, 0);
ASSERT_TRUE(va != MAP_FAILED);
int ret = munmap(va, PAGE_SIZE);
ASSERT_TRUE(ret == 0);
va = nullptr;
}
* @tc.number SUB_KERNEL_MEM_MAP_1200
* @tc.name mlockall001
* @tc.desc mlockall current pthread
*/
HWTEST_F(MmapVApiTest, mlockall001, Function | MediumTest | Level1)
{
void *va = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
ASSERT_TRUE(va != MAP_FAILED);
int rc = mlockall(MCL_CURRENT | MCL_ONFAULT);
ASSERT_TRUE(rc == 0);
int64_t rss = TstSmaps(va);
ASSERT_TRUE(rss == 0LL);
*(char *)va = 1;
ForceReclaim();
rss = TstSmaps(va);
ASSERT_TRUE(rss == (PAGE_SIZE >> KB_SHIFT));
rc = munlockall();
ASSERT_TRUE(rc == 0);
int ret = munmap(va, PAGE_SIZE);
ASSERT_TRUE(ret == 0);
va = nullptr;
}
* @tc.number SUB_KERNEL_MEM_MAP_1300
* @tc.name mlockall002
* @tc.desc create vregion after mlockall
*/
HWTEST_F(MmapVApiTest, mlockall002, Function | MediumTest | Level1)
{
int rc = mlockall(MCL_FUTURE | MCL_ONFAULT);
ASSERT_TRUE(rc == 0);
void *va = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
ASSERT_TRUE(va != MAP_FAILED);
int64_t rss = TstSmaps(va);
ASSERT_TRUE(rss == 0LL);
*(char *)va = 1;
ForceReclaim();
rss = TstSmaps(va);
ASSERT_TRUE(rss == (PAGE_SIZE >> KB_SHIFT));
rc = munlockall();
ASSERT_TRUE(rc == 0);
int ret = munmap(va, PAGE_SIZE);
ASSERT_TRUE(ret == 0);
va = nullptr;
}