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: v15.2.9~19^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=c25def8dde775e0cab0da5906c26b0a3c881631a;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) --- diff --git a/src/os/bluestore/AvlAllocator.cc b/src/os/bluestore/AvlAllocator.cc index e9d05107986..0ac70baa80c 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 78e018b7a57..f6f0c38bec2 100644 --- a/src/test/objectstore/Allocator_test.cc +++ b/src/test/objectstore/Allocator_test.cc @@ -480,6 +480,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,