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