| // 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 <fcntl.h> |
| |
| #include <lib/devmgr-integration-test/fixture.h> |
| #include <lib/fdio/namespace.h> |
| #include <ramdevice-client/ramdisk.h> |
| #include <zircon/assert.h> |
| #include <zircon/hw/gpt.h> |
| #include <zxtest/zxtest.h> |
| |
| #include "block-device.h" |
| #include "filesystem-mounter.h" |
| #include "fs-manager.h" |
| |
| namespace devmgr { |
| namespace { |
| |
| using devmgr_integration_test::IsolatedDevmgr; |
| |
| class BlockDeviceHarness : public zxtest::Test { |
| public: |
| void SetUp() override { |
| zx::event event; |
| ASSERT_OK(zx::event::create(0, &event)); |
| ASSERT_OK(event.duplicate(ZX_RIGHT_SAME_RIGHTS, &event_)); |
| |
| // Initialize FilesystemMounter. |
| ASSERT_OK(FsManager::Create(std::move(event), &manager_)); |
| |
| // Fshost really likes mounting filesystems at "/fs". |
| // Let's make that available in our namespace. |
| zx::channel client, server; |
| ASSERT_OK(zx::channel::create(0, &client, &server)); |
| ASSERT_OK(manager_->ServeRoot(std::move(server))); |
| fdio_ns_t* ns; |
| ASSERT_OK(fdio_ns_get_installed(&ns)); |
| ASSERT_OK(fdio_ns_bind(ns, "/fs", client.release())); |
| manager_->WatchExit(); |
| |
| devmgr_launcher::Args args; |
| args.disable_block_watcher = true; |
| args.sys_device_driver = devmgr_integration_test::IsolatedDevmgr::kSysdevDriver; |
| args.load_drivers.push_back(devmgr_integration_test::IsolatedDevmgr::kSysdevDriver); |
| args.driver_search_paths.push_back("/boot/driver"); |
| ASSERT_OK(IsolatedDevmgr::Create(std::move(args), &devmgr_)); |
| fbl::unique_fd ctl; |
| ASSERT_EQ(devmgr_integration_test::RecursiveWaitForFile(devmgr_.devfs_root(), "misc/ramctl", |
| &ctl), |
| ZX_OK); |
| } |
| |
| void TearDown() override { |
| fdio_ns_t* ns; |
| ASSERT_OK(fdio_ns_get_installed(&ns)); |
| fdio_ns_unbind(ns, "/fs"); |
| } |
| |
| std::unique_ptr<FsManager> TakeManager() { |
| return std::move(manager_); |
| } |
| |
| fbl::unique_fd devfs_root() { |
| return devmgr_.devfs_root().duplicate(); |
| } |
| |
| private: |
| zx::event event_; |
| std::unique_ptr<FsManager> manager_; |
| IsolatedDevmgr devmgr_; |
| }; |
| |
| TEST_F(BlockDeviceHarness, TestBadHandleDevice) { |
| std::unique_ptr<FsManager> manager = TakeManager(); |
| bool netboot = false; |
| bool check_filesystems = false; |
| FilesystemMounter mounter(std::move(manager), netboot, check_filesystems); |
| fbl::unique_fd fd; |
| BlockDevice device(&mounter, std::move(fd)); |
| EXPECT_EQ(device.Netbooting(), netboot); |
| EXPECT_EQ(device.GetFormat(), DISK_FORMAT_UNKNOWN); |
| fuchsia_hardware_block_BlockInfo info; |
| EXPECT_EQ(device.GetInfo(&info), ZX_ERR_BAD_HANDLE); |
| fuchsia_hardware_block_partition_GUID guid; |
| EXPECT_EQ(device.GetTypeGUID(&guid), ZX_ERR_BAD_HANDLE); |
| EXPECT_EQ(device.AttachDriver("/foobar"), ZX_ERR_BAD_HANDLE); |
| |
| // Returns ZX_OK because zxcrypt currently passes the empty fd to a background |
| // thread without observing the results. |
| EXPECT_OK(device.UnsealZxcrypt()); |
| |
| // Returns ZX_OK because filesystem checks are disabled. |
| EXPECT_OK(device.CheckFilesystem()); |
| |
| EXPECT_EQ(device.FormatFilesystem(), ZX_ERR_BAD_HANDLE); |
| EXPECT_EQ(device.MountFilesystem(), ZX_ERR_BAD_HANDLE); |
| } |
| |
| TEST_F(BlockDeviceHarness, TestEmptyDevice) { |
| std::unique_ptr<FsManager> manager = TakeManager(); |
| bool netboot = false; |
| bool check_filesystems = false; |
| FilesystemMounter mounter(std::move(manager), netboot, check_filesystems); |
| |
| // Initialize Ramdisk. |
| constexpr uint64_t kBlockSize = 512; |
| constexpr uint64_t kBlockCount = 1 << 20; |
| ramdisk_client_t* ramdisk; |
| ASSERT_OK(ramdisk_create_at(devfs_root().get(), kBlockSize, kBlockCount, &ramdisk)); |
| fbl::unique_fd fd; |
| ASSERT_EQ(devmgr_integration_test::RecursiveWaitForFile(devfs_root(), ramdisk_get_path(ramdisk), |
| &fd), |
| ZX_OK); |
| ASSERT_TRUE(fd); |
| |
| BlockDevice device(&mounter, std::move(fd)); |
| EXPECT_EQ(device.Netbooting(), netboot); |
| EXPECT_EQ(device.GetFormat(), DISK_FORMAT_UNKNOWN); |
| fuchsia_hardware_block_BlockInfo info; |
| EXPECT_OK(device.GetInfo(&info)); |
| EXPECT_EQ(info.block_count, kBlockCount); |
| EXPECT_EQ(info.block_size, kBlockSize); |
| |
| // Black-box: Since we're caching info, double check that re-calling GetInfo |
| // works correctly. |
| memset(&info, 0, sizeof(info)); |
| EXPECT_OK(device.GetInfo(&info)); |
| EXPECT_EQ(info.block_count, kBlockCount); |
| EXPECT_EQ(info.block_size, kBlockSize); |
| |
| fuchsia_hardware_block_partition_GUID guid; |
| EXPECT_OK(device.GetTypeGUID(&guid)); |
| |
| EXPECT_EQ(device.FormatFilesystem(), ZX_ERR_NOT_SUPPORTED); |
| EXPECT_EQ(device.MountFilesystem(), ZX_ERR_NOT_SUPPORTED); |
| ASSERT_OK(ramdisk_destroy(ramdisk)); |
| } |
| |
| TEST_F(BlockDeviceHarness, TestMinfsBadGUID) { |
| std::unique_ptr<FsManager> manager = TakeManager(); |
| bool netboot = false; |
| bool check_filesystems = false; |
| FilesystemMounter mounter(std::move(manager), netboot, check_filesystems); |
| |
| // Initialize Ramdisk with an empty GUID. |
| constexpr uint64_t kBlockSize = 512; |
| constexpr uint64_t kBlockCount = 1 << 20; |
| ramdisk_client_t* ramdisk; |
| ASSERT_OK(ramdisk_create_at(devfs_root().get(), kBlockSize, kBlockCount, &ramdisk)); |
| fbl::unique_fd fd; |
| ASSERT_EQ(devmgr_integration_test::RecursiveWaitForFile(devfs_root(), ramdisk_get_path(ramdisk), |
| &fd), |
| ZX_OK); |
| ASSERT_TRUE(fd); |
| |
| // We started with an empty block device, but let's lie and say it |
| // should have been a minfs device. |
| BlockDevice device(&mounter, std::move(fd)); |
| device.SetFormat(DISK_FORMAT_MINFS); |
| EXPECT_EQ(device.GetFormat(), DISK_FORMAT_MINFS); |
| EXPECT_OK(device.FormatFilesystem()); |
| |
| // Unlike earlier, where we received "ERR_NOT_SUPPORTED", we get "ERR_WRONG_TYPE" |
| // because the ramdisk doesn't have a data GUID. |
| EXPECT_EQ(device.MountFilesystem(), ZX_ERR_WRONG_TYPE); |
| |
| ASSERT_OK(ramdisk_destroy(ramdisk)); |
| } |
| |
| TEST_F(BlockDeviceHarness, TestMinfsGoodGUID) { |
| std::unique_ptr<FsManager> manager = TakeManager(); |
| |
| bool netboot = false; |
| bool check_filesystems = false; |
| FilesystemMounter mounter(std::move(manager), netboot, check_filesystems); |
| |
| // Initialize Ramdisk with a data GUID. |
| constexpr uint64_t kBlockSize = 512; |
| constexpr uint64_t kBlockCount = 1 << 20; |
| ramdisk_client_t* ramdisk; |
| const uint8_t data_guid[GPT_GUID_LEN] = GUID_DATA_VALUE; |
| ASSERT_OK(ramdisk_create_at_with_guid(devfs_root().get(), kBlockSize, kBlockCount, |
| data_guid, sizeof(data_guid), &ramdisk)); |
| fbl::unique_fd fd; |
| ASSERT_EQ(devmgr_integration_test::RecursiveWaitForFile(devfs_root(), ramdisk_get_path(ramdisk), |
| &fd), |
| ZX_OK); |
| ASSERT_TRUE(fd); |
| |
| BlockDevice device(&mounter, std::move(fd)); |
| device.SetFormat(DISK_FORMAT_MINFS); |
| EXPECT_EQ(device.GetFormat(), DISK_FORMAT_MINFS); |
| EXPECT_OK(device.FormatFilesystem()); |
| |
| EXPECT_OK(device.MountFilesystem()); |
| EXPECT_EQ(device.MountFilesystem(), ZX_ERR_ALREADY_BOUND); |
| |
| ASSERT_OK(ramdisk_destroy(ramdisk)); |
| } |
| |
| TEST_F(BlockDeviceHarness, TestMinfsReformat) { |
| std::unique_ptr<FsManager> manager = TakeManager(); |
| |
| bool netboot = false; |
| bool check_filesystems = true; |
| FilesystemMounter mounter(std::move(manager), netboot, check_filesystems); |
| |
| // Initialize Ramdisk with a data GUID. |
| constexpr uint64_t kBlockSize = 512; |
| constexpr uint64_t kBlockCount = 1 << 20; |
| ramdisk_client_t* ramdisk; |
| const uint8_t data_guid[GPT_GUID_LEN] = GUID_DATA_VALUE; |
| ASSERT_OK(ramdisk_create_at_with_guid(devfs_root().get(), kBlockSize, kBlockCount, |
| data_guid, |
| sizeof(data_guid), &ramdisk)); |
| fbl::unique_fd fd; |
| ASSERT_EQ(devmgr_integration_test::RecursiveWaitForFile(devfs_root(), ramdisk_get_path(ramdisk), |
| &fd), |
| ZX_OK); |
| |
| ASSERT_TRUE(fd); |
| |
| BlockDevice device(&mounter, std::move(fd)); |
| device.SetFormat(DISK_FORMAT_MINFS); |
| EXPECT_EQ(device.GetFormat(), DISK_FORMAT_MINFS); |
| |
| // Before formatting the device, this isn't a valid minfs partition. |
| EXPECT_NOT_OK(device.CheckFilesystem()); |
| EXPECT_NOT_OK(device.MountFilesystem()); |
| |
| // After formatting the device, it is a valid partition. We can check the device, |
| // and also mount it. |
| EXPECT_OK(device.FormatFilesystem()); |
| EXPECT_OK(device.CheckFilesystem()); |
| EXPECT_OK(device.MountFilesystem()); |
| |
| ASSERT_OK(ramdisk_destroy(ramdisk)); |
| } |
| |
| TEST_F(BlockDeviceHarness, TestBlobfs) { |
| std::unique_ptr<FsManager> manager = TakeManager(); |
| |
| bool netboot = false; |
| bool check_filesystems = true; |
| FilesystemMounter mounter(std::move(manager), netboot, check_filesystems); |
| |
| // Initialize Ramdisk with a data GUID. |
| constexpr uint64_t kBlockSize = 512; |
| constexpr uint64_t kBlockCount = 1 << 20; |
| ramdisk_client_t* ramdisk; |
| const uint8_t data_guid[GPT_GUID_LEN] = GUID_BLOB_VALUE; |
| ASSERT_OK(ramdisk_create_at_with_guid(devfs_root().get(), kBlockSize, kBlockCount, data_guid, |
| sizeof(data_guid), &ramdisk)); |
| fbl::unique_fd fd; |
| ASSERT_EQ(devmgr_integration_test::RecursiveWaitForFile(devfs_root(), ramdisk_get_path(ramdisk), |
| &fd), |
| ZX_OK); |
| ASSERT_TRUE(fd); |
| |
| BlockDevice device(&mounter, std::move(fd)); |
| device.SetFormat(DISK_FORMAT_BLOBFS); |
| EXPECT_EQ(device.GetFormat(), DISK_FORMAT_BLOBFS); |
| |
| // Before formatting the device, this isn't a valid blobfs partition. |
| // However, as implemented, we always validate the consistency of the filesystem. |
| EXPECT_OK(device.CheckFilesystem()); |
| EXPECT_NOT_OK(device.MountFilesystem()); |
| |
| // Additionally, blobfs does not yet support reformatting within fshost. |
| EXPECT_NOT_OK(device.FormatFilesystem()); |
| EXPECT_OK(device.CheckFilesystem()); |
| EXPECT_NOT_OK(device.MountFilesystem()); |
| |
| ASSERT_OK(ramdisk_destroy(ramdisk)); |
| } |
| |
| // TODO: Add tests for Zxcrypt binding. |
| |
| } // namespace |
| } // namespace devmgr |