qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

xen-block.c (24950B)


      1 /*
      2  * Copyright (c) 2018  Citrix Systems Inc.
      3  * (c) Gerd Hoffmann <kraxel@redhat.com>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation; under version 2 of the License.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  * GNU General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License along
     15  * with this program; if not, see <http://www.gnu.org/licenses/>.
     16  *
     17  * Contributions after 2012-01-13 are licensed under the terms of the
     18  * GNU GPL, version 2 or (at your option) any later version.
     19  */
     20 
     21 #include "qemu/osdep.h"
     22 #include "qemu/error-report.h"
     23 #include "qemu/main-loop.h"
     24 #include "qemu/memalign.h"
     25 #include "qapi/error.h"
     26 #include "hw/xen/xen_common.h"
     27 #include "hw/block/xen_blkif.h"
     28 #include "sysemu/block-backend.h"
     29 #include "sysemu/iothread.h"
     30 #include "xen-block.h"
     31 
     32 typedef struct XenBlockRequest {
     33     blkif_request_t req;
     34     int16_t status;
     35     off_t start;
     36     QEMUIOVector v;
     37     void *buf;
     38     size_t size;
     39     int presync;
     40     int aio_inflight;
     41     int aio_errors;
     42     XenBlockDataPlane *dataplane;
     43     QLIST_ENTRY(XenBlockRequest) list;
     44     BlockAcctCookie acct;
     45 } XenBlockRequest;
     46 
     47 struct XenBlockDataPlane {
     48     XenDevice *xendev;
     49     XenEventChannel *event_channel;
     50     unsigned int *ring_ref;
     51     unsigned int nr_ring_ref;
     52     void *sring;
     53     int protocol;
     54     blkif_back_rings_t rings;
     55     int more_work;
     56     QLIST_HEAD(inflight_head, XenBlockRequest) inflight;
     57     QLIST_HEAD(freelist_head, XenBlockRequest) freelist;
     58     int requests_total;
     59     int requests_inflight;
     60     unsigned int max_requests;
     61     BlockBackend *blk;
     62     unsigned int sector_size;
     63     QEMUBH *bh;
     64     IOThread *iothread;
     65     AioContext *ctx;
     66 };
     67 
     68 static int xen_block_send_response(XenBlockRequest *request);
     69 
     70 static void reset_request(XenBlockRequest *request)
     71 {
     72     memset(&request->req, 0, sizeof(request->req));
     73     request->status = 0;
     74     request->start = 0;
     75     request->size = 0;
     76     request->presync = 0;
     77 
     78     request->aio_inflight = 0;
     79     request->aio_errors = 0;
     80 
     81     request->dataplane = NULL;
     82     memset(&request->list, 0, sizeof(request->list));
     83     memset(&request->acct, 0, sizeof(request->acct));
     84 
     85     qemu_iovec_reset(&request->v);
     86 }
     87 
     88 static XenBlockRequest *xen_block_start_request(XenBlockDataPlane *dataplane)
     89 {
     90     XenBlockRequest *request = NULL;
     91 
     92     if (QLIST_EMPTY(&dataplane->freelist)) {
     93         if (dataplane->requests_total >= dataplane->max_requests) {
     94             goto out;
     95         }
     96         /* allocate new struct */
     97         request = g_malloc0(sizeof(*request));
     98         request->dataplane = dataplane;
     99         /*
    100          * We cannot need more pages per requests than this, and since we
    101          * re-use requests, allocate the memory once here. It will be freed
    102          * xen_block_dataplane_destroy() when the request list is freed.
    103          */
    104         request->buf = qemu_memalign(XC_PAGE_SIZE,
    105                                      BLKIF_MAX_SEGMENTS_PER_REQUEST *
    106                                      XC_PAGE_SIZE);
    107         dataplane->requests_total++;
    108         qemu_iovec_init(&request->v, 1);
    109     } else {
    110         /* get one from freelist */
    111         request = QLIST_FIRST(&dataplane->freelist);
    112         QLIST_REMOVE(request, list);
    113     }
    114     QLIST_INSERT_HEAD(&dataplane->inflight, request, list);
    115     dataplane->requests_inflight++;
    116 
    117 out:
    118     return request;
    119 }
    120 
    121 static void xen_block_complete_request(XenBlockRequest *request)
    122 {
    123     XenBlockDataPlane *dataplane = request->dataplane;
    124 
    125     if (xen_block_send_response(request)) {
    126         Error *local_err = NULL;
    127 
    128         xen_device_notify_event_channel(dataplane->xendev,
    129                                         dataplane->event_channel,
    130                                         &local_err);
    131         if (local_err) {
    132             error_report_err(local_err);
    133         }
    134     }
    135 
    136     QLIST_REMOVE(request, list);
    137     dataplane->requests_inflight--;
    138     reset_request(request);
    139     request->dataplane = dataplane;
    140     QLIST_INSERT_HEAD(&dataplane->freelist, request, list);
    141 }
    142 
    143 /*
    144  * translate request into iovec + start offset
    145  * do sanity checks along the way
    146  */
    147 static int xen_block_parse_request(XenBlockRequest *request)
    148 {
    149     XenBlockDataPlane *dataplane = request->dataplane;
    150     size_t len;
    151     int i;
    152 
    153     switch (request->req.operation) {
    154     case BLKIF_OP_READ:
    155         break;
    156     case BLKIF_OP_FLUSH_DISKCACHE:
    157         request->presync = 1;
    158         if (!request->req.nr_segments) {
    159             return 0;
    160         }
    161         /* fall through */
    162     case BLKIF_OP_WRITE:
    163         break;
    164     case BLKIF_OP_DISCARD:
    165         return 0;
    166     default:
    167         error_report("error: unknown operation (%d)", request->req.operation);
    168         goto err;
    169     };
    170 
    171     if (request->req.operation != BLKIF_OP_READ &&
    172         !blk_is_writable(dataplane->blk)) {
    173         error_report("error: write req for ro device");
    174         goto err;
    175     }
    176 
    177     request->start = request->req.sector_number * dataplane->sector_size;
    178     for (i = 0; i < request->req.nr_segments; i++) {
    179         if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
    180             error_report("error: nr_segments too big");
    181             goto err;
    182         }
    183         if (request->req.seg[i].first_sect > request->req.seg[i].last_sect) {
    184             error_report("error: first > last sector");
    185             goto err;
    186         }
    187         if (request->req.seg[i].last_sect * dataplane->sector_size >=
    188             XC_PAGE_SIZE) {
    189             error_report("error: page crossing");
    190             goto err;
    191         }
    192 
    193         len = (request->req.seg[i].last_sect -
    194                request->req.seg[i].first_sect + 1) * dataplane->sector_size;
    195         request->size += len;
    196     }
    197     if (request->start + request->size > blk_getlength(dataplane->blk)) {
    198         error_report("error: access beyond end of file");
    199         goto err;
    200     }
    201     return 0;
    202 
    203 err:
    204     request->status = BLKIF_RSP_ERROR;
    205     return -1;
    206 }
    207 
    208 static int xen_block_copy_request(XenBlockRequest *request)
    209 {
    210     XenBlockDataPlane *dataplane = request->dataplane;
    211     XenDevice *xendev = dataplane->xendev;
    212     XenDeviceGrantCopySegment segs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
    213     int i, count;
    214     bool to_domain = (request->req.operation == BLKIF_OP_READ);
    215     void *virt = request->buf;
    216     Error *local_err = NULL;
    217 
    218     if (request->req.nr_segments == 0) {
    219         return 0;
    220     }
    221 
    222     count = request->req.nr_segments;
    223 
    224     for (i = 0; i < count; i++) {
    225         if (to_domain) {
    226             segs[i].dest.foreign.ref = request->req.seg[i].gref;
    227             segs[i].dest.foreign.offset = request->req.seg[i].first_sect *
    228                 dataplane->sector_size;
    229             segs[i].source.virt = virt;
    230         } else {
    231             segs[i].source.foreign.ref = request->req.seg[i].gref;
    232             segs[i].source.foreign.offset = request->req.seg[i].first_sect *
    233                 dataplane->sector_size;
    234             segs[i].dest.virt = virt;
    235         }
    236         segs[i].len = (request->req.seg[i].last_sect -
    237                        request->req.seg[i].first_sect + 1) *
    238                       dataplane->sector_size;
    239         virt += segs[i].len;
    240     }
    241 
    242     xen_device_copy_grant_refs(xendev, to_domain, segs, count, &local_err);
    243 
    244     if (local_err) {
    245         error_reportf_err(local_err, "failed to copy data: ");
    246 
    247         request->aio_errors++;
    248         return -1;
    249     }
    250 
    251     return 0;
    252 }
    253 
    254 static int xen_block_do_aio(XenBlockRequest *request);
    255 
    256 static void xen_block_complete_aio(void *opaque, int ret)
    257 {
    258     XenBlockRequest *request = opaque;
    259     XenBlockDataPlane *dataplane = request->dataplane;
    260 
    261     aio_context_acquire(dataplane->ctx);
    262 
    263     if (ret != 0) {
    264         error_report("%s I/O error",
    265                      request->req.operation == BLKIF_OP_READ ?
    266                      "read" : "write");
    267         request->aio_errors++;
    268     }
    269 
    270     request->aio_inflight--;
    271     if (request->presync) {
    272         request->presync = 0;
    273         xen_block_do_aio(request);
    274         goto done;
    275     }
    276     if (request->aio_inflight > 0) {
    277         goto done;
    278     }
    279 
    280     switch (request->req.operation) {
    281     case BLKIF_OP_READ:
    282         /* in case of failure request->aio_errors is increased */
    283         if (ret == 0) {
    284             xen_block_copy_request(request);
    285         }
    286         break;
    287     case BLKIF_OP_WRITE:
    288     case BLKIF_OP_FLUSH_DISKCACHE:
    289     default:
    290         break;
    291     }
    292 
    293     request->status = request->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
    294 
    295     switch (request->req.operation) {
    296     case BLKIF_OP_WRITE:
    297     case BLKIF_OP_FLUSH_DISKCACHE:
    298         if (!request->req.nr_segments) {
    299             break;
    300         }
    301         /* fall through */
    302     case BLKIF_OP_READ:
    303         if (request->status == BLKIF_RSP_OKAY) {
    304             block_acct_done(blk_get_stats(dataplane->blk), &request->acct);
    305         } else {
    306             block_acct_failed(blk_get_stats(dataplane->blk), &request->acct);
    307         }
    308         break;
    309     case BLKIF_OP_DISCARD:
    310     default:
    311         break;
    312     }
    313 
    314     xen_block_complete_request(request);
    315 
    316     if (dataplane->more_work) {
    317         qemu_bh_schedule(dataplane->bh);
    318     }
    319 
    320 done:
    321     aio_context_release(dataplane->ctx);
    322 }
    323 
    324 static bool xen_block_split_discard(XenBlockRequest *request,
    325                                     blkif_sector_t sector_number,
    326                                     uint64_t nr_sectors)
    327 {
    328     XenBlockDataPlane *dataplane = request->dataplane;
    329     int64_t byte_offset;
    330     int byte_chunk;
    331     uint64_t byte_remaining;
    332     uint64_t sec_start = sector_number;
    333     uint64_t sec_count = nr_sectors;
    334 
    335     /* Wrap around, or overflowing byte limit? */
    336     if (sec_start + sec_count < sec_count ||
    337         sec_start + sec_count > INT64_MAX / dataplane->sector_size) {
    338         return false;
    339     }
    340 
    341     byte_offset = sec_start * dataplane->sector_size;
    342     byte_remaining = sec_count * dataplane->sector_size;
    343 
    344     do {
    345         byte_chunk = byte_remaining > BDRV_REQUEST_MAX_BYTES ?
    346             BDRV_REQUEST_MAX_BYTES : byte_remaining;
    347         request->aio_inflight++;
    348         blk_aio_pdiscard(dataplane->blk, byte_offset, byte_chunk,
    349                          xen_block_complete_aio, request);
    350         byte_remaining -= byte_chunk;
    351         byte_offset += byte_chunk;
    352     } while (byte_remaining > 0);
    353 
    354     return true;
    355 }
    356 
    357 static int xen_block_do_aio(XenBlockRequest *request)
    358 {
    359     XenBlockDataPlane *dataplane = request->dataplane;
    360 
    361     if (request->req.nr_segments &&
    362         (request->req.operation == BLKIF_OP_WRITE ||
    363          request->req.operation == BLKIF_OP_FLUSH_DISKCACHE) &&
    364         xen_block_copy_request(request)) {
    365         goto err;
    366     }
    367 
    368     request->aio_inflight++;
    369     if (request->presync) {
    370         blk_aio_flush(request->dataplane->blk, xen_block_complete_aio,
    371                       request);
    372         return 0;
    373     }
    374 
    375     switch (request->req.operation) {
    376     case BLKIF_OP_READ:
    377         qemu_iovec_add(&request->v, request->buf, request->size);
    378         block_acct_start(blk_get_stats(dataplane->blk), &request->acct,
    379                          request->v.size, BLOCK_ACCT_READ);
    380         request->aio_inflight++;
    381         blk_aio_preadv(dataplane->blk, request->start, &request->v, 0,
    382                        xen_block_complete_aio, request);
    383         break;
    384     case BLKIF_OP_WRITE:
    385     case BLKIF_OP_FLUSH_DISKCACHE:
    386         if (!request->req.nr_segments) {
    387             break;
    388         }
    389 
    390         qemu_iovec_add(&request->v, request->buf, request->size);
    391         block_acct_start(blk_get_stats(dataplane->blk), &request->acct,
    392                          request->v.size,
    393                          request->req.operation == BLKIF_OP_WRITE ?
    394                          BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH);
    395         request->aio_inflight++;
    396         blk_aio_pwritev(dataplane->blk, request->start, &request->v, 0,
    397                         xen_block_complete_aio, request);
    398         break;
    399     case BLKIF_OP_DISCARD:
    400     {
    401         struct blkif_request_discard *req = (void *)&request->req;
    402         if (!xen_block_split_discard(request, req->sector_number,
    403                                      req->nr_sectors)) {
    404             goto err;
    405         }
    406         break;
    407     }
    408     default:
    409         /* unknown operation (shouldn't happen -- parse catches this) */
    410         goto err;
    411     }
    412 
    413     xen_block_complete_aio(request, 0);
    414 
    415     return 0;
    416 
    417 err:
    418     request->status = BLKIF_RSP_ERROR;
    419     xen_block_complete_request(request);
    420     return -1;
    421 }
    422 
    423 static int xen_block_send_response(XenBlockRequest *request)
    424 {
    425     XenBlockDataPlane *dataplane = request->dataplane;
    426     int send_notify = 0;
    427     int have_requests = 0;
    428     blkif_response_t *resp;
    429 
    430     /* Place on the response ring for the relevant domain. */
    431     switch (dataplane->protocol) {
    432     case BLKIF_PROTOCOL_NATIVE:
    433         resp = (blkif_response_t *)RING_GET_RESPONSE(
    434             &dataplane->rings.native,
    435             dataplane->rings.native.rsp_prod_pvt);
    436         break;
    437     case BLKIF_PROTOCOL_X86_32:
    438         resp = (blkif_response_t *)RING_GET_RESPONSE(
    439             &dataplane->rings.x86_32_part,
    440             dataplane->rings.x86_32_part.rsp_prod_pvt);
    441         break;
    442     case BLKIF_PROTOCOL_X86_64:
    443         resp = (blkif_response_t *)RING_GET_RESPONSE(
    444             &dataplane->rings.x86_64_part,
    445             dataplane->rings.x86_64_part.rsp_prod_pvt);
    446         break;
    447     default:
    448         return 0;
    449     }
    450 
    451     resp->id = request->req.id;
    452     resp->operation = request->req.operation;
    453     resp->status = request->status;
    454 
    455     dataplane->rings.common.rsp_prod_pvt++;
    456 
    457     RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&dataplane->rings.common,
    458                                          send_notify);
    459     if (dataplane->rings.common.rsp_prod_pvt ==
    460         dataplane->rings.common.req_cons) {
    461         /*
    462          * Tail check for pending requests. Allows frontend to avoid
    463          * notifications if requests are already in flight (lower
    464          * overheads and promotes batching).
    465          */
    466         RING_FINAL_CHECK_FOR_REQUESTS(&dataplane->rings.common,
    467                                       have_requests);
    468     } else if (RING_HAS_UNCONSUMED_REQUESTS(&dataplane->rings.common)) {
    469         have_requests = 1;
    470     }
    471 
    472     if (have_requests) {
    473         dataplane->more_work++;
    474     }
    475     return send_notify;
    476 }
    477 
    478 static int xen_block_get_request(XenBlockDataPlane *dataplane,
    479                                  XenBlockRequest *request, RING_IDX rc)
    480 {
    481     switch (dataplane->protocol) {
    482     case BLKIF_PROTOCOL_NATIVE: {
    483         blkif_request_t *req =
    484             RING_GET_REQUEST(&dataplane->rings.native, rc);
    485 
    486         memcpy(&request->req, req, sizeof(request->req));
    487         break;
    488     }
    489     case BLKIF_PROTOCOL_X86_32: {
    490         blkif_x86_32_request_t *req =
    491             RING_GET_REQUEST(&dataplane->rings.x86_32_part, rc);
    492 
    493         blkif_get_x86_32_req(&request->req, req);
    494         break;
    495     }
    496     case BLKIF_PROTOCOL_X86_64: {
    497         blkif_x86_64_request_t *req =
    498             RING_GET_REQUEST(&dataplane->rings.x86_64_part, rc);
    499 
    500         blkif_get_x86_64_req(&request->req, req);
    501         break;
    502     }
    503     }
    504     /* Prevent the compiler from accessing the on-ring fields instead. */
    505     barrier();
    506     return 0;
    507 }
    508 
    509 /*
    510  * Threshold of in-flight requests above which we will start using
    511  * blk_io_plug()/blk_io_unplug() to batch requests.
    512  */
    513 #define IO_PLUG_THRESHOLD 1
    514 
    515 static bool xen_block_handle_requests(XenBlockDataPlane *dataplane)
    516 {
    517     RING_IDX rc, rp;
    518     XenBlockRequest *request;
    519     int inflight_atstart = dataplane->requests_inflight;
    520     int batched = 0;
    521     bool done_something = false;
    522 
    523     dataplane->more_work = 0;
    524 
    525     rc = dataplane->rings.common.req_cons;
    526     rp = dataplane->rings.common.sring->req_prod;
    527     xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
    528 
    529     /*
    530      * If there was more than IO_PLUG_THRESHOLD requests in flight
    531      * when we got here, this is an indication that there the bottleneck
    532      * is below us, so it's worth beginning to batch up I/O requests
    533      * rather than submitting them immediately. The maximum number
    534      * of requests we're willing to batch is the number already in
    535      * flight, so it can grow up to max_requests when the bottleneck
    536      * is below us.
    537      */
    538     if (inflight_atstart > IO_PLUG_THRESHOLD) {
    539         blk_io_plug(dataplane->blk);
    540     }
    541     while (rc != rp) {
    542         /* pull request from ring */
    543         if (RING_REQUEST_CONS_OVERFLOW(&dataplane->rings.common, rc)) {
    544             break;
    545         }
    546         request = xen_block_start_request(dataplane);
    547         if (request == NULL) {
    548             dataplane->more_work++;
    549             break;
    550         }
    551         xen_block_get_request(dataplane, request, rc);
    552         dataplane->rings.common.req_cons = ++rc;
    553         done_something = true;
    554 
    555         /* parse them */
    556         if (xen_block_parse_request(request) != 0) {
    557             switch (request->req.operation) {
    558             case BLKIF_OP_READ:
    559                 block_acct_invalid(blk_get_stats(dataplane->blk),
    560                                    BLOCK_ACCT_READ);
    561                 break;
    562             case BLKIF_OP_WRITE:
    563                 block_acct_invalid(blk_get_stats(dataplane->blk),
    564                                    BLOCK_ACCT_WRITE);
    565                 break;
    566             case BLKIF_OP_FLUSH_DISKCACHE:
    567                 block_acct_invalid(blk_get_stats(dataplane->blk),
    568                                    BLOCK_ACCT_FLUSH);
    569             default:
    570                 break;
    571             };
    572 
    573             xen_block_complete_request(request);
    574             continue;
    575         }
    576 
    577         if (inflight_atstart > IO_PLUG_THRESHOLD &&
    578             batched >= inflight_atstart) {
    579             blk_io_unplug(dataplane->blk);
    580         }
    581         xen_block_do_aio(request);
    582         if (inflight_atstart > IO_PLUG_THRESHOLD) {
    583             if (batched >= inflight_atstart) {
    584                 blk_io_plug(dataplane->blk);
    585                 batched = 0;
    586             } else {
    587                 batched++;
    588             }
    589         }
    590     }
    591     if (inflight_atstart > IO_PLUG_THRESHOLD) {
    592         blk_io_unplug(dataplane->blk);
    593     }
    594 
    595     return done_something;
    596 }
    597 
    598 static void xen_block_dataplane_bh(void *opaque)
    599 {
    600     XenBlockDataPlane *dataplane = opaque;
    601 
    602     aio_context_acquire(dataplane->ctx);
    603     xen_block_handle_requests(dataplane);
    604     aio_context_release(dataplane->ctx);
    605 }
    606 
    607 static bool xen_block_dataplane_event(void *opaque)
    608 {
    609     XenBlockDataPlane *dataplane = opaque;
    610 
    611     return xen_block_handle_requests(dataplane);
    612 }
    613 
    614 XenBlockDataPlane *xen_block_dataplane_create(XenDevice *xendev,
    615                                               BlockBackend *blk,
    616                                               unsigned int sector_size,
    617                                               IOThread *iothread)
    618 {
    619     XenBlockDataPlane *dataplane = g_new0(XenBlockDataPlane, 1);
    620 
    621     dataplane->xendev = xendev;
    622     dataplane->blk = blk;
    623     dataplane->sector_size = sector_size;
    624 
    625     QLIST_INIT(&dataplane->inflight);
    626     QLIST_INIT(&dataplane->freelist);
    627 
    628     if (iothread) {
    629         dataplane->iothread = iothread;
    630         object_ref(OBJECT(dataplane->iothread));
    631         dataplane->ctx = iothread_get_aio_context(dataplane->iothread);
    632     } else {
    633         dataplane->ctx = qemu_get_aio_context();
    634     }
    635     dataplane->bh = aio_bh_new(dataplane->ctx, xen_block_dataplane_bh,
    636                                dataplane);
    637 
    638     return dataplane;
    639 }
    640 
    641 void xen_block_dataplane_destroy(XenBlockDataPlane *dataplane)
    642 {
    643     XenBlockRequest *request;
    644 
    645     if (!dataplane) {
    646         return;
    647     }
    648 
    649     while (!QLIST_EMPTY(&dataplane->freelist)) {
    650         request = QLIST_FIRST(&dataplane->freelist);
    651         QLIST_REMOVE(request, list);
    652         qemu_iovec_destroy(&request->v);
    653         qemu_vfree(request->buf);
    654         g_free(request);
    655     }
    656 
    657     qemu_bh_delete(dataplane->bh);
    658     if (dataplane->iothread) {
    659         object_unref(OBJECT(dataplane->iothread));
    660     }
    661 
    662     g_free(dataplane);
    663 }
    664 
    665 void xen_block_dataplane_stop(XenBlockDataPlane *dataplane)
    666 {
    667     XenDevice *xendev;
    668 
    669     if (!dataplane) {
    670         return;
    671     }
    672 
    673     xendev = dataplane->xendev;
    674 
    675     aio_context_acquire(dataplane->ctx);
    676     if (dataplane->event_channel) {
    677         /* Only reason for failure is a NULL channel */
    678         xen_device_set_event_channel_context(xendev, dataplane->event_channel,
    679                                              qemu_get_aio_context(),
    680                                              &error_abort);
    681     }
    682     /* Xen doesn't have multiple users for nodes, so this can't fail */
    683     blk_set_aio_context(dataplane->blk, qemu_get_aio_context(), &error_abort);
    684     aio_context_release(dataplane->ctx);
    685 
    686     /*
    687      * Now that the context has been moved onto the main thread, cancel
    688      * further processing.
    689      */
    690     qemu_bh_cancel(dataplane->bh);
    691 
    692     if (dataplane->event_channel) {
    693         Error *local_err = NULL;
    694 
    695         xen_device_unbind_event_channel(xendev, dataplane->event_channel,
    696                                         &local_err);
    697         dataplane->event_channel = NULL;
    698 
    699         if (local_err) {
    700             error_report_err(local_err);
    701         }
    702     }
    703 
    704     if (dataplane->sring) {
    705         Error *local_err = NULL;
    706 
    707         xen_device_unmap_grant_refs(xendev, dataplane->sring,
    708                                     dataplane->nr_ring_ref, &local_err);
    709         dataplane->sring = NULL;
    710 
    711         if (local_err) {
    712             error_report_err(local_err);
    713         }
    714     }
    715 
    716     g_free(dataplane->ring_ref);
    717     dataplane->ring_ref = NULL;
    718 }
    719 
    720 void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
    721                                const unsigned int ring_ref[],
    722                                unsigned int nr_ring_ref,
    723                                unsigned int event_channel,
    724                                unsigned int protocol,
    725                                Error **errp)
    726 {
    727     ERRP_GUARD();
    728     XenDevice *xendev = dataplane->xendev;
    729     AioContext *old_context;
    730     unsigned int ring_size;
    731     unsigned int i;
    732 
    733     dataplane->nr_ring_ref = nr_ring_ref;
    734     dataplane->ring_ref = g_new(unsigned int, nr_ring_ref);
    735 
    736     for (i = 0; i < nr_ring_ref; i++) {
    737         dataplane->ring_ref[i] = ring_ref[i];
    738     }
    739 
    740     dataplane->protocol = protocol;
    741 
    742     ring_size = XC_PAGE_SIZE * dataplane->nr_ring_ref;
    743     switch (dataplane->protocol) {
    744     case BLKIF_PROTOCOL_NATIVE:
    745     {
    746         dataplane->max_requests = __CONST_RING_SIZE(blkif, ring_size);
    747         break;
    748     }
    749     case BLKIF_PROTOCOL_X86_32:
    750     {
    751         dataplane->max_requests = __CONST_RING_SIZE(blkif_x86_32, ring_size);
    752         break;
    753     }
    754     case BLKIF_PROTOCOL_X86_64:
    755     {
    756         dataplane->max_requests = __CONST_RING_SIZE(blkif_x86_64, ring_size);
    757         break;
    758     }
    759     default:
    760         error_setg(errp, "unknown protocol %u", dataplane->protocol);
    761         return;
    762     }
    763 
    764     xen_device_set_max_grant_refs(xendev, dataplane->nr_ring_ref,
    765                                   errp);
    766     if (*errp) {
    767         goto stop;
    768     }
    769 
    770     dataplane->sring = xen_device_map_grant_refs(xendev,
    771                                               dataplane->ring_ref,
    772                                               dataplane->nr_ring_ref,
    773                                               PROT_READ | PROT_WRITE,
    774                                               errp);
    775     if (*errp) {
    776         goto stop;
    777     }
    778 
    779     switch (dataplane->protocol) {
    780     case BLKIF_PROTOCOL_NATIVE:
    781     {
    782         blkif_sring_t *sring_native = dataplane->sring;
    783 
    784         BACK_RING_INIT(&dataplane->rings.native, sring_native, ring_size);
    785         break;
    786     }
    787     case BLKIF_PROTOCOL_X86_32:
    788     {
    789         blkif_x86_32_sring_t *sring_x86_32 = dataplane->sring;
    790 
    791         BACK_RING_INIT(&dataplane->rings.x86_32_part, sring_x86_32,
    792                        ring_size);
    793         break;
    794     }
    795     case BLKIF_PROTOCOL_X86_64:
    796     {
    797         blkif_x86_64_sring_t *sring_x86_64 = dataplane->sring;
    798 
    799         BACK_RING_INIT(&dataplane->rings.x86_64_part, sring_x86_64,
    800                        ring_size);
    801         break;
    802     }
    803     }
    804 
    805     dataplane->event_channel =
    806         xen_device_bind_event_channel(xendev, event_channel,
    807                                       xen_block_dataplane_event, dataplane,
    808                                       errp);
    809     if (*errp) {
    810         goto stop;
    811     }
    812 
    813     old_context = blk_get_aio_context(dataplane->blk);
    814     aio_context_acquire(old_context);
    815     /* If other users keep the BlockBackend in the iothread, that's ok */
    816     blk_set_aio_context(dataplane->blk, dataplane->ctx, NULL);
    817     aio_context_release(old_context);
    818 
    819     /* Only reason for failure is a NULL channel */
    820     aio_context_acquire(dataplane->ctx);
    821     xen_device_set_event_channel_context(xendev, dataplane->event_channel,
    822                                          dataplane->ctx, &error_abort);
    823     aio_context_release(dataplane->ctx);
    824 
    825     return;
    826 
    827 stop:
    828     xen_block_dataplane_stop(dataplane);
    829 }