gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/statfs.cc (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <fcntl.h>
    16  #include <linux/magic.h>
    17  #include <sys/mount.h>
    18  #include <sys/statfs.h>
    19  #include <unistd.h>
    20  
    21  #include <cstdint>
    22  #include <string>
    23  #include <vector>
    24  
    25  #include "gtest/gtest.h"
    26  #include "test/util/file_descriptor.h"
    27  #include "test/util/fs_util.h"
    28  #include "test/util/linux_capability_util.h"
    29  #include "test/util/mount_util.h"
    30  #include "test/util/temp_path.h"
    31  #include "test/util/test_util.h"
    32  
    33  namespace gvisor {
    34  namespace testing {
    35  
    36  namespace {
    37  
    38  TEST(StatfsTest, CannotStatBadPath) {
    39    auto temp_file = NewTempAbsPath();
    40  
    41    struct statfs st;
    42    EXPECT_THAT(statfs(temp_file.c_str(), &st), SyscallFailsWithErrno(ENOENT));
    43  }
    44  
    45  TEST(StatfsTest, TempPath) {
    46    auto temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
    47  
    48    struct statfs st;
    49    EXPECT_THAT(statfs(temp_file.path().c_str(), &st), SyscallSucceeds());
    50    EXPECT_GT(st.f_namelen, 0);
    51  }
    52  
    53  TEST(StatfsTest, InternalDevShm) {
    54    struct statfs st;
    55    EXPECT_THAT(statfs("/dev/shm", &st), SyscallSucceeds());
    56  
    57    EXPECT_GT(st.f_namelen, 0);
    58    // This assumes that /dev/shm is tmpfs.
    59    // Note: We could be an overlay on some configurations.
    60    EXPECT_TRUE(st.f_type == TMPFS_MAGIC || st.f_type == OVERLAYFS_SUPER_MAGIC);
    61  }
    62  
    63  TEST(StatFsTest, MountFlags) {
    64    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
    65  
    66    const std::vector<int64_t> flags = {MS_NOEXEC, MS_NOATIME, MS_NODEV,
    67                                        MS_NOSUID, MS_RDONLY};
    68  
    69    for (const auto& flag : flags) {
    70      auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
    71      auto const mount = ASSERT_NO_ERRNO_AND_VALUE(
    72          Mount("", dir.path(), "tmpfs", flag, "mode=0777", 0));
    73      struct statfs st;
    74      EXPECT_THAT(statfs(dir.path().c_str(), &st), SyscallSucceeds());
    75      EXPECT_TRUE((st.f_flags & flag) == flag);
    76    }
    77  }
    78  
    79  TEST(FstatfsTest, CannotStatBadFd) {
    80    struct statfs st;
    81    EXPECT_THAT(fstatfs(-1, &st), SyscallFailsWithErrno(EBADF));
    82  }
    83  
    84  TEST(FstatfsTest, TempPath) {
    85    auto temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
    86    const FileDescriptor fd =
    87        ASSERT_NO_ERRNO_AND_VALUE(Open(temp_file.path(), O_RDONLY));
    88  
    89    struct statfs st;
    90    EXPECT_THAT(fstatfs(fd.get(), &st), SyscallSucceeds());
    91    EXPECT_GT(st.f_namelen, 0);
    92  }
    93  
    94  TEST(FstatfsTest, CanStatFileWithOpath) {
    95    auto temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
    96    const FileDescriptor fd =
    97        ASSERT_NO_ERRNO_AND_VALUE(Open(temp_file.path(), O_PATH));
    98  
    99    struct statfs st;
   100    EXPECT_THAT(fstatfs(fd.get(), &st), SyscallSucceeds());
   101  }
   102  
   103  TEST(FstatfsTest, InternalDevShm) {
   104    auto temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   105    const FileDescriptor fd =
   106        ASSERT_NO_ERRNO_AND_VALUE(Open("/dev/shm", O_RDONLY));
   107  
   108    struct statfs st;
   109    EXPECT_THAT(fstatfs(fd.get(), &st), SyscallSucceeds());
   110    EXPECT_GT(st.f_namelen, 0);
   111    // This assumes that /dev/shm is tmpfs.
   112    // Note: We could be an overlay on some configurations.
   113    EXPECT_TRUE(st.f_type == TMPFS_MAGIC || st.f_type == OVERLAYFS_SUPER_MAGIC);
   114  }
   115  
   116  // Tests that the number of blocks free in the filesystem, as reported by
   117  // statfs(2) updates appropriately when pages are allocated.
   118  TEST(FstatfsTest, BlocksFree) {
   119    // This test relies on the test being the only user of the filesystem, which
   120    // is not feasible outside of a sandbox.
   121    SKIP_IF(!IsRunningOnGvisor());
   122  
   123    const std::string file_path = NewTempAbsPath();
   124    const std::string dir = std::string(Dirname(file_path));
   125    struct statfs st_before;
   126    EXPECT_THAT(statfs(dir.c_str(), &st_before), SyscallSucceeds());
   127    // Only test for tmpfs. Passthru gofer does not expose host filesystem
   128    // statfs(2) results. It always returns 0 for blocks free.
   129    SKIP_IF(st_before.f_type != TMPFS_MAGIC);
   130  
   131    ASSERT_NO_ERRNO(CreateWithContents(file_path, "abcd"));
   132    struct statfs st_after;
   133    EXPECT_THAT(statfs(dir.c_str(), &st_after), SyscallSucceeds());
   134    EXPECT_GT(st_before.f_bfree, st_after.f_bfree);
   135    EXPECT_GT(st_before.f_bavail, st_after.f_bavail);
   136  }
   137  
   138  }  // namespace
   139  }  // namespace testing
   140  }  // namespace gvisor