]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
blk/kernel: use open file description lock if available
authorKefu Chai <kchai@redhat.com>
Tue, 15 Sep 2020 07:38:36 +0000 (15:38 +0800)
committerNathan Cutler <ncutler@suse.com>
Tue, 27 Oct 2020 10:32:28 +0000 (11:32 +0100)
* use OFD lock if available. OFD is Linux specific, and only available
  on 3.15 kernels. OFD is able to synchronize both threads and
  processes. and has simpler semantics. this is just a cleanup.
  as we don't create threads for acquiring the flock.
* use BSD flock(2) as a fallback
* return the errno right away, without printing logging messages.
  for two reasons:
  - writing logging messages would reset the errno.
  - the caller of _lock() also prints the logging messages along
    with strerror(errno)

Fixes: https://tracker.ceph.com/issues/46124
Signed-off-by: Kefu Chai <kchai@redhat.com>
(cherry picked from commit ec7fa396247ecf20e58eeb3c6caa1e5f5f05ae98)

Conflicts:
src/blk/kernel/KernelDevice.cc
- file does not exist in nautilus; made changes manually in
  src/os/bluestore/KernelDevice.cc

src/os/bluestore/KernelDevice.cc

index 9e8843728088ff20279c61582a9aad41e7e03b62..ebd6a12d89c559efca69f38f1848322ca3b3690e 100644 (file)
@@ -59,24 +59,36 @@ KernelDevice::KernelDevice(CephContext* cct, aio_callback_t cb, void *cbpriv, ai
 int KernelDevice::_lock()
 {
   dout(10) << __func__ << " " << fd_directs[WRITE_LIFE_NOT_SET] << dendl;
-  double retry_interval = cct->_conf.get_val<double>("bdev_flock_retry_interval");
-  uint64_t max_retry = cct->_conf.get_val<uint64_t>("bdev_flock_retry");
   // When the block changes, systemd-udevd will open the block,
   // read some information and close it. Then a failure occurs here.
   // So we need to try again here.
-  for (uint64_t i = 0; i < max_retry + 1; i++) {
-    int r = ::flock(fd_directs[WRITE_LIFE_NOT_SET], LOCK_EX | LOCK_NB);
-    if (r < 0 && errno == EAGAIN) {
-      dout(1) << __func__ << " flock busy on " << path << dendl;
-      std::this_thread::sleep_for(ceph::make_timespan(retry_interval));
-    } else if (r < 0) {
-      derr << __func__ << " flock failed on " << path << dendl;    
-      break;
-    } else {
+  int fd = fd_directs[WRITE_LIFE_NOT_SET];
+  uint64_t nr_tries = 0;
+  for (;;) {
+    struct flock fl = { F_WRLCK,
+                        SEEK_SET };
+    int r = ::fcntl(fd, F_OFD_SETLK, &fl);
+    if (r < 0) {
+      if (errno == EINVAL) {
+        r = ::flock(fd, LOCK_EX | LOCK_NB);
+      }
+    }
+    if (r == 0) {
       return 0;
     }
+    if (errno != EAGAIN) {
+      return -errno;
+    }
+    dout(1) << __func__ << " flock busy on " << path << dendl;
+    if (const uint64_t max_retry =
+       cct->_conf.get_val<uint64_t>("bdev_flock_retry");
+        nr_tries++ == max_retry) {
+      return -EAGAIN;
+    }
+    double retry_interval =
+      cct->_conf.get_val<double>("bdev_flock_retry_interval");
+    std::this_thread::sleep_for(ceph::make_timespan(retry_interval));
   }
-  return -errno;
 }
 
 int KernelDevice::open(const string& p)