xref: /freebsd/sys/dev/vmware/vmci/vmci_qpair.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
163a93856SMark Peek /*-
23eeb7511SMark Peek  * Copyright (c) 2018 VMware, Inc.
363a93856SMark Peek  *
48c302b2eSMark Peek  * SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0)
563a93856SMark Peek  */
663a93856SMark Peek 
763a93856SMark Peek /* This file implements Queue accessor methods. */
863a93856SMark Peek 
963a93856SMark Peek /*
1063a93856SMark Peek  * vmci_qpair is an interface that hides the queue pair internals. Rather than
1163a93856SMark Peek  * access each queue in a pair directly, operations are performed on the queue
1263a93856SMark Peek  * as a whole. This is simpler and less error-prone, and allows for future
1363a93856SMark Peek  * queue pair features to be added under the hood with no change to the client
1463a93856SMark Peek  * code.
1563a93856SMark Peek  */
1663a93856SMark Peek 
1763a93856SMark Peek #include <sys/cdefs.h>
1863a93856SMark Peek #include "vmci_kernel_api.h"
1963a93856SMark Peek #include "vmci_kernel_defs.h"
2063a93856SMark Peek #include "vmci_kernel_if.h"
2163a93856SMark Peek #include "vmci_queue.h"
2263a93856SMark Peek #include "vmci_queue_pair.h"
2363a93856SMark Peek 
2463a93856SMark Peek /* This structure is opaque to the clients. */
2563a93856SMark Peek struct vmci_qpair {
2663a93856SMark Peek 	struct vmci_handle	handle;
2763a93856SMark Peek 	struct vmci_queue	*produce_q;
2863a93856SMark Peek 	struct vmci_queue	*consume_q;
2963a93856SMark Peek 	uint64_t		produce_q_size;
3063a93856SMark Peek 	uint64_t		consume_q_size;
3163a93856SMark Peek 	vmci_id			peer;
3263a93856SMark Peek 	uint32_t		flags;
3363a93856SMark Peek 	vmci_privilege_flags	priv_flags;
3463a93856SMark Peek 	uint32_t		blocked;
3563a93856SMark Peek 	vmci_event		event;
3663a93856SMark Peek };
3763a93856SMark Peek 
3863a93856SMark Peek static void	vmci_qpair_get_queue_headers(const struct vmci_qpair *qpair,
3963a93856SMark Peek 		    struct vmci_queue_header **produce_q_header,
4063a93856SMark Peek 		    struct vmci_queue_header **consume_q_header);
4163a93856SMark Peek 
4263a93856SMark Peek /*
4363a93856SMark Peek  *------------------------------------------------------------------------------
4463a93856SMark Peek  *
4563a93856SMark Peek  * vmci_queue_add_producer_tail --
4663a93856SMark Peek  *
4763a93856SMark Peek  *     Helper routine to increment the Producer Tail.
4863a93856SMark Peek  *
4963a93856SMark Peek  * Results:
5063a93856SMark Peek  *     VMCI_ERROR_NOT_FOUND if the vmm_world registered with the queue cannot
5163a93856SMark Peek  *     be found. Otherwise VMCI_SUCCESS.
5263a93856SMark Peek  *
5363a93856SMark Peek  * Side effects:
5463a93856SMark Peek  *     None.
5563a93856SMark Peek  *
5663a93856SMark Peek  *------------------------------------------------------------------------------
5763a93856SMark Peek  */
5863a93856SMark Peek 
5963a93856SMark Peek static inline int
vmci_queue_add_producer_tail(struct vmci_queue * queue,size_t add,uint64_t queue_size)6063a93856SMark Peek vmci_queue_add_producer_tail(struct vmci_queue *queue,
6163a93856SMark Peek     size_t add, uint64_t queue_size)
6263a93856SMark Peek {
6363a93856SMark Peek 
6463a93856SMark Peek 	vmci_queue_header_add_producer_tail(queue->q_header, add, queue_size);
6563a93856SMark Peek 	return (VMCI_SUCCESS);
6663a93856SMark Peek }
6763a93856SMark Peek 
6863a93856SMark Peek /*
6963a93856SMark Peek  *------------------------------------------------------------------------------
7063a93856SMark Peek  *
7163a93856SMark Peek  * vmci_queue_add_consumer_head --
7263a93856SMark Peek  *
7363a93856SMark Peek  *     Helper routine to increment the Consumer Head.
7463a93856SMark Peek  *
7563a93856SMark Peek  * Results:
7663a93856SMark Peek  *     VMCI_ERROR_NOT_FOUND if the vmm_world registered with the queue cannot
7763a93856SMark Peek  *     be found. Otherwise VMCI_SUCCESS.
7863a93856SMark Peek  *
7963a93856SMark Peek  * Side effects:
8063a93856SMark Peek  *     None.
8163a93856SMark Peek  *
8263a93856SMark Peek  *------------------------------------------------------------------------------
8363a93856SMark Peek  */
8463a93856SMark Peek 
8563a93856SMark Peek static inline int
vmci_queue_add_consumer_head(struct vmci_queue * queue,size_t add,uint64_t queue_size)8663a93856SMark Peek vmci_queue_add_consumer_head(struct vmci_queue *queue,
8763a93856SMark Peek     size_t add, uint64_t queue_size)
8863a93856SMark Peek {
8963a93856SMark Peek 
9063a93856SMark Peek 	vmci_queue_header_add_consumer_head(queue->q_header, add, queue_size);
9163a93856SMark Peek 	return (VMCI_SUCCESS);
9263a93856SMark Peek }
9363a93856SMark Peek 
9463a93856SMark Peek /*
9563a93856SMark Peek  *------------------------------------------------------------------------------
9663a93856SMark Peek  *
9763a93856SMark Peek  * vmci_qpair_get_queue_headers --
9863a93856SMark Peek  *
9963a93856SMark Peek  *     Helper routine that will retrieve the produce and consume headers of a
10063a93856SMark Peek  *     given queue pair.
10163a93856SMark Peek  *
10263a93856SMark Peek  * Results:
10363a93856SMark Peek  *     VMCI_SUCCESS if either current or saved queue headers are found.
10463a93856SMark Peek  *     Appropriate error code otherwise.
10563a93856SMark Peek  *
10663a93856SMark Peek  * Side effects:
10763a93856SMark Peek  *     None.
10863a93856SMark Peek  *
10963a93856SMark Peek  *------------------------------------------------------------------------------
11063a93856SMark Peek  */
11163a93856SMark Peek 
11263a93856SMark Peek 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)11363a93856SMark Peek vmci_qpair_get_queue_headers(const struct vmci_qpair *qpair,
11463a93856SMark Peek     struct vmci_queue_header **produce_q_header,
11563a93856SMark Peek     struct vmci_queue_header **consume_q_header)
11663a93856SMark Peek {
11763a93856SMark Peek 
11863a93856SMark Peek 	ASSERT((qpair->produce_q != NULL) && (qpair->consume_q != NULL));
11963a93856SMark Peek 	*produce_q_header = qpair->produce_q->q_header;
12063a93856SMark Peek 	*consume_q_header = qpair->consume_q->q_header;
12163a93856SMark Peek }
12263a93856SMark Peek 
12363a93856SMark Peek /*
12463a93856SMark Peek  *------------------------------------------------------------------------------
12563a93856SMark Peek  *
12663a93856SMark Peek  * vmci_qpair_alloc --
12763a93856SMark Peek  *
12863a93856SMark Peek  *     This is the client interface for allocating the memory for a vmci_qpair
12963a93856SMark Peek  *     structure and then attaching to the underlying queue. If an error occurs
13063a93856SMark Peek  *     allocating the memory for the vmci_qpair structure, no attempt is made to
13163a93856SMark Peek  *     attach. If an error occurs attaching, then there's the vmci_qpair
13263a93856SMark Peek  *     structure is freed.
13363a93856SMark Peek  *
13463a93856SMark Peek  * Results:
13563a93856SMark Peek  *     An err, if < 0.
13663a93856SMark Peek  *
13763a93856SMark Peek  * Side effects:
13863a93856SMark Peek  *     None.
13963a93856SMark Peek  *
14063a93856SMark Peek  *------------------------------------------------------------------------------
14163a93856SMark Peek  */
14263a93856SMark Peek 
14363a93856SMark Peek 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)14463a93856SMark Peek vmci_qpair_alloc(struct vmci_qpair **qpair, struct vmci_handle *handle,
14563a93856SMark Peek     uint64_t produce_q_size, uint64_t consume_q_size, vmci_id peer,
14663a93856SMark Peek     uint32_t flags, vmci_privilege_flags priv_flags)
14763a93856SMark Peek {
14863a93856SMark Peek 	struct vmci_qpair *my_qpair;
14963a93856SMark Peek 	int retval;
15063a93856SMark Peek 
15163a93856SMark Peek 	/*
15263a93856SMark Peek 	 * Restrict the size of a queuepair. Though the device enforces a limit
15363a93856SMark Peek 	 * on the total amount of memory that can be allocated to queuepairs for
15463a93856SMark Peek 	 * a guest, we avoid unnecessarily allocating a lot of memory. Also, we
15563a93856SMark Peek 	 * try to allocate this memory before we make the queuepair allocation
15663a93856SMark Peek 	 * hypercall.
15763a93856SMark Peek 	 *
15863a93856SMark Peek 	 * (Note that this doesn't prevent all cases; a user with only this much
15963a93856SMark Peek 	 * physical memory could still get into trouble.) The error used by the
16063a93856SMark Peek 	 * device is NO_RESOURCES, so use that here too.
16163a93856SMark Peek 	 */
16263a93856SMark Peek 
16363a93856SMark Peek 	if (produce_q_size + consume_q_size <
16463a93856SMark Peek 	    MAX(produce_q_size, consume_q_size) ||
16563a93856SMark Peek 	    produce_q_size + consume_q_size > VMCI_MAX_GUEST_QP_MEMORY)
16663a93856SMark Peek 		return (VMCI_ERROR_NO_RESOURCES);
16763a93856SMark Peek 
16863a93856SMark Peek 	if (flags & VMCI_QPFLAG_NONBLOCK)
16963a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
17063a93856SMark Peek 
17163a93856SMark Peek 	my_qpair = vmci_alloc_kernel_mem(sizeof(*my_qpair), VMCI_MEMORY_NORMAL);
17263a93856SMark Peek 	if (!my_qpair)
17363a93856SMark Peek 		return (VMCI_ERROR_NO_MEM);
17463a93856SMark Peek 
17563a93856SMark Peek 	my_qpair->produce_q_size = produce_q_size;
17663a93856SMark Peek 	my_qpair->consume_q_size = consume_q_size;
17763a93856SMark Peek 	my_qpair->peer = peer;
17863a93856SMark Peek 	my_qpair->flags = flags;
17963a93856SMark Peek 	my_qpair->priv_flags = priv_flags;
18063a93856SMark Peek 
18163a93856SMark Peek 	retval = vmci_queue_pair_alloc(handle, &my_qpair->produce_q,
18263a93856SMark Peek 	    my_qpair->produce_q_size, &my_qpair->consume_q,
18363a93856SMark Peek 	    my_qpair->consume_q_size, my_qpair->peer, my_qpair->flags,
18463a93856SMark Peek 	    my_qpair->priv_flags);
18563a93856SMark Peek 
18663a93856SMark Peek 	if (retval < VMCI_SUCCESS) {
18763a93856SMark Peek 		vmci_free_kernel_mem(my_qpair, sizeof(*my_qpair));
18863a93856SMark Peek 		return (retval);
18963a93856SMark Peek 	}
19063a93856SMark Peek 
19163a93856SMark Peek 	*qpair = my_qpair;
19263a93856SMark Peek 	my_qpair->handle = *handle;
19363a93856SMark Peek 
19463a93856SMark Peek 	return (retval);
19563a93856SMark Peek }
19663a93856SMark Peek 
19763a93856SMark Peek /*
19863a93856SMark Peek  *------------------------------------------------------------------------------
19963a93856SMark Peek  *
20063a93856SMark Peek  * vmci_qpair_detach --
20163a93856SMark Peek  *
20263a93856SMark Peek  *     This is the client interface for detaching from a vmci_qpair. Note that
20363a93856SMark Peek  *     this routine will free the memory allocated for the vmci_qpair structure,
20463a93856SMark Peek  *     too.
20563a93856SMark Peek  *
20663a93856SMark Peek  * Results:
20763a93856SMark Peek  *     An error, if < 0.
20863a93856SMark Peek  *
20963a93856SMark Peek  * Side effects:
21063a93856SMark Peek  *     Will clear the caller's pointer to the vmci_qpair structure.
21163a93856SMark Peek  *
21263a93856SMark Peek  *------------------------------------------------------------------------------
21363a93856SMark Peek  */
21463a93856SMark Peek 
21563a93856SMark Peek int
vmci_qpair_detach(struct vmci_qpair ** qpair)21663a93856SMark Peek vmci_qpair_detach(struct vmci_qpair **qpair)
21763a93856SMark Peek {
21863a93856SMark Peek 	struct vmci_qpair *old_qpair;
21963a93856SMark Peek 	int result;
22063a93856SMark Peek 
22163a93856SMark Peek 	if (!qpair || !(*qpair))
22263a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
22363a93856SMark Peek 
22463a93856SMark Peek 	old_qpair = *qpair;
22563a93856SMark Peek 	result = vmci_queue_pair_detach(old_qpair->handle);
22663a93856SMark Peek 
22763a93856SMark Peek 	/*
22863a93856SMark Peek 	 * The guest can fail to detach for a number of reasons, and if it does
22963a93856SMark Peek 	 * so, it will cleanup the entry (if there is one). We need to release
23063a93856SMark Peek 	 * the qpair struct here; there isn't much the caller can do, and we
23163a93856SMark Peek 	 * don't want to leak.
23263a93856SMark Peek 	 */
23363a93856SMark Peek 
23463a93856SMark Peek 	if (old_qpair->flags & VMCI_QPFLAG_LOCAL)
23563a93856SMark Peek 		vmci_destroy_event(&old_qpair->event);
23663a93856SMark Peek 
23763a93856SMark Peek 	vmci_free_kernel_mem(old_qpair, sizeof(*old_qpair));
23863a93856SMark Peek 	*qpair = NULL;
23963a93856SMark Peek 
24063a93856SMark Peek 	return (result);
24163a93856SMark Peek }
24263a93856SMark Peek 
24363a93856SMark Peek /*
24463a93856SMark Peek  *------------------------------------------------------------------------------
24563a93856SMark Peek  *
24663a93856SMark Peek  * vmci_qpair_get_produce_indexes --
24763a93856SMark Peek  *
24863a93856SMark Peek  *     This is the client interface for getting the current indexes of the
24963a93856SMark Peek  *     qpair from the point of the view of the caller as the producer.
25063a93856SMark Peek  *
25163a93856SMark Peek  * Results:
25263a93856SMark Peek  *     err, if < 0
25363a93856SMark Peek  *     Success otherwise.
25463a93856SMark Peek  *
25563a93856SMark Peek  * Side effects:
25663a93856SMark Peek  *     None.
25763a93856SMark Peek  *
25863a93856SMark Peek  *------------------------------------------------------------------------------
25963a93856SMark Peek  */
26063a93856SMark Peek 
26163a93856SMark Peek int
vmci_qpair_get_produce_indexes(const struct vmci_qpair * qpair,uint64_t * producer_tail,uint64_t * consumer_head)26263a93856SMark Peek vmci_qpair_get_produce_indexes(const struct vmci_qpair *qpair,
26363a93856SMark Peek     uint64_t *producer_tail, uint64_t *consumer_head)
26463a93856SMark Peek {
26563a93856SMark Peek 	struct vmci_queue_header *consume_q_header;
26663a93856SMark Peek 	struct vmci_queue_header *produce_q_header;
26763a93856SMark Peek 
26863a93856SMark Peek 	if (!qpair)
26963a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
27063a93856SMark Peek 
27163a93856SMark Peek 	vmci_qpair_get_queue_headers(qpair, &produce_q_header,
27263a93856SMark Peek 	    &consume_q_header);
27363a93856SMark Peek 	vmci_queue_header_get_pointers(produce_q_header, consume_q_header,
27463a93856SMark Peek 	    producer_tail, consumer_head);
27563a93856SMark Peek 
27663a93856SMark Peek 	if ((producer_tail && *producer_tail >= qpair->produce_q_size) ||
27763a93856SMark Peek 	    (consumer_head && *consumer_head >= qpair->produce_q_size))
27863a93856SMark Peek 		return (VMCI_ERROR_INVALID_SIZE);
27963a93856SMark Peek 
28063a93856SMark Peek 	return (VMCI_SUCCESS);
28163a93856SMark Peek }
28263a93856SMark Peek 
28363a93856SMark Peek /*
28463a93856SMark Peek  *------------------------------------------------------------------------------
28563a93856SMark Peek  *
28663a93856SMark Peek  * vmci_qpair_get_consume_indexes --
28763a93856SMark Peek  *
28863a93856SMark Peek  *     This is the client interface for getting the current indexes of the
28963a93856SMark Peek  *     QPair from the point of the view of the caller as the consumer.
29063a93856SMark Peek  *
29163a93856SMark Peek  * Results:
29263a93856SMark Peek  *     err, if < 0
29363a93856SMark Peek  *     Success otherwise.
29463a93856SMark Peek  *
29563a93856SMark Peek  * Side effects:
29663a93856SMark Peek  *     None.
29763a93856SMark Peek  *
29863a93856SMark Peek  *------------------------------------------------------------------------------
29963a93856SMark Peek  */
30063a93856SMark Peek 
30163a93856SMark Peek int
vmci_qpair_get_consume_indexes(const struct vmci_qpair * qpair,uint64_t * consumer_tail,uint64_t * producer_head)30263a93856SMark Peek vmci_qpair_get_consume_indexes(const struct vmci_qpair *qpair,
30363a93856SMark Peek     uint64_t *consumer_tail, uint64_t *producer_head)
30463a93856SMark Peek {
30563a93856SMark Peek 	struct vmci_queue_header *consume_q_header;
30663a93856SMark Peek 	struct vmci_queue_header *produce_q_header;
30763a93856SMark Peek 
30863a93856SMark Peek 	if (!qpair)
30963a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
31063a93856SMark Peek 
31163a93856SMark Peek 	vmci_qpair_get_queue_headers(qpair, &produce_q_header,
31263a93856SMark Peek 	    &consume_q_header);
31363a93856SMark Peek 	vmci_queue_header_get_pointers(consume_q_header, produce_q_header,
31463a93856SMark Peek 	    consumer_tail, producer_head);
31563a93856SMark Peek 
31663a93856SMark Peek 	if ((consumer_tail && *consumer_tail >= qpair->consume_q_size) ||
31763a93856SMark Peek 	    (producer_head && *producer_head >= qpair->consume_q_size))
31863a93856SMark Peek 		return (VMCI_ERROR_INVALID_SIZE);
31963a93856SMark Peek 
32063a93856SMark Peek 	return (VMCI_SUCCESS);
32163a93856SMark Peek }
32263a93856SMark Peek 
32363a93856SMark Peek /*
32463a93856SMark Peek  *------------------------------------------------------------------------------
32563a93856SMark Peek  *
32663a93856SMark Peek  * vmci_qpair_produce_free_space --
32763a93856SMark Peek  *
32863a93856SMark Peek  *     This is the client interface for getting the amount of free space in the
32963a93856SMark Peek  *     QPair from the point of the view of the caller as the producer which is
33063a93856SMark Peek  *     the common case.
33163a93856SMark Peek  *
33263a93856SMark Peek  * Results:
33363a93856SMark Peek  *     Err, if < 0.
33463a93856SMark Peek  *     Full queue if = 0.
33563a93856SMark Peek  *     Number of available bytes into which data can be enqueued if > 0.
33663a93856SMark Peek  *
33763a93856SMark Peek  * Side effects:
33863a93856SMark Peek  *     None.
33963a93856SMark Peek  *
34063a93856SMark Peek  *------------------------------------------------------------------------------
34163a93856SMark Peek  */
34263a93856SMark Peek 
34363a93856SMark Peek int64_t
vmci_qpair_produce_free_space(const struct vmci_qpair * qpair)34463a93856SMark Peek vmci_qpair_produce_free_space(const struct vmci_qpair *qpair)
34563a93856SMark Peek {
34663a93856SMark Peek 	struct vmci_queue_header *consume_q_header;
34763a93856SMark Peek 	struct vmci_queue_header *produce_q_header;
34863a93856SMark Peek 	int64_t result;
34963a93856SMark Peek 
35063a93856SMark Peek 	if (!qpair)
35163a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
35263a93856SMark Peek 
35363a93856SMark Peek 	vmci_qpair_get_queue_headers(qpair, &produce_q_header,
35463a93856SMark Peek 	    &consume_q_header);
35563a93856SMark Peek 	result = vmci_queue_header_free_space(produce_q_header, consume_q_header,
35663a93856SMark Peek 	    qpair->produce_q_size);
35763a93856SMark Peek 
35863a93856SMark Peek 	return (result);
35963a93856SMark Peek }
36063a93856SMark Peek 
36163a93856SMark Peek /*
36263a93856SMark Peek  *------------------------------------------------------------------------------
36363a93856SMark Peek  *
36463a93856SMark Peek  * vmci_qpair_consume_free_space --
36563a93856SMark Peek  *
36663a93856SMark Peek  *     This is the client interface for getting the amount of free space in the
36763a93856SMark Peek  *     QPair from the point of the view of the caller as the consumer which is
36863a93856SMark Peek  *     not the common case (see vmci_qpair_Produce_free_space(), above).
36963a93856SMark Peek  *
37063a93856SMark Peek  * Results:
37163a93856SMark Peek  *     Err, if < 0.
37263a93856SMark Peek  *     Full queue if = 0.
37363a93856SMark Peek  *     Number of available bytes into which data can be enqueued if > 0.
37463a93856SMark Peek  *
37563a93856SMark Peek  * Side effects:
37663a93856SMark Peek  *     None.
37763a93856SMark Peek  *
37863a93856SMark Peek  *------------------------------------------------------------------------------
37963a93856SMark Peek  */
38063a93856SMark Peek 
38163a93856SMark Peek int64_t
vmci_qpair_consume_free_space(const struct vmci_qpair * qpair)38263a93856SMark Peek vmci_qpair_consume_free_space(const struct vmci_qpair *qpair)
38363a93856SMark Peek {
38463a93856SMark Peek 	struct vmci_queue_header *consume_q_header;
38563a93856SMark Peek 	struct vmci_queue_header *produce_q_header;
38663a93856SMark Peek 	int64_t result;
38763a93856SMark Peek 
38863a93856SMark Peek 	if (!qpair)
38963a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
39063a93856SMark Peek 
39163a93856SMark Peek 	vmci_qpair_get_queue_headers(qpair, &produce_q_header,
39263a93856SMark Peek 	    &consume_q_header);
39363a93856SMark Peek 	result = vmci_queue_header_free_space(consume_q_header, produce_q_header,
39463a93856SMark Peek 	    qpair->consume_q_size);
39563a93856SMark Peek 
39663a93856SMark Peek 	return (result);
39763a93856SMark Peek }
39863a93856SMark Peek 
39963a93856SMark Peek /*
40063a93856SMark Peek  *------------------------------------------------------------------------------
40163a93856SMark Peek  *
40263a93856SMark Peek  * vmci_qpair_produce_buf_ready --
40363a93856SMark Peek  *
40463a93856SMark Peek  *     This is the client interface for getting the amount of enqueued data in
40563a93856SMark Peek  *     the QPair from the point of the view of the caller as the producer which
40663a93856SMark Peek  *     is not the common case (see vmci_qpair_Consume_buf_ready(), above).
40763a93856SMark Peek  *
40863a93856SMark Peek  * Results:
40963a93856SMark Peek  *     Err, if < 0.
41063a93856SMark Peek  *     Empty queue if = 0.
41163a93856SMark Peek  *     Number of bytes ready to be dequeued if > 0.
41263a93856SMark Peek  *
41363a93856SMark Peek  * Side effects:
41463a93856SMark Peek  *     None.
41563a93856SMark Peek  *
41663a93856SMark Peek  *------------------------------------------------------------------------------
41763a93856SMark Peek  */
41863a93856SMark Peek 
41963a93856SMark Peek int64_t
vmci_qpair_produce_buf_ready(const struct vmci_qpair * qpair)42063a93856SMark Peek vmci_qpair_produce_buf_ready(const struct vmci_qpair *qpair)
42163a93856SMark Peek {
42263a93856SMark Peek 	struct vmci_queue_header *consume_q_header;
42363a93856SMark Peek 	struct vmci_queue_header *produce_q_header;
42463a93856SMark Peek 	int64_t result;
42563a93856SMark Peek 
42663a93856SMark Peek 	if (!qpair)
42763a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
42863a93856SMark Peek 
42963a93856SMark Peek 	vmci_qpair_get_queue_headers(qpair, &produce_q_header,
43063a93856SMark Peek 	    &consume_q_header);
43163a93856SMark Peek 	result = vmci_queue_header_buf_ready(produce_q_header, consume_q_header,
43263a93856SMark Peek 	    qpair->produce_q_size);
43363a93856SMark Peek 
43463a93856SMark Peek 	return (result);
43563a93856SMark Peek }
43663a93856SMark Peek 
43763a93856SMark Peek /*
43863a93856SMark Peek  *------------------------------------------------------------------------------
43963a93856SMark Peek  *
44063a93856SMark Peek  * vmci_qpair_consume_buf_ready --
44163a93856SMark Peek  *
44263a93856SMark Peek  *     This is the client interface for getting the amount of enqueued data in
44363a93856SMark Peek  *     the QPair from the point of the view of the caller as the consumer which
44463a93856SMark Peek  *     is the normal case.
44563a93856SMark Peek  *
44663a93856SMark Peek  * Results:
44763a93856SMark Peek  *     Err, if < 0.
44863a93856SMark Peek  *     Empty queue if = 0.
44963a93856SMark Peek  *     Number of bytes ready to be dequeued if > 0.
45063a93856SMark Peek  *
45163a93856SMark Peek  * Side effects:
45263a93856SMark Peek  *     None.
45363a93856SMark Peek  *
45463a93856SMark Peek  *------------------------------------------------------------------------------
45563a93856SMark Peek  */
45663a93856SMark Peek 
45763a93856SMark Peek int64_t
vmci_qpair_consume_buf_ready(const struct vmci_qpair * qpair)45863a93856SMark Peek vmci_qpair_consume_buf_ready(const struct vmci_qpair *qpair)
45963a93856SMark Peek {
46063a93856SMark Peek 	struct vmci_queue_header *consume_q_header;
46163a93856SMark Peek 	struct vmci_queue_header *produce_q_header;
46263a93856SMark Peek 	int64_t result;
46363a93856SMark Peek 
46463a93856SMark Peek 	if (!qpair)
46563a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
46663a93856SMark Peek 
46763a93856SMark Peek 	vmci_qpair_get_queue_headers(qpair, &produce_q_header,
46863a93856SMark Peek 	    &consume_q_header);
46963a93856SMark Peek 	result = vmci_queue_header_buf_ready(consume_q_header, produce_q_header,
47063a93856SMark Peek 	    qpair->consume_q_size);
47163a93856SMark Peek 
47263a93856SMark Peek 	return (result);
47363a93856SMark Peek }
47463a93856SMark Peek 
47563a93856SMark Peek /*
47663a93856SMark Peek  *------------------------------------------------------------------------------
47763a93856SMark Peek  *
47863a93856SMark Peek  * enqueue --
47963a93856SMark Peek  *
48063a93856SMark Peek  *     Enqueues a given buffer to the produce queue using the provided function.
48163a93856SMark Peek  *     As many bytes as possible (space available in the queue) are enqueued.
48263a93856SMark Peek  *
48363a93856SMark Peek  * Results:
48463a93856SMark Peek  *     VMCI_ERROR_QUEUEPAIR_NOSPACE if no space was available to enqueue data.
48563a93856SMark Peek  *     VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
48663a93856SMark Peek  *     (as defined by the queue size).
487*f2e13c27SGordon Bergling  *     VMCI_ERROR_INVALID_ARGS, if an error occurred when accessing the buffer.
48863a93856SMark Peek  *     VMCI_ERROR_QUEUEPAIR_NOTATTACHED, if the queue pair pages aren't
48963a93856SMark Peek  *     available.
49063a93856SMark Peek  *     Otherwise, the number of bytes written to the queue is returned.
49163a93856SMark Peek  *
49263a93856SMark Peek  * Side effects:
49363a93856SMark Peek  *     Updates the tail pointer of the produce queue.
49463a93856SMark Peek  *
49563a93856SMark Peek  *------------------------------------------------------------------------------
49663a93856SMark Peek  */
49763a93856SMark Peek 
49863a93856SMark Peek 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)49963a93856SMark Peek enqueue(struct vmci_queue *produce_q, struct vmci_queue *consume_q,
50063a93856SMark Peek     const uint64_t produce_q_size, const void *buf, size_t buf_size,
50163a93856SMark Peek     int buf_type, vmci_memcpy_to_queue_func memcpy_to_queue, bool can_block)
50263a93856SMark Peek {
50363a93856SMark Peek 	ssize_t result;
50463a93856SMark Peek 	size_t written;
50563a93856SMark Peek 	int64_t free_space;
50663a93856SMark Peek 	uint64_t tail;
50763a93856SMark Peek 
50863a93856SMark Peek 	ASSERT((produce_q != NULL) && (consume_q != NULL));
50963a93856SMark Peek 
51063a93856SMark Peek 	free_space = vmci_queue_header_free_space(produce_q->q_header,
51163a93856SMark Peek 	    consume_q->q_header,
51263a93856SMark Peek 	    produce_q_size);
51363a93856SMark Peek 	if (free_space == 0)
51463a93856SMark Peek 		return (VMCI_ERROR_QUEUEPAIR_NOSPACE);
51563a93856SMark Peek 
51663a93856SMark Peek 	if (free_space < VMCI_SUCCESS)
51763a93856SMark Peek 		return ((ssize_t)free_space);
51863a93856SMark Peek 
51963a93856SMark Peek 	written = (size_t)(free_space > buf_size ? buf_size : free_space);
52063a93856SMark Peek 	tail = vmci_queue_header_producer_tail(produce_q->q_header);
52163a93856SMark Peek 	if (LIKELY(tail + written < produce_q_size))
52263a93856SMark Peek 		result = memcpy_to_queue(produce_q, tail, buf, 0, written,
52363a93856SMark Peek 		    buf_type, can_block);
52463a93856SMark Peek 	else {
52563a93856SMark Peek 		/* Tail pointer wraps around. */
52663a93856SMark Peek 
52763a93856SMark Peek 		const size_t tmp = (size_t)(produce_q_size - tail);
52863a93856SMark Peek 
52963a93856SMark Peek 		result = memcpy_to_queue(produce_q, tail, buf, 0, tmp, buf_type,
53063a93856SMark Peek 		    can_block);
53163a93856SMark Peek 		if (result >= VMCI_SUCCESS)
53263a93856SMark Peek 			result = memcpy_to_queue(produce_q, 0, buf, tmp,
53363a93856SMark Peek 			    written - tmp, buf_type, can_block);
53463a93856SMark Peek 	}
53563a93856SMark Peek 
53663a93856SMark Peek 	if (result < VMCI_SUCCESS)
53763a93856SMark Peek 		return (result);
53863a93856SMark Peek 
53963a93856SMark Peek 	result = vmci_queue_add_producer_tail(produce_q, written,
54063a93856SMark Peek 	    produce_q_size);
54163a93856SMark Peek 	if (result < VMCI_SUCCESS)
54263a93856SMark Peek 		return (result);
54363a93856SMark Peek 	return (written);
54463a93856SMark Peek }
54563a93856SMark Peek 
54663a93856SMark Peek /*
54763a93856SMark Peek  *------------------------------------------------------------------------------
54863a93856SMark Peek  *
54963a93856SMark Peek  * dequeue --
55063a93856SMark Peek  *
55163a93856SMark Peek  *     Dequeues data (if available) from the given consume queue. Writes data
55263a93856SMark Peek  *     to the user provided buffer using the provided function.
55363a93856SMark Peek  *
55463a93856SMark Peek  * Results:
55563a93856SMark Peek  *     VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue.
55663a93856SMark Peek  *     VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
55763a93856SMark Peek  *     (as defined by the queue size).
558*f2e13c27SGordon Bergling  *     VMCI_ERROR_INVALID_ARGS, if an error occurred when accessing the buffer.
55963a93856SMark Peek  *     VMCI_ERROR_NOT_FOUND, if the vmm_world registered with the queue pair
56063a93856SMark Peek  *     cannot be found.
56163a93856SMark Peek  *     Otherwise the number of bytes dequeued is returned.
56263a93856SMark Peek  *
56363a93856SMark Peek  * Side effects:
56463a93856SMark Peek  *     Updates the head pointer of the consume queue.
56563a93856SMark Peek  *
56663a93856SMark Peek  *------------------------------------------------------------------------------
56763a93856SMark Peek  */
56863a93856SMark Peek 
56963a93856SMark Peek 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)57063a93856SMark Peek dequeue(struct vmci_queue *produce_q,
57163a93856SMark Peek     struct vmci_queue *consume_q, const uint64_t consume_q_size, void *buf,
57263a93856SMark Peek     size_t buf_size, int buf_type,
57363a93856SMark Peek     vmci_memcpy_from_queue_func memcpy_from_queue, bool update_consumer,
57463a93856SMark Peek     bool can_block)
57563a93856SMark Peek {
57663a93856SMark Peek 	ssize_t result;
57763a93856SMark Peek 	size_t read;
57863a93856SMark Peek 	int64_t buf_ready;
57963a93856SMark Peek 	uint64_t head;
58063a93856SMark Peek 
58163a93856SMark Peek 	ASSERT((produce_q != NULL) && (consume_q != NULL));
58263a93856SMark Peek 
58363a93856SMark Peek 	buf_ready = vmci_queue_header_buf_ready(consume_q->q_header,
58463a93856SMark Peek 	    produce_q->q_header, consume_q_size);
58563a93856SMark Peek 	if (buf_ready == 0)
58663a93856SMark Peek 		return (VMCI_ERROR_QUEUEPAIR_NODATA);
58763a93856SMark Peek 	if (buf_ready < VMCI_SUCCESS)
58863a93856SMark Peek 		return ((ssize_t)buf_ready);
58963a93856SMark Peek 
59063a93856SMark Peek 	read = (size_t)(buf_ready > buf_size ? buf_size : buf_ready);
59163a93856SMark Peek 	head = vmci_queue_header_consumer_head(produce_q->q_header);
59263a93856SMark Peek 	if (LIKELY(head + read < consume_q_size))
59363a93856SMark Peek 		result = memcpy_from_queue(buf, 0, consume_q, head, read,
59463a93856SMark Peek 		    buf_type, can_block);
59563a93856SMark Peek 	else {
59663a93856SMark Peek 		/* Head pointer wraps around. */
59763a93856SMark Peek 
59863a93856SMark Peek 		const size_t tmp = (size_t)(consume_q_size - head);
59963a93856SMark Peek 
60063a93856SMark Peek 		result = memcpy_from_queue(buf, 0, consume_q, head, tmp,
60163a93856SMark Peek 		    buf_type, can_block);
60263a93856SMark Peek 		if (result >= VMCI_SUCCESS)
60363a93856SMark Peek 			result = memcpy_from_queue(buf, tmp, consume_q, 0,
60463a93856SMark Peek 			    read - tmp, buf_type, can_block);
60563a93856SMark Peek 	}
60663a93856SMark Peek 
60763a93856SMark Peek 	if (result < VMCI_SUCCESS)
60863a93856SMark Peek 		return (result);
60963a93856SMark Peek 
61063a93856SMark Peek 	if (update_consumer) {
61163a93856SMark Peek 		result = vmci_queue_add_consumer_head(produce_q, read,
61263a93856SMark Peek 		    consume_q_size);
61363a93856SMark Peek 		if (result < VMCI_SUCCESS)
61463a93856SMark Peek 			return (result);
61563a93856SMark Peek 	}
61663a93856SMark Peek 
61763a93856SMark Peek 	return (read);
61863a93856SMark Peek }
61963a93856SMark Peek 
62063a93856SMark Peek /*
62163a93856SMark Peek  *------------------------------------------------------------------------------
62263a93856SMark Peek  *
62363a93856SMark Peek  * vmci_qpair_enqueue --
62463a93856SMark Peek  *
62563a93856SMark Peek  *     This is the client interface for enqueueing data into the queue.
62663a93856SMark Peek  *
62763a93856SMark Peek  * Results:
62863a93856SMark Peek  *     Err, if < 0.
62963a93856SMark Peek  *     Number of bytes enqueued if >= 0.
63063a93856SMark Peek  *
63163a93856SMark Peek  * Side effects:
63263a93856SMark Peek  *     None.
63363a93856SMark Peek  *
63463a93856SMark Peek  *------------------------------------------------------------------------------
63563a93856SMark Peek  */
63663a93856SMark Peek 
63763a93856SMark Peek ssize_t
vmci_qpair_enqueue(struct vmci_qpair * qpair,const void * buf,size_t buf_size,int buf_type)63863a93856SMark Peek vmci_qpair_enqueue(struct vmci_qpair *qpair, const void *buf, size_t buf_size,
63963a93856SMark Peek     int buf_type)
64063a93856SMark Peek {
64163a93856SMark Peek 	ssize_t result;
64263a93856SMark Peek 
64363a93856SMark Peek 	if (!qpair || !buf)
64463a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
64563a93856SMark Peek 
64663a93856SMark Peek 	result = enqueue(qpair->produce_q, qpair->consume_q,
64763a93856SMark Peek 	    qpair->produce_q_size, buf, buf_size, buf_type,
64863a93856SMark Peek 	    qpair->flags & VMCI_QPFLAG_LOCAL?
64963a93856SMark Peek 	    vmci_memcpy_to_queue_local : vmci_memcpy_to_queue,
65063a93856SMark Peek 	    !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
65163a93856SMark Peek 
65263a93856SMark Peek 	return (result);
65363a93856SMark Peek }
65463a93856SMark Peek 
65563a93856SMark Peek /*
65663a93856SMark Peek  *------------------------------------------------------------------------------
65763a93856SMark Peek  *
65863a93856SMark Peek  * vmci_qpair_dequeue --
65963a93856SMark Peek  *
66063a93856SMark Peek  *     This is the client interface for dequeueing data from the queue.
66163a93856SMark Peek  *
66263a93856SMark Peek  * Results:
66363a93856SMark Peek  *     Err, if < 0.
66463a93856SMark Peek  *     Number of bytes dequeued if >= 0.
66563a93856SMark Peek  *
66663a93856SMark Peek  * Side effects:
66763a93856SMark Peek  *     None.
66863a93856SMark Peek  *
66963a93856SMark Peek  *------------------------------------------------------------------------------
67063a93856SMark Peek  */
67163a93856SMark Peek 
67263a93856SMark Peek ssize_t
vmci_qpair_dequeue(struct vmci_qpair * qpair,void * buf,size_t buf_size,int buf_type)67363a93856SMark Peek vmci_qpair_dequeue(struct vmci_qpair *qpair, void *buf, size_t buf_size,
67463a93856SMark Peek     int buf_type)
67563a93856SMark Peek {
67663a93856SMark Peek 	ssize_t result;
67763a93856SMark Peek 
67863a93856SMark Peek 	if (!qpair || !buf)
67963a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
68063a93856SMark Peek 
68163a93856SMark Peek 	result = dequeue(qpair->produce_q, qpair->consume_q,
68263a93856SMark Peek 	    qpair->consume_q_size, buf, buf_size, buf_type,
68363a93856SMark Peek 	    qpair->flags & VMCI_QPFLAG_LOCAL?
68463a93856SMark Peek 	    vmci_memcpy_from_queue_local : vmci_memcpy_from_queue, true,
68563a93856SMark Peek 	    !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
68663a93856SMark Peek 
68763a93856SMark Peek 	return (result);
68863a93856SMark Peek }
68963a93856SMark Peek 
69063a93856SMark Peek /*
69163a93856SMark Peek  *------------------------------------------------------------------------------
69263a93856SMark Peek  *
69363a93856SMark Peek  * vmci_qpair_peek --
69463a93856SMark Peek  *
69563a93856SMark Peek  *     This is the client interface for peeking into a queue.  (I.e., copy
69663a93856SMark Peek  *     data from the queue without updating the head pointer.)
69763a93856SMark Peek  *
69863a93856SMark Peek  * Results:
69963a93856SMark Peek  *     Err, if < 0.
70063a93856SMark Peek  *     Number of bytes peeked, if >= 0.
70163a93856SMark Peek  *
70263a93856SMark Peek  * Side effects:
70363a93856SMark Peek  *     None.
70463a93856SMark Peek  *
70563a93856SMark Peek  *------------------------------------------------------------------------------
70663a93856SMark Peek  */
70763a93856SMark Peek 
70863a93856SMark Peek ssize_t
vmci_qpair_peek(struct vmci_qpair * qpair,void * buf,size_t buf_size,int buf_type)70963a93856SMark Peek vmci_qpair_peek(struct vmci_qpair *qpair, void *buf, size_t buf_size,
71063a93856SMark Peek     int buf_type)
71163a93856SMark Peek {
71263a93856SMark Peek 	ssize_t result;
71363a93856SMark Peek 
71463a93856SMark Peek 	if (!qpair || !buf)
71563a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
71663a93856SMark Peek 
71763a93856SMark Peek 	result = dequeue(qpair->produce_q, qpair->consume_q,
71863a93856SMark Peek 	    qpair->consume_q_size, buf, buf_size, buf_type,
71963a93856SMark Peek 	    qpair->flags & VMCI_QPFLAG_LOCAL?
72063a93856SMark Peek 	    vmci_memcpy_from_queue_local : vmci_memcpy_from_queue, false,
72163a93856SMark Peek 	    !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
72263a93856SMark Peek 
72363a93856SMark Peek 	return (result);
72463a93856SMark Peek }
72563a93856SMark Peek 
72663a93856SMark Peek /*
72763a93856SMark Peek  *------------------------------------------------------------------------------
72863a93856SMark Peek  *
72963a93856SMark Peek  * vmci_qpair_enquev --
73063a93856SMark Peek  *
73163a93856SMark Peek  *     This is the client interface for enqueueing data into the queue.
73263a93856SMark Peek  *
73363a93856SMark Peek  * Results:
73463a93856SMark Peek  *     Err, if < 0.
73563a93856SMark Peek  *     Number of bytes enqueued if >= 0.
73663a93856SMark Peek  *
73763a93856SMark Peek  * Side effects:
73863a93856SMark Peek  *     None.
73963a93856SMark Peek  *
74063a93856SMark Peek  *------------------------------------------------------------------------------
74163a93856SMark Peek  */
74263a93856SMark Peek 
74363a93856SMark Peek ssize_t
vmci_qpair_enquev(struct vmci_qpair * qpair,void * iov,size_t iov_size,int buf_type)74463a93856SMark Peek vmci_qpair_enquev(struct vmci_qpair *qpair, void *iov, size_t iov_size,
74563a93856SMark Peek     int buf_type)
74663a93856SMark Peek {
74763a93856SMark Peek 	ssize_t result;
74863a93856SMark Peek 
74963a93856SMark Peek 	if (!qpair || !iov)
75063a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
75163a93856SMark Peek 
75263a93856SMark Peek 	result = enqueue(qpair->produce_q, qpair->consume_q,
75363a93856SMark Peek 	    qpair->produce_q_size, iov, iov_size, buf_type,
75463a93856SMark Peek 	    qpair->flags & VMCI_QPFLAG_LOCAL?
75563a93856SMark Peek 	    vmci_memcpy_to_queue_v_local : vmci_memcpy_to_queue_v,
75663a93856SMark Peek 	    !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
75763a93856SMark Peek 
75863a93856SMark Peek 	return (result);
75963a93856SMark Peek }
76063a93856SMark Peek 
76163a93856SMark Peek /*
76263a93856SMark Peek  *------------------------------------------------------------------------------
76363a93856SMark Peek  *
76463a93856SMark Peek  * vmci_qpair_dequev --
76563a93856SMark Peek  *
76663a93856SMark Peek  *     This is the client interface for dequeueing data from the queue.
76763a93856SMark Peek  *
76863a93856SMark Peek  * Results:
76963a93856SMark Peek  *     Err, if < 0.
77063a93856SMark Peek  *     Number of bytes dequeued if >= 0.
77163a93856SMark Peek  *
77263a93856SMark Peek  * Side effects:
77363a93856SMark Peek  *     None.
77463a93856SMark Peek  *
77563a93856SMark Peek  *------------------------------------------------------------------------------
77663a93856SMark Peek  */
77763a93856SMark Peek 
77863a93856SMark Peek ssize_t
vmci_qpair_dequev(struct vmci_qpair * qpair,void * iov,size_t iov_size,int buf_type)77963a93856SMark Peek vmci_qpair_dequev(struct vmci_qpair *qpair, void *iov, size_t iov_size,
78063a93856SMark Peek     int buf_type)
78163a93856SMark Peek {
78263a93856SMark Peek 	ssize_t result;
78363a93856SMark Peek 
78463a93856SMark Peek 	if (!qpair || !iov)
78563a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
78663a93856SMark Peek 
78763a93856SMark Peek 	result = dequeue(qpair->produce_q, qpair->consume_q,
78863a93856SMark Peek 	    qpair->consume_q_size, iov, iov_size, buf_type,
78963a93856SMark Peek 	    qpair->flags & VMCI_QPFLAG_LOCAL?
79063a93856SMark Peek 	    vmci_memcpy_from_queue_v_local : vmci_memcpy_from_queue_v, true,
79163a93856SMark Peek 	    !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
79263a93856SMark Peek 
79363a93856SMark Peek 	return (result);
79463a93856SMark Peek }
79563a93856SMark Peek 
79663a93856SMark Peek /*
79763a93856SMark Peek  *------------------------------------------------------------------------------
79863a93856SMark Peek  *
79963a93856SMark Peek  * vmci_qpair_peekv --
80063a93856SMark Peek  *
80163a93856SMark Peek  *     This is the client interface for peeking into a queue.  (I.e., copy
80263a93856SMark Peek  *     data from the queue without updating the head pointer.)
80363a93856SMark Peek  *
80463a93856SMark Peek  * Results:
80563a93856SMark Peek  *     Err, if < 0.
80663a93856SMark Peek  *     Number of bytes peeked, if >= 0.
80763a93856SMark Peek  *
80863a93856SMark Peek  * Side effects:
80963a93856SMark Peek  *     None.
81063a93856SMark Peek  *
81163a93856SMark Peek  *------------------------------------------------------------------------------
81263a93856SMark Peek  */
81363a93856SMark Peek 
81463a93856SMark Peek ssize_t
vmci_qpair_peekv(struct vmci_qpair * qpair,void * iov,size_t iov_size,int buf_type)81563a93856SMark Peek vmci_qpair_peekv(struct vmci_qpair *qpair, void *iov, size_t iov_size,
81663a93856SMark Peek     int buf_type)
81763a93856SMark Peek {
81863a93856SMark Peek 	ssize_t result;
81963a93856SMark Peek 
82063a93856SMark Peek 	if (!qpair || !iov)
82163a93856SMark Peek 		return (VMCI_ERROR_INVALID_ARGS);
82263a93856SMark Peek 
82363a93856SMark Peek 	result = dequeue(qpair->produce_q, qpair->consume_q,
82463a93856SMark Peek 	    qpair->consume_q_size, iov, iov_size, buf_type,
82563a93856SMark Peek 	    qpair->flags & VMCI_QPFLAG_LOCAL?
82663a93856SMark Peek 	    vmci_memcpy_from_queue_v_local : vmci_memcpy_from_queue_v, false,
82763a93856SMark Peek 	    !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
82863a93856SMark Peek 
82963a93856SMark Peek 	return (result);
83063a93856SMark Peek }
831