1 /*- 2 * Copyright (c) 2018 VMware, Inc. All Rights Reserved. 3 * 4 * SPDX-License-Identifier: (BSD-2-Clause AND GPL-2.0) 5 */ 6 7 /* This file implements Queue accessor methods. */ 8 9 /* 10 * vmci_qpair is an interface that hides the queue pair internals. Rather than 11 * access each queue in a pair directly, operations are performed on the queue 12 * as a whole. This is simpler and less error-prone, and allows for future 13 * queue pair features to be added under the hood with no change to the client 14 * code. 15 */ 16 17 #include <sys/cdefs.h> 18 __FBSDID("$FreeBSD$"); 19 20 #include "vmci_kernel_api.h" 21 #include "vmci_kernel_defs.h" 22 #include "vmci_kernel_if.h" 23 #include "vmci_queue.h" 24 #include "vmci_queue_pair.h" 25 26 /* This structure is opaque to the clients. */ 27 struct vmci_qpair { 28 struct vmci_handle handle; 29 struct vmci_queue *produce_q; 30 struct vmci_queue *consume_q; 31 uint64_t produce_q_size; 32 uint64_t consume_q_size; 33 vmci_id peer; 34 uint32_t flags; 35 vmci_privilege_flags priv_flags; 36 uint32_t blocked; 37 vmci_event event; 38 }; 39 40 static void vmci_qpair_get_queue_headers(const struct vmci_qpair *qpair, 41 struct vmci_queue_header **produce_q_header, 42 struct vmci_queue_header **consume_q_header); 43 44 /* 45 *------------------------------------------------------------------------------ 46 * 47 * vmci_queue_add_producer_tail -- 48 * 49 * Helper routine to increment the Producer Tail. 50 * 51 * Results: 52 * VMCI_ERROR_NOT_FOUND if the vmm_world registered with the queue cannot 53 * be found. Otherwise VMCI_SUCCESS. 54 * 55 * Side effects: 56 * None. 57 * 58 *------------------------------------------------------------------------------ 59 */ 60 61 static inline int 62 vmci_queue_add_producer_tail(struct vmci_queue *queue, 63 size_t add, uint64_t queue_size) 64 { 65 66 vmci_queue_header_add_producer_tail(queue->q_header, add, queue_size); 67 return (VMCI_SUCCESS); 68 } 69 70 /* 71 *------------------------------------------------------------------------------ 72 * 73 * vmci_queue_add_consumer_head -- 74 * 75 * Helper routine to increment the Consumer Head. 76 * 77 * Results: 78 * VMCI_ERROR_NOT_FOUND if the vmm_world registered with the queue cannot 79 * be found. Otherwise VMCI_SUCCESS. 80 * 81 * Side effects: 82 * None. 83 * 84 *------------------------------------------------------------------------------ 85 */ 86 87 static inline int 88 vmci_queue_add_consumer_head(struct vmci_queue *queue, 89 size_t add, uint64_t queue_size) 90 { 91 92 vmci_queue_header_add_consumer_head(queue->q_header, add, queue_size); 93 return (VMCI_SUCCESS); 94 } 95 96 /* 97 *------------------------------------------------------------------------------ 98 * 99 * vmci_qpair_get_queue_headers -- 100 * 101 * Helper routine that will retrieve the produce and consume headers of a 102 * given queue pair. 103 * 104 * Results: 105 * VMCI_SUCCESS if either current or saved queue headers are found. 106 * Appropriate error code otherwise. 107 * 108 * Side effects: 109 * None. 110 * 111 *------------------------------------------------------------------------------ 112 */ 113 114 static void 115 vmci_qpair_get_queue_headers(const struct vmci_qpair *qpair, 116 struct vmci_queue_header **produce_q_header, 117 struct vmci_queue_header **consume_q_header) 118 { 119 120 ASSERT((qpair->produce_q != NULL) && (qpair->consume_q != NULL)); 121 *produce_q_header = qpair->produce_q->q_header; 122 *consume_q_header = qpair->consume_q->q_header; 123 } 124 125 /* 126 *------------------------------------------------------------------------------ 127 * 128 * vmci_qpair_alloc -- 129 * 130 * This is the client interface for allocating the memory for a vmci_qpair 131 * structure and then attaching to the underlying queue. If an error occurs 132 * allocating the memory for the vmci_qpair structure, no attempt is made to 133 * attach. If an error occurs attaching, then there's the vmci_qpair 134 * structure is freed. 135 * 136 * Results: 137 * An err, if < 0. 138 * 139 * Side effects: 140 * None. 141 * 142 *------------------------------------------------------------------------------ 143 */ 144 145 int 146 vmci_qpair_alloc(struct vmci_qpair **qpair, struct vmci_handle *handle, 147 uint64_t produce_q_size, uint64_t consume_q_size, vmci_id peer, 148 uint32_t flags, vmci_privilege_flags priv_flags) 149 { 150 struct vmci_qpair *my_qpair; 151 vmci_event_release_cb wakeup_cb; 152 void *client_data; 153 int retval; 154 155 /* 156 * Restrict the size of a queuepair. Though the device enforces a limit 157 * on the total amount of memory that can be allocated to queuepairs for 158 * a guest, we avoid unnecessarily allocating a lot of memory. Also, we 159 * try to allocate this memory before we make the queuepair allocation 160 * hypercall. 161 * 162 * (Note that this doesn't prevent all cases; a user with only this much 163 * physical memory could still get into trouble.) The error used by the 164 * device is NO_RESOURCES, so use that here too. 165 */ 166 167 if (produce_q_size + consume_q_size < 168 MAX(produce_q_size, consume_q_size) || 169 produce_q_size + consume_q_size > VMCI_MAX_GUEST_QP_MEMORY) 170 return (VMCI_ERROR_NO_RESOURCES); 171 172 if (flags & VMCI_QPFLAG_NONBLOCK) 173 return (VMCI_ERROR_INVALID_ARGS); 174 175 my_qpair = vmci_alloc_kernel_mem(sizeof(*my_qpair), VMCI_MEMORY_NORMAL); 176 if (!my_qpair) 177 return (VMCI_ERROR_NO_MEM); 178 179 my_qpair->produce_q_size = produce_q_size; 180 my_qpair->consume_q_size = consume_q_size; 181 my_qpair->peer = peer; 182 my_qpair->flags = flags; 183 my_qpair->priv_flags = priv_flags; 184 185 client_data = NULL; 186 wakeup_cb = NULL; 187 188 retval = vmci_queue_pair_alloc(handle, &my_qpair->produce_q, 189 my_qpair->produce_q_size, &my_qpair->consume_q, 190 my_qpair->consume_q_size, my_qpair->peer, my_qpair->flags, 191 my_qpair->priv_flags); 192 193 if (retval < VMCI_SUCCESS) { 194 vmci_free_kernel_mem(my_qpair, sizeof(*my_qpair)); 195 return (retval); 196 } 197 198 *qpair = my_qpair; 199 my_qpair->handle = *handle; 200 201 return (retval); 202 } 203 204 /* 205 *------------------------------------------------------------------------------ 206 * 207 * vmci_qpair_detach -- 208 * 209 * This is the client interface for detaching from a vmci_qpair. Note that 210 * this routine will free the memory allocated for the vmci_qpair structure, 211 * too. 212 * 213 * Results: 214 * An error, if < 0. 215 * 216 * Side effects: 217 * Will clear the caller's pointer to the vmci_qpair structure. 218 * 219 *------------------------------------------------------------------------------ 220 */ 221 222 int 223 vmci_qpair_detach(struct vmci_qpair **qpair) 224 { 225 struct vmci_qpair *old_qpair; 226 int result; 227 228 if (!qpair || !(*qpair)) 229 return (VMCI_ERROR_INVALID_ARGS); 230 231 old_qpair = *qpair; 232 result = vmci_queue_pair_detach(old_qpair->handle); 233 234 /* 235 * The guest can fail to detach for a number of reasons, and if it does 236 * so, it will cleanup the entry (if there is one). We need to release 237 * the qpair struct here; there isn't much the caller can do, and we 238 * don't want to leak. 239 */ 240 241 if (old_qpair->flags & VMCI_QPFLAG_LOCAL) 242 vmci_destroy_event(&old_qpair->event); 243 244 vmci_free_kernel_mem(old_qpair, sizeof(*old_qpair)); 245 *qpair = NULL; 246 247 return (result); 248 } 249 250 /* 251 *------------------------------------------------------------------------------ 252 * 253 * vmci_qpair_get_produce_indexes -- 254 * 255 * This is the client interface for getting the current indexes of the 256 * qpair from the point of the view of the caller as the producer. 257 * 258 * Results: 259 * err, if < 0 260 * Success otherwise. 261 * 262 * Side effects: 263 * None. 264 * 265 *------------------------------------------------------------------------------ 266 */ 267 268 int 269 vmci_qpair_get_produce_indexes(const struct vmci_qpair *qpair, 270 uint64_t *producer_tail, uint64_t *consumer_head) 271 { 272 struct vmci_queue_header *consume_q_header; 273 struct vmci_queue_header *produce_q_header; 274 275 if (!qpair) 276 return (VMCI_ERROR_INVALID_ARGS); 277 278 vmci_qpair_get_queue_headers(qpair, &produce_q_header, 279 &consume_q_header); 280 vmci_queue_header_get_pointers(produce_q_header, consume_q_header, 281 producer_tail, consumer_head); 282 283 if ((producer_tail && *producer_tail >= qpair->produce_q_size) || 284 (consumer_head && *consumer_head >= qpair->produce_q_size)) 285 return (VMCI_ERROR_INVALID_SIZE); 286 287 return (VMCI_SUCCESS); 288 } 289 290 /* 291 *------------------------------------------------------------------------------ 292 * 293 * vmci_qpair_get_consume_indexes -- 294 * 295 * This is the client interface for getting the current indexes of the 296 * QPair from the point of the view of the caller as the consumer. 297 * 298 * Results: 299 * err, if < 0 300 * Success otherwise. 301 * 302 * Side effects: 303 * None. 304 * 305 *------------------------------------------------------------------------------ 306 */ 307 308 int 309 vmci_qpair_get_consume_indexes(const struct vmci_qpair *qpair, 310 uint64_t *consumer_tail, uint64_t *producer_head) 311 { 312 struct vmci_queue_header *consume_q_header; 313 struct vmci_queue_header *produce_q_header; 314 315 if (!qpair) 316 return (VMCI_ERROR_INVALID_ARGS); 317 318 vmci_qpair_get_queue_headers(qpair, &produce_q_header, 319 &consume_q_header); 320 vmci_queue_header_get_pointers(consume_q_header, produce_q_header, 321 consumer_tail, producer_head); 322 323 if ((consumer_tail && *consumer_tail >= qpair->consume_q_size) || 324 (producer_head && *producer_head >= qpair->consume_q_size)) 325 return (VMCI_ERROR_INVALID_SIZE); 326 327 return (VMCI_SUCCESS); 328 } 329 330 /* 331 *------------------------------------------------------------------------------ 332 * 333 * vmci_qpair_produce_free_space -- 334 * 335 * This is the client interface for getting the amount of free space in the 336 * QPair from the point of the view of the caller as the producer which is 337 * the common case. 338 * 339 * Results: 340 * Err, if < 0. 341 * Full queue if = 0. 342 * Number of available bytes into which data can be enqueued if > 0. 343 * 344 * Side effects: 345 * None. 346 * 347 *------------------------------------------------------------------------------ 348 */ 349 350 int64_t 351 vmci_qpair_produce_free_space(const struct vmci_qpair *qpair) 352 { 353 struct vmci_queue_header *consume_q_header; 354 struct vmci_queue_header *produce_q_header; 355 int64_t result; 356 357 if (!qpair) 358 return (VMCI_ERROR_INVALID_ARGS); 359 360 vmci_qpair_get_queue_headers(qpair, &produce_q_header, 361 &consume_q_header); 362 result = vmci_queue_header_free_space(produce_q_header, consume_q_header, 363 qpair->produce_q_size); 364 365 return (result); 366 } 367 368 /* 369 *------------------------------------------------------------------------------ 370 * 371 * vmci_qpair_consume_free_space -- 372 * 373 * This is the client interface for getting the amount of free space in the 374 * QPair from the point of the view of the caller as the consumer which is 375 * not the common case (see vmci_qpair_Produce_free_space(), above). 376 * 377 * Results: 378 * Err, if < 0. 379 * Full queue if = 0. 380 * Number of available bytes into which data can be enqueued if > 0. 381 * 382 * Side effects: 383 * None. 384 * 385 *------------------------------------------------------------------------------ 386 */ 387 388 int64_t 389 vmci_qpair_consume_free_space(const struct vmci_qpair *qpair) 390 { 391 struct vmci_queue_header *consume_q_header; 392 struct vmci_queue_header *produce_q_header; 393 int64_t result; 394 395 if (!qpair) 396 return (VMCI_ERROR_INVALID_ARGS); 397 398 vmci_qpair_get_queue_headers(qpair, &produce_q_header, 399 &consume_q_header); 400 result = vmci_queue_header_free_space(consume_q_header, produce_q_header, 401 qpair->consume_q_size); 402 403 return (result); 404 } 405 406 /* 407 *------------------------------------------------------------------------------ 408 * 409 * vmci_qpair_produce_buf_ready -- 410 * 411 * This is the client interface for getting the amount of enqueued data in 412 * the QPair from the point of the view of the caller as the producer which 413 * is not the common case (see vmci_qpair_Consume_buf_ready(), above). 414 * 415 * Results: 416 * Err, if < 0. 417 * Empty queue if = 0. 418 * Number of bytes ready to be dequeued if > 0. 419 * 420 * Side effects: 421 * None. 422 * 423 *------------------------------------------------------------------------------ 424 */ 425 426 int64_t 427 vmci_qpair_produce_buf_ready(const struct vmci_qpair *qpair) 428 { 429 struct vmci_queue_header *consume_q_header; 430 struct vmci_queue_header *produce_q_header; 431 int64_t result; 432 433 if (!qpair) 434 return (VMCI_ERROR_INVALID_ARGS); 435 436 vmci_qpair_get_queue_headers(qpair, &produce_q_header, 437 &consume_q_header); 438 result = vmci_queue_header_buf_ready(produce_q_header, consume_q_header, 439 qpair->produce_q_size); 440 441 return (result); 442 } 443 444 /* 445 *------------------------------------------------------------------------------ 446 * 447 * vmci_qpair_consume_buf_ready -- 448 * 449 * This is the client interface for getting the amount of enqueued data in 450 * the QPair from the point of the view of the caller as the consumer which 451 * is the normal case. 452 * 453 * Results: 454 * Err, if < 0. 455 * Empty queue if = 0. 456 * Number of bytes ready to be dequeued if > 0. 457 * 458 * Side effects: 459 * None. 460 * 461 *------------------------------------------------------------------------------ 462 */ 463 464 int64_t 465 vmci_qpair_consume_buf_ready(const struct vmci_qpair *qpair) 466 { 467 struct vmci_queue_header *consume_q_header; 468 struct vmci_queue_header *produce_q_header; 469 int64_t result; 470 471 if (!qpair) 472 return (VMCI_ERROR_INVALID_ARGS); 473 474 vmci_qpair_get_queue_headers(qpair, &produce_q_header, 475 &consume_q_header); 476 result = vmci_queue_header_buf_ready(consume_q_header, produce_q_header, 477 qpair->consume_q_size); 478 479 return (result); 480 } 481 482 /* 483 *------------------------------------------------------------------------------ 484 * 485 * enqueue -- 486 * 487 * Enqueues a given buffer to the produce queue using the provided function. 488 * As many bytes as possible (space available in the queue) are enqueued. 489 * 490 * Results: 491 * VMCI_ERROR_QUEUEPAIR_NOSPACE if no space was available to enqueue data. 492 * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue 493 * (as defined by the queue size). 494 * VMCI_ERROR_INVALID_ARGS, if an error occured when accessing the buffer. 495 * VMCI_ERROR_QUEUEPAIR_NOTATTACHED, if the queue pair pages aren't 496 * available. 497 * Otherwise, the number of bytes written to the queue is returned. 498 * 499 * Side effects: 500 * Updates the tail pointer of the produce queue. 501 * 502 *------------------------------------------------------------------------------ 503 */ 504 505 static ssize_t 506 enqueue(struct vmci_queue *produce_q, struct vmci_queue *consume_q, 507 const uint64_t produce_q_size, const void *buf, size_t buf_size, 508 int buf_type, vmci_memcpy_to_queue_func memcpy_to_queue, bool can_block) 509 { 510 ssize_t result; 511 size_t written; 512 int64_t free_space; 513 uint64_t tail; 514 515 ASSERT((produce_q != NULL) && (consume_q != NULL)); 516 517 free_space = vmci_queue_header_free_space(produce_q->q_header, 518 consume_q->q_header, 519 produce_q_size); 520 if (free_space == 0) 521 return (VMCI_ERROR_QUEUEPAIR_NOSPACE); 522 523 if (free_space < VMCI_SUCCESS) 524 return ((ssize_t)free_space); 525 526 written = (size_t)(free_space > buf_size ? buf_size : free_space); 527 tail = vmci_queue_header_producer_tail(produce_q->q_header); 528 if (LIKELY(tail + written < produce_q_size)) 529 result = memcpy_to_queue(produce_q, tail, buf, 0, written, 530 buf_type, can_block); 531 else { 532 /* Tail pointer wraps around. */ 533 534 const size_t tmp = (size_t)(produce_q_size - tail); 535 536 result = memcpy_to_queue(produce_q, tail, buf, 0, tmp, buf_type, 537 can_block); 538 if (result >= VMCI_SUCCESS) 539 result = memcpy_to_queue(produce_q, 0, buf, tmp, 540 written - tmp, buf_type, can_block); 541 } 542 543 if (result < VMCI_SUCCESS) 544 return (result); 545 546 result = vmci_queue_add_producer_tail(produce_q, written, 547 produce_q_size); 548 if (result < VMCI_SUCCESS) 549 return (result); 550 return (written); 551 } 552 553 /* 554 *------------------------------------------------------------------------------ 555 * 556 * dequeue -- 557 * 558 * Dequeues data (if available) from the given consume queue. Writes data 559 * to the user provided buffer using the provided function. 560 * 561 * Results: 562 * VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue. 563 * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue 564 * (as defined by the queue size). 565 * VMCI_ERROR_INVALID_ARGS, if an error occured when accessing the buffer. 566 * VMCI_ERROR_NOT_FOUND, if the vmm_world registered with the queue pair 567 * cannot be found. 568 * Otherwise the number of bytes dequeued is returned. 569 * 570 * Side effects: 571 * Updates the head pointer of the consume queue. 572 * 573 *------------------------------------------------------------------------------ 574 */ 575 576 static ssize_t 577 dequeue(struct vmci_queue *produce_q, 578 struct vmci_queue *consume_q, const uint64_t consume_q_size, void *buf, 579 size_t buf_size, int buf_type, 580 vmci_memcpy_from_queue_func memcpy_from_queue, bool update_consumer, 581 bool can_block) 582 { 583 ssize_t result; 584 size_t read; 585 int64_t buf_ready; 586 uint64_t head; 587 588 ASSERT((produce_q != NULL) && (consume_q != NULL)); 589 590 buf_ready = vmci_queue_header_buf_ready(consume_q->q_header, 591 produce_q->q_header, consume_q_size); 592 if (buf_ready == 0) 593 return (VMCI_ERROR_QUEUEPAIR_NODATA); 594 if (buf_ready < VMCI_SUCCESS) 595 return ((ssize_t)buf_ready); 596 597 read = (size_t)(buf_ready > buf_size ? buf_size : buf_ready); 598 head = vmci_queue_header_consumer_head(produce_q->q_header); 599 if (LIKELY(head + read < consume_q_size)) 600 result = memcpy_from_queue(buf, 0, consume_q, head, read, 601 buf_type, can_block); 602 else { 603 /* Head pointer wraps around. */ 604 605 const size_t tmp = (size_t)(consume_q_size - head); 606 607 result = memcpy_from_queue(buf, 0, consume_q, head, tmp, 608 buf_type, can_block); 609 if (result >= VMCI_SUCCESS) 610 result = memcpy_from_queue(buf, tmp, consume_q, 0, 611 read - tmp, buf_type, can_block); 612 } 613 614 if (result < VMCI_SUCCESS) 615 return (result); 616 617 if (update_consumer) { 618 result = vmci_queue_add_consumer_head(produce_q, read, 619 consume_q_size); 620 if (result < VMCI_SUCCESS) 621 return (result); 622 } 623 624 return (read); 625 } 626 627 /* 628 *------------------------------------------------------------------------------ 629 * 630 * vmci_qpair_enqueue -- 631 * 632 * This is the client interface for enqueueing data into the queue. 633 * 634 * Results: 635 * Err, if < 0. 636 * Number of bytes enqueued if >= 0. 637 * 638 * Side effects: 639 * None. 640 * 641 *------------------------------------------------------------------------------ 642 */ 643 644 ssize_t 645 vmci_qpair_enqueue(struct vmci_qpair *qpair, const void *buf, size_t buf_size, 646 int buf_type) 647 { 648 ssize_t result; 649 650 if (!qpair || !buf) 651 return (VMCI_ERROR_INVALID_ARGS); 652 653 result = enqueue(qpair->produce_q, qpair->consume_q, 654 qpair->produce_q_size, buf, buf_size, buf_type, 655 qpair->flags & VMCI_QPFLAG_LOCAL? 656 vmci_memcpy_to_queue_local : vmci_memcpy_to_queue, 657 !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); 658 659 return (result); 660 } 661 662 /* 663 *------------------------------------------------------------------------------ 664 * 665 * vmci_qpair_dequeue -- 666 * 667 * This is the client interface for dequeueing data from the queue. 668 * 669 * Results: 670 * Err, if < 0. 671 * Number of bytes dequeued if >= 0. 672 * 673 * Side effects: 674 * None. 675 * 676 *------------------------------------------------------------------------------ 677 */ 678 679 ssize_t 680 vmci_qpair_dequeue(struct vmci_qpair *qpair, void *buf, size_t buf_size, 681 int buf_type) 682 { 683 ssize_t result; 684 685 if (!qpair || !buf) 686 return (VMCI_ERROR_INVALID_ARGS); 687 688 result = dequeue(qpair->produce_q, qpair->consume_q, 689 qpair->consume_q_size, buf, buf_size, buf_type, 690 qpair->flags & VMCI_QPFLAG_LOCAL? 691 vmci_memcpy_from_queue_local : vmci_memcpy_from_queue, true, 692 !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); 693 694 return (result); 695 } 696 697 /* 698 *------------------------------------------------------------------------------ 699 * 700 * vmci_qpair_peek -- 701 * 702 * This is the client interface for peeking into a queue. (I.e., copy 703 * data from the queue without updating the head pointer.) 704 * 705 * Results: 706 * Err, if < 0. 707 * Number of bytes peeked, if >= 0. 708 * 709 * Side effects: 710 * None. 711 * 712 *------------------------------------------------------------------------------ 713 */ 714 715 ssize_t 716 vmci_qpair_peek(struct vmci_qpair *qpair, void *buf, size_t buf_size, 717 int buf_type) 718 { 719 ssize_t result; 720 721 if (!qpair || !buf) 722 return (VMCI_ERROR_INVALID_ARGS); 723 724 result = dequeue(qpair->produce_q, qpair->consume_q, 725 qpair->consume_q_size, buf, buf_size, buf_type, 726 qpair->flags & VMCI_QPFLAG_LOCAL? 727 vmci_memcpy_from_queue_local : vmci_memcpy_from_queue, false, 728 !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); 729 730 return (result); 731 } 732 733 /* 734 *------------------------------------------------------------------------------ 735 * 736 * vmci_qpair_enquev -- 737 * 738 * This is the client interface for enqueueing data into the queue. 739 * 740 * Results: 741 * Err, if < 0. 742 * Number of bytes enqueued if >= 0. 743 * 744 * Side effects: 745 * None. 746 * 747 *------------------------------------------------------------------------------ 748 */ 749 750 ssize_t 751 vmci_qpair_enquev(struct vmci_qpair *qpair, void *iov, size_t iov_size, 752 int buf_type) 753 { 754 ssize_t result; 755 756 if (!qpair || !iov) 757 return (VMCI_ERROR_INVALID_ARGS); 758 759 result = enqueue(qpair->produce_q, qpair->consume_q, 760 qpair->produce_q_size, iov, iov_size, buf_type, 761 qpair->flags & VMCI_QPFLAG_LOCAL? 762 vmci_memcpy_to_queue_v_local : vmci_memcpy_to_queue_v, 763 !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); 764 765 return (result); 766 } 767 768 /* 769 *------------------------------------------------------------------------------ 770 * 771 * vmci_qpair_dequev -- 772 * 773 * This is the client interface for dequeueing data from the queue. 774 * 775 * Results: 776 * Err, if < 0. 777 * Number of bytes dequeued if >= 0. 778 * 779 * Side effects: 780 * None. 781 * 782 *------------------------------------------------------------------------------ 783 */ 784 785 ssize_t 786 vmci_qpair_dequev(struct vmci_qpair *qpair, void *iov, size_t iov_size, 787 int buf_type) 788 { 789 ssize_t result; 790 791 if (!qpair || !iov) 792 return (VMCI_ERROR_INVALID_ARGS); 793 794 result = dequeue(qpair->produce_q, qpair->consume_q, 795 qpair->consume_q_size, iov, iov_size, buf_type, 796 qpair->flags & VMCI_QPFLAG_LOCAL? 797 vmci_memcpy_from_queue_v_local : vmci_memcpy_from_queue_v, true, 798 !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); 799 800 return (result); 801 } 802 803 /* 804 *------------------------------------------------------------------------------ 805 * 806 * vmci_qpair_peekv -- 807 * 808 * This is the client interface for peeking into a queue. (I.e., copy 809 * data from the queue without updating the head pointer.) 810 * 811 * Results: 812 * Err, if < 0. 813 * Number of bytes peeked, if >= 0. 814 * 815 * Side effects: 816 * None. 817 * 818 *------------------------------------------------------------------------------ 819 */ 820 821 ssize_t 822 vmci_qpair_peekv(struct vmci_qpair *qpair, void *iov, size_t iov_size, 823 int buf_type) 824 { 825 ssize_t result; 826 827 if (!qpair || !iov) 828 return (VMCI_ERROR_INVALID_ARGS); 829 830 result = dequeue(qpair->produce_q, qpair->consume_q, 831 qpair->consume_q_size, iov, iov_size, buf_type, 832 qpair->flags & VMCI_QPFLAG_LOCAL? 833 vmci_memcpy_from_queue_v_local : vmci_memcpy_from_queue_v, false, 834 !(qpair->flags & VMCI_QPFLAG_NONBLOCK)); 835 836 return (result); 837 } 838