diff --git a/CHANGELOG.md b/CHANGELOG.md index 2707832a..51c20995 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ * `AIS_USE_SANITIZERS` now also enables the following sanitizers: integer, float-divide-by-zero, local-bounds, vptr, nullability (in addition to address, leak, and undefined). Sanitizers should also now emit usable stack trace info. * Added check in the Fastpath/AIS backend to ensure the HIP Runtime is initialized. This avoids causing a segfault in the HIP Runtime. * The default CMake build type was changed from `Debug` to `RelWithDebInfo` +* Added `HIPFILE_UNSUPPORTED_FILE_SYSTEMS` environment variable to allow fastpath operations on unsupported file systems (defaults to false) +* Added validation in Fastpath::score() to ensure the file is a regular file (not a directory, symlink, character device, etc.) +* Added file system validation in Fastpath::score() to accept only ext4 file systems with ordered journaling mode and XFS file systems. Other file systems can be explicitly allowed via the `HIPFILE_UNSUPPORTED_FILE_SYSTEMS` environment variable. ### Removed * The rocFile library has been completely removed and the code is now a part of hipFile. diff --git a/src/amd_detail/backend/fastpath.cpp b/src/amd_detail/backend/fastpath.cpp index 35652363..4d643bd3 100644 --- a/src/amd_detail/backend/fastpath.cpp +++ b/src/amd_detail/backend/fastpath.cpp @@ -11,6 +11,7 @@ #include "hip.h" #include "hipfile.h" #include "io.h" +#include "mountinfo.h" #include "stats.h" #include @@ -138,6 +139,17 @@ Fastpath::score(shared_ptr file, shared_ptr buffer, size_t size, accept_io &= 0 <= file_offset; accept_io &= 0 <= buffer_offset; + bool unsupported_file_systems{Context::get()->unsupportedFileSystems()}; + bool ext4_ordered{false}; + bool xfs{false}; + auto mount_info{file->getMountInfo()}; + if (mount_info.has_value()) { + ext4_ordered = mount_info->type == FilesystemType::ext4 && + mount_info->options.ext4.journaling_mode == ExtJournalingMode::ordered; + xfs = mount_info->type == FilesystemType::xfs; + } + accept_io &= unsupported_file_systems || ext4_ordered || xfs; + uint64_t mem_align_mask{4096 - 1}; uint64_t offset_align_mask{4096 - 1}; diff --git a/src/amd_detail/configuration.cpp b/src/amd_detail/configuration.cpp index 97b88e19..427e8622 100644 --- a/src/amd_detail/configuration.cpp +++ b/src/amd_detail/configuration.cpp @@ -46,3 +46,10 @@ Configuration::statsLevel() const noexcept HIPFILE_STATIC unsigned int stats_level_env{Environment::stats_level().value_or(0)}; return stats_level_env; } + +bool +Configuration::unsupportedFileSystems() const noexcept +{ + HIPFILE_STATIC bool unsupported_file_systems_env{Environment::unsupported_file_systems().value_or(false)}; + return unsupported_file_systems_env; +} diff --git a/src/amd_detail/configuration.h b/src/amd_detail/configuration.h index 8648a62d..c8a7eab1 100644 --- a/src/amd_detail/configuration.h +++ b/src/amd_detail/configuration.h @@ -37,6 +37,11 @@ class Configuration { /// @brief Shows the level of detail for stats collection /// @return 0 if stats collection disabled, higher levels of detail as value increases virtual unsigned int statsLevel() const noexcept; + + /// @brief Checks if unsupported file systems are allowed in the fastpath backend + /// @return true if unsupported file systems are allowed, false if only supported file systems are + /// permitted (default) + virtual bool unsupportedFileSystems() const noexcept; }; } diff --git a/src/amd_detail/environment.cpp b/src/amd_detail/environment.cpp index 1f6d15ed..efbf1608 100644 --- a/src/amd_detail/environment.cpp +++ b/src/amd_detail/environment.cpp @@ -64,6 +64,12 @@ Environment::force_compat_mode() return Environment::get(Environment::FORCE_COMPAT_MODE); } +optional +Environment::unsupported_file_systems() +{ + return Environment::get(Environment::UNSUPPORTED_FILE_SYSTEMS); +} + optional Environment::stats_level() { diff --git a/src/amd_detail/environment.h b/src/amd_detail/environment.h index dc6f63d9..374b85ea 100644 --- a/src/amd_detail/environment.h +++ b/src/amd_detail/environment.h @@ -47,6 +47,19 @@ class Environment { static constexpr const char *const STATS_LEVEL{"HIPFILE_STATS_LEVEL"}; static std::optional stats_level(); + + /// @brief Allow unsupported file systems in the fastpath backend + /// + /// If enabled, the fastpath backend will allow I/O on file systems other than + /// ext4 (with ordered journaling) and xfs. If disabled (default), only supported + /// file systems are permitted. + static constexpr const char *const UNSUPPORTED_FILE_SYSTEMS{"HIPFILE_UNSUPPORTED_FILE_SYSTEMS"}; + + /// @brief Get the value of HIPFILE_UNSUPPORTED_FILE_SYSTEMS from the environment + /// @return An optional boolean value if HIPFILE_UNSUPPORTED_FILE_SYSTEMS was set, + /// nullopt if HIPFILE_UNSUPPORTED_FILE_SYSTEMS was unset or had a value other than + /// true or false. + static std::optional unsupported_file_systems(); }; } diff --git a/test/amd_detail/configuration.cpp b/test/amd_detail/configuration.cpp index e465f99f..3a719940 100644 --- a/test/amd_detail/configuration.cpp +++ b/test/amd_detail/configuration.cpp @@ -48,6 +48,12 @@ struct HipFileConfiguration : public Test { EXPECT_CALL(msys, getenv(StrEq(hipFile::Environment::STATS_LEVEL))) .WillOnce(Return(const_cast(hipfile_stats_level))); } + + void expect_configuration_unsupported_file_systems(const char *hipfile_unsupported_file_systems) + { + EXPECT_CALL(msys, getenv(StrEq(hipFile::Environment::UNSUPPORTED_FILE_SYSTEMS))) + .WillOnce(Return(const_cast(hipfile_unsupported_file_systems))); + } }; TEST_F(HipFileConfiguration, FastpathEnabledIfForceCompatModeEnvironmentVariableIsNotSet) @@ -194,4 +200,28 @@ TEST_F(HipFileConfiguration, StatsLevelEnvironmentVariableIsSet) ASSERT_EQ(1, Configuration().statsLevel()); } +TEST_F(HipFileConfiguration, UnsupportedFilesystemsDisabledIfEnvironmentVariableIsNotSet) +{ + expect_configuration_unsupported_file_systems(nullptr); + ASSERT_FALSE(Configuration().unsupportedFileSystems()); +} + +TEST_F(HipFileConfiguration, UnsupportedFilesystemsDisabledIfEnvironmentVariableIsInvalid) +{ + expect_configuration_unsupported_file_systems("not-a-bool"); + ASSERT_FALSE(Configuration().unsupportedFileSystems()); +} + +TEST_F(HipFileConfiguration, UnsupportedFilesystemsEnabledIfEnvironmentVariableIsTrue) +{ + expect_configuration_unsupported_file_systems("true"); + ASSERT_TRUE(Configuration().unsupportedFileSystems()); +} + +TEST_F(HipFileConfiguration, UnsupportedFilesystemsDisabledIfEnvironmentVariableIsFalse) +{ + expect_configuration_unsupported_file_systems("false"); + ASSERT_FALSE(Configuration().unsupportedFileSystems()); +} + HIPFILE_WARN_NO_GLOBAL_CTOR_ON diff --git a/test/amd_detail/fastpath.cpp b/test/amd_detail/fastpath.cpp index 06098b70..6788fee2 100644 --- a/test/amd_detail/fastpath.cpp +++ b/test/amd_detail/fastpath.cpp @@ -73,6 +73,9 @@ struct FastpathTestBase { return stx; }() }; + const bool DEFAULT_UNSUPPORTED_FILE_SYSTEMS{false}; + const MountInfo DEFAULT_MOUNT_INFO{FilesystemType::ext4, + MountOptions{Ext4MountOptions{ExtJournalingMode::ordered}}}; // Buffer and file mocks used to setup expectations shared_ptr> mfile{make_shared>()}; @@ -94,6 +97,9 @@ TEST_F(FastpathTest, TestDefaults) ASSERT_FALSE((DEFAULT_BUFFER_OFFSET & (DEFAULT_MEM_ALIGN - 1))); ASSERT_FALSE((DEFAULT_IO_SIZE & (DEFAULT_OFFSET_ALIGN - 1))); ASSERT_FALSE((DEFAULT_FILE_OFFSET & (DEFAULT_OFFSET_ALIGN - 1))); + ASSERT_FALSE(DEFAULT_UNSUPPORTED_FILE_SYSTEMS); + ASSERT_EQ(DEFAULT_MOUNT_INFO.type, FilesystemType::ext4); + ASSERT_EQ(DEFAULT_MOUNT_INFO.options.ext4.journaling_mode, ExtJournalingMode::ordered); } TEST_F(FastpathTest, ScoreAcceptsIoWithDefaults) @@ -101,6 +107,8 @@ TEST_F(FastpathTest, ScoreAcceptsIoWithDefaults) EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(DEFAULT_MOUNT_INFO)); #if defined(STATX_DIOALIGN) EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); #endif @@ -115,6 +123,8 @@ TEST_F(FastpathTest, ScoreRejectsIoIfFastpathIsDisabled) EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(false)); EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(DEFAULT_MOUNT_INFO)); #if defined(STATX_DIOALIGN) EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); #endif @@ -129,6 +139,8 @@ TEST_F(FastpathTest, ScoreRejectsIoIfUnbufferedFdNotAvailable) EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(nullopt)); EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(DEFAULT_MOUNT_INFO)); #if defined(STATX_DIOALIGN) EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); #endif @@ -143,6 +155,8 @@ TEST_F(FastpathTest, ScoreRejectsIoWithNegativeAlignedFileOffset) EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(DEFAULT_MOUNT_INFO)); #if defined(STATX_DIOALIGN) EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); #endif @@ -158,6 +172,8 @@ TEST_F(FastpathTest, ScoreRejectsIoWithNegativeAlignedBufferOffset) EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(DEFAULT_MOUNT_INFO)); #if defined(STATX_DIOALIGN) EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); #endif @@ -173,6 +189,8 @@ TEST_F(FastpathTest, ScoreRejectsIoIfBufferAddressPlusBufferOffsetIsUnaligned) EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(DEFAULT_MOUNT_INFO)); #if defined(STATX_DIOALIGN) EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); #endif @@ -194,6 +212,8 @@ TEST_P(FastpathSupportedHipMemoryParam, Score) EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); EXPECT_CALL(*mbuffer, getType).WillOnce(Return(GetParam())); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(DEFAULT_MOUNT_INFO)); #if defined(STATX_DIOALIGN) EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); #endif @@ -212,6 +232,8 @@ TEST_P(FastpathUnsupportedHipMemoryParam, Score) EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); EXPECT_CALL(*mbuffer, getType).WillOnce(Return(GetParam())); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(DEFAULT_MOUNT_INFO)); #if defined(STATX_DIOALIGN) EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); #endif @@ -231,6 +253,8 @@ TEST_P(FastpathAlignedIoSizesParam, Score) EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(DEFAULT_MOUNT_INFO)); #if defined(STATX_DIOALIGN) EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); #endif @@ -251,6 +275,8 @@ TEST_P(FastpathUnalignedIoSizesParam, Score) EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(DEFAULT_MOUNT_INFO)); #if defined(STATX_DIOALIGN) EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); #endif @@ -271,6 +297,8 @@ TEST_P(FastpathAlignedFileOffsetsParam, Score) EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(DEFAULT_MOUNT_INFO)); #if defined(STATX_DIOALIGN) EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); #endif @@ -293,6 +321,8 @@ TEST_P(FastpathUnalignedFileOffsetsParam, Score) EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(DEFAULT_MOUNT_INFO)); #if defined(STATX_DIOALIGN) EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); #endif @@ -317,6 +347,8 @@ TEST_P(FastpathAlignedBufferOffsetsParam, Score) EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(DEFAULT_MOUNT_INFO)); #if defined(STATX_DIOALIGN) EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); #endif @@ -340,6 +372,8 @@ TEST_P(FastpathUnalignedBufferOffsetsParam, Score) EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(DEFAULT_MOUNT_INFO)); #if defined(STATX_DIOALIGN) EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); #endif @@ -357,6 +391,146 @@ INSTANTIATE_TEST_SUITE_P(FastpathTest, FastpathUnalignedBufferOffsetsParam, DEFAULT_MEM_ALIGN - 1, (DEFAULT_MEM_ALIGN << 1) + 1, (DEFAULT_MEM_ALIGN << 2) - 1)); +TEST_F(FastpathTest, ScoreRejectsIoIfMountInfoUnavailable) +{ + EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); + EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); + EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(nullopt)); +#if defined(STATX_DIOALIGN) + EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); +#endif + EXPECT_CALL(*mbuffer, getBuffer).WillOnce(Return(DEFAULT_BUFFER_ADDR)); + + ASSERT_EQ(Fastpath().score(mfile, mbuffer, DEFAULT_IO_SIZE, DEFAULT_FILE_OFFSET, DEFAULT_BUFFER_OFFSET), + SCORE_REJECT); +} + +TEST_F(FastpathTest, ScoreRejectsIoIfFileSystemIsOther) +{ + MountInfo mountinfo{FilesystemType::other, {}}; + + EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); + EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); + EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(mountinfo)); +#if defined(STATX_DIOALIGN) + EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); +#endif + EXPECT_CALL(*mbuffer, getBuffer).WillOnce(Return(DEFAULT_BUFFER_ADDR)); + + ASSERT_EQ(Fastpath().score(mfile, mbuffer, DEFAULT_IO_SIZE, DEFAULT_FILE_OFFSET, DEFAULT_BUFFER_OFFSET), + SCORE_REJECT); +} + +TEST_F(FastpathTest, ScoreRejectsIoIfExt4JournalingModeIsWriteback) +{ + MountInfo mountinfo{FilesystemType::ext4, MountOptions{Ext4MountOptions{ExtJournalingMode::writeback}}}; + + EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); + EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); + EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(mountinfo)); +#if defined(STATX_DIOALIGN) + EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); +#endif + EXPECT_CALL(*mbuffer, getBuffer).WillOnce(Return(DEFAULT_BUFFER_ADDR)); + + ASSERT_EQ(Fastpath().score(mfile, mbuffer, DEFAULT_IO_SIZE, DEFAULT_FILE_OFFSET, DEFAULT_BUFFER_OFFSET), + SCORE_REJECT); +} + +TEST_F(FastpathTest, ScoreRejectsIoIfExt4JournalingModeIsJournal) +{ + MountInfo mountinfo{FilesystemType::ext4, MountOptions{Ext4MountOptions{ExtJournalingMode::journal}}}; + + EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); + EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); + EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(mountinfo)); +#if defined(STATX_DIOALIGN) + EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); +#endif + EXPECT_CALL(*mbuffer, getBuffer).WillOnce(Return(DEFAULT_BUFFER_ADDR)); + + ASSERT_EQ(Fastpath().score(mfile, mbuffer, DEFAULT_IO_SIZE, DEFAULT_FILE_OFFSET, DEFAULT_BUFFER_OFFSET), + SCORE_REJECT); +} + +TEST_F(FastpathTest, ScoreAcceptsIoIfFileSystemIsXfs) +{ + MountInfo mountinfo{FilesystemType::xfs, {}}; + + EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); + EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); + EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(DEFAULT_UNSUPPORTED_FILE_SYSTEMS)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(mountinfo)); +#if defined(STATX_DIOALIGN) + EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); +#endif + EXPECT_CALL(*mbuffer, getBuffer).WillOnce(Return(DEFAULT_BUFFER_ADDR)); + + ASSERT_EQ(Fastpath().score(mfile, mbuffer, DEFAULT_IO_SIZE, DEFAULT_FILE_OFFSET, DEFAULT_BUFFER_OFFSET), + SCORE_ACCEPT); +} + +TEST_F(FastpathTest, ScoreAcceptsIoIfUnsupportedFileSystemsFlagIsTrueAndMountInfoUnavailable) +{ + EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); + EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); + EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(true)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(nullopt)); +#if defined(STATX_DIOALIGN) + EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); +#endif + EXPECT_CALL(*mbuffer, getBuffer).WillOnce(Return(DEFAULT_BUFFER_ADDR)); + + ASSERT_EQ(Fastpath().score(mfile, mbuffer, DEFAULT_IO_SIZE, DEFAULT_FILE_OFFSET, DEFAULT_BUFFER_OFFSET), + SCORE_ACCEPT); +} + +TEST_F(FastpathTest, ScoreAcceptsIoIfUnsupportedFileSystemsFlagIsTrueAndFileSystemIsOther) +{ + MountInfo mountinfo{FilesystemType::other, {}}; + + EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); + EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); + EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(true)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(mountinfo)); +#if defined(STATX_DIOALIGN) + EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); +#endif + EXPECT_CALL(*mbuffer, getBuffer).WillOnce(Return(DEFAULT_BUFFER_ADDR)); + + ASSERT_EQ(Fastpath().score(mfile, mbuffer, DEFAULT_IO_SIZE, DEFAULT_FILE_OFFSET, DEFAULT_BUFFER_OFFSET), + SCORE_ACCEPT); +} + +TEST_F(FastpathTest, ScoreAcceptsIoIfUnsupportedFileSystemsFlagIsTrueWithNonOrderedExt4) +{ + MountInfo mountinfo{FilesystemType::ext4, MountOptions{Ext4MountOptions{ExtJournalingMode::writeback}}}; + + EXPECT_CALL(mcfg, fastpath()).WillOnce(Return(DEFAULT_ENABLE)); + EXPECT_CALL(*mfile, getUnbufferedFd).WillOnce(Return(DEFAULT_UNBUFFERED_FD)); + EXPECT_CALL(*mbuffer, getType).WillOnce(Return(DEFAULT_BUFFER_TYPE)); + EXPECT_CALL(mcfg, unsupportedFileSystems()).WillOnce(Return(true)); + EXPECT_CALL(*mfile, getMountInfo).WillOnce(Return(mountinfo)); +#if defined(STATX_DIOALIGN) + EXPECT_CALL(*mfile, getStatx).WillOnce(ReturnRef(DEFAULT_STATX)); +#endif + EXPECT_CALL(*mbuffer, getBuffer).WillOnce(Return(DEFAULT_BUFFER_ADDR)); + + ASSERT_EQ(Fastpath().score(mfile, mbuffer, DEFAULT_IO_SIZE, DEFAULT_FILE_OFFSET, DEFAULT_BUFFER_OFFSET), + SCORE_ACCEPT); +} + struct FastpathIoParam : public FastpathTestBase, public TestWithParam { StrictMock mhip; diff --git a/test/amd_detail/mconfiguration.h b/test/amd_detail/mconfiguration.h index fe910247..1194ad74 100644 --- a/test/amd_detail/mconfiguration.h +++ b/test/amd_detail/mconfiguration.h @@ -22,6 +22,7 @@ struct MConfiguration : Configuration { MOCK_METHOD(bool, fallback, (), (const, noexcept, override)); MOCK_METHOD(void, fallback, (bool), (noexcept, override)); MOCK_METHOD(unsigned int, statsLevel, (), (const, noexcept, override)); + MOCK_METHOD(bool, unsupportedFileSystems, (), (const, noexcept, override)); }; }