From 809ed124d8c814cb23de2e695f3b28a88a99af0d Mon Sep 17 00:00:00 2001 From: Igor Fedotov Date: Thu, 3 Dec 2020 22:08:43 +0300 Subject: [PATCH] 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 --- src/os/bluestore/AvlAllocator.cc | 10 +++++++++- src/test/objectstore/Allocator_test.cc | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/os/bluestore/AvlAllocator.cc b/src/os/bluestore/AvlAllocator.cc index e9d05107986..0ac70baa80c 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 1881cfa822c..d4291e38515 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, -- 2.47.3