libibverbs: Fall back to the write ABI in ibv_cmd_reg_mr_ex() ibv_cmd_reg_mr_ex() issued the REG_MR ioctl unconditionally (execute_ioctl) with no fallback to the legacy write-based registration, unlike ibv_cmd_reg_mr() which is write-ABI based. An address-based MR registered through the extended path therefore fails on a kernel old enough to lack the REG_MR ioctl method, even though it still supports the legacy write ABI that ibv_cmd_reg_mr() uses. Issue the command through the existing ioctl/write fallback machinery instead: declare the command buffer with DECLARE_FBCMD_BUFFER and dispatch via execute_ioctl_fallback(). On TRY_WRITE -- the kernel has no REG_MR ioctl method -- fall back to the legacy write REG_MR command via ibv_cmd_reg_mr() for the address-based case. A dma-buf (fd) or DMA-handle request has no write-ABI equivalent, and a kernel without the ioctl could not service it anyway, so those return EOPNOTSUPP. Signed-off-by: Yishai Hadas <yishaih@nvidia.com> Signed-off-by: Jiri Pirko <jiri@nvidia.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
diff --git a/libibverbs/cmd_mr.c b/libibverbs/cmd_mr.c index f45ce39..02c7f2e 100644 --- a/libibverbs/cmd_mr.c +++ b/libibverbs/cmd_mr.c
@@ -160,8 +160,8 @@ int ibv_cmd_reg_mr_ex(struct ibv_pd *pd, struct verbs_mr *vmr, struct ibv_mr_init_attr *mr_init_attr) { - DECLARE_COMMAND_BUFFER(cmdb, UVERBS_OBJECT_MR, - UVERBS_METHOD_REG_MR, 11); + DECLARE_FBCMD_BUFFER(cmdb, UVERBS_OBJECT_MR, + UVERBS_METHOD_REG_MR, 11, NULL); bool fd_based = (mr_init_attr->comp_mask & IBV_REG_MR_MASK_FD); struct ib_uverbs_attr *handle; uint64_t length = mr_init_attr->length; @@ -222,9 +222,43 @@ fill_attr_in_obj(cmdb, UVERBS_ATTR_REG_MR_DMA_HANDLE, verbs_get_dmah(mr_init_attr->dmah)->handle); - ret = execute_ioctl(pd->context, cmdb); - if (ret) - return errno; + switch (execute_ioctl_fallback(pd->context, reg_mr_ex, cmdb, &ret)) { + case SUCCESS: + break; + + case TRY_WRITE: + case TRY_WRITE_EX: { + /* + * The kernel has no REG_MR ioctl method. Only an address-based + * request maps to the legacy write-ABI REG_MR command; a + * dma-buf (fd) or DMA-handle request has no write-ABI + * equivalent (and such a kernel could not service it anyway). + * This mirrors ibv_cmd_reg_mr()'s write path so an ordinary + * buffer registered via ibv_reg_mr_ex() -- e.g. through + * ibv_reg_buf_mr() -- keeps working on a write-ABI-only kernel. + */ + struct ib_uverbs_reg_mr_resp wresp; + struct ibv_reg_mr req; + uint64_t hca_va; + + if (fd_based || + (mr_init_attr->comp_mask & IBV_REG_MR_MASK_DMAH)) { + errno = EOPNOTSUPP; + return EOPNOTSUPP; + } + + hca_va = (mr_init_attr->comp_mask & IBV_REG_MR_MASK_IOVA) ? + mr_init_attr->iova : + (uintptr_t)mr_init_attr->addr; + + return ibv_cmd_reg_mr(pd, mr_init_attr->addr, length, hca_va, + mr_init_attr->access, vmr, &req, + sizeof(req), &wresp, sizeof(wresp)); + } + + default: + return ret; + } vmr->ibv_mr.handle = read_attr_obj(UVERBS_ATTR_REG_MR_HANDLE, handle);