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