static int archipelago_aio_segmented_rw(BDRVArchipelagoState *s,

                                        size_t count,

                                        off_t offset,

                                        ArchipelagoAIOCB *aio_cb,

                                        int op)

{

    int i, ret, segments_nr, last_segment_size;

    ArchipelagoSegmentedRequest *segreq;



    segreq = g_malloc(sizeof(ArchipelagoSegmentedRequest));



    if (op == ARCHIP_OP_FLUSH) {

        segments_nr = 1;

        segreq->ref = segments_nr;

        segreq->total = count;

        segreq->count = 0;

        segreq->failed = 0;

        ret = archipelago_submit_request(s, 0, count, offset, aio_cb,

                                           segreq, ARCHIP_OP_FLUSH);

        if (ret < 0) {

            goto err_exit;

        }

        return 0;

    }



    segments_nr = (int)(count / MAX_REQUEST_SIZE) + \

                  ((count % MAX_REQUEST_SIZE) ? 1 : 0);

    last_segment_size = (int)(count % MAX_REQUEST_SIZE);



    segreq->ref = segments_nr;

    segreq->total = count;

    segreq->count = 0;

    segreq->failed = 0;



    for (i = 0; i < segments_nr - 1; i++) {

        ret = archipelago_submit_request(s, i * MAX_REQUEST_SIZE,

                                           MAX_REQUEST_SIZE,

                                           offset + i * MAX_REQUEST_SIZE,

                                           aio_cb, segreq, op);



        if (ret < 0) {

            goto err_exit;

        }

    }



    if ((segments_nr > 1) && last_segment_size) {

        ret = archipelago_submit_request(s, i * MAX_REQUEST_SIZE,

                                           last_segment_size,

                                           offset + i * MAX_REQUEST_SIZE,

                                           aio_cb, segreq, op);

    } else if ((segments_nr > 1) && !last_segment_size) {

        ret = archipelago_submit_request(s, i * MAX_REQUEST_SIZE,

                                           MAX_REQUEST_SIZE,

                                           offset + i * MAX_REQUEST_SIZE,

                                           aio_cb, segreq, op);

    } else if (segments_nr == 1) {

            ret = archipelago_submit_request(s, 0, count, offset, aio_cb,

                                               segreq, op);

    }



    if (ret < 0) {

        goto err_exit;

    }



    return 0;



err_exit:

    __sync_add_and_fetch(&segreq->failed, 1);

    if (segments_nr == 1) {

        if (__sync_add_and_fetch(&segreq->ref, -1) == 0) {

            g_free(segreq);

        }

    } else {

        if ((__sync_add_and_fetch(&segreq->ref, -segments_nr + i)) == 0) {

            g_free(segreq);

        }

    }



    return ret;

}
