]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
os/BlueStore: NCB fix for leaked space when bdev_async_discard is enabled
authorGabriel BenHanokh <gbenhano@redhat.com>
Sun, 7 Apr 2024 10:57:14 +0000 (10:57 +0000)
committerYite Gu <yitegu0@gmail.com>
Wed, 7 Aug 2024 02:46:19 +0000 (10:46 +0800)
Fix calls bdev->discard_drain() before calling store_allocator() to make sure all freed space is reflected in the allocator before destaging it
The fix set a timeout for the drain call (500msec) and if expires will not store the allocator (forcing a recovery on the next startup)
Fixes: https://tracker.ceph.com/issues/65298
Signed-off-by: Gabriel BenHanokh <gbenhano@redhat.com>
(cherry picked from commit 3aa891dbf6dafd3b1983fbe2efcbfd1d11d52b40)

src/blk/BlockDevice.h
src/blk/kernel/KernelDevice.cc
src/blk/kernel/KernelDevice.h
src/os/bluestore/BlueStore.cc

index 6c55646fc76df8d5594bbb66d1a7729e9a0966c5..7431b062dce887c9ce06f694574fcf9197074e4b 100644 (file)
@@ -285,7 +285,7 @@ public:
     int write_hint = WRITE_LIFE_NOT_SET) = 0;
   virtual int flush() = 0;
   virtual bool try_discard(interval_set<uint64_t> &to_release, bool async=true) { return false; }
-  virtual void discard_drain() { return; }
+  virtual int discard_drain(uint32_t timeout_msec = 0) { return 0; }
 
   // for managing buffered readers/writers
   virtual int invalidate_cache(uint64_t off, uint64_t len) = 0;
index 6337292f5dec25e95766e5db79b1e9cc9dcff8ad..716004e6c89543463da55013ecde59438e1835f5 100644 (file)
@@ -587,13 +587,35 @@ bool KernelDevice::_discard_started()
   return !discard_threads.empty();
 }
 
-void KernelDevice::discard_drain()
+int KernelDevice::discard_drain(uint32_t timeout_msec = 0)
 {
   dout(10) << __func__ << dendl;
+  bool check_timeout = false;
+  utime_t end_time;
+  if (timeout_msec) {
+    check_timeout = true;
+    uint32_t timeout_sec = 0;
+    if (timeout_msec >= 1000) {
+      timeout_sec = (timeout_msec / 1000);
+      timeout_msec = (timeout_msec % 1000);
+    }
+    end_time = ceph_clock_now();
+    // add the timeout after converting from msec to nsec
+    end_time.tv.tv_nsec += (timeout_msec * (1000*1000));
+    if (end_time.tv.tv_nsec > (1000*1000*1000)) {
+      end_time.tv.tv_nsec -= (1000*1000*1000);
+      end_time.tv.tv_sec += 1;
+    }
+    end_time.tv.tv_sec += timeout_sec;
+  }
   std::unique_lock l(discard_lock);
   while (!discard_queued.empty() || discard_running) {
     discard_cond.wait(l);
+    if (check_timeout && ceph_clock_now() > end_time) {
+      return -1;
+    }
   }
+  return 0;
 }
 
 static bool is_expected_ioerr(const int r)
index 914f05e64c43ddc647234c30f336bf8f5d93c6c8..b7b0a7dc38bc16077fe0e4277ac45cc3d8eb405d 100644 (file)
@@ -123,7 +123,7 @@ public:
   ~KernelDevice();
 
   void aio_submit(IOContext *ioc) override;
-  void discard_drain() override;
+  int discard_drain(uint32_t timeout_msec) override;
 
   int collect_metadata(const std::string& prefix, std::map<std::string,std::string> *pm) const override;
   int get_devname(std::string *s) const override {
index f8ab4720b649efb0676130730375e30bbb6e25ca..108afc4038d4870f132aa0073caf822f8a336df9 100644 (file)
@@ -7754,9 +7754,17 @@ void BlueStore::_close_db()
   db = nullptr;
 
   if (do_destage && fm && fm->is_null_manager()) {
-    int ret = store_allocator(alloc);
-    if (ret != 0) {
-      derr << __func__ << "::NCB::store_allocator() failed (continue with bitmapFreelistManager)" << dendl;
+    // force all backgrounds discards to be committed before storing allocator
+    // set timeout to 500msec
+    int ret = bdev->discard_drain(500);
+    if (ret == 0) {
+      ret = store_allocator(alloc);
+      if (unlikely(ret != 0)) {
+       derr << __func__ << "::NCB::store_allocator() failed (we will need to rebuild it on startup)" << dendl;
+      }
+    }
+    else {
+      derr << __func__ << "::NCB::discard_drain() exceeded timeout (abort!)" << dendl;
     }
   }