summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux/flock.cc
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls/linux/flock.cc')
-rw-r--r--test/syscalls/linux/flock.cc159
1 files changed, 143 insertions, 16 deletions
diff --git a/test/syscalls/linux/flock.cc b/test/syscalls/linux/flock.cc
index 3ecb8db8e..b286e84fe 100644
--- a/test/syscalls/linux/flock.cc
+++ b/test/syscalls/linux/flock.cc
@@ -21,6 +21,7 @@
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "test/syscalls/linux/file_base.h"
+#include "test/syscalls/linux/socket_test_util.h"
#include "test/util/file_descriptor.h"
#include "test/util/temp_path.h"
#include "test/util/test_util.h"
@@ -34,11 +35,6 @@ namespace {
class FlockTest : public FileTest {};
-TEST_F(FlockTest, BadFD) {
- // EBADF: fd is not an open file descriptor.
- ASSERT_THAT(flock(-1, 0), SyscallFailsWithErrno(EBADF));
-}
-
TEST_F(FlockTest, InvalidOpCombinations) {
// The operation cannot be both exclusive and shared.
EXPECT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_SH | LOCK_NB),
@@ -57,15 +53,6 @@ TEST_F(FlockTest, NoOperationSpecified) {
SyscallFailsWithErrno(EINVAL));
}
-TEST(FlockTestNoFixture, FlockSupportsPipes) {
- int fds[2];
- ASSERT_THAT(pipe(fds), SyscallSucceeds());
-
- EXPECT_THAT(flock(fds[0], LOCK_EX | LOCK_NB), SyscallSucceeds());
- EXPECT_THAT(close(fds[0]), SyscallSucceeds());
- EXPECT_THAT(close(fds[1]), SyscallSucceeds());
-}
-
TEST_F(FlockTest, TestSimpleExLock) {
// Test that we can obtain an exclusive lock (no other holders)
// and that we can unlock it.
@@ -198,7 +185,7 @@ TEST_F(FlockTest, TestMultipleHolderSharedExclusive) {
ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
}
-TEST_F(FlockTest, TestSharedLockFailExclusiveHolder) {
+TEST_F(FlockTest, TestSharedLockFailExclusiveHolderNonblocking) {
// This test will verify that a shared lock is denied while
// someone holds an exclusive lock.
ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB),
@@ -216,7 +203,48 @@ TEST_F(FlockTest, TestSharedLockFailExclusiveHolder) {
ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
}
-TEST_F(FlockTest, TestExclusiveLockFailExclusiveHolder) {
+void trivial_handler(int signum) {}
+
+TEST_F(FlockTest, TestSharedLockFailExclusiveHolderBlocking_NoRandomSave) {
+ const DisableSave ds; // Timing-related.
+
+ // This test will verify that a shared lock is denied while
+ // someone holds an exclusive lock.
+ ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB),
+ SyscallSucceedsWithValue(0));
+
+ const FileDescriptor fd =
+ ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
+
+ // Make sure that a blocking flock() call will return EINTR when interrupted
+ // by a signal. Create a timer that will go off while blocking on flock(), and
+ // register the corresponding signal handler.
+ auto timer = ASSERT_NO_ERRNO_AND_VALUE(
+ TimerCreate(CLOCK_MONOTONIC, sigevent_t{
+ .sigev_signo = SIGALRM,
+ .sigev_notify = SIGEV_SIGNAL,
+ }));
+
+ struct sigaction act = {};
+ act.sa_handler = trivial_handler;
+ ASSERT_THAT(sigaction(SIGALRM, &act, NULL), SyscallSucceeds());
+
+ // Now that the signal handler is registered, set the timer. Set an interval
+ // so that it's ok if the timer goes off before we call flock.
+ ASSERT_NO_ERRNO(
+ timer.Set(0, itimerspec{
+ .it_interval = absl::ToTimespec(absl::Milliseconds(10)),
+ .it_value = absl::ToTimespec(absl::Milliseconds(10)),
+ }));
+
+ ASSERT_THAT(flock(fd.get(), LOCK_SH), SyscallFailsWithErrno(EINTR));
+ timer.reset();
+
+ // Unlock
+ ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
+}
+
+TEST_F(FlockTest, TestExclusiveLockFailExclusiveHolderNonblocking) {
// This test will verify that an exclusive lock is denied while
// someone already holds an exclsuive lock.
ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB),
@@ -234,6 +262,45 @@ TEST_F(FlockTest, TestExclusiveLockFailExclusiveHolder) {
ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
}
+TEST_F(FlockTest, TestExclusiveLockFailExclusiveHolderBlocking_NoRandomSave) {
+ const DisableSave ds; // Timing-related.
+
+ // This test will verify that an exclusive lock is denied while
+ // someone already holds an exclsuive lock.
+ ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB),
+ SyscallSucceedsWithValue(0));
+
+ const FileDescriptor fd =
+ ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR));
+
+ // Make sure that a blocking flock() call will return EINTR when interrupted
+ // by a signal. Create a timer that will go off while blocking on flock(), and
+ // register the corresponding signal handler.
+ auto timer = ASSERT_NO_ERRNO_AND_VALUE(
+ TimerCreate(CLOCK_MONOTONIC, sigevent_t{
+ .sigev_signo = SIGALRM,
+ .sigev_notify = SIGEV_SIGNAL,
+ }));
+
+ struct sigaction act = {};
+ act.sa_handler = trivial_handler;
+ ASSERT_THAT(sigaction(SIGALRM, &act, NULL), SyscallSucceeds());
+
+ // Now that the signal handler is registered, set the timer. Set an interval
+ // so that it's ok if the timer goes off before we call flock.
+ ASSERT_NO_ERRNO(
+ timer.Set(0, itimerspec{
+ .it_interval = absl::ToTimespec(absl::Milliseconds(10)),
+ .it_value = absl::ToTimespec(absl::Milliseconds(10)),
+ }));
+
+ ASSERT_THAT(flock(fd.get(), LOCK_EX), SyscallFailsWithErrno(EINTR));
+ timer.reset();
+
+ // Unlock
+ ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0));
+}
+
TEST_F(FlockTest, TestMultipleHolderSharedExclusiveUpgrade) {
// This test will verify that we cannot obtain an exclusive lock while
// a shared lock is held by another descriptor, then verify that an upgrade
@@ -583,6 +650,66 @@ TEST_F(FlockTest, BlockingLockFirstExclusiveSecondExclusive_NoRandomSave) {
EXPECT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceeds());
}
+TEST(FlockTestNoFixture, BadFD) {
+ // EBADF: fd is not an open file descriptor.
+ ASSERT_THAT(flock(-1, 0), SyscallFailsWithErrno(EBADF));
+}
+
+TEST(FlockTestNoFixture, FlockDir) {
+ auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
+ auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_RDONLY, 0000));
+ EXPECT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceeds());
+}
+
+TEST(FlockTestNoFixture, FlockSymlink) {
+ // TODO(gvisor.dev/issue/2782): Replace with IsRunningWithVFS1() when O_PATH
+ // is supported.
+ SKIP_IF(IsRunningOnGvisor());
+
+ auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
+ auto symlink = ASSERT_NO_ERRNO_AND_VALUE(
+ TempPath::CreateSymlinkTo(GetAbsoluteTestTmpdir(), file.path()));
+
+ auto fd =
+ ASSERT_NO_ERRNO_AND_VALUE(Open(symlink.path(), O_RDONLY | O_PATH, 0000));
+ EXPECT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallFailsWithErrno(EBADF));
+}
+
+TEST(FlockTestNoFixture, FlockProc) {
+ auto fd =
+ ASSERT_NO_ERRNO_AND_VALUE(Open("/proc/self/status", O_RDONLY, 0000));
+ EXPECT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceeds());
+}
+
+TEST(FlockTestNoFixture, FlockPipe) {
+ int fds[2];
+ ASSERT_THAT(pipe(fds), SyscallSucceeds());
+
+ EXPECT_THAT(flock(fds[0], LOCK_EX | LOCK_NB), SyscallSucceeds());
+ // Check that the pipe was locked above.
+ EXPECT_THAT(flock(fds[1], LOCK_EX | LOCK_NB), SyscallFailsWithErrno(EAGAIN));
+
+ EXPECT_THAT(flock(fds[0], LOCK_UN), SyscallSucceeds());
+ EXPECT_THAT(flock(fds[1], LOCK_EX | LOCK_NB), SyscallSucceeds());
+
+ EXPECT_THAT(close(fds[0]), SyscallSucceeds());
+ EXPECT_THAT(close(fds[1]), SyscallSucceeds());
+}
+
+TEST(FlockTestNoFixture, FlockSocket) {
+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ ASSERT_THAT(sock, SyscallSucceeds());
+
+ struct sockaddr_un addr =
+ ASSERT_NO_ERRNO_AND_VALUE(UniqueUnixAddr(true /* abstract */, AF_UNIX));
+ ASSERT_THAT(
+ bind(sock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)),
+ SyscallSucceeds());
+
+ EXPECT_THAT(flock(sock, LOCK_EX | LOCK_NB), SyscallSucceeds());
+ EXPECT_THAT(close(sock), SyscallSucceeds());
+}
+
} // namespace
} // namespace testing