[GH-ISSUE #3131] [Bug]: NoF 写入失败:spdk_rdma_get_translation: No translation for ptr 是否是我配置的不对导致的这个问题? #802

Closed
opened 2026-10-29 21:19:42 +00:00 by bsakaguchi · 6 comments
Owner

Originally created by @1002135342 on GitHub (Jul 27, 2026).
Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/3131

Bug Report

问题描述

当 Mooncake Store 客户端使用 ReplicateConfig{replica_num=0, nof_replica_num=1}(仅 NoF 副本模式)写入对象时,Master 成功在 NVMe-oF SSD 池上分配空间,SPDK NVMe-oF controller 也成功 attach。但实际数据传输失败,因为 SPDK 的 RDMA 传输层找不到用户 buffer 的内存翻译记录。

环境信息

  • Mooncake 版本:v0.3.12(tag v0.3.12,commit a1ca71f4)
  • 同时验证了 v0.3.12-pre1-185-ga1ca71f4(截至 2026-07-27 的最新 main 分支)——代码完全相同,未修复
  • SPDK:v23.01.1
  • RDMA 网卡:ConnectX-6(mlx5_0),RoCE v2
  • NVMe-oF target:Samsung PM1753 over RDMA(192.168.3.110:4420-4423)
  • LMCache:v0.5.3.dev30(MP 模式,lmcache server + mooncake_store L2 adapter)

复现步骤

  1. 启动 Mooncake master + metadata server,注册 NVMe-oF SSD 池(4 × Samsung PM1753 namespace)
  2. 启动 Mooncake Store 客户端,配置 protocol: "rdma"、global_segment_size: "0"、local_buffer_size: 536870912
  3. 调用 batch_put_from(key, buffer, size, ReplicateConfig{replica_num=0, nof_replica_num=1}),其中 buffer 指向已通过 client->register_buffer() 预注册的 DRAM 内存

期望行为

对象数据通过 SPDK RDMA 写入 NVMe-oF SSD 池。

实际行为

Master 日志显示分配成功:

master_service.cpp:3088] key=..., config=ReplicateConfig: { replica_num: 0, nof_replica_num: 1, ... }, action=put_start_begin
allocator.cpp:261] allocation_succeeded size=33554432 segment=traddr:192.168.3.110 trsvcid:4422 subnqn:nqn.1994-11.com.samsung:nvme:PM1753:2.5-inch:S8FFNG0Y901187 trtype:RDMA

SPDK NVMe-oF controller attach 成功:

spdk_wrapper.cpp:297] Attached to 192.168.3.110 nqn.1994-11.com.samsung:nvme:PM1753:2.5-inch:S8FFNG0Y901187

但数据传输失败:

common.c:216: spdk_rdma_get_translation: *ERROR*: No translation for ptr 0x7f1644000000, size 131072
nvme_rdma.c:1461: nvme_rdma_get_memory_translation: *ERROR*: RDMA memory translation failed, rc -22
nvme_rdma.c:2316: nvme_rdma_qpair_submit_request: *ERROR*: nvme_rdma_req_init() failed
transfer_task.cpp:511] work 0, seg 0x7f1398016730 submit io fail
client_service.cpp:2449] Operation for key ... failed: TRANSFER_FAIL (Transfer 0 failed)

ptr 0x7f1644000000 是用户提供的 buffer(LMCache L1 DRAM,128KB chunk = MC_NOF_SUBMIT_CHUNK_BYTES)。该 buffer 已通过 Mooncake Transfer Engine 的 client->register_buffer() → ibv_reg_mr() 注册,但未注册到 SPDK NVMe-oF RDMA 的内存映射。

根因分析

transfer_task.cpp 的 NoF 写入路径直接将用户 buffer 指针传给 SPDK,没有先注册到 SPDK NVMe-oF RDMA 传输层的内存映射:

// transfer_task.cpp:491-503(SpdkNofWorkerPool::workerThread)
void* submit_ptr = reinterpret_cast<void*>(
    reinterpret_cast<char*>(task->ptr) + lba_off * block_size);

int ret = SpdkWrapper::GetInstance().SubmitRequest(
    task->seg_handle, submit_ptr, submit_lba, submit_lba_count, ...);
// spdk_wrapper.cpp:387(SpdkWrapper::SubmitRequest)
return spdk_nvme_ns_cmd_write(ns, qpair, ptr, lba, lba_count, cb_fn, cb_ctx, 0);

SPDK 的 NVMe-oF RDMA 传输层维护着自己独立的 RDMA 内存映射(nvme_rdma_qpair::rkey_map),与 Mooncake Transfer Engine 的 RDMA 内存注册相互独立。当 spdk_nvme_ns_cmd_write() 被调用时,SPDK 内部通过 nvme_rdma_get_memory_translation() 在自己的内存映射中查找 buffer。由于用户 buffer 从未注册到 SPDK 的 RDMA context,查找失败返回 -22 (EINVAL)。

Before submitting...

  • Ensure you searched for relevant issues and read the [documentation]
Originally created by @1002135342 on GitHub (Jul 27, 2026). Original GitHub issue: https://github.com/kvcache-ai/Mooncake/issues/3131 ### Bug Report ### 问题描述 当 Mooncake Store 客户端使用 `ReplicateConfig{replica_num=0, nof_replica_num=1}`(仅 NoF 副本模式)写入对象时,Master 成功在 NVMe-oF SSD 池上分配空间,SPDK NVMe-oF controller 也成功 attach。但实际数据传输失败,因为 SPDK 的 RDMA 传输层找不到用户 buffer 的内存翻译记录。 ### 环境信息 - Mooncake 版本:v0.3.12(tag `v0.3.12`,commit `a1ca71f4`) - 同时验证了 `v0.3.12-pre1-185-ga1ca71f4`(截至 2026-07-27 的最新 main 分支)——**代码完全相同,未修复** - SPDK:v23.01.1 - RDMA 网卡:ConnectX-6(mlx5_0),RoCE v2 - NVMe-oF target:Samsung PM1753 over RDMA(192.168.3.110:4420-4423) - LMCache:v0.5.3.dev30(MP 模式,`lmcache server` + `mooncake_store` L2 adapter) ### 复现步骤 1. 启动 Mooncake master + metadata server,注册 NVMe-oF SSD 池(4 × Samsung PM1753 namespace) 2. 启动 Mooncake Store 客户端,配置 `protocol: "rdma"`、`global_segment_size: "0"`、`local_buffer_size: 536870912` 3. 调用 `batch_put_from(key, buffer, size, ReplicateConfig{replica_num=0, nof_replica_num=1})`,其中 `buffer` 指向已通过 `client->register_buffer()` 预注册的 DRAM 内存 ### 期望行为 对象数据通过 SPDK RDMA 写入 NVMe-oF SSD 池。 ### 实际行为 Master 日志显示分配成功: ``` master_service.cpp:3088] key=..., config=ReplicateConfig: { replica_num: 0, nof_replica_num: 1, ... }, action=put_start_begin allocator.cpp:261] allocation_succeeded size=33554432 segment=traddr:192.168.3.110 trsvcid:4422 subnqn:nqn.1994-11.com.samsung:nvme:PM1753:2.5-inch:S8FFNG0Y901187 trtype:RDMA ``` SPDK NVMe-oF controller attach 成功: ``` spdk_wrapper.cpp:297] Attached to 192.168.3.110 nqn.1994-11.com.samsung:nvme:PM1753:2.5-inch:S8FFNG0Y901187 ``` 但数据传输失败: ``` common.c:216: spdk_rdma_get_translation: *ERROR*: No translation for ptr 0x7f1644000000, size 131072 nvme_rdma.c:1461: nvme_rdma_get_memory_translation: *ERROR*: RDMA memory translation failed, rc -22 nvme_rdma.c:2316: nvme_rdma_qpair_submit_request: *ERROR*: nvme_rdma_req_init() failed transfer_task.cpp:511] work 0, seg 0x7f1398016730 submit io fail client_service.cpp:2449] Operation for key ... failed: TRANSFER_FAIL (Transfer 0 failed) ``` `ptr 0x7f1644000000` 是用户提供的 buffer(LMCache L1 DRAM,128KB chunk = `MC_NOF_SUBMIT_CHUNK_BYTES`)。该 buffer 已通过 Mooncake Transfer Engine 的 `client->register_buffer()` → `ibv_reg_mr()` 注册,但**未注册到 SPDK NVMe-oF RDMA 的内存映射**。 ### 根因分析 `transfer_task.cpp` 的 NoF 写入路径直接将用户 buffer 指针传给 SPDK,没有先注册到 SPDK NVMe-oF RDMA 传输层的内存映射: ```cpp // transfer_task.cpp:491-503(SpdkNofWorkerPool::workerThread) void* submit_ptr = reinterpret_cast<void*>( reinterpret_cast<char*>(task->ptr) + lba_off * block_size); int ret = SpdkWrapper::GetInstance().SubmitRequest( task->seg_handle, submit_ptr, submit_lba, submit_lba_count, ...); ``` ```cpp // spdk_wrapper.cpp:387(SpdkWrapper::SubmitRequest) return spdk_nvme_ns_cmd_write(ns, qpair, ptr, lba, lba_count, cb_fn, cb_ctx, 0); ``` SPDK 的 NVMe-oF RDMA 传输层维护着自己独立的 RDMA 内存映射(`nvme_rdma_qpair::rkey_map`),与 Mooncake Transfer Engine 的 RDMA 内存注册**相互独立**。当 `spdk_nvme_ns_cmd_write()` 被调用时,SPDK 内部通过 `nvme_rdma_get_memory_translation()` 在自己的内存映射中查找 buffer。由于用户 buffer 从未注册到 SPDK 的 RDMA context,查找失败返回 `-22 (EINVAL)`。 ### Before submitting... - [ ] Ensure you searched for relevant issues and read the [documentation]
bsakaguchi 2026-10-29 21:19:42 +00:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@github-actions[bot] commented on GitHub (Jul 27, 2026):

Thanks for opening this issue, @1002135342!

Field Value
Issue #3131
GitHub user ID 22439389
Reporter @1002135342

A maintainer will triage this when possible. To help us respond faster, please include:

  • Mooncake version or commit SHA
  • Environment (OS, CUDA/driver, RDMA stack if relevant)
  • Steps to reproduce and expected vs. actual behavior

Useful links: Documentation · Contributing guide

This message was posted automatically by the issue bot.

<!-- gh-comment-id:5087408954 --> @github-actions[bot] commented on GitHub (Jul 27, 2026): Thanks for opening this issue, @1002135342! | Field | Value | |-------|-------| | **Issue** | #3131 | | **GitHub user ID** | `22439389` | | **Reporter** | @1002135342 | A maintainer will triage this when possible. To help us respond faster, please include: - Mooncake version or commit SHA - Environment (OS, CUDA/driver, RDMA stack if relevant) - Steps to reproduce and expected vs. actual behavior Useful links: [Documentation](https://kvcache-ai.github.io/Mooncake/) · [Contributing guide](https://github.com/kvcache-ai/Mooncake/blob/main/CONTRIBUTING.md) > This message was posted automatically by the issue bot.
Author
Owner

@he-yufeng commented on GitHub (Jul 28, 2026):

不是你的配置问题,这是 NoF 数据面的一个真实缺口。看了 main 上这条路径:NoF 读写把用户 buffer 原样传给 spdk_nvme_ns_cmd_read/write(spdk_wrapper.cpp 里 SubmitRequest),全程没有把这块内存注册进 SPDK RDMA 的 translation 表。SPDK 的 spdk_rdma_get_translation 只认两类内存:SPDK 自己 spdk_zmalloc(SPDK_MALLOC_DMA) 出来的 DMA buffer(attach 后的 probe 读用的就是这种,所以 probe 正常),或者事先在该 RDMA device 上注册过的区域。你经 client->register_buffer() 注册的 LMCache DRAM 只进了 Mooncake transfer engine 自己的 MR 表,SPDK 的表里没有它,于是一提交 IO 就报 No translation for ptr。

修法两个方向:

  1. 在 NoF 后端给用户 buffer 做 SPDK 侧注册(首次使用注册、释放注销,要管一张注册生命周期表),零拷贝;
  2. 走 staging DMA buffer 中转(用户 buffer -> SPDK DMA buffer -> SSD),任何来源的 buffer 都通用,代价是多一次 memcpy。

无论选哪个,当前"buffer 必须落在 SPDK translation 表内"这个隐含约束都应该写进文档,现在文档里完全没提。@alogfans @ykwd NoF 这块倾向哪条路?方向定了我可以来做。

<!-- gh-comment-id:5098770091 --> @he-yufeng commented on GitHub (Jul 28, 2026): 不是你的配置问题,这是 NoF 数据面的一个真实缺口。看了 main 上这条路径:NoF 读写把用户 buffer 原样传给 `spdk_nvme_ns_cmd_read/write`(spdk_wrapper.cpp 里 SubmitRequest),全程没有把这块内存注册进 SPDK RDMA 的 translation 表。SPDK 的 `spdk_rdma_get_translation` 只认两类内存:SPDK 自己 `spdk_zmalloc(SPDK_MALLOC_DMA)` 出来的 DMA buffer(attach 后的 probe 读用的就是这种,所以 probe 正常),或者事先在该 RDMA device 上注册过的区域。你经 `client->register_buffer()` 注册的 LMCache DRAM 只进了 Mooncake transfer engine 自己的 MR 表,SPDK 的表里没有它,于是一提交 IO 就报 No translation for ptr。 修法两个方向: 1. 在 NoF 后端给用户 buffer 做 SPDK 侧注册(首次使用注册、释放注销,要管一张注册生命周期表),零拷贝; 2. 走 staging DMA buffer 中转(用户 buffer -> SPDK DMA buffer -> SSD),任何来源的 buffer 都通用,代价是多一次 memcpy。 无论选哪个,当前"buffer 必须落在 SPDK translation 表内"这个隐含约束都应该写进文档,现在文档里完全没提。@alogfans @ykwd NoF 这块倾向哪条路?方向定了我可以来做。
Author
Owner

@LujhCoconut commented on GitHub (Jul 28, 2026):

SPDK+NOF还是比较实验性的,没有完全production ready。 目前代码NOF和SPDK的耦合度太高了,我们后续会先进行这部分的解耦重构,对代码质量进行优化。然后再进行缺口面的修复和优化。

<!-- gh-comment-id:5101003206 --> @LujhCoconut commented on GitHub (Jul 28, 2026): SPDK+NOF还是比较实验性的,没有完全production ready。 目前代码NOF和SPDK的耦合度太高了,我们后续会先进行这部分的解耦重构,对代码质量进行优化。然后再进行缺口面的修复和优化。
Author
Owner

@1002135342 commented on GitHub (Jul 28, 2026):

SPDK+NOF还是比较实验性的,没有完全production ready。 目前代码NOF和SPDK的耦合度太高了,我们后续会先进行这部分的解耦重构,对代码质量进行优化。然后再进行缺口面的修复和优化。

关于您描述的这个NoF和SPDK的解耦重构,目前是否有具体的思路,或许我们这边可以按照这个思路进行尝试?

<!-- gh-comment-id:5101739863 --> @1002135342 commented on GitHub (Jul 28, 2026): > SPDK+NOF还是比较实验性的,没有完全production ready。 目前代码NOF和SPDK的耦合度太高了,我们后续会先进行这部分的解耦重构,对代码质量进行优化。然后再进行缺口面的修复和优化。 关于您描述的这个NoF和SPDK的解耦重构,目前是否有具体的思路,或许我们这边可以按照这个思路进行尝试?
Author
Owner

@LujhCoconut commented on GitHub (Jul 28, 2026):

SPDK+NOF还是比较实验性的,没有完全production ready。 目前代码NOF和SPDK的耦合度太高了,我们后续会先进行这部分的解耦重构,对代码质量进行优化。然后再进行缺口面的修复和优化。

关于您描述的这个NoF和SPDK的解耦重构,目前是否有具体的思路,或许我们这边可以按照这个思路进行尝试?

具体的方案还没确定。我个人目前的想法是把SPDK变成接口后面可插拔的插件。(i)在I/O加一层NVMeoFInitiaor的抽象,然后实现一些虚接口,SPDK相关的API收到SpdkInitiaor的实现类里; (ii)然后内存分配上也需要拆分一个DmaBufferAllocator的抽象 (iii)一些SPDK类型从公共头文件里移除,做一些类型隔离之类的。这个可能需要和相关代码的原作者 @Enigmo-x 讨论一下什么的。

<!-- gh-comment-id:5102144409 --> @LujhCoconut commented on GitHub (Jul 28, 2026): > > SPDK+NOF还是比较实验性的,没有完全production ready。 目前代码NOF和SPDK的耦合度太高了,我们后续会先进行这部分的解耦重构,对代码质量进行优化。然后再进行缺口面的修复和优化。 > > 关于您描述的这个NoF和SPDK的解耦重构,目前是否有具体的思路,或许我们这边可以按照这个思路进行尝试? 具体的方案还没确定。我个人目前的想法是把SPDK变成接口后面可插拔的插件。(i)在I/O加一层NVMeoFInitiaor的抽象,然后实现一些虚接口,SPDK相关的API收到SpdkInitiaor的实现类里; (ii)然后内存分配上也需要拆分一个DmaBufferAllocator的抽象 (iii)一些SPDK类型从公共头文件里移除,做一些类型隔离之类的。这个可能需要和相关代码的原作者 @Enigmo-x 讨论一下什么的。
Author
Owner

@he-yufeng commented on GitHub (Jul 28, 2026):

这个节奏合理,先解耦再补缺口。我分诊里提的两个修法(用户 buffer 注册进 SPDK 翻译表、staging DMA buffer 中转)都属于"缺口面",按你说的顺序排在解耦重构后面跟进即可。抽象层落下来之后,buffer 注册生命周期表挂在 DmaBufferAllocator 那一侧会比较自然。

到解耦方案成型、需要人搭手的时候叫我,NoF 这块我可以接一部分。

<!-- gh-comment-id:5102867350 --> @he-yufeng commented on GitHub (Jul 28, 2026): 这个节奏合理,先解耦再补缺口。我分诊里提的两个修法(用户 buffer 注册进 SPDK 翻译表、staging DMA buffer 中转)都属于"缺口面",按你说的顺序排在解耦重构后面跟进即可。抽象层落下来之后,buffer 注册生命周期表挂在 DmaBufferAllocator 那一侧会比较自然。 到解耦方案成型、需要人搭手的时候叫我,NoF 这块我可以接一部分。
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kvcache-ai/Mooncake#802
No description provided.