Fix 2 bugs in NFS-RDMA allocator, add a test for both

1) alloc() could add the region start into freelist instead of its free part
2) free() was merging freed buffers incorrectly both forward and backward
This commit is contained in:
Vitaliy Filippov
2026-06-19 02:08:41 +03:00
parent 4161f0bd01
commit 5248d7f324
3 changed files with 72 additions and 1 deletions
+5
View File
@@ -35,3 +35,8 @@ target_link_libraries(vitastor-nfs
vitastor_kv
${RDMACM_LIBRARIES}
)
# test_rdma_alloc
add_executable(test_rdma_alloc EXCLUDE_FROM_ALL test_rdma_alloc.cpp rdma_alloc.cpp)
add_dependencies(build_tests test_rdma_alloc)
add_test(NAME test_rdma_alloc COMMAND test_rdma_alloc)
+4 -1
View File
@@ -136,9 +136,9 @@ void *rdma_malloc_alloc(rdma_allocator_t *self, size_t size)
}
else
{
self->freelist.insert((rdma_free_t){ .len = frag.len-size, .buf = ptr });
frag.len -= size;
ptr = (uint8_t*)ptr + frag.len;
self->freelist.insert((rdma_free_t){ .len = frag.len, .buf = frag.rgn->buf });
self->frags[ptr] = (rdma_frag_t){ .rgn = frag.rgn, .len = size, .is_free = false };
}
return ptr;
@@ -174,8 +174,10 @@ void rdma_malloc_free(rdma_allocator_t *self, void *buf)
}
else if (merge_back)
{
self->freelist.erase((rdma_free_t){ .len = prev_it->second.len, .buf = prev_it->first });
prev_it->second.len += frag_it->second.len;
self->frags.erase(frag_it);
self->freelist.insert((rdma_free_t){ .len = prev_it->second.len, .buf = prev_it->first });
frag_it = prev_it;
}
else if (merge_next)
@@ -184,6 +186,7 @@ void rdma_malloc_free(rdma_allocator_t *self, void *buf)
frag_it->second.len += next_it->second.len;
self->freelist.erase((rdma_free_t){ .len = next_it->second.len, .buf = next_it->first });
self->frags.erase(next_it);
self->freelist.insert((rdma_free_t){ .len = frag_it->second.len, .buf = frag_it->first });
}
else
{
+63
View File
@@ -0,0 +1,63 @@
// Copyright (c) Vitaliy Filippov, 2019+
// License: VNPL-1.1 (see README.md for details)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <set>
#include "rdma_alloc.h"
std::set<void*> mrs;
extern "C" {
ibv_mr *ibv_reg_mr_iova2(ibv_pd *pd, void *addr, size_t length, uint64_t, unsigned)
{
bool added = mrs.insert(addr).second;
assert(added);
return (ibv_mr*)addr;
}
int ibv_dereg_mr(ibv_mr *mr)
{
auto erased = mrs.erase((void*)mr);
assert(erased);
return 0;
}
}
void test_split()
{
rdma_allocator_t *alloc = rdma_malloc_create(NULL, 1048576, 64*1048576, IBV_ACCESS_LOCAL_WRITE);
auto buf0 = rdma_malloc_alloc(alloc, 1024*1024);
rdma_malloc_free(alloc, buf0);
auto buf1 = rdma_malloc_alloc(alloc, 224*1024);
auto buf2 = rdma_malloc_alloc(alloc, 500*1024);
auto buf3 = rdma_malloc_alloc(alloc, 300*1024);
rdma_malloc_free(alloc, buf2);
auto buf4 = rdma_malloc_alloc(alloc, 300*1024);
auto buf5 = rdma_malloc_alloc(alloc, 200*1024);
assert((buf5 == buf2 || buf4 == buf2) && buf5 != buf4 && buf5 != buf3 && buf5 != buf1 &&
buf4 != buf3 && buf4 != buf1 && buf3 != buf1);
rdma_malloc_free(alloc, buf5);
rdma_malloc_free(alloc, buf4);
rdma_malloc_free(alloc, buf3);
rdma_malloc_free(alloc, buf1);
// now check merge-both
buf1 = rdma_malloc_alloc(alloc, 224*1024);
buf2 = rdma_malloc_alloc(alloc, 500*1024);
buf3 = rdma_malloc_alloc(alloc, 300*1024);
rdma_malloc_free(alloc, buf3);
rdma_malloc_free(alloc, buf1);
rdma_malloc_free(alloc, buf2);
rdma_malloc_destroy(alloc);
printf("ok test_split\n");
}
int main(int narg, char *args[])
{
test_split();
return 0;
}