mirror of
https://github.com/kvcache-ai/Mooncake.git
synced 2026-11-05 01:17:55 +00:00
[GH-ISSUE #4592] [Bug]: TENT MnnvlTransport reuses an imported mapping after the peer re-registers the same address #1170
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#1170
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 @SongOf on GitHub (Oct 12, 2026).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/4592
Bug Report
Version: origin/main
559f83cb73eb870d208a8d4f333b1a24ee992f26Environment: TENT with the MNNVL transport, Fabric or POSIX-FD handle type. Reproducible without a second node; requires two GPUs with P2P or one GPU with two processes.
Description
MnnvlTransportcaches imported mappings keyed only by(target_id, remote base address). When the peer publishes a new allocation at the same virtual address (process restart, or free + re-allocate inside the same process) the consumer keeps using the mapping imported from the oldmnnvl_handle. Transfers complete successfully against the old allocation, which the consumer's own mapping keeps alive.Three contributing points in the code:
relocateSharedMemoryAddressresolves from the map before consultingSegmentManager, and the map entry stores onlymnnvl_addr,length,cuda_id— no handle identity:github.com/kvcache-ai/Mooncake@559f83cb73/mooncake-transfer-engine/tent/include/tent/transport/mnnvl/mnnvl_transport.h (L113-L117)github.com/kvcache-ai/Mooncake@559f83cb73/mooncake-transfer-engine/tent/src/transport/mnnvl/mnnvl_transport.cpp (L799)thread_localcopy of the map that is only refilled when empty or after a miss, so invalidating the global map does not reach threads that already hold a copy:github.com/kvcache-ai/Mooncake@559f83cb73/mooncake-transfer-engine/tent/src/transport/mnnvl/mnnvl_transport.cpp (L769-L778)github.com/kvcache-ai/Mooncake@559f83cb73/mooncake-transfer-engine/tent/src/transport/mnnvl/mnnvl_transport.cpp (L857)uninstall()clears the map withoutcuMemUnmap/cuMemRelease/cuMemAddressFree, and there is no path for a desc update to retire entries:github.com/kvcache-ai/Mooncake@559f83cb73/mooncake-transfer-engine/tent/src/transport/mnnvl/mnnvl_transport.cpp (L242-L247)SegmentManager's push invalidation (NotifySegmentUpdated) bumpsversion_for the descriptor cache only; transport mapping caches are not notified. The subscriber list is held in the provider process, so a provider restart sends no notification and consumers rely onTENT_SEGMENT_DESC_TTL_MS(1 hour).Steps to reproduce
allocateLocalMemory+registerLocalMemorya bufferB0at addressA, write pattern0xA0, publish segmentS.S,submitTransferREAD ofA→ observes0xA0. (Mapping for(S, A)is now cached in C.)B0and allocates again; with the same allocation sequence the new bufferB1lands atA. RegisterB1, write pattern0xB1, publishSagain. (Equivalently: kill P0, start P1 with the same segment name; it getsAagain.)submitTransferREAD ofA.Expected: C reads
0xB1, or the transfer fails with a clear error.Actual: C reads
0xA0and the transfer reports success. With the push notification delivered, the descriptor cache in C is refreshed but the result is unchanged because the mapping cache is keyed by address only and thethread_localcopy is never invalidated. Without a notification (restart case) the same result persists until the 1h TTL.Side effect: P0's
B0allocation is not released while C holds the mapping, so after a few restart cycles the provider can failcuMemCreatewith OOM.Correction after reproduction (2026-10-12)
Reproduced on
b198a191with POSIX-FD handles, see the comment below. Two things in the description above need adjusting:NeedsRefreshCachepath and imports the new buffer correctly; the old mapping is then only a leak that keeps the old allocation alive. The restart case in the repro needssetarch -R(orrandomize_va_space=0) to hit; with ASLR off it is deterministic.The reproduction also exposed an independent blocker: POSIX-FD import passes
&fdinstead of the fd value tocuMemImportFromShareableHandle, so FD mode cannot import anything on main. Fixed in #4597, which is a prerequisite for FD-mode tests of this issue.Proposed fix (no wire-format change)
mnnvl_handle(and length) inOpenedMnnvlEntry; a hit requires base address and handle to match.thread_localcopy, or tag it withSegmentManager::version_and drop it on change.NeedsRefreshCachesowithCachedSegmentrefreshes once and retries; still mismatched →InvalidEntry. Never fall back to the old mapping.cuMemUnmap→cuMemRelease→cuMemAddressFree; close the imported fd in POSIX-FD mode) and use it fromuninstall()and from aSegmentManagerobserver hook on desc replacement.transport_attrs[MNNVL], which needs noBufferDescfield change.Related: #2832 (RFC covering this and the legacy
NvlinkTransport; this issue scopes the TENT part that does not need the wire-format decision), #3581 (same pattern for TENT SHM), #4108.Before submitting...
@github-actions[bot] commented on GitHub (Oct 12, 2026):
Thanks for opening this issue, @SongOf!
46475785A maintainer will triage this when possible. To help us respond faster, please include:
Useful links: Documentation · Contributing guide
@SongOf commented on GitHub (Oct 12, 2026):
Reproduced on current main
Reproduced on
b198a191(main) with POSIX-FD handles, two processes sharing one GPU. Both the in-process re-allocation case and the provider-restart case return the old allocation's data, and the transfer reportsCOMPLETED.Environment
-DUSE_CUDA=ON -DUSE_TENT=ONMC_ENABLE_MNNVL=1 CUDA_VISIBLE_DEVICES=0, configmetadata_type=p2p,transports/nvlink/handle_type=posix_fd, TCP/RDMA/io_uring disabled so MNNVL is usedTransferEngineAPI is used. The provider is fork+exec'd, so neither process forks after CUDA init.Results
unregister+freeB0 (0xA0),allocate+registerB1 (0xB1)COMPLETEDip:port, fills 0xB1 (setarch -Rso the VA repeats)COMPLETED(2/2 runs)In the restart case the consumer still reads 0xA0 after P0 has exited. This confirms the side effect described above: the consumer's imported mapping keeps the old physical allocation alive. With address-space randomization enabled, P1 usually gets a different VA and the restart case does not trigger. The realloc case hits the same VA every time.
Separate blocker: POSIX-FD import is broken on main
To reach this code path I had to locally patch an unrelated bug.
relocateSharedMemoryAddresspasses the fd by address:github.com/kvcache-ai/Mooncake@b198a191/mooncake-transfer-engine/tent/src/transport/mnnvl/mnnvl_transport.cpp (L818)For
CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTORthe driver expects the fd value itself cast tovoid *. Passing&local_fdfails withCUDA_ERROR_UNKNOWN(999), and theLOG(FATAL)insubmitTransferTasksthen aborts the process. A standalone CUDA program confirms it:(void *)(uintptr_t)fdimports fine,&fdreturns 999. So on main, MNNVL in POSIX-FD mode cannot import any peer buffer. The results above were obtained with only this line changed to(void *)(uintptr_t)local_fd. Fixed in #4597.Notes on Fabric mode
Fabric mode could not be tested on this box.
CU_DEVICE_ATTRIBUTE_HANDLE_TYPE_FABRIC_SUPPORTEDreports 1, sosupportFabricMem()passes and MNNVL installs. However,cuMemCreatewithrequestedHandleTypes = FABRICreturnsCUDA_ERROR_NOT_PERMITTED(800): there is no IMEX channel and no NVLink fabric on L20. Because the cache logic does not depend on the handle type, the same behaviour is expected with Fabric handles on an IMEX-enabled system, but that still needs confirming on GB200-class hardware.The repro pins
CUDA_VISIBLE_DEVICES=0because the two L20s have no P2P path and MNNVL grants every visible device access to a mapping. That only matters on PCIe boxes like this one, not on NVLink-domain hardware, and is unrelated to this issue.Repro program (
mnnvl_reregister_repro.cpp)Build it as an extra target next to the TENT tests, linked against
tent_link_group, then run: