static size_t qemu_rdma_save_page(QEMUFile *f, void *opaque,

                                  ram_addr_t block_offset, ram_addr_t offset,

                                  size_t size, int *bytes_sent)

{

    QEMUFileRDMA *rfile = opaque;

    RDMAContext *rdma = rfile->rdma;

    int ret;



    CHECK_ERROR_STATE();



    qemu_fflush(f);



    if (size > 0) {

        /*

         * Add this page to the current 'chunk'. If the chunk

         * is full, or the page doen't belong to the current chunk,

         * an actual RDMA write will occur and a new chunk will be formed.

         */

        ret = qemu_rdma_write(f, rdma, block_offset, offset, size);

        if (ret < 0) {

            fprintf(stderr, "rdma migration: write error! %d\n", ret);

            goto err;

        }



        /*

         * We always return 1 bytes because the RDMA

         * protocol is completely asynchronous. We do not yet know

         * whether an  identified chunk is zero or not because we're

         * waiting for other pages to potentially be merged with

         * the current chunk. So, we have to call qemu_update_position()

         * later on when the actual write occurs.

         */

        if (bytes_sent) {

            *bytes_sent = 1;

        }

    } else {

        uint64_t index, chunk;



        /* TODO: Change QEMUFileOps prototype to be signed: size_t => long

        if (size < 0) {

            ret = qemu_rdma_drain_cq(f, rdma);

            if (ret < 0) {

                fprintf(stderr, "rdma: failed to synchronously drain"

                                " completion queue before unregistration.\n");

                goto err;

            }

        }

        */



        ret = qemu_rdma_search_ram_block(rdma, block_offset,

                                         offset, size, &index, &chunk);



        if (ret) {

            fprintf(stderr, "ram block search failed\n");

            goto err;

        }



        qemu_rdma_signal_unregister(rdma, index, chunk, 0);



        /*

         * TODO: Synchronous, guaranteed unregistration (should not occur during

         * fast-path). Otherwise, unregisters will process on the next call to

         * qemu_rdma_drain_cq()

        if (size < 0) {

            qemu_rdma_unregister_waiting(rdma);

        }

        */

    }



    /*

     * Drain the Completion Queue if possible, but do not block,

     * just poll.

     *

     * If nothing to poll, the end of the iteration will do this

     * again to make sure we don't overflow the request queue.

     */

    while (1) {

        uint64_t wr_id, wr_id_in;

        int ret = qemu_rdma_poll(rdma, &wr_id_in);

        if (ret < 0) {

            fprintf(stderr, "rdma migration: polling error! %d\n", ret);

            goto err;

        }



        wr_id = wr_id_in & RDMA_WRID_TYPE_MASK;



        if (wr_id == RDMA_WRID_NONE) {

            break;

        }

    }



    return RAM_SAVE_CONTROL_DELAYED;

err:

    rdma->error_state = ret;

    return ret;

}
