On Sun, Aug 23, 2026 at 4:18 AM Yanfei Xu <[email protected]> wrote:
>
> RAM writes and control messages share the send queue. If outstanding
> writes fill it, RDMA writes drain a completion and retry, but control
> sends fail the migration.
>
> Move send posting and queue-full handling into a common helper. On
> ENOMEM, drain one outstanding RDMA write and retry the failed request
> once. If no write is outstanding, or the retry still fails, propagate
> the error.
>
> Signed-off-by: Yanfei Xu <[email protected]>
> Reviewed-by: Peter Xu <[email protected]>
Reviewed-by: Jack Wang <[email protected]>
> ---
>  migration/rdma.c       | 75 ++++++++++++++++++++++++++----------------
>  migration/trace-events |  2 +-
>  2 files changed, 48 insertions(+), 29 deletions(-)
>
> diff --git a/migration/rdma.c b/migration/rdma.c
> index b79f4263f7..b7580ab54f 100644
> --- a/migration/rdma.c
> +++ b/migration/rdma.c
> @@ -1553,6 +1553,51 @@ err_block_for_wrid:
>      return -1;
>  }
>
> +/*
> + * Post a send work request, draining an outstanding RDMA write if the send
> + * queue is full.
> + */
> +static bool qemu_rdma_post_send(RDMAContext *rdma,
> +                               struct ibv_send_wr *send_wr,
> +                               Error **errp)
> +{
> +    struct ibv_send_wr *bad_wr;
> +    uint64_t wr_id = send_wr->wr_id & RDMA_WRID_TYPE_MASK;
> +    const char *wr_desc;
> +    int ret;
> +
> +    switch (wr_id) {
> +    case RDMA_WRID_RDMA_WRITE:
> +        wr_desc = "RDMA write";
> +        break;
> +    case RDMA_WRID_SEND_CONTROL:
> +        wr_desc = "control send";
> +        break;
> +    default:
> +        g_assert_not_reached();
> +    }
> +
> +    ret = ibv_post_send(rdma->qp, send_wr, &bad_wr);
> +    if (ret == ENOMEM && rdma->nb_sent) {
> +        trace_qemu_rdma_post_send_queue_full(send_wr->wr_id, rdma->nb_sent);
> +        ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE, NULL);
> +        if (ret < 0) {
> +            error_setg(errp, "rdma migration: failed to make room for %s",
> +                       wr_desc);
> +            return false;
> +        }
> +        ret = ibv_post_send(rdma->qp, send_wr, &bad_wr);
> +    }
> +
> +    if (ret > 0) {
> +        error_setg_errno(errp, ret, "rdma migration: post %s failed",
> +                         wr_desc);
> +        return false;
> +    }
> +
> +    return true;
> +}
> +
>  /*
>   * Post a SEND message work request for the control channel
>   * containing some data and block until the post completes.
> @@ -1563,7 +1608,6 @@ static int qemu_rdma_post_send_control(RDMAContext 
> *rdma, uint8_t *buf,
>  {
>      int ret;
>      RDMAWorkRequestData *wr = &rdma->wr_data[RDMA_WRID_CONTROL];
> -    struct ibv_send_wr *bad_wr;
>      struct ibv_sge sge = {
>                             .addr = (uintptr_t)(wr->control),
>                             .length = head->len + sizeof(RDMAControlHeader),
> @@ -1595,11 +1639,7 @@ static int qemu_rdma_post_send_control(RDMAContext 
> *rdma, uint8_t *buf,
>          memcpy(wr->control + sizeof(RDMAControlHeader), buf, head->len);
>      }
>
> -
> -    ret = ibv_post_send(rdma->qp, &send_wr, &bad_wr);
> -
> -    if (ret > 0) {
> -        error_setg(errp, "Failed to use post IB SEND for control");
> +    if (!qemu_rdma_post_send(rdma, &send_wr, errp)) {
>          return -1;
>      }
>
> @@ -1859,7 +1899,6 @@ static int qemu_rdma_write_one(RDMAContext *rdma,
>  {
>      struct ibv_sge sge;
>      struct ibv_send_wr send_wr = { 0 };
> -    struct ibv_send_wr *bad_wr;
>      int reg_result_idx, ret;
>      uint64_t chunk, chunks;
>      uint64_t chunk_size = migrate_rdma_chunk_size();
> @@ -1873,7 +1912,6 @@ static int qemu_rdma_write_one(RDMAContext *rdma,
>                                 .repeat = 1,
>                               };
>
> -retry:
>      sge.addr = (uintptr_t)(block->local_host_addr +
>                              (current_addr - block->offset));
>      sge.length = length;
> @@ -2026,26 +2064,7 @@ retry:
>      trace_qemu_rdma_write_one_post(chunk, sge.addr, 
> send_wr.wr.rdma.remote_addr,
>                                     sge.length);
>
> -    /*
> -     * ibv_post_send() does not return negative error numbers,
> -     * per the specification they are positive - no idea why.
> -     */
> -    ret = ibv_post_send(rdma->qp, &send_wr, &bad_wr);
> -
> -    if (ret == ENOMEM) {
> -        trace_qemu_rdma_write_one_queue_full();
> -        ret = qemu_rdma_block_for_wrid(rdma, RDMA_WRID_RDMA_WRITE, NULL);
> -        if (ret < 0) {
> -            error_setg(errp, "rdma migration: failed to make "
> -                         "room in full send queue!");
> -            return -1;
> -        }
> -
> -        goto retry;
> -
> -    } else if (ret > 0) {
> -        error_setg_errno(errp, ret,
> -                         "rdma migration: post rdma write failed");
> +    if (!qemu_rdma_post_send(rdma, &send_wr, errp)) {
>          return -1;
>      }
>
> diff --git a/migration/trace-events b/migration/trace-events
> index bcc102e323..7197c9dc6d 100644
> --- a/migration/trace-events
> +++ b/migration/trace-events
> @@ -250,7 +250,7 @@ qemu_rdma_unregister_waiting_send(uint64_t chunk) 
> "Sending unregister for chunk:
>  qemu_rdma_unregister_waiting_complete(uint64_t chunk) "Unregister for chunk: 
> %" PRIu64 " complete."
>  qemu_rdma_write_flush(int sent) "sent total: %d"
>  qemu_rdma_write_one_post(uint64_t chunk, long addr, long remote, uint32_t 
> len) "Posting chunk: %" PRIu64 ", addr: 0x%lx remote: 0x%lx, bytes %" PRIu32
> -qemu_rdma_write_one_queue_full(void) ""
> +qemu_rdma_post_send_queue_full(uint64_t wr_id, int sent) "send queue full, 
> wr_id=%" PRIu64 ", outstanding writes=%d"
>  qemu_rdma_write_one_recvregres(int mykey, int theirkey, uint64_t chunk) 
> "Received registration result: my key: 0x%x their key 0x%x, chunk %" PRIu64
>  qemu_rdma_write_one_sendreg(uint64_t chunk, int len, int index, int64_t 
> offset) "Sending registration request chunk %" PRIu64 " for %d bytes, index: 
> %d, offset: %" PRId64
>  qemu_rdma_write_one_top(uint64_t chunks, uint64_t size) "Writing %" PRIu64 " 
> chunks, (%" PRIu64 " MB)"
> --
> 2.20.1

Reply via email to