]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
os/bluestore: fix inappropriate ENOSPC from avl/hybrid allocator 38475/head
authorIgor Fedotov <ifedotov@suse.com>
Thu, 3 Dec 2020 19:08:43 +0000 (22:08 +0300)
committerIgor Fedotov <ifedotov@suse.com>
Mon, 7 Dec 2020 13:38:19 +0000 (16:38 +0300)
Under high fragmentation circumstances (in best-fit mode) these allocators might fail to
return continuous(longer than a single alloc unit) extents. Occurs when
requested size is longer than the maximum available extents and these
extents are unaligned with alloc unit. The latter results in the actual lengths of these extens are shorter
than the requested length and they do not match to the lookup. Which
finally causes no allocation at all.

Fixes: https://tracker.ceph.com/issues/47883
Signed-off-by: Igor Fedotov <ifedotov@suse.com>
(cherry picked from commit f927549d2d54e7464151d234377aa82bb753bca9)

 Conflicts:
src/test/objectstore/Allocator_test.cc
 Legacy gtest macros name

src/os/bluestore/AvlAllocator.cc
src/test/objectstore/Allocator_test.cc

index e9d0510798626b614b01982d977f6f6fe1a7ecc5..0ac70baa80c3acd6cd87c03bfb59d06158730842 100755 (executable)
@@ -240,7 +240,15 @@ int AvlAllocator::_allocate(
       max_size < range_size_alloc_threshold ||
       free_pct < range_size_alloc_free_pct) {
     *cursor = 0;
-    start = _block_picker(range_size_tree, cursor, size, unit);
+    do {
+      start = _block_picker(range_size_tree, cursor, size, unit);
+      if (start != -1ULL || !force_range_size_alloc) {
+        break;
+      }
+      // try to collect smaller extents as we could fail to retrieve
+      // that large block due to misaligned extents
+      size = p2align(size >> 1, unit);
+    } while (size >= unit);
   } else {
     start = _block_picker(range_tree, cursor, size, unit);
   }
index 1881cfa822ce34b86772739a0c22fcacae32b12d..d4291e38515844437bfbbec7e41edbfdbf3788ff 100644 (file)
@@ -475,6 +475,24 @@ TEST_P(AllocTest, test_alloc_contiguous)
   alloc->shutdown();
 }
 
+TEST_P(AllocTest, test_alloc_47883)
+{
+  uint64_t block = 0x1000;
+  uint64_t size = 1599858540544ul;
+
+  init_alloc(size, block);
+
+  alloc->init_add_free(0x1b970000, 0x26000);
+  alloc->init_add_free(0x1747e9d5000, 0x493000);
+  alloc->init_add_free(0x1747ee6a000, 0x196000);
+
+  PExtentVector extents;
+  auto need = 0x3f980000;
+  auto got = alloc->allocate(need, 0x10000, 0, (int64_t)0, &extents);
+  EXPECT_GT(got, 0);
+  EXPECT_EQ(got, 0x630000);
+}
+
 INSTANTIATE_TEST_CASE_P(
   Allocator,
   AllocTest,