diff options
author | Andrei Vagin <avagin@google.com> | 2019-06-24 17:44:00 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2019-06-24 17:45:02 -0700 |
commit | e9ea7230f7dc70d3e1bb5ae32b6927209cafb465 (patch) | |
tree | 2f8b5aacade58f48ad3f4748c5fe6875f2761f0b /test/syscalls/linux/open.cc | |
parent | 7f5d0afe525af4728ed5ec75193e9e4560d9558c (diff) |
fs: synchronize concurrent writes into files with O_APPEND
For files with O_APPEND, a file write operation gets a file size and uses it as
offset to call an inode write operation. This means that all other operations
which can change a file size should be blocked while the write operation doesn't
complete.
PiperOrigin-RevId: 254873771
Diffstat (limited to 'test/syscalls/linux/open.cc')
-rw-r--r-- | test/syscalls/linux/open.cc | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/test/syscalls/linux/open.cc b/test/syscalls/linux/open.cc index 42646bb02..e0525f386 100644 --- a/test/syscalls/linux/open.cc +++ b/test/syscalls/linux/open.cc @@ -28,6 +28,7 @@ #include "test/util/fs_util.h" #include "test/util/temp_path.h" #include "test/util/test_util.h" +#include "test/util/thread_util.h" namespace gvisor { namespace testing { @@ -214,6 +215,42 @@ TEST_F(OpenTest, AppendOnly) { SyscallSucceedsWithValue(kBufSize * 3)); } +TEST_F(OpenTest, AppendConcurrentWrite) { + constexpr int kThreadCount = 5; + constexpr int kBytesPerThread = 10000; + std::unique_ptr<ScopedThread> threads[kThreadCount]; + + // In case of the uncached policy, we expect that a file system can be changed + // externally, so we create a new inode each time when we open a file and we + // can't guarantee that writes to files with O_APPEND will work correctly. + SKIP_IF(getenv("GVISOR_GOFER_UNCACHED")); + + EXPECT_THAT(truncate(test_file_name_.c_str(), 0), SyscallSucceeds()); + + std::string filename = test_file_name_; + DisableSave ds; // Too many syscalls. + // Start kThreadCount threads which will write concurrently into the same + // file. + for (int i = 0; i < kThreadCount; i++) { + threads[i] = absl::make_unique<ScopedThread>([filename]() { + const FileDescriptor fd = + ASSERT_NO_ERRNO_AND_VALUE(Open(filename, O_RDWR | O_APPEND)); + + for (int j = 0; j < kBytesPerThread; j++) { + EXPECT_THAT(WriteFd(fd.get(), &j, 1), SyscallSucceedsWithValue(1)); + } + }); + } + for (int i = 0; i < kThreadCount; i++) { + threads[i]->Join(); + } + + // Check that the size of the file is correct. + struct stat st; + EXPECT_THAT(stat(test_file_name_.c_str(), &st), SyscallSucceeds()); + EXPECT_EQ(st.st_size, kThreadCount * kBytesPerThread); +} + TEST_F(OpenTest, Truncate) { { // First write some data to the new file and close it. |