From: Igor Fedotov Date: Thu, 3 Dec 2020 19:08:43 +0000 (+0300) Subject: os/bluestore: fix inappropriate ENOSPC from avl/hybrid allocator X-Git-Tag: v14.2.17~91^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=809ed124d8c814cb23de2e695f3b28a88a99af0d;p=ceph.git os/bluestore: fix inappropriate ENOSPC from avl/hybrid allocator 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 (cherry picked from commit f927549d2d54e7464151d234377aa82bb753bca9) Conflicts: src/test/objectstore/Allocator_test.cc Legacy gtest macros name --- diff --git a/src/os/bluestore/AvlAllocator.cc b/src/os/bluestore/AvlAllocator.cc index e9d051079862..0ac70baa80c3 100755 --- a/src/os/bluestore/AvlAllocator.cc +++ b/src/os/bluestore/AvlAllocator.cc @@ -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); } diff --git a/src/test/objectstore/Allocator_test.cc b/src/test/objectstore/Allocator_test.cc index 1881cfa822ce..d4291e385158 100644 --- a/src/test/objectstore/Allocator_test.cc +++ b/src/test/objectstore/Allocator_test.cc @@ -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,