blob: a7813809662b4c453ba2adf56914bd827c2aa332 [file] [log] [blame] [edit]
// Copyright 2020 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 <fuchsia/device/llcpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/fzl/owned-vmo-mapper.h>
#include <lib/zx/channel.h>
#include <random>
#include <thread>
#include <fbl/unique_fd.h>
#include <gtest/gtest.h>
#include "src/storage/fs_test/fs_test.h"
namespace fs_test {
namespace {
namespace device = ::llcpp::fuchsia::device;
TEST(CorruptTest, CorruptTest) {
// 768 blocks containing 64 pages of 4 KiB with 8 bytes OOB
constexpr int kSize = 768 * 64 * (4096 + 8);
fzl::OwnedVmoMapper vmo;
ASSERT_EQ(vmo.CreateAndMap(kSize, "corrupt-test-vmo"), ZX_OK);
memset(vmo.start(), 0xff, kSize);
TestFilesystemOptions options = TestFilesystemOptions::DefaultMinfs();
options.device_block_size = 8192;
options.device_block_count = 0; // Use VMO size.
options.use_ram_nand = true;
options.ram_nand_vmo = zx::unowned_vmo(vmo.vmo());
// In one thread, repeatedly create a file, write to it, sync and then delete two files. Then,
// some random amount of time later, tear down the Ram Nand driver, then rebind and fsck. The
// journal should ensure the file system remains consistent.
{
auto fs_or = TestFilesystem::Create(options);
ASSERT_TRUE(fs_or.is_ok()) << fs_or.status_string();
TestFilesystem fs = std::move(fs_or).value();
const std::string file1 = fs.mount_path() + "/file1";
const std::string file2 = fs.mount_path() + "/file2";
std::thread thread([&]() {
for (;;) {
{
fbl::unique_fd fd(open(file1.c_str(), O_RDWR | O_CREAT, 0644));
if (!fd || write(fd.get(), "hello", 5) != 5 || ftruncate(fd.get(), 0) != 0 ||
fsync(fd.get()) != 0 || unlink(file1.c_str()) != 0) {
break;
}
}
{
fbl::unique_fd fd(open(file2.c_str(), O_RDWR | O_CREAT, 0644));
if (!fd || write(fd.get(), "hello", 5) != 5 || ftruncate(fd.get(), 0) != 0 ||
fsync(fd.get()) != 0 || unlink(file2.c_str()) != 0) {
break;
}
}
}
});
std::random_device random;
std::uniform_int_distribution distribution(0, 20000);
const int usec = distribution(random);
std::cout << "sleeping for " << usec << "us" << std::endl;
zx_nanosleep(zx_deadline_after(zx::usec(usec).get()));
// Unbind the NAND driver.
zx::channel local, remote;
ASSERT_EQ(zx::channel::create(0, &local, &remote), ZX_OK);
ASSERT_EQ(fdio_service_connect(fs.GetRamNand()->path(), remote.release()), ZX_OK);
auto resp = device::Controller::Call::ScheduleUnbind(local.borrow());
ASSERT_EQ(resp.status(), ZX_OK);
ASSERT_FALSE(resp->result.is_err());
thread.join();
}
auto fs_or = TestFilesystem::Open(options);
ASSERT_TRUE(fs_or.is_ok()) << fs_or.status_string();
TestFilesystem fs = std::move(fs_or).value();
EXPECT_EQ(fs.Unmount().status_value(), ZX_OK);
EXPECT_EQ(fs.Fsck().status_value(), ZX_OK);
}
} // namespace
} // namespace fs_test