blob: 5d6249eec108cd81d4b5b7735aa45d62a8c8aefe [file] [log] [blame]
// Copyright 2019 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 "fvm.h"
#include <lib/devmgr-integration-test/fixture.h>
#include <fs-management/fvm.h>
#include <zxtest/zxtest.h>
#include "fvm/format.h"
#include "fvm/fvm-sparse.h"
#include "test/test-utils.h"
namespace {
using devmgr_integration_test::IsolatedDevmgr;
using devmgr_integration_test::RecursiveWaitForFile;
constexpr size_t kSliceSize = kBlockSize * 2;
constexpr uint8_t kFvmType[GPT_GUID_LEN] = GUID_FVM_VALUE;
constexpr fvm::sparse_image_t SparseHeaderForSliceSize(size_t slice_size) {
fvm::sparse_image_t header = {};
header.slice_size = slice_size;
return header;
}
constexpr fvm::sparse_image_t SparseHeaderForSliceSizeAndMaxDiskSize(size_t slice_size,
size_t max_disk_size) {
fvm::sparse_image_t header = SparseHeaderForSliceSize(slice_size);
header.maximum_disk_size = max_disk_size;
return header;
}
class FvmTest : public zxtest::Test {
public:
FvmTest() {
devmgr_launcher::Args args;
args.sys_device_driver = IsolatedDevmgr::kSysdevDriver;
args.driver_search_paths.push_back("/boot/driver");
args.disable_block_watcher = true;
ASSERT_OK(IsolatedDevmgr::Create(std::move(args), &devmgr_));
fbl::unique_fd ctl;
ASSERT_OK(RecursiveWaitForFile(devmgr_.devfs_root(), "misc/ramctl", &ctl));
}
void CreateRamdisk() { CreateRamdiskWithBlockCount(); }
void CreateRamdiskWithBlockCount(size_t block_count = kBlockCount) {
ASSERT_NO_FATAL_FAILURES(
BlockDevice::Create(devmgr_.devfs_root(), kFvmType, block_count, &device_));
ASSERT_TRUE(device_);
}
int borrow_fd() { return device_->fd(); }
fbl::unique_fd fd() { return fbl::unique_fd(dup(device_->fd())); }
const fbl::unique_fd& devfs_root() { return devmgr_.devfs_root(); }
private:
IsolatedDevmgr devmgr_;
std::unique_ptr<BlockDevice> device_;
};
TEST_F(FvmTest, FormatFvmEmpty) {
ASSERT_NO_FAILURES(CreateRamdisk());
fbl::unique_fd fvm_part = FvmPartitionFormat(
devfs_root(), fd(), SparseHeaderForSliceSize(kSliceSize), paver::BindOption::Reformat);
ASSERT_TRUE(fvm_part.is_valid());
}
TEST_F(FvmTest, TryBindEmpty) {
ASSERT_NO_FAILURES(CreateRamdisk());
fbl::unique_fd fvm_part = FvmPartitionFormat(
devfs_root(), fd(), SparseHeaderForSliceSize(kSliceSize), paver::BindOption::TryBind);
ASSERT_TRUE(fvm_part.is_valid());
}
TEST_F(FvmTest, TryBindAlreadyFormatted) {
ASSERT_NO_FAILURES(CreateRamdisk());
ASSERT_OK(fvm_init(borrow_fd(), kSliceSize));
fbl::unique_fd fvm_part = FvmPartitionFormat(
devfs_root(), fd(), SparseHeaderForSliceSize(kSliceSize), paver::BindOption::TryBind);
ASSERT_TRUE(fvm_part.is_valid());
}
TEST_F(FvmTest, TryBindAlreadyBound) {
ASSERT_NO_FAILURES(CreateRamdisk());
fbl::unique_fd fvm_part = FvmPartitionFormat(
devfs_root(), fd(), SparseHeaderForSliceSize(kSliceSize), paver::BindOption::Reformat);
ASSERT_TRUE(fvm_part.is_valid());
fvm_part = FvmPartitionFormat(devfs_root(), fd(), SparseHeaderForSliceSize(kSliceSize),
paver::BindOption::TryBind);
ASSERT_TRUE(fvm_part.is_valid());
}
TEST_F(FvmTest, TryBindAlreadyFormattedWrongSliceSize) {
ASSERT_NO_FAILURES(CreateRamdisk());
ASSERT_OK(fvm_init(borrow_fd(), kSliceSize * 2));
fbl::unique_fd fvm_part = FvmPartitionFormat(
devfs_root(), fd(), SparseHeaderForSliceSize(kSliceSize), paver::BindOption::TryBind);
ASSERT_TRUE(fvm_part.is_valid());
}
TEST_F(FvmTest, TryBindAlreadyFormattedWithSmallerSize) {
constexpr size_t kBlockDeviceInitialSize = 1000 * kSliceSize;
constexpr size_t kBlockDeviceMaxSize = 100000 * kSliceSize;
ASSERT_NO_FAILURES(CreateRamdiskWithBlockCount(kBlockDeviceMaxSize / kBlockSize));
ASSERT_OK(
fvm_init_preallocated(borrow_fd(), kBlockDeviceInitialSize, kBlockDeviceMaxSize, kSliceSize));
// Same slice size but can reference up to 200 Slices, which is far less than what the
// preallocated can have.
fvm::sparse_image_t header =
SparseHeaderForSliceSizeAndMaxDiskSize(kSliceSize, 2 * kBlockDeviceInitialSize);
paver::FormatResult result;
fbl::unique_fd fvm_part =
FvmPartitionFormat(devfs_root(), fd(), header, paver::BindOption::TryBind, &result);
ASSERT_TRUE(fvm_part.is_valid());
ASSERT_EQ(paver::FormatResult::kPreserved, result);
}
TEST_F(FvmTest, TryBindAlreadyFormattedWithBiggerSize) {
constexpr size_t kBlockDeviceInitialSize = 1000 * kSliceSize;
constexpr size_t kBlockDeviceMaxSize = 100000 * kSliceSize;
ASSERT_NO_FAILURES(CreateRamdiskWithBlockCount(kBlockDeviceMaxSize / kBlockSize));
ASSERT_OK(fvm_init_preallocated(borrow_fd(), kBlockDeviceInitialSize, kBlockDeviceMaxSize / 100,
kSliceSize));
// Same slice size but can reference up to 200 Slices, which is far less than what the
// preallocated can have.
fvm::sparse_image_t header =
SparseHeaderForSliceSizeAndMaxDiskSize(kSliceSize, kBlockDeviceMaxSize);
paver::FormatResult result;
fbl::unique_fd fvm_part =
FvmPartitionFormat(devfs_root(), fd(), header, paver::BindOption::TryBind, &result);
ASSERT_TRUE(fvm_part.is_valid());
ASSERT_EQ(paver::FormatResult::kReformatted, result);
}
} // namespace