blob: e0d904f6f5cd1aa2d200dbbd4bdd802645f4d9a9 [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 "blobfs_test.h"
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#include <fbl/unique_fd.h>
#include <fs-management/fvm.h>
#include <fs-management/mount.h>
#include <fuchsia/device/c/fidl.h>
#include <fuchsia/io/c/fidl.h>
#include <fvm/format.h>
#include <lib/fzl/fdio.h>
#include <zxtest/zxtest.h>
namespace {
constexpr char kFvmDriverLib[] = "/boot/driver/fvm.so";
bool GetFsInfo(fuchsia_io_FilesystemInfo* info) {
fbl::unique_fd fd(open(kMountPath, O_RDONLY | O_DIRECTORY));
if (!fd) {
return false;
}
zx_status_t status;
fzl::FdioCaller caller(std::move(fd));
zx_status_t io_status =
fuchsia_io_DirectoryAdminQueryFilesystem(caller.borrow_channel(), &status, info);
if (io_status != ZX_OK) {
status = io_status;
}
if (status != ZX_OK) {
printf("Could not query block FS info: %s\n", zx_status_get_string(status));
return false;
}
return true;
}
} // namespace
BlobfsTest::BlobfsTest(FsTestType type)
: type_(type), environment_(g_environment), device_path_(environment_->device_path()) {
}
void BlobfsTest::SetUp() {
ASSERT_TRUE(mkdir(kMountPath, 0755) == 0 || errno == EEXIST, "Could not create mount point");
ASSERT_OK(mkfs(device_path_.c_str(), DISK_FORMAT_BLOBFS, launch_stdio_sync, &default_mkfs_options));
Mount();
}
void BlobfsTest::TearDown() {
CheckInfo(); // Failures here should not prevent unmount.
ASSERT_NO_FAILURES(Unmount());
ASSERT_OK(CheckFs());
}
void BlobfsTest::Remount() {
ASSERT_NO_FAILURES(Unmount());
ASSERT_OK(CheckFs());
Mount();
}
void BlobfsTest::Mount() {
ASSERT_FALSE(mounted_);
int flags = read_only_ ? O_RDONLY : O_RDWR;
fbl::unique_fd fd(open(device_path_.c_str(), flags));
ASSERT_TRUE(fd, "Could not open ramdisk");
mount_options_t options = default_mount_options;
options.enable_journal = environment_->use_journal();
if (read_only_) {
options.readonly = true;
}
// fd consumed by mount. By default, mount waits until the filesystem is
// ready to accept commands.
ASSERT_OK(mount(fd.release(), kMountPath, DISK_FORMAT_BLOBFS, &options, launch_stdio_async));
mounted_ = true;
}
void BlobfsTest::Unmount() {
if (!mounted_) {
return;
}
ASSERT_OK(umount(kMountPath));
mounted_ = false;
}
zx_status_t BlobfsTest::CheckFs() {
fsck_options_t test_fsck_options = {
.verbose = false,
.never_modify = true,
.always_modify = false,
.force = true,
.apply_journal = true,
};
return fsck(device_path_.c_str(), DISK_FORMAT_BLOBFS, &test_fsck_options, launch_stdio_sync);
}
void BlobfsTest::CheckInfo() {
fuchsia_io_FilesystemInfo info;
ASSERT_TRUE(GetFsInfo(&info));
const char kFsName[] = "blobfs";
const char* name = reinterpret_cast<const char*>(info.name);
ASSERT_STR_EQ(kFsName, name);
ASSERT_LE(info.used_nodes, info.total_nodes, "Used nodes greater than free nodes");
ASSERT_LE(info.used_bytes, info.total_bytes, "Used bytes greater than free bytes");
}
void BlobfsTestWithFvm::SetUp() {
fvm_path_.assign(device_path_);
fvm_path_.append("/fvm");
// Minimum size required by ResizePartition test:
const size_t kMinDataSize = 507 * kTestFvmSliceSize;
const size_t kMinFvmSize = fvm::MetadataSize(kMinDataSize, kTestFvmSliceSize) * 2 +
kMinDataSize; // ~8.5mb
ASSERT_GE(environment_->disk_size(), kMinFvmSize, "Insufficient disk space for FVM tests");
CreatePartition();
BlobfsTest::SetUp();
}
void BlobfsTestWithFvm::TearDown() {
BlobfsTest::TearDown();
ASSERT_OK(fvm_destroy(partition_path_.c_str()));
}
void BlobfsTestWithFvm::BindFvm() {
fbl::unique_fd fd(open(device_path_.c_str(), O_RDWR));
ASSERT_TRUE(fd, "Could not open test disk");
ASSERT_OK(fvm_init(fd.get(), kTestFvmSliceSize));
fzl::FdioCaller caller(std::move(fd));
zx_status_t status;
zx_status_t io_status = fuchsia_device_ControllerBind(caller.borrow_channel(),
kFvmDriverLib, sizeof(kFvmDriverLib) - 1,
&status);
ASSERT_OK(io_status, "Could not send bind to FVM driver");
ASSERT_OK(status, "Could not bind disk to FVM driver");
ASSERT_OK(wait_for_device(fvm_path_.c_str(), zx::sec(10).get()));
}
void BlobfsTestWithFvm::CreatePartition() {
ASSERT_EQ(kTestFvmSliceSize % blobfs::kBlobfsBlockSize, 0);
ASSERT_NO_FAILURES(BindFvm());
fbl::unique_fd fd(open(fvm_path_.c_str(), O_RDWR));
ASSERT_TRUE(fd, "Could not open FVM driver");
alloc_req_t request = {};
request.slice_count = 1;
strcpy(request.name, "fs-test-partition");
memcpy(request.type, kTestPartGUID, sizeof(request.type));
memcpy(request.guid, kTestUniqueGUID, sizeof(request.guid));
fd.reset(fvm_allocate_partition(fd.get(), &request));
ASSERT_TRUE(fd, "Could not allocate FVM partition");
char path[PATH_MAX];
fd.reset(open_partition(kTestUniqueGUID, kTestPartGUID, 0, path));
ASSERT_TRUE(fd, "Could not locate FVM partition");
// The base test must see the FVM volume as the device to work with.
partition_path_.swap(device_path_);
device_path_.assign(path);
}
void MakeBlob(const fs_test_utils::BlobInfo* info, fbl::unique_fd* fd) {
fd->reset(open(info->path, O_CREAT | O_RDWR));
ASSERT_TRUE(*fd, "Failed to create blob");
ASSERT_EQ(ftruncate(fd->get(), info->size_data), 0);
ASSERT_EQ(fs_test_utils::StreamAll(write, fd->get(), info->data.get(), info->size_data), 0,
"Failed to write Data");
ASSERT_TRUE(fs_test_utils::VerifyContents(fd->get(), info->data.get(), info->size_data));
}