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