@@ -70,6 +70,18 @@ static inline void io_uring_cmd_complete_in_task(struct io_uring_cmd *ioucmd,
__io_uring_cmd_do_in_task(ioucmd, task_work_cb, 0);
}
+struct io_zc_rx_ifq;
+struct io_zc_rx_buf *io_zc_rx_get_buf(struct io_zc_rx_ifq *ifq);
+void io_zc_rx_put_buf(struct io_zc_rx_ifq *ifq, struct io_zc_rx_buf *buf);
+
+static inline dma_addr_t io_zc_rx_buf_dma(struct io_zc_rx_buf *buf)
+{
+ return buf->dma;
+}
+static inline struct page *io_zc_rx_buf_page(struct io_zc_rx_buf *buf)
+{
+ return buf->page;
+}
static inline void io_uring_files_cancel(void)
{
if (current->io_uring) {
@@ -106,6 +118,13 @@ static inline void io_uring_cmd_do_in_task_lazy(struct io_uring_cmd *ioucmd,
void (*task_work_cb)(struct io_uring_cmd *, unsigned))
{
}
+static inline struct io_zc_rx_buf *io_zc_rx_get_buf(struct io_zc_rx_ifq *ifq)
+{
+ return NULL;
+}
+static inline void io_zc_rx_put_buf(struct io_zc_rx_ifq *ifq, struct io_zc_rx_buf *buf)
+{
+}
static inline struct sock *io_uring_get_socket(struct file *file)
{
return NULL;
@@ -16,6 +16,9 @@
#include "rsrc.h"
#define POOL_CACHE_SIZE 128
+#define POOL_REFILL_COUNT 64
+#define IO_ZC_RX_UREF 0x10000
+#define IO_ZC_RX_KREF_MASK (IO_ZC_RX_UREF - 1)
struct io_zc_rx_pool {
struct io_zc_rx_ifq *ifq;
@@ -269,6 +272,8 @@ int io_register_zc_rx_ifq(struct io_ring_ctx *ctx,
ifq->rq_entries = reg.rq_entries;
ifq->cq_entries = reg.cq_entries;
+ ifq->cached_rq_head = 0;
+ ifq->cached_cq_tail = 0;
ifq->if_rxq_id = reg.if_rxq_id;
ctx->ifq = ifq;
@@ -371,4 +376,94 @@ int io_register_zc_rx_sock(struct io_ring_ctx *ctx,
ifq->nr_sockets++;
return 0;
}
+
+static bool io_zc_rx_put_buf_uref(struct io_zc_rx_buf *buf)
+{
+ if (atomic_read(&buf->refcount) < IO_ZC_RX_UREF)
+ return false;
+
+ return atomic_sub_and_test(IO_ZC_RX_UREF, &buf->refcount);
+}
+
+static void io_zc_rx_refill_cache(struct io_zc_rx_ifq *ifq, int count)
+{
+ unsigned int entries = io_zc_rx_rqring_entries(ifq);
+ unsigned int mask = ifq->rq_entries - 1;
+ struct io_zc_rx_pool *pool = ifq->pool;
+ struct io_uring_rbuf_rqe *rqe;
+ struct io_zc_rx_buf *buf;
+ int i, filled;
+
+ if (!entries)
+ return;
+
+ for (i = 0, filled = 0; i < entries && filled < count; i++) {
+ unsigned int rq_idx = ifq->cached_rq_head++ & mask;
+ u32 pgid;
+
+ rqe = &ifq->rqes[rq_idx];
+ pgid = rqe->off / PAGE_SIZE;
+ buf = &pool->bufs[pgid];
+ if (!io_zc_rx_put_buf_uref(buf))
+ continue;
+ pool->cache[filled++] = pgid;
+ }
+
+ smp_store_release(&ifq->ring->rq.head, ifq->cached_rq_head);
+ pool->cache_count += filled;
+}
+
+struct io_zc_rx_buf *io_zc_rx_get_buf(struct io_zc_rx_ifq *ifq)
+{
+ struct io_zc_rx_pool *pool = ifq->pool;
+ struct io_zc_rx_buf *buf;
+ int count;
+ u32 pgid;
+
+ lockdep_assert_no_hardirq();
+
+ if (likely(pool->cache_count))
+ goto out;
+
+ io_zc_rx_refill_cache(ifq, POOL_REFILL_COUNT);
+ if (pool->cache_count)
+ goto out;
+
+ spin_lock_bh(&pool->freelist_lock);
+ count = min_t(u32, pool->free_count, POOL_CACHE_SIZE);
+ pool->free_count -= count;
+ pool->cache_count += count;
+ memcpy(pool->cache, &pool->freelist[pool->free_count],
+ count * sizeof(u32));
+ spin_unlock_bh(&pool->freelist_lock);
+
+ if (!pool->cache_count)
+ return NULL;
+out:
+ pgid = pool->cache[--pool->cache_count];
+ buf = &pool->bufs[pgid];
+ atomic_set(&buf->refcount, 1);
+ return buf;
+}
+EXPORT_SYMBOL(io_zc_rx_get_buf);
+
+static void io_zc_rx_recycle_buf(struct io_zc_rx_pool *pool,
+ struct io_zc_rx_buf *buf)
+{
+ spin_lock_bh(&pool->freelist_lock);
+ pool->freelist[pool->free_count++] = buf - pool->bufs;
+ spin_unlock_bh(&pool->freelist_lock);
+}
+
+void io_zc_rx_put_buf(struct io_zc_rx_ifq *ifq, struct io_zc_rx_buf *buf)
+{
+ struct io_zc_rx_pool *pool = ifq->pool;
+
+ if (!atomic_dec_and_test(&buf->refcount))
+ return;
+
+ io_zc_rx_recycle_buf(pool, buf);
+}
+EXPORT_SYMBOL(io_zc_rx_put_buf);
+
#endif
@@ -16,6 +16,8 @@ struct io_zc_rx_ifq {
struct io_uring_rbuf_rqe *rqes;
struct io_uring_rbuf_cqe *cqes;
u32 rq_entries, cq_entries;
+ u32 cached_rq_head;
+ u32 cached_cq_tail;
void *pool;
unsigned nr_sockets;
@@ -26,6 +28,15 @@ struct io_zc_rx_ifq {
};
#if defined(CONFIG_NET)
+static inline u32 io_zc_rx_rqring_entries(struct io_zc_rx_ifq *ifq)
+{
+ struct io_rbuf_ring *ring = ifq->ring;
+ u32 entries;
+
+ entries = smp_load_acquire(&ring->rq.tail) - ifq->cached_rq_head;
+ return min(entries, ifq->rq_entries);
+}
+
int io_register_zc_rx_ifq(struct io_ring_ctx *ctx,
struct io_uring_zc_rx_ifq_reg __user *arg);
int io_unregister_zc_rx_ifq(struct io_ring_ctx *ctx);