From f927549d2d54e7464151d234377aa82bb753bca9 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 --- 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 3a1f66f7f2bce..ba4ec4ee28190 100644 --- 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 21e7318889a6e..43f2fbf51ecaf 100644 --- a/src/test/objectstore/Allocator_test.cc +++ b/src/test/objectstore/Allocator_test.cc @@ -482,6 +482,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_SUITE_P( Allocator, AllocTest, -- 2.39.5