gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/flock.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 <errno.h> 16 #include <sys/file.h> 17 18 #include <string> 19 20 #include "gtest/gtest.h" 21 #include "absl/time/clock.h" 22 #include "absl/time/time.h" 23 #include "test/syscalls/linux/file_base.h" 24 #include "test/util/file_descriptor.h" 25 #include "test/util/socket_util.h" 26 #include "test/util/temp_path.h" 27 #include "test/util/test_util.h" 28 #include "test/util/thread_util.h" 29 #include "test/util/timer_util.h" 30 31 namespace gvisor { 32 namespace testing { 33 34 namespace { 35 36 class FlockTest : public FileTest {}; 37 38 TEST_F(FlockTest, InvalidOpCombinations) { 39 // The operation cannot be both exclusive and shared. 40 EXPECT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_SH | LOCK_NB), 41 SyscallFailsWithErrno(EINVAL)); 42 43 // Locking and Unlocking doesn't make sense. 44 EXPECT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_UN | LOCK_NB), 45 SyscallFailsWithErrno(EINVAL)); 46 EXPECT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_UN | LOCK_NB), 47 SyscallFailsWithErrno(EINVAL)); 48 } 49 50 TEST_F(FlockTest, NoOperationSpecified) { 51 // Not specifying an operation is invalid. 52 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB), 53 SyscallFailsWithErrno(EINVAL)); 54 } 55 56 TEST_F(FlockTest, TestSimpleExLock) { 57 // Test that we can obtain an exclusive lock (no other holders) 58 // and that we can unlock it. 59 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB), 60 SyscallSucceedsWithValue(0)); 61 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 62 } 63 64 TEST_F(FlockTest, TestSimpleShLock) { 65 // Test that we can obtain a shared lock (no other holders) 66 // and that we can unlock it. 67 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_NB), 68 SyscallSucceedsWithValue(0)); 69 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 70 } 71 72 TEST_F(FlockTest, TestLockableAnyMode) { 73 // flock(2): A shared or exclusive lock can be placed on a file 74 // regardless of the mode in which the file was opened. 75 const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE( 76 Open(test_file_name_, O_RDONLY)); // open read only to test 77 78 // Mode shouldn't prevent us from taking an exclusive lock. 79 ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceedsWithValue(0)); 80 81 // Unlock 82 ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 83 } 84 85 TEST_F(FlockTest, TestUnlockWithNoHolders) { 86 // Test that unlocking when no one holds a lock succeeeds. 87 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 88 } 89 90 TEST_F(FlockTest, TestRepeatedExLockingBySameHolder) { 91 // Test that repeated locking by the same holder for the 92 // same type of lock works correctly. 93 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_EX), 94 SyscallSucceedsWithValue(0)); 95 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_EX), 96 SyscallSucceedsWithValue(0)); 97 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 98 } 99 100 TEST_F(FlockTest, TestRepeatedExLockingSingleUnlock) { 101 // Test that repeated locking by the same holder for the 102 // same type of lock works correctly and that a single unlock is required. 103 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_EX), 104 SyscallSucceedsWithValue(0)); 105 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_EX), 106 SyscallSucceedsWithValue(0)); 107 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 108 109 const FileDescriptor fd = 110 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDONLY)); 111 112 // Should be unlocked at this point 113 ASSERT_THAT(flock(fd.get(), LOCK_NB | LOCK_EX), SyscallSucceedsWithValue(0)); 114 115 ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 116 } 117 118 TEST_F(FlockTest, TestRepeatedShLockingBySameHolder) { 119 // Test that repeated locking by the same holder for the 120 // same type of lock works correctly. 121 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_SH), 122 SyscallSucceedsWithValue(0)); 123 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_SH), 124 SyscallSucceedsWithValue(0)); 125 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 126 } 127 128 TEST_F(FlockTest, TestSingleHolderUpgrade) { 129 // Test that a shared lock is upgradable when no one else holds a lock. 130 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_SH), 131 SyscallSucceedsWithValue(0)); 132 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_NB | LOCK_EX), 133 SyscallSucceedsWithValue(0)); 134 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 135 } 136 137 TEST_F(FlockTest, TestSingleHolderDowngrade) { 138 // Test single holder lock downgrade case. 139 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB), 140 SyscallSucceedsWithValue(0)); 141 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_NB), 142 SyscallSucceedsWithValue(0)); 143 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 144 } 145 146 TEST_F(FlockTest, TestMultipleShared) { 147 // This is a simple test to verify that multiple independent shared 148 // locks will be granted. 149 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_NB), 150 SyscallSucceedsWithValue(0)); 151 152 const FileDescriptor fd = 153 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 154 155 // A shared lock should be granted as there only exists other shared locks. 156 ASSERT_THAT(flock(fd.get(), LOCK_SH | LOCK_NB), SyscallSucceedsWithValue(0)); 157 158 // Unlock both. 159 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 160 ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 161 } 162 163 /* 164 * flock(2): If a process uses open(2) (or similar) to obtain more than one 165 * descriptor for the same file, these descriptors are treated 166 * independently by flock(). An attempt to lock the file using one of 167 * these file descriptors may be denied by a lock that the calling process 168 * has already placed via another descriptor. 169 */ 170 TEST_F(FlockTest, TestMultipleHolderSharedExclusive) { 171 // This test will verify that an exclusive lock will not be granted 172 // while a shared is held. 173 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_NB), 174 SyscallSucceedsWithValue(0)); 175 176 const FileDescriptor fd = 177 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 178 179 // Verify We're unable to get an exlcusive lock via the second FD. 180 // because someone is holding a shared lock. 181 ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), 182 SyscallFailsWithErrno(EWOULDBLOCK)); 183 184 // Unlock 185 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 186 } 187 188 TEST_F(FlockTest, TestSharedLockFailExclusiveHolderNonblocking) { 189 // This test will verify that a shared lock is denied while 190 // someone holds an exclusive lock. 191 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB), 192 SyscallSucceedsWithValue(0)); 193 194 const FileDescriptor fd = 195 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 196 197 // Verify we're unable to get an shared lock via the second FD. 198 // because someone is holding an exclusive lock. 199 ASSERT_THAT(flock(fd.get(), LOCK_SH | LOCK_NB), 200 SyscallFailsWithErrno(EWOULDBLOCK)); 201 202 // Unlock 203 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 204 } 205 206 void trivial_handler(int signum) {} 207 208 TEST_F(FlockTest, TestSharedLockFailExclusiveHolderBlocking) { 209 const DisableSave ds; // Timing-related. 210 211 // This test will verify that a shared lock is denied while 212 // someone holds an exclusive lock. 213 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB), 214 SyscallSucceedsWithValue(0)); 215 216 const FileDescriptor fd = 217 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 218 219 // Make sure that a blocking flock() call will return EINTR when interrupted 220 // by a signal. Create a timer that will go off while blocking on flock(), and 221 // register the corresponding signal handler. 222 auto timer = ASSERT_NO_ERRNO_AND_VALUE( 223 TimerCreate(CLOCK_MONOTONIC, sigevent_t{ 224 .sigev_signo = SIGALRM, 225 .sigev_notify = SIGEV_SIGNAL, 226 })); 227 228 struct sigaction act = {}; 229 act.sa_handler = trivial_handler; 230 ASSERT_THAT(sigaction(SIGALRM, &act, NULL), SyscallSucceeds()); 231 232 // Now that the signal handler is registered, set the timer. Set an interval 233 // so that it's ok if the timer goes off before we call flock. 234 ASSERT_NO_ERRNO( 235 timer.Set(0, itimerspec{ 236 .it_interval = absl::ToTimespec(absl::Milliseconds(10)), 237 .it_value = absl::ToTimespec(absl::Milliseconds(10)), 238 })); 239 240 ASSERT_THAT(flock(fd.get(), LOCK_SH), SyscallFailsWithErrno(EINTR)); 241 timer.reset(); 242 243 // Unlock 244 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 245 } 246 247 TEST_F(FlockTest, TestExclusiveLockFailExclusiveHolderNonblocking) { 248 // This test will verify that an exclusive lock is denied while 249 // someone already holds an exclsuive lock. 250 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB), 251 SyscallSucceedsWithValue(0)); 252 253 const FileDescriptor fd = 254 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 255 256 // Verify we're unable to get an exclusive lock via the second FD 257 // because someone is already holding an exclusive lock. 258 ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), 259 SyscallFailsWithErrno(EWOULDBLOCK)); 260 261 // Unlock 262 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 263 } 264 265 TEST_F(FlockTest, TestExclusiveLockFailExclusiveHolderBlocking) { 266 const DisableSave ds; // Timing-related. 267 268 // This test will verify that an exclusive lock is denied while 269 // someone already holds an exclsuive lock. 270 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB), 271 SyscallSucceedsWithValue(0)); 272 273 const FileDescriptor fd = 274 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 275 276 // Make sure that a blocking flock() call will return EINTR when interrupted 277 // by a signal. Create a timer that will go off while blocking on flock(), and 278 // register the corresponding signal handler. 279 auto timer = ASSERT_NO_ERRNO_AND_VALUE( 280 TimerCreate(CLOCK_MONOTONIC, sigevent_t{ 281 .sigev_signo = SIGALRM, 282 .sigev_notify = SIGEV_SIGNAL, 283 })); 284 285 struct sigaction act = {}; 286 act.sa_handler = trivial_handler; 287 ASSERT_THAT(sigaction(SIGALRM, &act, NULL), SyscallSucceeds()); 288 289 // Now that the signal handler is registered, set the timer. Set an interval 290 // so that it's ok if the timer goes off before we call flock. 291 ASSERT_NO_ERRNO( 292 timer.Set(0, itimerspec{ 293 .it_interval = absl::ToTimespec(absl::Milliseconds(10)), 294 .it_value = absl::ToTimespec(absl::Milliseconds(10)), 295 })); 296 297 ASSERT_THAT(flock(fd.get(), LOCK_EX), SyscallFailsWithErrno(EINTR)); 298 timer.reset(); 299 300 // Unlock 301 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 302 } 303 304 TEST_F(FlockTest, TestMultipleHolderSharedExclusiveUpgrade) { 305 // This test will verify that we cannot obtain an exclusive lock while 306 // a shared lock is held by another descriptor, then verify that an upgrade 307 // is possible on a shared lock once all other shared locks have closed. 308 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_NB), 309 SyscallSucceedsWithValue(0)); 310 311 const FileDescriptor fd = 312 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 313 314 // Verify we're unable to get an exclusive lock via the second FD because 315 // a shared lock is held. 316 ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), 317 SyscallFailsWithErrno(EWOULDBLOCK)); 318 319 // Verify that we can get a shared lock via the second descriptor instead 320 ASSERT_THAT(flock(fd.get(), LOCK_SH | LOCK_NB), SyscallSucceedsWithValue(0)); 321 322 // Unlock the first and there will only be one shared lock remaining. 323 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 324 325 // Upgrade 2nd fd. 326 ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceedsWithValue(0)); 327 328 // Finally unlock the second 329 ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 330 } 331 332 TEST_F(FlockTest, TestMultipleHolderSharedExclusiveDowngrade) { 333 // This test will verify that a shared lock is not obtainable while an 334 // exclusive lock is held but that once the first is downgraded that 335 // the second independent file descriptor can also get a shared lock. 336 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB), 337 SyscallSucceedsWithValue(0)); 338 339 const FileDescriptor fd = 340 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 341 342 // Verify We're unable to get a shared lock via the second FD because 343 // an exclusive lock is held. 344 ASSERT_THAT(flock(fd.get(), LOCK_SH | LOCK_NB), 345 SyscallFailsWithErrno(EWOULDBLOCK)); 346 347 // Verify that we can downgrade the first. 348 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_NB), 349 SyscallSucceedsWithValue(0)); 350 351 // Now verify that we can obtain a shared lock since the first was downgraded. 352 ASSERT_THAT(flock(fd.get(), LOCK_SH | LOCK_NB), SyscallSucceedsWithValue(0)); 353 354 // Finally unlock both. 355 ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 356 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 357 } 358 359 /* 360 * flock(2): Locks created by flock() are associated with an open file table 361 * entry. This means that duplicate file descriptors (created by, for example, 362 * fork(2) or dup(2)) refer to the same lock, and this lock may be modified or 363 * released using any of these descriptors. Furthermore, the lock is released 364 * either by an explicit LOCK_UN operation on any of these duplicate descriptors 365 * or when all such descriptors have been closed. 366 */ 367 TEST_F(FlockTest, TestDupFdUpgrade) { 368 // This test will verify that a shared lock is upgradeable via a dupped 369 // file descriptor, if the FD wasn't dupped this would fail. 370 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH | LOCK_NB), 371 SyscallSucceedsWithValue(0)); 372 373 const FileDescriptor dup_fd = ASSERT_NO_ERRNO_AND_VALUE(test_file_fd_.Dup()); 374 375 // Now we should be able to upgrade via the dupped fd. 376 ASSERT_THAT(flock(dup_fd.get(), LOCK_EX | LOCK_NB), 377 SyscallSucceedsWithValue(0)); 378 379 // Validate unlock via dupped fd. 380 ASSERT_THAT(flock(dup_fd.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 381 } 382 383 TEST_F(FlockTest, TestDupFdDowngrade) { 384 // This test will verify that a exclusive lock is downgradable via a dupped 385 // file descriptor, if the FD wasn't dupped this would fail. 386 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB), 387 SyscallSucceedsWithValue(0)); 388 389 const FileDescriptor dup_fd = ASSERT_NO_ERRNO_AND_VALUE(test_file_fd_.Dup()); 390 391 // Now we should be able to downgrade via the dupped fd. 392 ASSERT_THAT(flock(dup_fd.get(), LOCK_SH | LOCK_NB), 393 SyscallSucceedsWithValue(0)); 394 395 // Validate unlock via dupped fd 396 ASSERT_THAT(flock(dup_fd.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 397 } 398 399 TEST_F(FlockTest, TestDupFdCloseRelease) { 400 // flock(2): Furthermore, the lock is released either by an explicit LOCK_UN 401 // operation on any of these duplicate descriptors, or when all such 402 // descriptors have been closed. 403 // 404 // This test will verify that a dupped fd closing will not release the 405 // underlying lock until all such dupped fds have closed. 406 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB), 407 SyscallSucceedsWithValue(0)); 408 409 FileDescriptor dup_fd = ASSERT_NO_ERRNO_AND_VALUE(test_file_fd_.Dup()); 410 411 // At this point we have ONE exclusive locked referenced by two different fds. 412 const FileDescriptor fd = 413 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 414 415 // Validate that we cannot get a lock on a new unrelated FD. 416 ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), 417 SyscallFailsWithErrno(EWOULDBLOCK)); 418 419 // Closing the dupped fd shouldn't affect the lock until all are closed. 420 dup_fd.reset(); // Closed the duped fd. 421 422 // Validate that we still cannot get a lock on a new unrelated FD. 423 ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), 424 SyscallFailsWithErrno(EWOULDBLOCK)); 425 426 // Closing the first fd 427 CloseFile(); // Will validate the syscall succeeds. 428 429 // Now we should actually be able to get a lock since all fds related to 430 // the first lock are closed. 431 ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceedsWithValue(0)); 432 433 // Unlock. 434 ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 435 } 436 437 TEST_F(FlockTest, TestDupFdUnlockRelease) { 438 /* flock(2): Furthermore, the lock is released either by an explicit LOCK_UN 439 * operation on any of these duplicate descriptors, or when all such 440 * descriptors have been closed. 441 */ 442 // This test will verify that an explict unlock on a dupped FD will release 443 // the underlying lock unlike the previous case where close on a dup was 444 // not enough to release the lock. 445 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX | LOCK_NB), 446 SyscallSucceedsWithValue(0)); 447 448 const FileDescriptor dup_fd = ASSERT_NO_ERRNO_AND_VALUE(test_file_fd_.Dup()); 449 450 // At this point we have ONE exclusive locked referenced by two different fds. 451 const FileDescriptor fd = 452 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 453 454 // Validate that we cannot get a lock on a new unrelated FD. 455 ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), 456 SyscallFailsWithErrno(EWOULDBLOCK)); 457 458 // Explicitly unlock via the dupped descriptor. 459 ASSERT_THAT(flock(dup_fd.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 460 461 // Validate that we can now get the lock since we explicitly unlocked. 462 ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceedsWithValue(0)); 463 464 // Unlock 465 ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 466 } 467 468 TEST_F(FlockTest, TestDupFdFollowedByLock) { 469 // This test will verify that taking a lock on a file descriptor that has 470 // already been dupped means that the lock is shared between both. This is 471 // slightly different than than duping on an already locked FD. 472 FileDescriptor dup_fd = ASSERT_NO_ERRNO_AND_VALUE(test_file_fd_.Dup()); 473 474 // Take a lock. 475 ASSERT_THAT(flock(dup_fd.get(), LOCK_EX | LOCK_NB), SyscallSucceeds()); 476 477 // Now dup_fd and test_file_ should both reference the same lock. 478 // We shouldn't be able to obtain a lock until both are closed. 479 const FileDescriptor fd = 480 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 481 482 // Closing the first fd 483 dup_fd.reset(); // Close the duped fd. 484 485 // Validate that we cannot get a lock yet because the dupped descriptor. 486 ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), 487 SyscallFailsWithErrno(EWOULDBLOCK)); 488 489 // Closing the second fd. 490 CloseFile(); // CloseFile() will validate the syscall succeeds. 491 492 // Now we should be able to get the lock. 493 ASSERT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceeds()); 494 495 // Unlock. 496 ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceedsWithValue(0)); 497 } 498 499 // NOTE: These blocking tests are not perfect. Unfortunately it's very hard to 500 // determine if a thread was actually blocked in the kernel so we're forced 501 // to use timing. 502 TEST_F(FlockTest, BlockingLockNoBlockingForSharedLocks) { 503 // This test will verify that although LOCK_NB isn't specified 504 // two different fds can obtain shared locks without blocking. 505 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH), SyscallSucceeds()); 506 507 // kHoldLockTime is the amount of time we will hold the lock before releasing. 508 constexpr absl::Duration kHoldLockTime = absl::Seconds(30); 509 510 const DisableSave ds; // Timing-related. 511 512 // We do this in another thread so we can determine if it was actually 513 // blocked by timing the amount of time it took for the syscall to complete. 514 ScopedThread t([&] { 515 MonotonicTimer timer; 516 const FileDescriptor fd = 517 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 518 519 // Only a single shared lock is held, the lock will be granted immediately. 520 // This should be granted without any blocking. Don't save here to avoid 521 // wild discrepencies on timing. 522 timer.Start(); 523 ASSERT_THAT(flock(fd.get(), LOCK_SH), SyscallSucceeds()); 524 525 // We held the lock for 30 seconds but this thread should not have 526 // blocked at all so we expect a very small duration on syscall completion. 527 ASSERT_LT(timer.Duration(), 528 absl::Seconds(1)); // 1000ms is much less than 30s. 529 530 // We can release our second shared lock 531 ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceeds()); 532 }); 533 534 // Sleep before unlocking. 535 absl::SleepFor(kHoldLockTime); 536 537 // Release the first shared lock. Don't save in this situation to avoid 538 // discrepencies in timing. 539 EXPECT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceeds()); 540 } 541 542 TEST_F(FlockTest, BlockingLockFirstSharedSecondExclusive) { 543 // This test will verify that if someone holds a shared lock any attempt to 544 // obtain an exclusive lock will result in blocking. 545 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_SH), SyscallSucceeds()); 546 547 // kHoldLockTime is the amount of time we will hold the lock before releasing. 548 constexpr absl::Duration kHoldLockTime = absl::Seconds(2); 549 550 const DisableSave ds; // Timing-related. 551 552 // We do this in another thread so we can determine if it was actually 553 // blocked by timing the amount of time it took for the syscall to complete. 554 ScopedThread t([&] { 555 MonotonicTimer timer; 556 const FileDescriptor fd = 557 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 558 559 // This exclusive lock should block because someone is already holding a 560 // shared lock. We don't save here to avoid wild discrepencies on timing. 561 timer.Start(); 562 ASSERT_THAT(RetryEINTR(flock)(fd.get(), LOCK_EX), SyscallSucceeds()); 563 564 // We should be blocked, we will expect to be blocked for more than 1.0s. 565 ASSERT_GT(timer.Duration(), absl::Seconds(1)); 566 567 // We can release our exclusive lock. 568 ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceeds()); 569 }); 570 571 // Sleep before unlocking. 572 absl::SleepFor(kHoldLockTime); 573 574 // Release the shared lock allowing the thread to proceed. 575 // We don't save here to avoid wild discrepencies in timing. 576 EXPECT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceeds()); 577 } 578 579 TEST_F(FlockTest, BlockingLockFirstExclusiveSecondShared) { 580 // This test will verify that if someone holds an exclusive lock any attempt 581 // to obtain a shared lock will result in blocking. 582 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX), SyscallSucceeds()); 583 584 // kHoldLockTime is the amount of time we will hold the lock before releasing. 585 constexpr absl::Duration kHoldLockTime = absl::Seconds(2); 586 587 const DisableSave ds; // Timing-related. 588 589 // We do this in another thread so we can determine if it was actually 590 // blocked by timing the amount of time it took for the syscall to complete. 591 ScopedThread t([&] { 592 MonotonicTimer timer; 593 const FileDescriptor fd = 594 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 595 596 // This shared lock should block because someone is already holding an 597 // exclusive lock. We don't save here to avoid wild discrepencies on timing. 598 timer.Start(); 599 ASSERT_THAT(RetryEINTR(flock)(fd.get(), LOCK_SH), SyscallSucceeds()); 600 601 // We should be blocked, we will expect to be blocked for more than 1.0s. 602 ASSERT_GT(timer.Duration(), absl::Seconds(1)); 603 604 // We can release our shared lock. 605 ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceeds()); 606 }); 607 608 // Sleep before unlocking. 609 absl::SleepFor(kHoldLockTime); 610 611 // Release the exclusive lock allowing the blocked thread to proceed. 612 // We don't save here to avoid wild discrepencies in timing. 613 EXPECT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceeds()); 614 } 615 616 TEST_F(FlockTest, BlockingLockFirstExclusiveSecondExclusive) { 617 // This test will verify that if someone holds an exclusive lock any attempt 618 // to obtain another exclusive lock will result in blocking. 619 ASSERT_THAT(flock(test_file_fd_.get(), LOCK_EX), SyscallSucceeds()); 620 621 // kHoldLockTime is the amount of time we will hold the lock before releasing. 622 constexpr absl::Duration kHoldLockTime = absl::Seconds(2); 623 624 const DisableSave ds; // Timing-related. 625 626 // We do this in another thread so we can determine if it was actually 627 // blocked by timing the amount of time it took for the syscall to complete. 628 ScopedThread t([&] { 629 MonotonicTimer timer; 630 const FileDescriptor fd = 631 ASSERT_NO_ERRNO_AND_VALUE(Open(test_file_name_, O_RDWR)); 632 633 // This exclusive lock should block because someone is already holding an 634 // exclusive lock. 635 timer.Start(); 636 ASSERT_THAT(RetryEINTR(flock)(fd.get(), LOCK_EX), SyscallSucceeds()); 637 638 // We should be blocked, we will expect to be blocked for more than 1.0s. 639 ASSERT_GT(timer.Duration(), absl::Seconds(1)); 640 641 // We can release our exclusive lock. 642 ASSERT_THAT(flock(fd.get(), LOCK_UN), SyscallSucceeds()); 643 }); 644 645 // Sleep before unlocking. 646 absl::SleepFor(kHoldLockTime); 647 648 // Release the exclusive lock allowing the blocked thread to proceed. 649 // We don't save to avoid wild discrepencies in timing. 650 EXPECT_THAT(flock(test_file_fd_.get(), LOCK_UN), SyscallSucceeds()); 651 } 652 653 TEST(FlockTestNoFixture, BadFD) { 654 // EBADF: fd is not an open file descriptor. 655 ASSERT_THAT(flock(-1, LOCK_UN), SyscallFailsWithErrno(EBADF)); 656 } 657 658 TEST(FlockTestNoFixture, FlockDir) { 659 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 660 auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_RDONLY, 0000)); 661 EXPECT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceeds()); 662 } 663 664 TEST(FlockTestNoFixture, FlockSymlink) { 665 auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 666 auto symlink = ASSERT_NO_ERRNO_AND_VALUE( 667 TempPath::CreateSymlinkTo(GetAbsoluteTestTmpdir(), file.path())); 668 669 auto fd = 670 ASSERT_NO_ERRNO_AND_VALUE(Open(symlink.path(), O_RDONLY | O_PATH, 0000)); 671 EXPECT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallFailsWithErrno(EBADF)); 672 } 673 674 TEST(FlockTestNoFixture, FlockProc) { 675 auto fd = 676 ASSERT_NO_ERRNO_AND_VALUE(Open("/proc/self/status", O_RDONLY, 0000)); 677 EXPECT_THAT(flock(fd.get(), LOCK_EX | LOCK_NB), SyscallSucceeds()); 678 } 679 680 TEST(FlockTestNoFixture, FlockPipe) { 681 int fds[2]; 682 ASSERT_THAT(pipe(fds), SyscallSucceeds()); 683 684 EXPECT_THAT(flock(fds[0], LOCK_EX | LOCK_NB), SyscallSucceeds()); 685 // Check that the pipe was locked above. 686 EXPECT_THAT(flock(fds[1], LOCK_EX | LOCK_NB), SyscallFailsWithErrno(EAGAIN)); 687 688 EXPECT_THAT(flock(fds[0], LOCK_UN), SyscallSucceeds()); 689 EXPECT_THAT(flock(fds[1], LOCK_EX | LOCK_NB), SyscallSucceeds()); 690 691 EXPECT_THAT(close(fds[0]), SyscallSucceeds()); 692 EXPECT_THAT(close(fds[1]), SyscallSucceeds()); 693 } 694 695 TEST(FlockTestNoFixture, FlockSocket) { 696 int sock = socket(AF_UNIX, SOCK_STREAM, 0); 697 ASSERT_THAT(sock, SyscallSucceeds()); 698 699 struct sockaddr_un addr = 700 ASSERT_NO_ERRNO_AND_VALUE(UniqueUnixAddr(true /* abstract */, AF_UNIX)); 701 ASSERT_THAT( 702 bind(sock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)), 703 SyscallSucceeds()); 704 705 EXPECT_THAT(flock(sock, LOCK_EX | LOCK_NB), SyscallSucceeds()); 706 EXPECT_THAT(close(sock), SyscallSucceeds()); 707 } 708 709 } // namespace 710 711 } // namespace testing 712 } // namespace gvisor