From 5b538f75e447d934ac81a1bfc167306ef8f55814 Mon Sep 17 00:00:00 2001 From: Shambhavi Srivastava Date: Fri, 1 Apr 2022 14:59:38 -0700 Subject: [PATCH] Created tests for mounting tmpfs with size option enabled. Tests include: Allocating memory below and above range for single file. Allocating memory above range for multiple file. PiperOrigin-RevId: 438918539 --- test/syscalls/linux/mount.cc | 91 ++++++++++++++++++++++++++++++++++++ test/util/posix_error.h | 6 +-- 2 files changed, 94 insertions(+), 3 deletions(-) diff --git a/test/syscalls/linux/mount.cc b/test/syscalls/linux/mount.cc index a86a8bf1f..c0c751488 100644 --- a/test/syscalls/linux/mount.cc +++ b/test/syscalls/linux/mount.cc @@ -15,17 +15,25 @@ #include #include #include +#include #include +#include +#include #include #include #include +#include #include +#include #include +#include +#include #include #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/strings/str_cat.h" #include "absl/strings/str_split.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" @@ -433,6 +441,89 @@ TEST(MountTest, MountInfo) { } } +// TODO(b/29637826): Enable this test on gVisor once tmpfs supports size option. +TEST(MountTest, TmpfsSizeRoundUpSinglePageSize) { + SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)) || + IsRunningOnGvisor()); + auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + auto tmpfs_size_opt = absl::StrCat("size=", kPageSize / 2); + auto const mount = ASSERT_NO_ERRNO_AND_VALUE( + Mount("", dir.path(), "tmpfs", 0, tmpfs_size_opt, 0)); + auto fd = ASSERT_NO_ERRNO_AND_VALUE( + Open(JoinPath(dir.path(), "foo"), O_CREAT | O_RDWR, 0777)); + + // Check that it starts at size zero. + struct stat buf; + ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); + EXPECT_EQ(buf.st_size, 0); + + // Grow to 1 Page Size. + ASSERT_THAT(fallocate(fd.get(), 0, 0, kPageSize), SyscallSucceeds()); + ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); + EXPECT_EQ(buf.st_size, kPageSize); + + // Grow to size beyond tmpfs allocated bytes. + ASSERT_THAT(fallocate(fd.get(), 0, 0, kPageSize + 1), + SyscallFailsWithErrno(ENOSPC)); + ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); + EXPECT_EQ(buf.st_size, kPageSize); +} + +TEST(MountTest, TmpfsSizeRoundUpMultiplePages) { + SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)) || + IsRunningOnGvisor()); + auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + auto page_multiple = 2; + auto size = kPageSize * page_multiple; + auto tmpfs_size_opt = absl::StrCat("size=", size); + auto const mount = ASSERT_NO_ERRNO_AND_VALUE( + Mount("", dir.path(), "tmpfs", 0, tmpfs_size_opt, 0)); + auto fd = ASSERT_NO_ERRNO_AND_VALUE( + Open(JoinPath(dir.path(), "foo"), O_CREAT | O_RDWR, 0777)); + + // Check that it starts at size zero. + struct stat buf; + ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); + EXPECT_EQ(buf.st_size, 0); + + // Grow to multiple of page size. + ASSERT_THAT(fallocate(fd.get(), 0, 0, size), SyscallSucceeds()); + ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); + EXPECT_EQ(buf.st_size, size); + + // Grow to beyond tmpfs size bytes. + ASSERT_THAT(fallocate(fd.get(), 0, 0, size + 1), + SyscallFailsWithErrno(ENOSPC)); + ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); + EXPECT_EQ(buf.st_size, size); +} + +TEST(MountTest, TmpfsSizeMoreThanSinglePgSZMultipleFiles) { + SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)) || + IsRunningOnGvisor()); + auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + auto const page_multiple = 10; + auto const size = kPageSize * page_multiple; + auto tmpfs_size_opt = absl::StrCat("size=", size); + auto const mount = ASSERT_NO_ERRNO_AND_VALUE( + Mount("", dir.path(), "tmpfs", 0, tmpfs_size_opt, 0)); + for (int i = 0; i < page_multiple; i++) { + auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open( + JoinPath(dir.path(), absl::StrCat("foo_", i)), O_CREAT | O_RDWR, 0777)); + // Create buffer & Grow to 100 bytes. + struct stat buf; + ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); + ASSERT_THAT(fallocate(fd.get(), 0, 0, 100), SyscallSucceeds()); + ASSERT_THAT(fstat(fd.get(), &buf), SyscallSucceeds()); + EXPECT_EQ(buf.st_size, 100); + } + auto fd = ASSERT_NO_ERRNO_AND_VALUE( + Open(JoinPath(dir.path(), absl::StrCat("foo_", page_multiple + 1)), + O_CREAT | O_RDWR, 0777)); + // Grow to beyond tmpfs size bytes after exhausting the size. + ASSERT_THAT(fallocate(fd.get(), 0, 0, kPageSize), + SyscallFailsWithErrno(ENOSPC)); +} } // namespace } // namespace testing diff --git a/test/util/posix_error.h b/test/util/posix_error.h index 40853cb21..8f4f97488 100644 --- a/test/util/posix_error.h +++ b/test/util/posix_error.h @@ -231,8 +231,8 @@ template class IsPosixErrorOkAndHoldsMatcherImpl : public ::testing::MatcherInterface { public: - using ValueType = typename std::remove_reference().ValueOrDie())>::type; + using ValueType = typename std::remove_reference< + decltype(std::declval().ValueOrDie())>::type; template explicit IsPosixErrorOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher) @@ -435,7 +435,7 @@ IsPosixErrorOkAndHolds(InnerMatcher&& inner_matcher) { #define RETURN_IF_ERRNO(s) \ do { \ if (!s.ok()) { \ - return s; \ + return s.error(); \ } \ } while (false);