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