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 occurred 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 occurred 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 }
Cache object: c0ff588dc80d82f2fd8c26d760dcf49e
|