Skip to content

Commit

Permalink
vhost: add thread-unsafe async registration
Browse files Browse the repository at this point in the history
This patch adds thread unsafe version for async register and
unregister functions.

Signed-off-by: Jiayu Hu <[email protected]>
Reviewed-by: Chenbo Xia <[email protected]>
Reviewed-by: Maxime Coquelin <[email protected]>
  • Loading branch information
humasama authored and chenbo-xia committed Jul 21, 2021
1 parent acbc388 commit fa51f1a
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 36 deletions.
16 changes: 16 additions & 0 deletions doc/guides/prog_guide/vhost_lib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ The following is an overview of some key Vhost API functions:
vhost invokes this function to get the copy data completed by async
devices.

* ``rte_vhost_async_channel_register_thread_unsafe(vid, queue_id, config, ops)``

Register an async copy device channel for a vhost queue without
performing any locking.

This function is only safe to call in vhost callback functions
(i.e., struct vhost_device_ops).

* ``rte_vhost_async_channel_unregister(vid, queue_id)``

Unregister the async copy device channel from a vhost queue.
Expand All @@ -268,6 +276,14 @@ The following is an overview of some key Vhost API functions:
devices for all vhost queues in destroy_device(), when a
virtio device is paused or shut down.

* ``rte_vhost_async_channel_unregister_thread_unsafe(vid, queue_id)``

Unregister the async copy device channel for a vhost queue without
performing any locking.

This function is only safe to call in vhost callback functions
(i.e., struct vhost_device_ops).

* ``rte_vhost_submit_enqueue_burst(vid, queue_id, pkts, count, comp_pkts, comp_count)``

Submit an enqueue request to transmit ``count`` packets from host to guest
Expand Down
41 changes: 41 additions & 0 deletions lib/vhost/rte_vhost_async.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,47 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id,
__rte_experimental
int rte_vhost_async_channel_unregister(int vid, uint16_t queue_id);

/**
* Register an async channel for a vhost queue without performing any
* locking
*
* @note This function does not perform any locking, and is only safe to
* call in vhost callback functions.
*
* @param vid
* vhost device id async channel to be attached to
* @param queue_id
* vhost queue id async channel to be attached to
* @param config
* Async channel configuration
* @param ops
* Async channel operation callbacks
* @return
* 0 on success, -1 on failures
*/
__rte_experimental
int rte_vhost_async_channel_register_thread_unsafe(int vid, uint16_t queue_id,
struct rte_vhost_async_config config,
struct rte_vhost_async_channel_ops *ops);

/**
* Unregister an async channel for a vhost queue without performing any
* locking
*
* @note This function does not perform any locking, and is only safe to
* call in vhost callback functions.
*
* @param vid
* vhost device id async channel to be detached from
* @param queue_id
* vhost queue id async channel to be detached from
* @return
* 0 on success, -1 on failures
*/
__rte_experimental
int rte_vhost_async_channel_unregister_thread_unsafe(int vid,
uint16_t queue_id);

/**
* This function submits enqueue data to async engine. Successfully
* enqueued packets can be transfer completed or being occupied by DMA
Expand Down
2 changes: 2 additions & 0 deletions lib/vhost/version.map
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,6 @@ EXPERIMENTAL {

# added in 21.08
rte_vhost_async_get_inflight;
rte_vhost_async_channel_register_thread_unsafe;
rte_vhost_async_channel_unregister_thread_unsafe;
};
150 changes: 114 additions & 36 deletions lib/vhost/vhost.c
Original file line number Diff line number Diff line change
Expand Up @@ -1619,43 +1619,19 @@ int rte_vhost_extern_callback_register(int vid,
return 0;
}

int
rte_vhost_async_channel_register(int vid, uint16_t queue_id,
static __rte_always_inline int
async_channel_register(int vid, uint16_t queue_id,
struct rte_vhost_async_config config,
struct rte_vhost_async_channel_ops *ops)
{
struct vhost_virtqueue *vq;
struct virtio_net *dev = get_device(vid);

if (dev == NULL || ops == NULL)
return -1;

if (queue_id >= VHOST_MAX_VRING)
return -1;

vq = dev->virtqueue[queue_id];

if (unlikely(vq == NULL || !dev->async_copy))
return -1;

if (unlikely(!(config.features & RTE_VHOST_ASYNC_INORDER))) {
VHOST_LOG_CONFIG(ERR,
"async copy is not supported on non-inorder mode "
"(vid %d, qid: %d)\n", vid, queue_id);
return -1;
}

if (unlikely(ops->check_completed_copies == NULL ||
ops->transfer_data == NULL))
return -1;

rte_spinlock_lock(&vq->access_lock);
struct vhost_virtqueue *vq = dev->virtqueue[queue_id];

if (unlikely(vq->async_registered)) {
VHOST_LOG_CONFIG(ERR,
"async register failed: channel already registered "
"(vid %d, qid: %d)\n", vid, queue_id);
goto reg_out;
return -1;
}

vq->async_pkts_info = rte_malloc_socket(NULL,
Expand All @@ -1666,7 +1642,7 @@ rte_vhost_async_channel_register(int vid, uint16_t queue_id,
VHOST_LOG_CONFIG(ERR,
"async register failed: cannot allocate memory for async_pkts_info "
"(vid %d, qid: %d)\n", vid, queue_id);
goto reg_out;
return -1;
}

vq->it_pool = rte_malloc_socket(NULL,
Expand All @@ -1677,7 +1653,7 @@ rte_vhost_async_channel_register(int vid, uint16_t queue_id,
VHOST_LOG_CONFIG(ERR,
"async register failed: cannot allocate memory for it_pool "
"(vid %d, qid: %d)\n", vid, queue_id);
goto reg_out;
return -1;
}

vq->vec_pool = rte_malloc_socket(NULL,
Expand All @@ -1688,7 +1664,7 @@ rte_vhost_async_channel_register(int vid, uint16_t queue_id,
VHOST_LOG_CONFIG(ERR,
"async register failed: cannot allocate memory for vec_pool "
"(vid %d, qid: %d)\n", vid, queue_id);
goto reg_out;
return -1;
}

if (vq_is_packed(dev)) {
Expand All @@ -1700,7 +1676,7 @@ rte_vhost_async_channel_register(int vid, uint16_t queue_id,
VHOST_LOG_CONFIG(ERR,
"async register failed: cannot allocate memory for async buffers "
"(vid %d, qid: %d)\n", vid, queue_id);
goto reg_out;
return -1;
}
} else {
vq->async_descs_split = rte_malloc_socket(NULL,
Expand All @@ -1711,7 +1687,7 @@ rte_vhost_async_channel_register(int vid, uint16_t queue_id,
VHOST_LOG_CONFIG(ERR,
"async register failed: cannot allocate memory for async descs "
"(vid %d, qid: %d)\n", vid, queue_id);
goto reg_out;
return -1;
}
}

Expand All @@ -1721,10 +1697,78 @@ rte_vhost_async_channel_register(int vid, uint16_t queue_id,

vq->async_registered = true;

reg_out:
return 0;
}

int
rte_vhost_async_channel_register(int vid, uint16_t queue_id,
struct rte_vhost_async_config config,
struct rte_vhost_async_channel_ops *ops)
{
struct vhost_virtqueue *vq;
struct virtio_net *dev = get_device(vid);
int ret;

if (dev == NULL || ops == NULL)
return -1;

if (queue_id >= VHOST_MAX_VRING)
return -1;

vq = dev->virtqueue[queue_id];

if (unlikely(vq == NULL || !dev->async_copy))
return -1;

if (unlikely(!(config.features & RTE_VHOST_ASYNC_INORDER))) {
VHOST_LOG_CONFIG(ERR,
"async copy is not supported on non-inorder mode "
"(vid %d, qid: %d)\n", vid, queue_id);
return -1;
}

if (unlikely(ops->check_completed_copies == NULL ||
ops->transfer_data == NULL))
return -1;

rte_spinlock_lock(&vq->access_lock);
ret = async_channel_register(vid, queue_id, config, ops);
rte_spinlock_unlock(&vq->access_lock);

return 0;
return ret;
}

int
rte_vhost_async_channel_register_thread_unsafe(int vid, uint16_t queue_id,
struct rte_vhost_async_config config,
struct rte_vhost_async_channel_ops *ops)
{
struct vhost_virtqueue *vq;
struct virtio_net *dev = get_device(vid);

if (dev == NULL || ops == NULL)
return -1;

if (queue_id >= VHOST_MAX_VRING)
return -1;

vq = dev->virtqueue[queue_id];

if (unlikely(vq == NULL || !dev->async_copy))
return -1;

if (unlikely(!(config.features & RTE_VHOST_ASYNC_INORDER))) {
VHOST_LOG_CONFIG(ERR,
"async copy is not supported on non-inorder mode "
"(vid %d, qid: %d)\n", vid, queue_id);
return -1;
}

if (unlikely(ops->check_completed_copies == NULL ||
ops->transfer_data == NULL))
return -1;

return async_channel_register(vid, queue_id, config, ops);
}

int
Expand Down Expand Up @@ -1775,6 +1819,41 @@ rte_vhost_async_channel_unregister(int vid, uint16_t queue_id)
return ret;
}

int
rte_vhost_async_channel_unregister_thread_unsafe(int vid, uint16_t queue_id)
{
struct vhost_virtqueue *vq;
struct virtio_net *dev = get_device(vid);

if (dev == NULL)
return -1;

if (queue_id >= VHOST_MAX_VRING)
return -1;

vq = dev->virtqueue[queue_id];

if (vq == NULL)
return -1;

if (!vq->async_registered)
return 0;

if (vq->async_pkts_inflight_n) {
VHOST_LOG_CONFIG(ERR, "Failed to unregister async channel. "
"async inflight packets must be completed before unregistration.\n");
return -1;
}

vhost_free_async_mem(vq);

vq->async_ops.transfer_data = NULL;
vq->async_ops.check_completed_copies = NULL;
vq->async_registered = false;

return 0;
}

int rte_vhost_async_get_inflight(int vid, uint16_t queue_id)
{
struct vhost_virtqueue *vq;
Expand Down Expand Up @@ -1805,7 +1884,6 @@ int rte_vhost_async_get_inflight(int vid, uint16_t queue_id)
rte_spinlock_unlock(&vq->access_lock);

return ret;

}

RTE_LOG_REGISTER_SUFFIX(vhost_config_log_level, config, INFO);
Expand Down

0 comments on commit fa51f1a

Please sign in to comment.