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