Fix multilist_alloc_t bug (not triggerable in real operation but still a bug)

This commit is contained in:
Vitaliy Filippov
2026-06-10 01:01:20 +03:00
parent 0e300f4c50
commit 236ffbb24e
4 changed files with 23 additions and 6 deletions
+2 -1
View File
@@ -2322,7 +2322,8 @@ void blockstore_heap_t::use_buffer_area(inode_t inode, uint64_t location, uint64
return; return;
} }
assert(!(size % dsk->bitmap_granularity)); assert(!(size % dsk->bitmap_granularity));
buffer_alloc->use(location / dsk->bitmap_granularity, size / dsk->bitmap_granularity); bool ok = buffer_alloc->use(location / dsk->bitmap_granularity, size / dsk->bitmap_granularity);
assert(ok);
buffer_area_used_space += size; buffer_area_used_space += size;
} }
+7 -4
View File
@@ -171,7 +171,7 @@ void multilist_alloc_t::print()
printf("\n"); printf("\n");
} }
void multilist_alloc_t::use(uint32_t pos, uint32_t size) bool multilist_alloc_t::use(uint32_t pos, uint32_t size)
{ {
assert(pos+size <= count && size > 0); assert(pos+size <= count && size > 0);
if (sizes[pos] <= 0) if (sizes[pos] <= 0)
@@ -182,7 +182,8 @@ void multilist_alloc_t::use(uint32_t pos, uint32_t size)
else else
while (start > 0 && !sizes[start]) while (start > 0 && !sizes[start])
start--; start--;
assert(sizes[start] >= size); if (sizes[start] < size+(pos-start))
return false;
use_full(start); use_full(start);
uint32_t full = sizes[start]; uint32_t full = sizes[start];
sizes[pos-1] = -pos+start; sizes[pos-1] = -pos+start;
@@ -199,7 +200,8 @@ void multilist_alloc_t::use(uint32_t pos, uint32_t size)
} }
else else
{ {
assert(sizes[pos] >= size); if (sizes[pos] < size)
return false;
use_full(pos); use_full(pos);
if (sizes[pos] > size) if (sizes[pos] > size)
{ {
@@ -214,12 +216,13 @@ void multilist_alloc_t::use(uint32_t pos, uint32_t size)
#ifdef MULTILIST_TRACE #ifdef MULTILIST_TRACE
print(); print();
#endif #endif
return true;
} }
void multilist_alloc_t::use_full(uint32_t pos) void multilist_alloc_t::use_full(uint32_t pos)
{ {
uint32_t prevsize = sizes[pos]; uint32_t prevsize = sizes[pos];
assert(prevsize); assert(prevsize > 0);
assert(nexts[pos]); assert(nexts[pos]);
uint32_t pi = (prevsize < maxn ? prevsize : maxn)-1; uint32_t pi = (prevsize < maxn ? prevsize : maxn)-1;
if (heads[pi] == pos+1) if (heads[pi] == pos+1)
+1 -1
View File
@@ -17,7 +17,7 @@ struct multilist_alloc_t
bool is_free(uint32_t pos); bool is_free(uint32_t pos);
uint32_t find(uint32_t size); uint32_t find(uint32_t size);
void use_full(uint32_t pos); void use_full(uint32_t pos);
void use(uint32_t pos, uint32_t size); bool use(uint32_t pos, uint32_t size);
void do_free(uint32_t pos); void do_free(uint32_t pos);
void free(uint32_t pos); void free(uint32_t pos);
void verify(); void verify();
+13
View File
@@ -1902,6 +1902,19 @@ void test_alloc_buffer()
alloc.verify(); alloc.verify();
} }
{
multilist_alloc_t alloc(100, 10);
alloc.use(50, 10);
alloc.verify();
// 48, 5 overlaps with 50, 10 -> should fail to allocate
bool ok = alloc.use(48, 5);
assert(!ok);
alloc.verify();
}
blockstore_heap_t heap(&dsk, buffer_area.data()); blockstore_heap_t heap(&dsk, buffer_area.data());
heap.finish_recheck(); heap.finish_recheck();