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