github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/preadv.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 <sys/syscall.h>
    16  #include <sys/types.h>
    17  #include <sys/uio.h>
    18  #include <sys/wait.h>
    19  #include <unistd.h>
    20  
    21  #include <atomic>
    22  #include <string>
    23  
    24  #include "gtest/gtest.h"
    25  #include "absl/time/clock.h"
    26  #include "absl/time/time.h"
    27  #include "test/util/file_descriptor.h"
    28  #include "test/util/logging.h"
    29  #include "test/util/memory_util.h"
    30  #include "test/util/temp_path.h"
    31  #include "test/util/test_util.h"
    32  #include "test/util/thread_util.h"
    33  #include "test/util/timer_util.h"
    34  
    35  namespace gvisor {
    36  namespace testing {
    37  
    38  namespace {
    39  
    40  // Stress copy-on-write. Attempts to reproduce b/38430174.
    41  TEST(PreadvTest, MMConcurrencyStress) {
    42    // Fill a one-page file with zeroes (the contents don't really matter).
    43    const auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
    44        /* parent = */ GetAbsoluteTestTmpdir(),
    45        /* content = */ std::string(kPageSize, 0), TempPath::kDefaultFileMode));
    46    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_RDONLY));
    47  
    48    // Get a one-page private mapping to read to.
    49    const Mapping m = ASSERT_NO_ERRNO_AND_VALUE(
    50        MmapAnon(kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE));
    51  
    52    // Repeatedly fork in a separate thread to force the mapping to become
    53    // copy-on-write.
    54    std::atomic<bool> done(false);
    55    const ScopedThread t([&] {
    56      while (!done.load()) {
    57        const pid_t pid = fork();
    58        TEST_CHECK(pid >= 0);
    59        if (pid == 0) {
    60          // In child. The parent was obviously multithreaded, so it's neither
    61          // safe nor necessary to do much more than exit.
    62          syscall(SYS_exit_group, 0);
    63        }
    64        int status;
    65        ASSERT_THAT(RetryEINTR(waitpid)(pid, &status, 0),
    66                    SyscallSucceedsWithValue(pid));
    67        EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0)
    68            << "status = " << status;
    69      }
    70    });
    71  
    72    // Repeatedly read to the mapping.
    73    struct iovec iov[2];
    74    iov[0].iov_base = m.ptr();
    75    iov[0].iov_len = kPageSize / 2;
    76    iov[1].iov_base = reinterpret_cast<void*>(m.addr() + kPageSize / 2);
    77    iov[1].iov_len = kPageSize / 2;
    78    constexpr absl::Duration kTestDuration = absl::Seconds(5);
    79    const absl::Time end = absl::Now() + kTestDuration;
    80    while (absl::Now() < end) {
    81      // Among other causes, save/restore cycles may cause interruptions resulting
    82      // in partial reads, so we don't expect any particular return value.
    83      EXPECT_THAT(RetryEINTR(preadv)(fd.get(), iov, 2, 0), SyscallSucceeds());
    84    }
    85  
    86    // Stop the other thread.
    87    done.store(true);
    88  
    89    // The test passes if it neither deadlocks nor crashes the OS.
    90  }
    91  
    92  // This test calls preadv with an O_PATH fd.
    93  TEST(PreadvTest, PreadvWithOpath) {
    94    SKIP_IF(IsRunningWithVFS1());
    95    const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
    96    const FileDescriptor fd =
    97        ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_PATH));
    98  
    99    struct iovec iov;
   100    iov.iov_base = nullptr;
   101    iov.iov_len = 0;
   102  
   103    EXPECT_THAT(preadv(fd.get(), &iov, 1, 0), SyscallFailsWithErrno(EBADF));
   104  }
   105  
   106  }  // namespace
   107  
   108  }  // namespace testing
   109  }  // namespace gvisor