blob: 98ed97aed4a036dcf095911123665cd377d9a331 [file]
// Copyright 2026 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/storage/lib/buffer/mapped_vmo.h"
#include <lib/zx/vmo.h>
#include <zircon/errors.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/object.h>
#include <zircon/types.h>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <limits>
#include <utility>
#include <gtest/gtest.h>
#include "src/lib/testing/predicates/status.h"
namespace storage {
namespace {
TEST(MappedVmoTest, Uninitialized) {
MappedVmo vmo;
EXPECT_EQ(0u, vmo.size());
EXPECT_EQ(nullptr, vmo.start());
EXPECT_FALSE(vmo.vmo().is_valid());
EXPECT_STATUS(ZX_ERR_BAD_STATE, vmo.Grow(zx_system_get_page_size()));
EXPECT_STATUS(ZX_ERR_BAD_STATE, vmo.Shrink(zx_system_get_page_size()));
}
TEST(MappedVmoTest, CreateAndMap) {
MappedVmo vmo;
EXPECT_STATUS(ZX_ERR_INVALID_ARGS, vmo.CreateAndMap(0, "test"));
const size_t kSize = zx_system_get_page_size() * 2;
ASSERT_OK(vmo.CreateAndMap(kSize, "test-vmo"));
EXPECT_EQ(kSize, vmo.size());
EXPECT_NE(nullptr, vmo.start());
EXPECT_TRUE(vmo.vmo().is_valid());
char name[ZX_MAX_NAME_LEN] = {};
EXPECT_OK(vmo.vmo().get_property(ZX_PROP_NAME, name, sizeof(name)));
EXPECT_STREQ("test-vmo", name);
EXPECT_STATUS(ZX_ERR_BAD_STATE, vmo.CreateAndMap(kSize, "another"));
}
TEST(MappedVmoTest, Grow) {
MappedVmo vmo;
const size_t kPageSize = zx_system_get_page_size();
const size_t kInitialSize = kPageSize * 2;
ASSERT_OK(vmo.CreateAndMap(kInitialSize, "grow-test"));
memset(vmo.start(), 0xaa, kInitialSize);
EXPECT_STATUS(ZX_ERR_INVALID_ARGS, vmo.Grow(kPageSize));
EXPECT_OK(vmo.Grow(kInitialSize));
EXPECT_EQ(kInitialSize, vmo.size());
const size_t kGrownSize = kPageSize * 4;
ASSERT_OK(vmo.Grow(kGrownSize));
EXPECT_EQ(kGrownSize, vmo.size());
EXPECT_NE(nullptr, vmo.start());
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(vmo.start());
for (size_t i = 0; i < kInitialSize; ++i) {
EXPECT_EQ(0xaa, ptr[i]);
}
}
TEST(MappedVmoTest, Shrink) {
MappedVmo vmo;
const size_t kPageSize = zx_system_get_page_size();
const size_t kInitialSize = kPageSize * 4;
ASSERT_OK(vmo.CreateAndMap(kInitialSize, "shrink-test"));
memset(vmo.start(), 0xcc, kInitialSize);
EXPECT_STATUS(ZX_ERR_INVALID_ARGS, vmo.Shrink(kInitialSize * 2));
EXPECT_OK(vmo.Shrink(kInitialSize));
EXPECT_EQ(kInitialSize, vmo.size());
void* original_start = vmo.start();
const size_t kShrunkSize = kPageSize;
ASSERT_OK(vmo.Shrink(kShrunkSize));
EXPECT_EQ(kShrunkSize, vmo.size());
EXPECT_EQ(original_start, vmo.start());
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(vmo.start());
for (size_t i = 0; i < kShrunkSize; ++i) {
EXPECT_EQ(0xcc, ptr[i]);
}
zx_info_vmo_t info;
ASSERT_OK(vmo.vmo().get_info(ZX_INFO_VMO, &info, sizeof(info), nullptr, nullptr));
EXPECT_EQ(kShrunkSize, info.committed_bytes);
EXPECT_STATUS(ZX_ERR_INVALID_ARGS, vmo.Shrink(0));
}
TEST(MappedVmoTest, Move) {
MappedVmo vmo1;
const size_t kSize = zx_system_get_page_size() * 2;
ASSERT_OK(vmo1.CreateAndMap(kSize, "move-test"));
MappedVmo vmo2 = std::move(vmo1);
EXPECT_EQ(0u, vmo1.size());
EXPECT_EQ(nullptr, vmo1.start());
EXPECT_FALSE(vmo1.vmo().is_valid());
EXPECT_EQ(kSize, vmo2.size());
EXPECT_NE(nullptr, vmo2.start());
EXPECT_TRUE(vmo2.vmo().is_valid());
MappedVmo vmo3;
vmo3 = std::move(vmo2);
EXPECT_EQ(0u, vmo2.size());
EXPECT_FALSE(vmo2.vmo().is_valid());
EXPECT_EQ(kSize, vmo3.size());
EXPECT_TRUE(vmo3.vmo().is_valid());
MappedVmo vmo_dest;
ASSERT_OK(vmo_dest.CreateAndMap(zx_system_get_page_size(), "dest-vmo"));
vmo_dest = std::move(vmo3);
EXPECT_EQ(0u, vmo3.size());
EXPECT_FALSE(vmo3.vmo().is_valid());
EXPECT_EQ(kSize, vmo_dest.size());
EXPECT_TRUE(vmo_dest.vmo().is_valid());
}
TEST(MappedVmoTest, PageAlignment) {
MappedVmo vmo;
const size_t kPageSize = zx_system_get_page_size();
ASSERT_OK(vmo.CreateAndMap(1, "align-test"));
EXPECT_EQ(kPageSize, vmo.size());
ASSERT_OK(vmo.Grow(kPageSize + 1));
EXPECT_EQ(kPageSize * 2, vmo.size());
ASSERT_OK(vmo.Shrink(kPageSize + 1));
EXPECT_EQ(kPageSize * 2, vmo.size());
ASSERT_OK(vmo.Shrink(kPageSize));
EXPECT_EQ(kPageSize, vmo.size());
EXPECT_STATUS(ZX_ERR_INVALID_ARGS, vmo.Grow(std::numeric_limits<size_t>::max()));
MappedVmo overflow_vmo;
EXPECT_STATUS(ZX_ERR_INVALID_ARGS,
overflow_vmo.CreateAndMap(std::numeric_limits<size_t>::max(), "overflow"));
}
} // namespace
} // namespace storage