Move devmem's freelist to an index-based approach similar to io_uring. This halves the memory requirements for the freelist. Reviewed-by: Mina Almasry Signed-off-by: Stanislav Fomichev --- net/core/devmem.c | 50 ++++++++++++++++++++++++++++++++++++----------- net/core/devmem.h | 4 ++-- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/net/core/devmem.c b/net/core/devmem.c index a9d86b5a5588..704d02bd8bc8 100644 --- a/net/core/devmem.c +++ b/net/core/devmem.c @@ -29,6 +29,29 @@ static DEFINE_XARRAY_FLAGS(net_devmem_dmabuf_bindings, XA_FLAGS_ALLOC1); static const struct memory_provider_ops dmabuf_devmem_ops; +static struct net_iov *net_iov_free_pop(struct net_iov_area *area, + u32 *freelist, u32 *free_count) +{ + u32 idx; + + if (unlikely(!*free_count)) + return NULL; + + idx = freelist[--(*free_count)]; + return &area->niovs[idx]; +} + +static void net_iov_free_push(struct net_iov_area *area, + u32 *freelist, u32 *free_count, + struct net_iov *niov) +{ + if (WARN_ON_ONCE(net_iov_owner(niov) != area || + *free_count >= area->num_niovs)) + return; + + freelist[(*free_count)++] = net_iov_idx(niov); +} + static void net_devmem_dmabuf_binding_release(struct percpu_ref *ref) { struct net_devmem_dmabuf_binding *binding = @@ -44,7 +67,7 @@ void __net_devmem_dmabuf_binding_free(struct work_struct *wq) if (binding->freelist) WARN(binding->free_count != binding->area.num_niovs, - "destroying dmabuf binding with outstanding net_iovs: total=%zu, free=%zu", + "destroying dmabuf binding with outstanding net_iovs: total=%zu, free=%u", binding->area.num_niovs, binding->free_count); kvfree(binding->area.niovs); @@ -63,14 +86,15 @@ static unsigned int net_devmem_alloc_dmabuf_bulk(struct net_devmem_dmabuf_binding *binding, netmem_ref *netmems, unsigned int count) { + struct net_iov *niov; unsigned int i; spin_lock_bh(&binding->freelist_lock); - count = min_t(size_t, count, binding->free_count); + count = min(count, binding->free_count); for (i = 0; i < count; i++) { - struct net_iov *niov = binding->freelist[--binding->free_count]; - + niov = net_iov_free_pop(&binding->area, binding->freelist, + &binding->free_count); netmems[i] = net_iov_to_netmem(niov); } @@ -84,12 +108,8 @@ void net_devmem_free_dmabuf(struct net_iov *niov) struct net_devmem_dmabuf_binding *binding = net_devmem_iov_binding(niov); spin_lock_bh(&binding->freelist_lock); - if (WARN_ON_ONCE(binding->free_count >= binding->area.num_niovs)) { - spin_unlock_bh(&binding->freelist_lock); - return; - } - - binding->freelist[binding->free_count++] = niov; + net_iov_free_push(&binding->area, binding->freelist, + &binding->free_count, niov); spin_unlock_bh(&binding->freelist_lock); } @@ -228,6 +248,12 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev, goto err_unmap; } + if ((dmabuf->size >> niov_shift) > U32_MAX) { + err = -E2BIG; + NL_SET_ERR_MSG(extack, "dmabuf contains too many net_iovs"); + goto err_unmap; + } + binding->area.base_virtual = 0; binding->area.num_niovs = dmabuf->size >> niov_shift; if (direction == DMA_TO_DEVICE) { @@ -279,7 +305,9 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev, if (direction == DMA_TO_DEVICE) binding->tx_vec[niov_idx] = niov; else - binding->freelist[binding->free_count++] = niov; + net_iov_free_push(&binding->area, + binding->freelist, + &binding->free_count, niov); dma_addr += niov_size; } } diff --git a/net/core/devmem.h b/net/core/devmem.h index f71d9a2bcb3d..28d6fa7bcb57 100644 --- a/net/core/devmem.h +++ b/net/core/devmem.h @@ -58,8 +58,8 @@ struct net_devmem_dmabuf_binding { struct xarray bound_rxqs; spinlock_t freelist_lock ____cacheline_aligned_in_smp; - size_t free_count; - struct net_iov **freelist; + u32 free_count; + u32 *freelist; /* ID of this binding. Globally unique to all bindings currently * active. -- 2.53.0-Meta