From d4f868ae7b9df723a9f785cbe6caee1f718e5e33 Mon Sep 17 00:00:00 2001 From: tangwenjun Date: Mon, 20 Nov 2017 15:28:29 +0800 Subject: [PATCH] os/bluestore: fix the allocate in bluefs when bluefs succeed to reserve but failed to alloc in db space, it will cause a assert, just because of the space fragmentation. in this situation, it could not use slow device space, and it would happen in stupid or avl allocator. Signed-off-by: tangwenjun --- src/os/bluestore/BlueFS.cc | 42 +++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/os/bluestore/BlueFS.cc b/src/os/bluestore/BlueFS.cc index 3f6ba2544ea75..9786af2a22636 100644 --- a/src/os/bluestore/BlueFS.cc +++ b/src/os/bluestore/BlueFS.cc @@ -1927,10 +1927,30 @@ int BlueFS::_allocate(uint8_t id, uint64_t len, uint64_t left = ROUND_UP_TO(len, min_alloc_size); int r = -ENOSPC; + int64_t alloc_len = 0; + AllocExtentVector extents; + if (alloc[id]) { r = alloc[id]->reserve(left); } - if (r < 0) { + + if (r == 0) { + uint64_t hint = 0; + if (!node->extents.empty() && node->extents.back().bdev == id) { + hint = node->extents.back().end(); + } + extents.reserve(4); // 4 should be (more than) enough for most allocations + alloc_len = alloc[id]->allocate(left, min_alloc_size, hint, &extents); + } + if (r < 0 || (alloc_len < (int64_t)left)) { + if (r == 0) { + interval_set to_release; + alloc[id]->unreserve(left - alloc_len); + for (auto& p : extents) { + to_release.insert(p.offset, p.length); + } + alloc[id]->release(to_release); + } if (id != BDEV_SLOW) { if (bdev[id]) { dout(1) << __func__ << " failed to allocate 0x" << std::hex << left @@ -1948,24 +1968,8 @@ int BlueFS::_allocate(uint8_t id, uint64_t len, else derr << __func__ << " failed to allocate 0x" << std::hex << left << " on bdev " << (int)id << ", dne" << std::dec << dendl; - return r; - } - - uint64_t hint = 0; - if (!node->extents.empty() && node->extents.back().bdev == id) { - hint = node->extents.back().end(); - } - - AllocExtentVector extents; - extents.reserve(4); // 4 should be (more than) enough for most allocations - int64_t alloc_len = alloc[id]->allocate(left, min_alloc_size, hint, - &extents); - if (alloc_len < (int64_t)left) { - derr << __func__ << " allocate failed on 0x" << std::hex << left - << " min_alloc_size 0x" << min_alloc_size - << " hint 0x" << hint << std::dec << dendl; - alloc[id]->dump(); - assert(0 == "allocate failed... wtf"); + if (alloc[id]) + alloc[id]->dump(); return -ENOSPC; } -- 2.39.5