]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/os/bluestore/BlueStore.cc
update sources to v12.2.0
[ceph.git] / ceph / src / os / bluestore / BlueStore.cc
index 9672e34b0c68a892601d1b0fb955c4f003f2b65b..b87d0302b306a9fc5526e001391e0f67cf9f2b4d 100644 (file)
@@ -5995,12 +5995,92 @@ int BlueStore::fsck(bool deep)
     }
     fm->enumerate_reset();
     size_t count = used_blocks.count();
+    if (used_blocks.size() == count + 1) {
+      // this due to http://tracker.ceph.com/issues/21089
+      bufferlist fm_bpb_bl, fm_blocks_bl, fm_bpk_bl;
+      db->get(PREFIX_ALLOC, "bytes_per_block", &fm_bpb_bl);
+      db->get(PREFIX_ALLOC, "blocks", &fm_blocks_bl);
+      db->get(PREFIX_ALLOC, "blocks_per_key", &fm_bpk_bl);
+      uint64_t fm_blocks = 0;
+      uint64_t fm_bsize = 1;
+      uint64_t fm_blocks_per_key = 1;
+      try {
+       auto p = fm_blocks_bl.begin();
+       ::decode(fm_blocks, p);
+       auto q = fm_bpb_bl.begin();
+       ::decode(fm_bsize, q);
+       auto r = fm_bpk_bl.begin();
+       ::decode(fm_blocks_per_key, r);
+      } catch (buffer::error& e) {
+      }
+      uint64_t dev_bsize = bdev->get_block_size();
+      uint64_t bad_size = bdev->get_size() & ~fm_bsize;
+      if (used_blocks.test(bad_size / dev_bsize) == 0) {
+       // this is the last block of the device that we previously
+       // (incorrectly) truncated off of the effective device size.  this
+       // prevented BitmapFreelistManager from marking it as used along with
+       // the other "past-eof" blocks in the last key slot.  mark it used
+       // now.
+       derr << __func__ << " warning: fixing leaked block 0x" << std::hex
+            << bad_size << "~" << fm_bsize << std::dec << " due to old bug"
+            << dendl;
+       KeyValueDB::Transaction t = db->get_transaction();
+       // fix freelistmanager metadata (the internal 'blocks' count is
+       // rounded up to include the trailing key, past eof)
+       uint64_t new_blocks = bdev->get_size() / fm_bsize;
+       if (new_blocks / fm_blocks_per_key * fm_blocks_per_key != new_blocks) {
+         new_blocks = (new_blocks / fm_blocks_per_key + 1) *
+           fm_blocks_per_key;
+       }
+       if (new_blocks != fm_blocks) {
+         // the fm block count increased
+         derr << __func__ << "  freelist block and key count changed, fixing 0x"
+              << std::hex << bdev->get_size() << "~"
+              << ((new_blocks * fm_bsize) - bdev->get_size()) << std::dec
+              << dendl;
+         bufferlist bl;
+         ::encode(new_blocks, bl);
+         t->set(PREFIX_ALLOC, "blocks", bl);
+         fm->allocate(bdev->get_size(),
+                      (new_blocks * fm_bsize) - bdev->get_size(),
+                      t);
+       } else {
+         // block count is the same, but size changed; fix just the size
+         derr << __func__ << "  fixing just the stray block at 0x"
+              << std::hex << bad_size << "~" << fm_bsize << std::dec << dendl;
+         fm->allocate(bad_size, fm_bsize, t);
+       }
+       bufferlist sizebl;
+       ::encode(bdev->get_size(), sizebl);
+       t->set(PREFIX_ALLOC, "size", sizebl);
+       int r = db->submit_transaction_sync(t);
+       assert(r == 0);
+
+       used_blocks.set(bad_size / dev_bsize);
+       ++count;
+      }
+    }
     if (used_blocks.size() != count) {
       assert(used_blocks.size() > count);
-      derr << __func__ << " error: leaked some space;"
-          << (used_blocks.size() - count) * min_alloc_size
-          << " bytes leaked" << dendl;
       ++errors;
+      used_blocks.flip();
+      size_t start = used_blocks.find_first();
+      while (start != decltype(used_blocks)::npos) {
+       size_t cur = start;
+       while (true) {
+         size_t next = used_blocks.find_next(cur);
+         if (next != cur + 1) {
+           derr << __func__ << " error: leaked extent 0x" << std::hex
+                << ((uint64_t)start * block_size) << "~"
+                << ((cur + 1 - start) * block_size) << std::dec
+                << dendl;
+           start = next;
+           break;
+         }
+         cur = next;
+       }
+      }
+      used_blocks.flip();
     }
   }