gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/splice.cc (about) 1 // Copyright 2019 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/unistd.h> 17 #include <sys/eventfd.h> 18 #include <sys/resource.h> 19 #include <sys/sendfile.h> 20 #include <sys/time.h> 21 #include <unistd.h> 22 23 #include "gmock/gmock.h" 24 #include "gtest/gtest.h" 25 #include "absl/cleanup/cleanup.h" 26 #include "absl/strings/string_view.h" 27 #include "absl/time/clock.h" 28 #include "absl/time/time.h" 29 #include "test/util/file_descriptor.h" 30 #include "test/util/memory_util.h" 31 #include "test/util/signal_util.h" 32 #include "test/util/temp_path.h" 33 #include "test/util/test_util.h" 34 #include "test/util/thread_util.h" 35 #include "test/util/timer_util.h" 36 37 namespace gvisor { 38 namespace testing { 39 40 namespace { 41 42 TEST(SpliceTest, TwoRegularFiles) { 43 // Create temp files. 44 const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 45 const TempPath out_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 46 47 // Open the input file as read only. 48 const FileDescriptor in_fd = 49 ASSERT_NO_ERRNO_AND_VALUE(Open(in_file.path(), O_RDONLY)); 50 51 // Open the output file as write only. 52 const FileDescriptor out_fd = 53 ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_WRONLY)); 54 55 // Verify that it is rejected as expected; regardless of offsets. 56 loff_t in_offset = 0; 57 loff_t out_offset = 0; 58 EXPECT_THAT(splice(in_fd.get(), &in_offset, out_fd.get(), &out_offset, 1, 0), 59 SyscallFailsWithErrno(EINVAL)); 60 EXPECT_THAT(splice(in_fd.get(), nullptr, out_fd.get(), &out_offset, 1, 0), 61 SyscallFailsWithErrno(EINVAL)); 62 EXPECT_THAT(splice(in_fd.get(), &in_offset, out_fd.get(), nullptr, 1, 0), 63 SyscallFailsWithErrno(EINVAL)); 64 EXPECT_THAT(splice(in_fd.get(), nullptr, out_fd.get(), nullptr, 1, 0), 65 SyscallFailsWithErrno(EINVAL)); 66 } 67 68 int memfd_create(const std::string& name, unsigned int flags) { 69 return syscall(__NR_memfd_create, name.c_str(), flags); 70 } 71 72 TEST(SpliceTest, NegativeOffset) { 73 // Create a new pipe. 74 int fds[2]; 75 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 76 const FileDescriptor rfd(fds[0]); 77 const FileDescriptor wfd(fds[1]); 78 79 // Fill the pipe. 80 std::vector<char> buf(kPageSize); 81 RandomizeBuffer(buf.data(), buf.size()); 82 ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()), 83 SyscallSucceedsWithValue(kPageSize)); 84 85 // Open the output file as write only. 86 int fd; 87 EXPECT_THAT(fd = memfd_create("negative", 0), SyscallSucceeds()); 88 const FileDescriptor out_fd(fd); 89 90 loff_t out_offset = 0xffffffffffffffffull; 91 constexpr int kSize = 2; 92 EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), &out_offset, kSize, 0), 93 SyscallFailsWithErrno(EINVAL)); 94 } 95 96 // Write offset + size overflows int64. 97 // 98 // This is a regression test for b/148041624. 99 TEST(SpliceTest, WriteOverflow) { 100 // Create a new pipe. 101 int fds[2]; 102 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 103 const FileDescriptor rfd(fds[0]); 104 const FileDescriptor wfd(fds[1]); 105 106 // Fill the pipe. 107 std::vector<char> buf(kPageSize); 108 RandomizeBuffer(buf.data(), buf.size()); 109 ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()), 110 SyscallSucceedsWithValue(kPageSize)); 111 112 // Open the output file. 113 int fd; 114 EXPECT_THAT(fd = memfd_create("overflow", 0), SyscallSucceeds()); 115 const FileDescriptor out_fd(fd); 116 117 // out_offset + kSize overflows INT64_MAX. 118 loff_t out_offset = 0x7ffffffffffffffeull; 119 constexpr int kSize = 3; 120 EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), &out_offset, kSize, 0), 121 SyscallFailsWithErrno(EINVAL)); 122 } 123 124 TEST(SpliceTest, SamePipe) { 125 // Create a new pipe. 126 int fds[2]; 127 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 128 const FileDescriptor rfd(fds[0]); 129 const FileDescriptor wfd(fds[1]); 130 131 // Fill the pipe. 132 std::vector<char> buf(kPageSize); 133 RandomizeBuffer(buf.data(), buf.size()); 134 ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()), 135 SyscallSucceedsWithValue(kPageSize)); 136 137 // Attempt to splice to itself. 138 EXPECT_THAT(splice(rfd.get(), nullptr, wfd.get(), nullptr, kPageSize, 0), 139 SyscallFailsWithErrno(EINVAL)); 140 } 141 142 TEST(TeeTest, SamePipe) { 143 // Create a new pipe. 144 int fds[2]; 145 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 146 const FileDescriptor rfd(fds[0]); 147 const FileDescriptor wfd(fds[1]); 148 149 // Fill the pipe. 150 std::vector<char> buf(kPageSize); 151 RandomizeBuffer(buf.data(), buf.size()); 152 ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()), 153 SyscallSucceedsWithValue(kPageSize)); 154 155 // Attempt to tee to itself. 156 EXPECT_THAT(tee(rfd.get(), wfd.get(), kPageSize, 0), 157 SyscallFailsWithErrno(EINVAL)); 158 } 159 160 TEST(TeeTest, RegularFile) { 161 // Open some file. 162 const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 163 const FileDescriptor in_fd = 164 ASSERT_NO_ERRNO_AND_VALUE(Open(in_file.path(), O_RDWR)); 165 166 // Create a new pipe. 167 int fds[2]; 168 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 169 const FileDescriptor rfd(fds[0]); 170 const FileDescriptor wfd(fds[1]); 171 172 // Attempt to tee from the file. 173 EXPECT_THAT(tee(in_fd.get(), wfd.get(), kPageSize, 0), 174 SyscallFailsWithErrno(EINVAL)); 175 EXPECT_THAT(tee(rfd.get(), in_fd.get(), kPageSize, 0), 176 SyscallFailsWithErrno(EINVAL)); 177 } 178 179 TEST(SpliceTest, PipeOffsets) { 180 // Create two new pipes. 181 int first[2], second[2]; 182 ASSERT_THAT(pipe(first), SyscallSucceeds()); 183 const FileDescriptor rfd1(first[0]); 184 const FileDescriptor wfd1(first[1]); 185 ASSERT_THAT(pipe(second), SyscallSucceeds()); 186 const FileDescriptor rfd2(second[0]); 187 const FileDescriptor wfd2(second[1]); 188 189 // All pipe offsets should be rejected. 190 loff_t in_offset = 0; 191 loff_t out_offset = 0; 192 EXPECT_THAT(splice(rfd1.get(), &in_offset, wfd2.get(), &out_offset, 1, 0), 193 SyscallFailsWithErrno(ESPIPE)); 194 EXPECT_THAT(splice(rfd1.get(), nullptr, wfd2.get(), &out_offset, 1, 0), 195 SyscallFailsWithErrno(ESPIPE)); 196 EXPECT_THAT(splice(rfd1.get(), &in_offset, wfd2.get(), nullptr, 1, 0), 197 SyscallFailsWithErrno(ESPIPE)); 198 } 199 200 TEST(SpliceTest, ToPipe) { 201 // Open the input file. 202 const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 203 const FileDescriptor in_fd = 204 ASSERT_NO_ERRNO_AND_VALUE(Open(in_file.path(), O_RDWR)); 205 206 // Fill with some random data. 207 std::vector<char> buf(kPageSize); 208 RandomizeBuffer(buf.data(), buf.size()); 209 ASSERT_THAT(write(in_fd.get(), buf.data(), buf.size()), 210 SyscallSucceedsWithValue(kPageSize)); 211 ASSERT_THAT(lseek(in_fd.get(), 0, SEEK_SET), SyscallSucceedsWithValue(0)); 212 213 // Create a new pipe. 214 int fds[2]; 215 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 216 const FileDescriptor rfd(fds[0]); 217 const FileDescriptor wfd(fds[1]); 218 219 // Splice to the pipe. 220 EXPECT_THAT(splice(in_fd.get(), nullptr, wfd.get(), nullptr, kPageSize, 0), 221 SyscallSucceedsWithValue(kPageSize)); 222 223 // Contents should be equal. 224 std::vector<char> rbuf(kPageSize); 225 ASSERT_THAT(read(rfd.get(), rbuf.data(), rbuf.size()), 226 SyscallSucceedsWithValue(kPageSize)); 227 EXPECT_EQ(memcmp(rbuf.data(), buf.data(), buf.size()), 0); 228 } 229 230 TEST(SpliceTest, ToPipeEOF) { 231 // Create and open an empty input file. 232 const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 233 const FileDescriptor in_fd = 234 ASSERT_NO_ERRNO_AND_VALUE(Open(in_file.path(), O_RDONLY)); 235 236 // Create a new pipe. 237 int fds[2]; 238 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 239 const FileDescriptor rfd(fds[0]); 240 const FileDescriptor wfd(fds[1]); 241 242 // Splice from the empty file to the pipe. 243 EXPECT_THAT(splice(in_fd.get(), nullptr, wfd.get(), nullptr, 123, 0), 244 SyscallSucceedsWithValue(0)); 245 } 246 247 TEST(SpliceTest, ToPipeOffset) { 248 // Open the input file. 249 const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 250 const FileDescriptor in_fd = 251 ASSERT_NO_ERRNO_AND_VALUE(Open(in_file.path(), O_RDWR)); 252 253 // Fill with some random data. 254 std::vector<char> buf(kPageSize); 255 RandomizeBuffer(buf.data(), buf.size()); 256 ASSERT_THAT(write(in_fd.get(), buf.data(), buf.size()), 257 SyscallSucceedsWithValue(kPageSize)); 258 259 // Create a new pipe. 260 int fds[2]; 261 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 262 const FileDescriptor rfd(fds[0]); 263 const FileDescriptor wfd(fds[1]); 264 265 // Splice to the pipe. 266 loff_t in_offset = kPageSize / 2; 267 EXPECT_THAT( 268 splice(in_fd.get(), &in_offset, wfd.get(), nullptr, kPageSize / 2, 0), 269 SyscallSucceedsWithValue(kPageSize / 2)); 270 271 // Contents should be equal to only the second part. 272 std::vector<char> rbuf(kPageSize / 2); 273 ASSERT_THAT(read(rfd.get(), rbuf.data(), rbuf.size()), 274 SyscallSucceedsWithValue(kPageSize / 2)); 275 EXPECT_EQ(memcmp(rbuf.data(), buf.data() + (kPageSize / 2), rbuf.size()), 0); 276 } 277 278 TEST(SpliceTest, FromPipe) { 279 // Create a new pipe. 280 int fds[2]; 281 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 282 const FileDescriptor rfd(fds[0]); 283 const FileDescriptor wfd(fds[1]); 284 285 // Fill with some random data. 286 std::vector<char> buf(kPageSize); 287 RandomizeBuffer(buf.data(), buf.size()); 288 ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()), 289 SyscallSucceedsWithValue(kPageSize)); 290 291 // Open the output file. 292 const TempPath out_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 293 const FileDescriptor out_fd = 294 ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_RDWR)); 295 296 // Splice to the output file. 297 EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), nullptr, kPageSize, 0), 298 SyscallSucceedsWithValue(kPageSize)); 299 300 // The offset of the output should be equal to kPageSize. We assert that and 301 // reset to zero so that we can read the contents and ensure they match. 302 EXPECT_THAT(lseek(out_fd.get(), 0, SEEK_CUR), 303 SyscallSucceedsWithValue(kPageSize)); 304 ASSERT_THAT(lseek(out_fd.get(), 0, SEEK_SET), SyscallSucceedsWithValue(0)); 305 306 // Contents should be equal. 307 std::vector<char> rbuf(kPageSize); 308 ASSERT_THAT(read(out_fd.get(), rbuf.data(), rbuf.size()), 309 SyscallSucceedsWithValue(kPageSize)); 310 EXPECT_EQ(memcmp(rbuf.data(), buf.data(), buf.size()), 0); 311 } 312 313 TEST(SpliceTest, FromPipeMultiple) { 314 // Create a new pipe. 315 int fds[2]; 316 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 317 const FileDescriptor rfd(fds[0]); 318 const FileDescriptor wfd(fds[1]); 319 320 std::string buf = "abcABC123"; 321 ASSERT_THAT(write(wfd.get(), buf.c_str(), buf.size()), 322 SyscallSucceedsWithValue(buf.size())); 323 324 // Open the output file. 325 const TempPath out_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 326 const FileDescriptor out_fd = 327 ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_RDWR)); 328 329 // Splice from the pipe to the output file over several calls. 330 EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), nullptr, 3, 0), 331 SyscallSucceedsWithValue(3)); 332 EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), nullptr, 3, 0), 333 SyscallSucceedsWithValue(3)); 334 EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), nullptr, 3, 0), 335 SyscallSucceedsWithValue(3)); 336 337 // Reset cursor to zero so that we can check the contents. 338 ASSERT_THAT(lseek(out_fd.get(), 0, SEEK_SET), SyscallSucceedsWithValue(0)); 339 340 // Contents should be equal. 341 std::vector<char> rbuf(buf.size()); 342 ASSERT_THAT(read(out_fd.get(), rbuf.data(), rbuf.size()), 343 SyscallSucceedsWithValue(rbuf.size())); 344 EXPECT_EQ(memcmp(rbuf.data(), buf.c_str(), buf.size()), 0); 345 } 346 347 TEST(SpliceTest, FromPipeOffset) { 348 // Create a new pipe. 349 int fds[2]; 350 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 351 const FileDescriptor rfd(fds[0]); 352 const FileDescriptor wfd(fds[1]); 353 354 // Fill with some random data. 355 std::vector<char> buf(kPageSize); 356 RandomizeBuffer(buf.data(), buf.size()); 357 ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()), 358 SyscallSucceedsWithValue(kPageSize)); 359 360 // Open the input file. 361 const TempPath out_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 362 const FileDescriptor out_fd = 363 ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_RDWR)); 364 365 // Splice to the output file. 366 loff_t out_offset = kPageSize / 2; 367 EXPECT_THAT( 368 splice(rfd.get(), nullptr, out_fd.get(), &out_offset, kPageSize, 0), 369 SyscallSucceedsWithValue(kPageSize)); 370 371 // Content should reflect the splice. We write to a specific offset in the 372 // file, so the internals should now be allocated sparsely. 373 std::vector<char> rbuf(kPageSize); 374 ASSERT_THAT(read(out_fd.get(), rbuf.data(), rbuf.size()), 375 SyscallSucceedsWithValue(kPageSize)); 376 std::vector<char> zbuf(kPageSize / 2); 377 memset(zbuf.data(), 0, zbuf.size()); 378 EXPECT_EQ(memcmp(rbuf.data(), zbuf.data(), zbuf.size()), 0); 379 EXPECT_EQ(memcmp(rbuf.data() + kPageSize / 2, buf.data(), kPageSize / 2), 0); 380 } 381 382 TEST(SpliceTest, TwoPipes) { 383 // Create two new pipes. 384 int first[2], second[2]; 385 ASSERT_THAT(pipe(first), SyscallSucceeds()); 386 const FileDescriptor rfd1(first[0]); 387 const FileDescriptor wfd1(first[1]); 388 ASSERT_THAT(pipe(second), SyscallSucceeds()); 389 const FileDescriptor rfd2(second[0]); 390 const FileDescriptor wfd2(second[1]); 391 392 // Fill with some random data. 393 std::vector<char> buf(kPageSize); 394 RandomizeBuffer(buf.data(), buf.size()); 395 ASSERT_THAT(write(wfd1.get(), buf.data(), buf.size()), 396 SyscallSucceedsWithValue(kPageSize)); 397 398 // Splice to the second pipe, using two operations. 399 EXPECT_THAT( 400 splice(rfd1.get(), nullptr, wfd2.get(), nullptr, kPageSize / 2, 0), 401 SyscallSucceedsWithValue(kPageSize / 2)); 402 EXPECT_THAT( 403 splice(rfd1.get(), nullptr, wfd2.get(), nullptr, kPageSize / 2, 0), 404 SyscallSucceedsWithValue(kPageSize / 2)); 405 406 // Content should reflect the splice. 407 std::vector<char> rbuf(kPageSize); 408 ASSERT_THAT(read(rfd2.get(), rbuf.data(), rbuf.size()), 409 SyscallSucceedsWithValue(kPageSize)); 410 EXPECT_EQ(memcmp(rbuf.data(), buf.data(), kPageSize), 0); 411 } 412 413 TEST(SpliceTest, TwoPipesPartialRead) { 414 // Create two pipes. 415 int fds[2]; 416 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 417 const FileDescriptor first_rfd(fds[0]); 418 const FileDescriptor first_wfd(fds[1]); 419 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 420 const FileDescriptor second_rfd(fds[0]); 421 const FileDescriptor second_wfd(fds[1]); 422 423 // Write half a page of data to the first pipe. 424 std::vector<char> buf(kPageSize / 2); 425 RandomizeBuffer(buf.data(), buf.size()); 426 ASSERT_THAT(write(first_wfd.get(), buf.data(), buf.size()), 427 SyscallSucceedsWithValue(kPageSize / 2)); 428 429 // Attempt to splice one page from the first pipe to the second; it should 430 // immediately return after splicing the half-page previously written to the 431 // first pipe. 432 EXPECT_THAT( 433 splice(first_rfd.get(), nullptr, second_wfd.get(), nullptr, kPageSize, 0), 434 SyscallSucceedsWithValue(kPageSize / 2)); 435 } 436 437 TEST(SpliceTest, TwoPipesPartialWrite) { 438 // Create two pipes. 439 int fds[2]; 440 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 441 const FileDescriptor first_rfd(fds[0]); 442 const FileDescriptor first_wfd(fds[1]); 443 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 444 const FileDescriptor second_rfd(fds[0]); 445 const FileDescriptor second_wfd(fds[1]); 446 447 // Write two pages of data to the first pipe. 448 std::vector<char> buf(2 * kPageSize); 449 RandomizeBuffer(buf.data(), buf.size()); 450 ASSERT_THAT(write(first_wfd.get(), buf.data(), buf.size()), 451 SyscallSucceedsWithValue(2 * kPageSize)); 452 453 // Limit the second pipe to two pages, then write one page of data to it. 454 ASSERT_THAT(fcntl(second_wfd.get(), F_SETPIPE_SZ, 2 * kPageSize), 455 SyscallSucceeds()); 456 ASSERT_THAT(write(second_wfd.get(), buf.data(), buf.size() / 2), 457 SyscallSucceedsWithValue(kPageSize)); 458 459 // Attempt to splice two pages from the first pipe to the second; it should 460 // immediately return after splicing the first page previously written to the 461 // first pipe. 462 EXPECT_THAT(splice(first_rfd.get(), nullptr, second_wfd.get(), nullptr, 463 2 * kPageSize, 0), 464 SyscallSucceedsWithValue(kPageSize)); 465 } 466 467 TEST(TeeTest, TwoPipesPartialRead) { 468 // Create two pipes. 469 int fds[2]; 470 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 471 const FileDescriptor first_rfd(fds[0]); 472 const FileDescriptor first_wfd(fds[1]); 473 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 474 const FileDescriptor second_rfd(fds[0]); 475 const FileDescriptor second_wfd(fds[1]); 476 477 // Write half a page of data to the first pipe. 478 std::vector<char> buf(kPageSize / 2); 479 RandomizeBuffer(buf.data(), buf.size()); 480 ASSERT_THAT(write(first_wfd.get(), buf.data(), buf.size()), 481 SyscallSucceedsWithValue(kPageSize / 2)); 482 483 // Attempt to tee one page from the first pipe to the second; it should 484 // immediately return after copying the half-page previously written to the 485 // first pipe. 486 EXPECT_THAT(tee(first_rfd.get(), second_wfd.get(), kPageSize, 0), 487 SyscallSucceedsWithValue(kPageSize / 2)); 488 } 489 490 TEST(TeeTest, TwoPipesPartialWrite) { 491 // Create two pipes. 492 int fds[2]; 493 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 494 const FileDescriptor first_rfd(fds[0]); 495 const FileDescriptor first_wfd(fds[1]); 496 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 497 const FileDescriptor second_rfd(fds[0]); 498 const FileDescriptor second_wfd(fds[1]); 499 500 // Write two pages of data to the first pipe. 501 std::vector<char> buf(2 * kPageSize); 502 RandomizeBuffer(buf.data(), buf.size()); 503 ASSERT_THAT(write(first_wfd.get(), buf.data(), buf.size()), 504 SyscallSucceedsWithValue(2 * kPageSize)); 505 506 // Limit the second pipe to two pages, then write one page of data to it. 507 ASSERT_THAT(fcntl(second_wfd.get(), F_SETPIPE_SZ, 2 * kPageSize), 508 SyscallSucceeds()); 509 ASSERT_THAT(write(second_wfd.get(), buf.data(), buf.size() / 2), 510 SyscallSucceedsWithValue(kPageSize)); 511 512 // Attempt to tee two pages from the first pipe to the second; it should 513 // immediately return after copying the first page previously written to the 514 // first pipe. 515 EXPECT_THAT(tee(first_rfd.get(), second_wfd.get(), 2 * kPageSize, 0), 516 SyscallSucceedsWithValue(kPageSize)); 517 } 518 519 TEST(SpliceTest, TwoPipesCircular) { 520 // Create two pipes. 521 int fds[2]; 522 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 523 const FileDescriptor first_rfd(fds[0]); 524 const FileDescriptor first_wfd(fds[1]); 525 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 526 const FileDescriptor second_rfd(fds[0]); 527 const FileDescriptor second_wfd(fds[1]); 528 529 // On Linux, each pipe is normally limited to 530 // include/linux/pipe_fs_i.h:PIPE_DEF_BUFFERS buffers worth of data. 531 constexpr size_t PIPE_DEF_BUFFERS = 16; 532 533 // Write some data to each pipe. Below we splice 1 byte at a time between 534 // pipes, which very quickly causes each byte to be stored in a separate 535 // buffer, so we must ensure that the total amount of data in the system is <= 536 // PIPE_DEF_BUFFERS bytes. 537 std::vector<char> buf(PIPE_DEF_BUFFERS / 2); 538 RandomizeBuffer(buf.data(), buf.size()); 539 ASSERT_THAT(write(first_wfd.get(), buf.data(), buf.size()), 540 SyscallSucceedsWithValue(buf.size())); 541 ASSERT_THAT(write(second_wfd.get(), buf.data(), buf.size()), 542 SyscallSucceedsWithValue(buf.size())); 543 544 // Have another thread splice from the second pipe to the first, while we 545 // splice from the first to the second. The test passes if this does not 546 // deadlock. 547 const int kIterations = 1000; 548 DisableSave ds; 549 ScopedThread t([&]() { 550 for (int i = 0; i < kIterations; i++) { 551 ASSERT_THAT( 552 splice(second_rfd.get(), nullptr, first_wfd.get(), nullptr, 1, 0), 553 SyscallSucceedsWithValue(1)); 554 } 555 }); 556 for (int i = 0; i < kIterations; i++) { 557 ASSERT_THAT( 558 splice(first_rfd.get(), nullptr, second_wfd.get(), nullptr, 1, 0), 559 SyscallSucceedsWithValue(1)); 560 } 561 } 562 563 TEST(SpliceTest, Blocking) { 564 // Create two new pipes. 565 int first[2], second[2]; 566 ASSERT_THAT(pipe(first), SyscallSucceeds()); 567 const FileDescriptor rfd1(first[0]); 568 const FileDescriptor wfd1(first[1]); 569 ASSERT_THAT(pipe(second), SyscallSucceeds()); 570 const FileDescriptor rfd2(second[0]); 571 const FileDescriptor wfd2(second[1]); 572 573 // This thread writes to the main pipe. 574 std::vector<char> buf(kPageSize); 575 RandomizeBuffer(buf.data(), buf.size()); 576 ScopedThread t([&]() { 577 ASSERT_THAT(write(wfd1.get(), buf.data(), buf.size()), 578 SyscallSucceedsWithValue(kPageSize)); 579 }); 580 581 // Attempt a splice immediately; it should block. 582 EXPECT_THAT(splice(rfd1.get(), nullptr, wfd2.get(), nullptr, kPageSize, 0), 583 SyscallSucceedsWithValue(kPageSize)); 584 585 // Thread should be joinable. 586 t.Join(); 587 588 // Content should reflect the splice. 589 std::vector<char> rbuf(kPageSize); 590 ASSERT_THAT(read(rfd2.get(), rbuf.data(), rbuf.size()), 591 SyscallSucceedsWithValue(kPageSize)); 592 EXPECT_EQ(memcmp(rbuf.data(), buf.data(), kPageSize), 0); 593 } 594 595 TEST(TeeTest, Blocking) { 596 // Create two new pipes. 597 int first[2], second[2]; 598 ASSERT_THAT(pipe(first), SyscallSucceeds()); 599 const FileDescriptor rfd1(first[0]); 600 const FileDescriptor wfd1(first[1]); 601 ASSERT_THAT(pipe(second), SyscallSucceeds()); 602 const FileDescriptor rfd2(second[0]); 603 const FileDescriptor wfd2(second[1]); 604 605 // This thread writes to the main pipe. 606 std::vector<char> buf(kPageSize); 607 RandomizeBuffer(buf.data(), buf.size()); 608 ScopedThread t([&]() { 609 ASSERT_THAT(write(wfd1.get(), buf.data(), buf.size()), 610 SyscallSucceedsWithValue(kPageSize)); 611 }); 612 613 // Attempt a tee immediately; it should block. 614 EXPECT_THAT(tee(rfd1.get(), wfd2.get(), kPageSize, 0), 615 SyscallSucceedsWithValue(kPageSize)); 616 617 // Thread should be joinable. 618 t.Join(); 619 620 // Content should reflect the splice, in both pipes. 621 std::vector<char> rbuf(kPageSize); 622 ASSERT_THAT(read(rfd2.get(), rbuf.data(), rbuf.size()), 623 SyscallSucceedsWithValue(kPageSize)); 624 EXPECT_EQ(memcmp(rbuf.data(), buf.data(), kPageSize), 0); 625 ASSERT_THAT(read(rfd1.get(), rbuf.data(), rbuf.size()), 626 SyscallSucceedsWithValue(kPageSize)); 627 EXPECT_EQ(memcmp(rbuf.data(), buf.data(), kPageSize), 0); 628 } 629 630 TEST(TeeTest, BlockingWrite) { 631 // Create two new pipes. 632 int first[2], second[2]; 633 ASSERT_THAT(pipe(first), SyscallSucceeds()); 634 const FileDescriptor rfd1(first[0]); 635 const FileDescriptor wfd1(first[1]); 636 ASSERT_THAT(pipe(second), SyscallSucceeds()); 637 const FileDescriptor rfd2(second[0]); 638 const FileDescriptor wfd2(second[1]); 639 640 // Make some data available to be read. 641 std::vector<char> buf1(kPageSize); 642 RandomizeBuffer(buf1.data(), buf1.size()); 643 ASSERT_THAT(write(wfd1.get(), buf1.data(), buf1.size()), 644 SyscallSucceedsWithValue(kPageSize)); 645 646 // Fill up the write pipe's buffer. 647 int pipe_size = -1; 648 ASSERT_THAT(pipe_size = fcntl(wfd2.get(), F_GETPIPE_SZ), SyscallSucceeds()); 649 std::vector<char> buf2(pipe_size); 650 ASSERT_THAT(write(wfd2.get(), buf2.data(), buf2.size()), 651 SyscallSucceedsWithValue(pipe_size)); 652 653 ScopedThread t([&]() { 654 absl::SleepFor(absl::Milliseconds(100)); 655 ASSERT_THAT(read(rfd2.get(), buf2.data(), buf2.size()), 656 SyscallSucceedsWithValue(pipe_size)); 657 }); 658 659 // Attempt a tee immediately; it should block. 660 EXPECT_THAT(tee(rfd1.get(), wfd2.get(), kPageSize, 0), 661 SyscallSucceedsWithValue(kPageSize)); 662 663 // Thread should be joinable. 664 t.Join(); 665 666 // Content should reflect the tee. 667 std::vector<char> rbuf(kPageSize); 668 ASSERT_THAT(read(rfd2.get(), rbuf.data(), rbuf.size()), 669 SyscallSucceedsWithValue(kPageSize)); 670 EXPECT_EQ(memcmp(rbuf.data(), buf1.data(), kPageSize), 0); 671 } 672 673 TEST(SpliceTest, NonBlocking) { 674 // Create two new pipes. 675 int first[2], second[2]; 676 ASSERT_THAT(pipe(first), SyscallSucceeds()); 677 const FileDescriptor rfd1(first[0]); 678 const FileDescriptor wfd1(first[1]); 679 ASSERT_THAT(pipe(second), SyscallSucceeds()); 680 const FileDescriptor rfd2(second[0]); 681 const FileDescriptor wfd2(second[1]); 682 683 // Splice with no data to back it. 684 EXPECT_THAT(splice(rfd1.get(), nullptr, wfd2.get(), nullptr, kPageSize, 685 SPLICE_F_NONBLOCK), 686 SyscallFailsWithErrno(EAGAIN)); 687 } 688 689 TEST(TeeTest, NonBlocking) { 690 // Create two new pipes. 691 int first[2], second[2]; 692 ASSERT_THAT(pipe(first), SyscallSucceeds()); 693 const FileDescriptor rfd1(first[0]); 694 const FileDescriptor wfd1(first[1]); 695 ASSERT_THAT(pipe(second), SyscallSucceeds()); 696 const FileDescriptor rfd2(second[0]); 697 const FileDescriptor wfd2(second[1]); 698 699 // Splice with no data to back it. 700 EXPECT_THAT(tee(rfd1.get(), wfd2.get(), kPageSize, SPLICE_F_NONBLOCK), 701 SyscallFailsWithErrno(EAGAIN)); 702 } 703 704 TEST(TeeTest, MultiPage) { 705 // Create two new pipes. 706 int first[2], second[2]; 707 ASSERT_THAT(pipe(first), SyscallSucceeds()); 708 const FileDescriptor rfd1(first[0]); 709 const FileDescriptor wfd1(first[1]); 710 ASSERT_THAT(pipe(second), SyscallSucceeds()); 711 const FileDescriptor rfd2(second[0]); 712 const FileDescriptor wfd2(second[1]); 713 714 // Make some data available to be read. 715 std::vector<char> wbuf(8 * kPageSize); 716 RandomizeBuffer(wbuf.data(), wbuf.size()); 717 ASSERT_THAT(write(wfd1.get(), wbuf.data(), wbuf.size()), 718 SyscallSucceedsWithValue(wbuf.size())); 719 720 // Attempt a tee immediately; it should complete. 721 EXPECT_THAT(tee(rfd1.get(), wfd2.get(), wbuf.size(), 0), 722 SyscallSucceedsWithValue(wbuf.size())); 723 724 // Content should reflect the tee. 725 std::vector<char> rbuf(wbuf.size()); 726 ASSERT_THAT(read(rfd2.get(), rbuf.data(), rbuf.size()), 727 SyscallSucceedsWithValue(rbuf.size())); 728 EXPECT_EQ(memcmp(rbuf.data(), wbuf.data(), rbuf.size()), 0); 729 ASSERT_THAT(read(rfd1.get(), rbuf.data(), rbuf.size()), 730 SyscallSucceedsWithValue(rbuf.size())); 731 EXPECT_EQ(memcmp(rbuf.data(), wbuf.data(), rbuf.size()), 0); 732 } 733 734 TEST(SpliceTest, FromPipeMaxFileSize) { 735 // Create a new pipe. 736 int fds[2]; 737 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 738 const FileDescriptor rfd(fds[0]); 739 const FileDescriptor wfd(fds[1]); 740 741 // Fill with some random data. 742 std::vector<char> buf(kPageSize); 743 RandomizeBuffer(buf.data(), buf.size()); 744 ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()), 745 SyscallSucceedsWithValue(kPageSize)); 746 747 // Open the input file. 748 const TempPath out_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 749 const FileDescriptor out_fd = 750 ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_RDWR)); 751 752 EXPECT_THAT(ftruncate(out_fd.get(), 13 << 20), SyscallSucceeds()); 753 EXPECT_THAT(lseek(out_fd.get(), 0, SEEK_END), 754 SyscallSucceedsWithValue(13 << 20)); 755 756 // Set our file size limit. 757 sigset_t set; 758 sigemptyset(&set); 759 sigaddset(&set, SIGXFSZ); 760 TEST_PCHECK(sigprocmask(SIG_BLOCK, &set, nullptr) == 0); 761 rlimit rlim = {}; 762 rlim.rlim_cur = rlim.rlim_max = (13 << 20); 763 EXPECT_THAT(setrlimit(RLIMIT_FSIZE, &rlim), SyscallSucceeds()); 764 765 // Splice to the output file. 766 EXPECT_THAT( 767 splice(rfd.get(), nullptr, out_fd.get(), nullptr, 3 * kPageSize, 0), 768 SyscallFailsWithErrno(EFBIG)); 769 770 // Contents should be equal. 771 std::vector<char> rbuf(kPageSize); 772 ASSERT_THAT(read(rfd.get(), rbuf.data(), rbuf.size()), 773 SyscallSucceedsWithValue(kPageSize)); 774 EXPECT_EQ(memcmp(rbuf.data(), buf.data(), buf.size()), 0); 775 } 776 777 static volatile int signaled = 0; 778 void SigUsr1Handler(int sig, siginfo_t* info, void* context) { signaled = 1; } 779 780 TEST(SpliceTest, ToPipeWithSmallCapacityDoesNotSpin) { 781 // Writes to a pipe that are less than PIPE_BUF must be atomic. This test 782 // creates a pipe with only 128 bytes of capacity (< PIPE_BUF) and checks that 783 // splicing to the pipe does not spin. See b/170743336. 784 785 // Create a file with one page of data. 786 std::vector<char> buf(kPageSize); 787 RandomizeBuffer(buf.data(), buf.size()); 788 auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith( 789 GetAbsoluteTestTmpdir(), absl::string_view(buf.data(), buf.size()), 790 TempPath::kDefaultFileMode)); 791 auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDONLY)); 792 793 // Create a pipe with size 4096, and fill all but 128 bytes of it. 794 int p[2]; 795 ASSERT_THAT(pipe(p), SyscallSucceeds()); 796 ASSERT_THAT(fcntl(p[1], F_SETPIPE_SZ, kPageSize), SyscallSucceeds()); 797 const int kWriteSize = kPageSize - 128; 798 std::vector<char> writeBuf(kWriteSize); 799 RandomizeBuffer(writeBuf.data(), writeBuf.size()); 800 ASSERT_THAT(write(p[1], writeBuf.data(), writeBuf.size()), 801 SyscallSucceedsWithValue(kWriteSize)); 802 803 // Set up signal handler. 804 struct sigaction sa = {}; 805 sa.sa_sigaction = SigUsr1Handler; 806 sa.sa_flags = SA_SIGINFO; 807 const auto cleanup_sigact = 808 ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGUSR1, sa)); 809 810 // Send SIGUSR1 to this thread in 1 second. 811 struct sigevent sev = {}; 812 sev.sigev_notify = SIGEV_THREAD_ID; 813 sev.sigev_signo = SIGUSR1; 814 sev.sigev_notify_thread_id = gettid(); 815 auto timer = ASSERT_NO_ERRNO_AND_VALUE(TimerCreate(CLOCK_MONOTONIC, sev)); 816 struct itimerspec its = {}; 817 its.it_value = absl::ToTimespec(absl::Seconds(1)); 818 DisableSave ds; // Asserting an EINTR. 819 ASSERT_NO_ERRNO(timer.Set(0, its)); 820 821 // Now splice the file to the pipe. This should block, but not spin, and 822 // should return EINTR because it is interrupted by the signal. 823 EXPECT_THAT(splice(fd.get(), nullptr, p[1], nullptr, kPageSize, 0), 824 SyscallFailsWithErrno(EINTR)); 825 826 // Alarm should have been handled. 827 EXPECT_EQ(signaled, 1); 828 } 829 830 // Regression test for b/208679047. 831 TEST(SpliceTest, FromPipeWithConcurrentIo) { 832 // Create a file containing two copies of the same byte. Two bytes are 833 // necessary because both the read() and splice() loops below advance the file 834 // offset by one byte before lseek(); use of the file offset is required since 835 // the mutex protecting the file offset is implicated in the circular lock 836 // ordering that this test attempts to reproduce. 837 // 838 // This can't use memfd_create() because, in Linux, memfd_create(2) creates a 839 // struct file using alloc_file_pseudo() without going through 840 // do_dentry_open(), so FMODE_ATOMIC_POS is not set despite the created file 841 // having type S_IFREG ("regular file"). 842 const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 843 const FileDescriptor fd = 844 ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR)); 845 constexpr char kSplicedByte = 0x01; 846 for (int i = 0; i < 2; i++) { 847 ASSERT_THAT(WriteFd(fd.get(), &kSplicedByte, 1), 848 SyscallSucceedsWithValue(1)); 849 } 850 851 // Create a pipe. 852 int pipe_fds[2]; 853 ASSERT_THAT(pipe(pipe_fds), SyscallSucceeds()); 854 const FileDescriptor rfd(pipe_fds[0]); 855 FileDescriptor wfd(pipe_fds[1]); 856 857 DisableSave ds; 858 std::atomic<bool> done(false); 859 860 // Create a thread that reads from fd until the end of the test. 861 ScopedThread memfd_reader([&] { 862 char file_buf; 863 while (!done.load()) { 864 ASSERT_THAT(lseek(fd.get(), 0, SEEK_SET), SyscallSucceeds()); 865 int n = ReadFd(fd.get(), &file_buf, 1); 866 if (n == 0) { 867 // fd was at offset 2 (EOF). In Linux, this is possible even after 868 // lseek(0) because splice() doesn't attempt atomicity with respect to 869 // concurrent lseek(), so the effect of lseek() may be lost. 870 continue; 871 } 872 ASSERT_THAT(n, SyscallSucceedsWithValue(1)); 873 ASSERT_EQ(file_buf, kSplicedByte); 874 } 875 }); 876 877 // Create a thread that reads from the pipe until the end of the test. 878 ScopedThread pipe_reader([&] { 879 char pipe_buf; 880 while (!done.load()) { 881 int n = ReadFd(rfd.get(), &pipe_buf, 1); 882 if (n == 0) { 883 // This should only happen due to cleanup_threads (below) closing wfd. 884 EXPECT_TRUE(done.load()); 885 return; 886 } 887 ASSERT_THAT(n, SyscallSucceedsWithValue(1)); 888 ASSERT_EQ(pipe_buf, kSplicedByte); 889 } 890 }); 891 892 // Create a thread that repeatedly invokes madvise(MADV_DONTNEED) on the same 893 // page of memory. (Having a thread attempt to lock MM.activeMu for writing is 894 // necessary to create a deadlock from the circular lock ordering, since 895 // otherwise both uses of MM.activeMu are for reading and may proceed 896 // concurrently.) 897 ScopedThread mm_locker([&] { 898 const Mapping m = ASSERT_NO_ERRNO_AND_VALUE( 899 MmapAnon(kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE)); 900 while (!done.load()) { 901 madvise(m.ptr(), kPageSize, MADV_DONTNEED); 902 } 903 }); 904 905 // This must come after the ScopedThreads since its destructor must run before 906 // theirs. 907 const absl::Cleanup cleanup_threads = [&] { 908 done.store(true); 909 // Ensure that pipe_reader is unblocked after setting done, so that it will 910 // be able to observe done being true. 911 wfd.reset(); 912 }; 913 914 // Repeatedly splice from memfd to the pipe. The test passes if this does not 915 // deadlock. 916 const int kIterations = 5000; 917 for (int i = 0; i < kIterations; i++) { 918 ASSERT_THAT(lseek(fd.get(), 0, SEEK_SET), SyscallSucceeds()); 919 ASSERT_THAT(splice(fd.get(), nullptr, wfd.get(), nullptr, 1, 0), 920 SyscallSucceedsWithValue(1)); 921 } 922 } 923 924 // Regression test for #9736 and #10046. 925 TEST(SpliceTest, FromPipeWithWriterToDevNull) { 926 int fds[2]; 927 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 928 const FileDescriptor rfd(fds[0]); 929 const FileDescriptor wfd(fds[1]); 930 const FileDescriptor out_fd = 931 ASSERT_NO_ERRNO_AND_VALUE(Open("/dev/null", O_WRONLY)); 932 933 // Write one byte to the pipe and expect it to be successfully spliced to 934 // /dev/null. 935 constexpr char kSplicedByte = '.'; 936 ASSERT_THAT(WriteFd(wfd.get(), &kSplicedByte, 1), 937 SyscallSucceedsWithValue(1)); 938 ASSERT_THAT( 939 splice(rfd.get(), nullptr, out_fd.get(), nullptr, 1, SPLICE_F_NONBLOCK), 940 SyscallSucceedsWithValue(1)); 941 942 // Expect that splicing from the pipe again fails with EAGAIN since the pipe 943 // is now empty. 944 ASSERT_THAT( 945 splice(rfd.get(), nullptr, out_fd.get(), nullptr, 1, SPLICE_F_NONBLOCK), 946 SyscallFailsWithErrno(EAGAIN)); 947 } 948 949 } // namespace 950 951 } // namespace testing 952 } // namespace gvisor