Skip to content

Commit e67645b

Browse files
isilenceaxboe
authored andcommitted
io_uring/zcrx: prepare fallback for larger pages
io_zcrx_copy_chunk() processes one page at a time, which won't be sufficient when the net_iov size grows. Introduce a structure keeping the target niov page and other parameters, it's more convenient and can be reused later. And add a helper function that can efficient copy buffers of an arbitrary length. For 64bit archs the loop inside should be compiled out. Signed-off-by: Pavel Begunkov <[email protected]> Link: https://lore.kernel.org/r/e84bc705a4e1edeb9aefff470d96558d8232388f.1751466461.git.asml.silence@gmail.com Signed-off-by: Jens Axboe <[email protected]>
1 parent 1b4dc1f commit e67645b

1 file changed

Lines changed: 56 additions & 27 deletions

File tree

io_uring/zcrx.c

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,51 @@ static struct net_iov *io_zcrx_alloc_fallback(struct io_zcrx_area *area)
929929
return niov;
930930
}
931931

932+
struct io_copy_cache {
933+
struct page *page;
934+
unsigned long offset;
935+
size_t size;
936+
};
937+
938+
static ssize_t io_copy_page(struct io_copy_cache *cc, struct page *src_page,
939+
unsigned int src_offset, size_t len)
940+
{
941+
size_t copied = 0;
942+
943+
len = min(len, cc->size);
944+
945+
while (len) {
946+
void *src_addr, *dst_addr;
947+
struct page *dst_page = cc->page;
948+
unsigned dst_offset = cc->offset;
949+
size_t n = len;
950+
951+
if (folio_test_partial_kmap(page_folio(dst_page)) ||
952+
folio_test_partial_kmap(page_folio(src_page))) {
953+
dst_page = nth_page(dst_page, dst_offset / PAGE_SIZE);
954+
dst_offset = offset_in_page(dst_offset);
955+
src_page = nth_page(src_page, src_offset / PAGE_SIZE);
956+
src_offset = offset_in_page(src_offset);
957+
n = min(PAGE_SIZE - src_offset, PAGE_SIZE - dst_offset);
958+
n = min(n, len);
959+
}
960+
961+
dst_addr = kmap_local_page(dst_page) + dst_offset;
962+
src_addr = kmap_local_page(src_page) + src_offset;
963+
964+
memcpy(dst_addr, src_addr, n);
965+
966+
kunmap_local(src_addr);
967+
kunmap_local(dst_addr);
968+
969+
cc->size -= n;
970+
cc->offset += n;
971+
len -= n;
972+
copied += n;
973+
}
974+
return copied;
975+
}
976+
932977
static ssize_t io_zcrx_copy_chunk(struct io_kiocb *req, struct io_zcrx_ifq *ifq,
933978
struct page *src_page, unsigned int src_offset,
934979
size_t len)
@@ -941,37 +986,32 @@ static ssize_t io_zcrx_copy_chunk(struct io_kiocb *req, struct io_zcrx_ifq *ifq,
941986
return -EFAULT;
942987

943988
while (len) {
944-
size_t copy_size = min_t(size_t, PAGE_SIZE, len);
945-
const int dst_off = 0;
989+
struct io_copy_cache cc;
946990
struct net_iov *niov;
947-
struct page *dst_page;
948-
void *dst_addr, *src_addr;
991+
size_t n;
949992

950993
niov = io_zcrx_alloc_fallback(area);
951994
if (!niov) {
952995
ret = -ENOMEM;
953996
break;
954997
}
955998

956-
dst_page = io_zcrx_iov_page(niov);
957-
dst_addr = kmap_local_page(dst_page);
958-
src_addr = kmap_local_page(src_page);
959-
960-
memcpy(dst_addr, src_addr + src_offset, copy_size);
999+
cc.page = io_zcrx_iov_page(niov);
1000+
cc.offset = 0;
1001+
cc.size = PAGE_SIZE;
9611002

962-
kunmap_local(src_addr);
963-
kunmap_local(dst_addr);
1003+
n = io_copy_page(&cc, src_page, src_offset, len);
9641004

965-
if (!io_zcrx_queue_cqe(req, niov, ifq, dst_off, copy_size)) {
1005+
if (!io_zcrx_queue_cqe(req, niov, ifq, 0, n)) {
9661006
io_zcrx_return_niov(niov);
9671007
ret = -ENOSPC;
9681008
break;
9691009
}
9701010

9711011
io_zcrx_get_niov_uref(niov);
972-
src_offset += copy_size;
973-
len -= copy_size;
974-
copied += copy_size;
1012+
src_offset += n;
1013+
len -= n;
1014+
copied += n;
9751015
}
9761016

9771017
return copied ? copied : ret;
@@ -981,19 +1021,8 @@ static int io_zcrx_copy_frag(struct io_kiocb *req, struct io_zcrx_ifq *ifq,
9811021
const skb_frag_t *frag, int off, int len)
9821022
{
9831023
struct page *page = skb_frag_page(frag);
984-
u32 p_off, p_len, t, copied = 0;
985-
int ret = 0;
9861024

987-
off += skb_frag_off(frag);
988-
989-
skb_frag_foreach_page(frag, off, len,
990-
page, p_off, p_len, t) {
991-
ret = io_zcrx_copy_chunk(req, ifq, page, p_off, p_len);
992-
if (ret < 0)
993-
return copied ? copied : ret;
994-
copied += ret;
995-
}
996-
return copied;
1025+
return io_zcrx_copy_chunk(req, ifq, page, off + skb_frag_off(frag), len);
9971026
}
9981027

9991028
static int io_zcrx_recv_frag(struct io_kiocb *req, struct io_zcrx_ifq *ifq,

0 commit comments

Comments
 (0)