summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux
diff options
context:
space:
mode:
authorDean Deng <deandeng@google.com>2020-08-27 16:52:21 -0700
committerAndrei Vagin <avagin@gmail.com>2020-09-09 17:53:10 -0700
commitbb089f9c9075a78e8bde7ff946bac77badc08894 (patch)
tree86026686e411a273239a8a5637853194c6e97022 /test/syscalls/linux
parent05166f14c93323d6279987ae3fe9a803ad188ade (diff)
Fix vfs2 pipe behavior when splicing to a non-pipe.
Fixes *.sh Java runtime tests, where splice()-ing from a pipe to /dev/zero would not actually empty the pipe. There was no guarantee that the data would actually be consumed on a splice operation unless the output file's implementation of Write/PWrite actually called VFSPipeFD.CopyIn. Now, whatever bytes are "written" are consumed regardless of whether CopyIn is called or not. Furthermore, the number of bytes in the IOSequence for reads is now capped at the amount of data actually available. Before, splicing to /dev/zero would always return the requested splice size without taking the actual available data into account. This change also refactors the case where an input file is spliced into an output pipe so that it follows a similar pattern, which is arguably cleaner anyway. Updates #3576. PiperOrigin-RevId: 328843954
Diffstat (limited to 'test/syscalls/linux')
-rw-r--r--test/syscalls/linux/sendfile.cc36
-rw-r--r--test/syscalls/linux/splice.cc64
2 files changed, 97 insertions, 3 deletions
diff --git a/test/syscalls/linux/sendfile.cc b/test/syscalls/linux/sendfile.cc
index 64123e904..e65387f59 100644
--- a/test/syscalls/linux/sendfile.cc
+++ b/test/syscalls/linux/sendfile.cc
@@ -198,7 +198,39 @@ TEST(SendFileTest, SendAndUpdateFileOffset) {
EXPECT_EQ(absl::string_view(kData, kHalfDataSize),
absl::string_view(actual, bytes_sent));
- // Verify that the input file offset has been updated
+ // Verify that the input file offset has been updated.
+ ASSERT_THAT(read(inf.get(), &actual, kDataSize - bytes_sent),
+ SyscallSucceedsWithValue(kHalfDataSize));
+ EXPECT_EQ(
+ absl::string_view(kData + kDataSize - bytes_sent, kDataSize - bytes_sent),
+ absl::string_view(actual, kHalfDataSize));
+}
+
+TEST(SendFileTest, SendToDevZeroAndUpdateFileOffset) {
+ // Create temp files.
+ // Test input string length must be > 2 AND even.
+ constexpr char kData[] = "The slings and arrows of outrageous fortune,";
+ constexpr int kDataSize = sizeof(kData) - 1;
+ constexpr int kHalfDataSize = kDataSize / 2;
+ const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
+ GetAbsoluteTestTmpdir(), kData, TempPath::kDefaultFileMode));
+
+ // Open the input file as read only.
+ const FileDescriptor inf =
+ ASSERT_NO_ERRNO_AND_VALUE(Open(in_file.path(), O_RDONLY));
+
+ // Open /dev/zero as write only.
+ const FileDescriptor outf =
+ ASSERT_NO_ERRNO_AND_VALUE(Open("/dev/zero", O_WRONLY));
+
+ // Send data and verify that sendfile returns the correct value.
+ int bytes_sent;
+ EXPECT_THAT(
+ bytes_sent = sendfile(outf.get(), inf.get(), nullptr, kHalfDataSize),
+ SyscallSucceedsWithValue(kHalfDataSize));
+
+ char actual[kHalfDataSize];
+ // Verify that the input file offset has been updated.
ASSERT_THAT(read(inf.get(), &actual, kDataSize - bytes_sent),
SyscallSucceedsWithValue(kHalfDataSize));
EXPECT_EQ(
@@ -250,7 +282,7 @@ TEST(SendFileTest, SendAndUpdateFileOffsetFromNonzeroStartingPoint) {
EXPECT_EQ(absl::string_view(kData + kQuarterDataSize, kHalfDataSize),
absl::string_view(actual, bytes_sent));
- // Verify that the input file offset has been updated
+ // Verify that the input file offset has been updated.
ASSERT_THAT(read(inf.get(), &actual, kQuarterDataSize),
SyscallSucceedsWithValue(kQuarterDataSize));
diff --git a/test/syscalls/linux/splice.cc b/test/syscalls/linux/splice.cc
index 08fc4b1b7..be3fb4840 100644
--- a/test/syscalls/linux/splice.cc
+++ b/test/syscalls/linux/splice.cc
@@ -342,7 +342,7 @@ TEST(SpliceTest, FromPipe) {
ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()),
SyscallSucceedsWithValue(kPageSize));
- // Open the input file.
+ // Open the output file.
const TempPath out_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
const FileDescriptor out_fd =
ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_RDWR));
@@ -364,6 +364,40 @@ TEST(SpliceTest, FromPipe) {
EXPECT_EQ(memcmp(rbuf.data(), buf.data(), buf.size()), 0);
}
+TEST(SpliceTest, FromPipeMultiple) {
+ // Create a new pipe.
+ int fds[2];
+ ASSERT_THAT(pipe(fds), SyscallSucceeds());
+ const FileDescriptor rfd(fds[0]);
+ const FileDescriptor wfd(fds[1]);
+
+ std::string buf = "abcABC123";
+ ASSERT_THAT(write(wfd.get(), buf.c_str(), buf.size()),
+ SyscallSucceedsWithValue(buf.size()));
+
+ // Open the output file.
+ const TempPath out_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
+ const FileDescriptor out_fd =
+ ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_RDWR));
+
+ // Splice from the pipe to the output file over several calls.
+ EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), nullptr, 3, 0),
+ SyscallSucceedsWithValue(3));
+ EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), nullptr, 3, 0),
+ SyscallSucceedsWithValue(3));
+ EXPECT_THAT(splice(rfd.get(), nullptr, out_fd.get(), nullptr, 3, 0),
+ SyscallSucceedsWithValue(3));
+
+ // Reset cursor to zero so that we can check the contents.
+ ASSERT_THAT(lseek(out_fd.get(), 0, SEEK_SET), SyscallSucceedsWithValue(0));
+
+ // Contents should be equal.
+ std::vector<char> rbuf(buf.size());
+ ASSERT_THAT(read(out_fd.get(), rbuf.data(), rbuf.size()),
+ SyscallSucceedsWithValue(rbuf.size()));
+ EXPECT_EQ(memcmp(rbuf.data(), buf.c_str(), buf.size()), 0);
+}
+
TEST(SpliceTest, FromPipeOffset) {
// Create a new pipe.
int fds[2];
@@ -693,6 +727,34 @@ TEST(SpliceTest, FromPipeMaxFileSize) {
EXPECT_EQ(memcmp(rbuf.data(), buf.data(), buf.size()), 0);
}
+TEST(SpliceTest, FromPipeToDevZero) {
+ // Create a new pipe.
+ int fds[2];
+ ASSERT_THAT(pipe(fds), SyscallSucceeds());
+ const FileDescriptor rfd(fds[0]);
+ FileDescriptor wfd(fds[1]);
+
+ // Fill with some random data.
+ std::vector<char> buf(kPageSize);
+ RandomizeBuffer(buf.data(), buf.size());
+ ASSERT_THAT(write(wfd.get(), buf.data(), buf.size()),
+ SyscallSucceedsWithValue(kPageSize));
+
+ const FileDescriptor zero =
+ ASSERT_NO_ERRNO_AND_VALUE(Open("/dev/zero", O_WRONLY));
+
+ // Close the write end to prevent blocking below.
+ wfd.reset();
+
+ // Splice to /dev/zero. The first call should empty the pipe, and the return
+ // value should not exceed the number of bytes available for reading.
+ EXPECT_THAT(
+ splice(rfd.get(), nullptr, zero.get(), nullptr, kPageSize + 123, 0),
+ SyscallSucceedsWithValue(kPageSize));
+ EXPECT_THAT(splice(rfd.get(), nullptr, zero.get(), nullptr, 1, 0),
+ SyscallSucceedsWithValue(0));
+}
+
} // namespace
} // namespace testing