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
vmci_queue_add_producer_tail(struct vmci_queue * queue,size_t add,uint64_t queue_size)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
vmci_queue_add_consumer_head(struct vmci_queue * queue,size_t add,uint64_t queue_size)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
vmci_qpair_get_queue_headers(const struct vmci_qpair * qpair,struct vmci_queue_header ** produce_q_header,struct vmci_queue_header ** consume_q_header)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
vmci_qpair_alloc(struct vmci_qpair ** qpair,struct vmci_handle * handle,uint64_t produce_q_size,uint64_t consume_q_size,vmci_id peer,uint32_t flags,vmci_privilege_flags priv_flags)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
vmci_qpair_detach(struct vmci_qpair ** qpair)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
vmci_qpair_get_produce_indexes(const struct vmci_qpair * qpair,uint64_t * producer_tail,uint64_t * consumer_head)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
vmci_qpair_get_consume_indexes(const struct vmci_qpair * qpair,uint64_t * consumer_tail,uint64_t * producer_head)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
vmci_qpair_produce_free_space(const struct vmci_qpair * qpair)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
vmci_qpair_consume_free_space(const struct vmci_qpair * qpair)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
vmci_qpair_produce_buf_ready(const struct vmci_qpair * qpair)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
vmci_qpair_consume_buf_ready(const struct vmci_qpair * qpair)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
enqueue(struct vmci_queue * produce_q,struct vmci_queue * consume_q,const uint64_t produce_q_size,const void * buf,size_t buf_size,int buf_type,vmci_memcpy_to_queue_func memcpy_to_queue,bool can_block)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
dequeue(struct vmci_queue * produce_q,struct vmci_queue * consume_q,const uint64_t consume_q_size,void * buf,size_t buf_size,int buf_type,vmci_memcpy_from_queue_func memcpy_from_queue,bool update_consumer,bool can_block)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
vmci_qpair_enqueue(struct vmci_qpair * qpair,const void * buf,size_t buf_size,int buf_type)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
vmci_qpair_dequeue(struct vmci_qpair * qpair,void * buf,size_t buf_size,int buf_type)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
vmci_qpair_peek(struct vmci_qpair * qpair,void * buf,size_t buf_size,int buf_type)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
vmci_qpair_enquev(struct vmci_qpair * qpair,void * iov,size_t iov_size,int buf_type)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
vmci_qpair_dequev(struct vmci_qpair * qpair,void * iov,size_t iov_size,int buf_type)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
vmci_qpair_peekv(struct vmci_qpair * qpair,void * iov,size_t iov_size,int buf_type)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