mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #2017] [Bug]: ibv_reg_mr is silently truncated to max_mr_size, but BufferDesc.length advertises the original size → IBV_WC_REM_ACCESS_ERR #559
Labels
No labels
ascend
auto-closed
bug
bug
CI/Build
Common
documentation
enhancement
feature request
good first issue
help wanted
high priority
MetaX
nightly-failure
pull-request
PyTorch Backend
question
RFC
Roadmap
stale
Store
Tests
Transfer Engine
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/Mooncake#559
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @Jasen2201 on GitHub (Apr 30, 2026).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/2017
Bug Report
Summary
When
registerLocalMemory()is called withlength > device.max_mr_size,Mooncake registers only
max_mr_sizebytes but tells peers the buffer is thefull original length. Any RDMA WRITE to an address past the truncation
boundary hits
IBV_WC_REM_ACCESS_ERR(CQE error 10).The bug is address-driven, not size-driven: even a tiny 64 KiB write fails
if its target address falls past the boundary.
Root cause
lengthis shrunk locally insideregisterMemoryRegionInternal, but thecaller still uses the original value when building the segment descriptor:
rdma_context.cpp:212-218rdma_transport.cpp:234, 295-297config.cpp:387also clampsmax_mr_sizeto the device cap, so raisingMC_MAX_MR_SIZEcannot work around it on hardware-limited NICs.Why this is hit on AMD MI355X (288 GB HBM)
max_mr_size = 2 GiBgpu-memory-utilization=0.9(room for ~6 M tokens; the 2 GiB MR cutoff sits at ~3.73 M tokens)
This will hit any deployment where per-layer KV exceeds
max_mr_size—large-HBM AMD MI300/355 today, larger GPUs in the future.
Minimal reproducer
Two nodes, one RDMA NIC each. Register a 3 GiB buffer, write to offsets
straddling the 2 GiB boundary.
target.pyinitiator.pyResult on ionic (
max_mr_size = 2 GiB)01.9 GiB2G + 1M2.5 GiBSuggested fixes
registerLocalMemoryInternal— split buffers larger thanmax_mr_sizeinto multiple MRs, publishing oneBufferDescper chunk.BufferDescschema does not need to change; the existing address-basedlookup naturally routes each WRITE to the right
rkey.Before submitting...
@he-yufeng commented on GitHub (May 4, 2026):
Happy to take this. The root cause and fix-1 (auto-chunk in
registerLocalMemoryInternal) read clean, and #1912 already established the auto-split pattern in the EFA twin (efa_context.cpp/efa_transport.cpp), so there is a reference implementation to mirror.Quick sketch of the plan, want to confirm direction before coding so I do not duplicate work:
RdmaContext::registerMemoryRegionInternal(rdma_context.cpp:222-228), drop the silentlength = max_mr_sizeshrink. Instead, haveregisterMemoryRegion(the public entry) split[addr, length)intoceil(length / max_mr_size)chunks, callregisterMemoryRegionInternalonce per chunk, and store oneMemoryRegionMetaper chunk inmemory_region_metas_keyed by the chunk start address.RdmaTransport::registerLocalMemory(rdma_transport.cpp:234, 295-297), publish oneBufferDescper chunk (each with its ownlkey/rkeyand chunk-locallength), so the address-based lookup at the WRITE side naturally routes each slice to the right MR.BufferDescschema does not need to change.MemoryRegionMetalist.efa_single_nic_large_mr_testfor the ibverbs path — register a2 * max_mr_size + 1MiBbuffer, write at offsets0,max_mr_size - 1MiB,max_mr_size + 1MiB,2 * max_mr_size + 1MiB, all return 0.A few open questions before I code:
max_mr_sizeexactly, or expose anMC_MR_CHUNK_SIZEknob (analogous to EFA-side tuning)?max_mr_size, sincemax_num_pteis not exposed by ibverbs the same way. Confirm this is correct?registerMemoryRegionkeep silent-shrink semantics behind a config flag for backward compat, or is the new auto-split the only path?If this all looks reasonable to you, I will start on the patch this week. Thanks!
@alogfans commented on GitHub (May 8, 2026):
@he-yufeng Two issues to be carefully considered:
1' the buffers in the metadata reflect the actual presentation of memory regions (rather than user invocations)
2' when a single transfer request across multiple real memory regions, the slice should be splited according to the memory region boundary.
@he-yufeng commented on GitHub (May 8, 2026):
Thanks, that helps. I will treat the split as part of the visible MR model, not just as a registration fallback.
Concretely:
memory_region_metas_/ publishedBufferDescs should be per actual ibverbs MR chunk, keyed by the chunk start, with chunk-local length/lkey/rkey. The original user call is only the input range.I will check the lookup and transfer path first so the patch handles both the registration-side metadata and the transfer-side boundary split in the same change.
@wangshaochuang commented on GitHub (May 26, 2026):
Hi, 我在其他的网卡上也遇到了这个问题,请问这个问题当前有patch可以验证了吗?🙏