Skip to content

Commit 33d379b

Browse files
committed
Merge branch 'for-6.17/io_uring' into for-next
* for-6.17/io_uring: io_uring/zcrx: prepare fallback for larger pages io_uring/zcrx: assert area type in io_zcrx_iov_page io_uring/zcrx: allocate sgtable for umem areas io_uring/zcrx: introduce io_populate_area_dma io_uring/zcrx: return error from io_zcrx_map_area_* io_uring/zcrx: always pass page to io_zcrx_copy_chunk
2 parents 6f91dad + e67645b commit 33d379b

2 files changed

Lines changed: 128 additions & 114 deletions

File tree

io_uring/zcrx.c

Lines changed: 127 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,40 @@ static inline struct page *io_zcrx_iov_page(const struct net_iov *niov)
4444
{
4545
struct io_zcrx_area *area = io_zcrx_iov_to_area(niov);
4646

47+
lockdep_assert(!area->mem.is_dmabuf);
48+
4749
return area->mem.pages[net_iov_idx(niov)];
4850
}
4951

52+
static int io_populate_area_dma(struct io_zcrx_ifq *ifq,
53+
struct io_zcrx_area *area,
54+
struct sg_table *sgt, unsigned long off)
55+
{
56+
struct scatterlist *sg;
57+
unsigned i, niov_idx = 0;
58+
59+
for_each_sgtable_dma_sg(sgt, sg, i) {
60+
dma_addr_t dma = sg_dma_address(sg);
61+
unsigned long sg_len = sg_dma_len(sg);
62+
unsigned long sg_off = min(sg_len, off);
63+
64+
off -= sg_off;
65+
sg_len -= sg_off;
66+
dma += sg_off;
67+
68+
while (sg_len && niov_idx < area->nia.num_niovs) {
69+
struct net_iov *niov = &area->nia.niovs[niov_idx];
70+
71+
if (net_mp_niov_set_dma_addr(niov, dma))
72+
return -EFAULT;
73+
sg_len -= PAGE_SIZE;
74+
dma += PAGE_SIZE;
75+
niov_idx++;
76+
}
77+
}
78+
return 0;
79+
}
80+
5081
static void io_release_dmabuf(struct io_zcrx_mem *mem)
5182
{
5283
if (!IS_ENABLED(CONFIG_DMA_SHARED_BUFFER))
@@ -121,41 +152,18 @@ static int io_import_dmabuf(struct io_zcrx_ifq *ifq,
121152

122153
static int io_zcrx_map_area_dmabuf(struct io_zcrx_ifq *ifq, struct io_zcrx_area *area)
123154
{
124-
unsigned long off = area->mem.dmabuf_offset;
125-
struct scatterlist *sg;
126-
unsigned i, niov_idx = 0;
127-
128155
if (!IS_ENABLED(CONFIG_DMA_SHARED_BUFFER))
129156
return -EINVAL;
130-
131-
for_each_sgtable_dma_sg(area->mem.sgt, sg, i) {
132-
dma_addr_t dma = sg_dma_address(sg);
133-
unsigned long sg_len = sg_dma_len(sg);
134-
unsigned long sg_off = min(sg_len, off);
135-
136-
off -= sg_off;
137-
sg_len -= sg_off;
138-
dma += sg_off;
139-
140-
while (sg_len && niov_idx < area->nia.num_niovs) {
141-
struct net_iov *niov = &area->nia.niovs[niov_idx];
142-
143-
if (net_mp_niov_set_dma_addr(niov, dma))
144-
return 0;
145-
sg_len -= PAGE_SIZE;
146-
dma += PAGE_SIZE;
147-
niov_idx++;
148-
}
149-
}
150-
return niov_idx;
157+
return io_populate_area_dma(ifq, area, area->mem.sgt,
158+
area->mem.dmabuf_offset);
151159
}
152160

153161
static int io_import_umem(struct io_zcrx_ifq *ifq,
154162
struct io_zcrx_mem *mem,
155163
struct io_uring_zcrx_area_reg *area_reg)
156164
{
157165
struct page **pages;
158-
int nr_pages;
166+
int nr_pages, ret;
159167

160168
if (area_reg->dmabuf_fd)
161169
return -EINVAL;
@@ -166,6 +174,12 @@ static int io_import_umem(struct io_zcrx_ifq *ifq,
166174
if (IS_ERR(pages))
167175
return PTR_ERR(pages);
168176

177+
ret = sg_alloc_table_from_pages(&mem->page_sg_table, pages, nr_pages,
178+
0, nr_pages << PAGE_SHIFT,
179+
GFP_KERNEL_ACCOUNT);
180+
if (ret)
181+
return ret;
182+
169183
mem->pages = pages;
170184
mem->nr_folios = nr_pages;
171185
mem->size = area_reg->len;
@@ -180,6 +194,7 @@ static void io_release_area_mem(struct io_zcrx_mem *mem)
180194
}
181195
if (mem->pages) {
182196
unpin_user_pages(mem->pages, mem->nr_folios);
197+
sg_free_table(&mem->page_sg_table);
183198
kvfree(mem->pages);
184199
}
185200
}
@@ -201,84 +216,54 @@ static int io_import_area(struct io_zcrx_ifq *ifq,
201216
return io_import_umem(ifq, mem, area_reg);
202217
}
203218

204-
static void io_zcrx_unmap_umem(struct io_zcrx_ifq *ifq,
205-
struct io_zcrx_area *area, int nr_mapped)
206-
{
207-
int i;
208-
209-
for (i = 0; i < nr_mapped; i++) {
210-
netmem_ref netmem = net_iov_to_netmem(&area->nia.niovs[i]);
211-
dma_addr_t dma = page_pool_get_dma_addr_netmem(netmem);
212-
213-
dma_unmap_page_attrs(ifq->dev, dma, PAGE_SIZE,
214-
DMA_FROM_DEVICE, IO_DMA_ATTR);
215-
}
216-
}
217-
218-
static void __io_zcrx_unmap_area(struct io_zcrx_ifq *ifq,
219-
struct io_zcrx_area *area, int nr_mapped)
219+
static void io_zcrx_unmap_area(struct io_zcrx_ifq *ifq,
220+
struct io_zcrx_area *area)
220221
{
221222
int i;
222223

223-
if (area->mem.is_dmabuf)
224-
io_release_dmabuf(&area->mem);
225-
else
226-
io_zcrx_unmap_umem(ifq, area, nr_mapped);
224+
guard(mutex)(&ifq->dma_lock);
225+
if (!area->is_mapped)
226+
return;
227+
area->is_mapped = false;
227228

228229
for (i = 0; i < area->nia.num_niovs; i++)
229230
net_mp_niov_set_dma_addr(&area->nia.niovs[i], 0);
230-
}
231-
232-
static void io_zcrx_unmap_area(struct io_zcrx_ifq *ifq, struct io_zcrx_area *area)
233-
{
234-
guard(mutex)(&ifq->dma_lock);
235231

236-
if (area->is_mapped)
237-
__io_zcrx_unmap_area(ifq, area, area->nia.num_niovs);
238-
area->is_mapped = false;
232+
if (area->mem.is_dmabuf) {
233+
io_release_dmabuf(&area->mem);
234+
} else {
235+
dma_unmap_sgtable(ifq->dev, &area->mem.page_sg_table,
236+
DMA_FROM_DEVICE, IO_DMA_ATTR);
237+
}
239238
}
240239

241-
static int io_zcrx_map_area_umem(struct io_zcrx_ifq *ifq, struct io_zcrx_area *area)
240+
static unsigned io_zcrx_map_area_umem(struct io_zcrx_ifq *ifq, struct io_zcrx_area *area)
242241
{
243-
int i;
244-
245-
for (i = 0; i < area->nia.num_niovs; i++) {
246-
struct net_iov *niov = &area->nia.niovs[i];
247-
dma_addr_t dma;
242+
int ret;
248243

249-
dma = dma_map_page_attrs(ifq->dev, area->mem.pages[i], 0,
250-
PAGE_SIZE, DMA_FROM_DEVICE, IO_DMA_ATTR);
251-
if (dma_mapping_error(ifq->dev, dma))
252-
break;
253-
if (net_mp_niov_set_dma_addr(niov, dma)) {
254-
dma_unmap_page_attrs(ifq->dev, dma, PAGE_SIZE,
255-
DMA_FROM_DEVICE, IO_DMA_ATTR);
256-
break;
257-
}
258-
}
259-
return i;
244+
ret = dma_map_sgtable(ifq->dev, &area->mem.page_sg_table,
245+
DMA_FROM_DEVICE, IO_DMA_ATTR);
246+
if (ret < 0)
247+
return ret;
248+
return io_populate_area_dma(ifq, area, &area->mem.page_sg_table, 0);
260249
}
261250

262251
static int io_zcrx_map_area(struct io_zcrx_ifq *ifq, struct io_zcrx_area *area)
263252
{
264-
unsigned nr;
253+
int ret;
265254

266255
guard(mutex)(&ifq->dma_lock);
267256
if (area->is_mapped)
268257
return 0;
269258

270259
if (area->mem.is_dmabuf)
271-
nr = io_zcrx_map_area_dmabuf(ifq, area);
260+
ret = io_zcrx_map_area_dmabuf(ifq, area);
272261
else
273-
nr = io_zcrx_map_area_umem(ifq, area);
262+
ret = io_zcrx_map_area_umem(ifq, area);
274263

275-
if (nr != area->nia.num_niovs) {
276-
__io_zcrx_unmap_area(ifq, area, nr);
277-
return -EINVAL;
278-
}
279-
280-
area->is_mapped = true;
281-
return 0;
264+
if (ret == 0)
265+
area->is_mapped = true;
266+
return ret;
282267
}
283268

284269
static void io_zcrx_sync_for_device(const struct page_pool *pool,
@@ -941,9 +926,54 @@ static struct net_iov *io_zcrx_alloc_fallback(struct io_zcrx_area *area)
941926
return niov;
942927
}
943928

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

955985
while (len) {
956-
size_t copy_size = min_t(size_t, PAGE_SIZE, len);
957-
const int dst_off = 0;
986+
struct io_copy_cache cc;
958987
struct net_iov *niov;
959-
struct page *dst_page;
960-
void *dst_addr;
988+
size_t n;
961989

962990
niov = io_zcrx_alloc_fallback(area);
963991
if (!niov) {
964992
ret = -ENOMEM;
965993
break;
966994
}
967995

968-
dst_page = io_zcrx_iov_page(niov);
969-
dst_addr = kmap_local_page(dst_page);
970-
if (src_page)
971-
src_base = kmap_local_page(src_page);
996+
cc.page = io_zcrx_iov_page(niov);
997+
cc.offset = 0;
998+
cc.size = PAGE_SIZE;
972999

973-
memcpy(dst_addr, src_base + src_offset, copy_size);
1000+
n = io_copy_page(&cc, src_page, src_offset, len);
9741001

975-
if (src_page)
976-
kunmap_local(src_base);
977-
kunmap_local(dst_addr);
978-
979-
if (!io_zcrx_queue_cqe(req, niov, ifq, dst_off, copy_size)) {
1002+
if (!io_zcrx_queue_cqe(req, niov, ifq, 0, n)) {
9801003
io_zcrx_return_niov(niov);
9811004
ret = -ENOSPC;
9821005
break;
9831006
}
9841007

9851008
io_zcrx_get_niov_uref(niov);
986-
src_offset += copy_size;
987-
len -= copy_size;
988-
copied += copy_size;
1009+
src_offset += n;
1010+
len -= n;
1011+
copied += n;
9891012
}
9901013

9911014
return copied ? copied : ret;
@@ -995,19 +1018,8 @@ static int io_zcrx_copy_frag(struct io_kiocb *req, struct io_zcrx_ifq *ifq,
9951018
const skb_frag_t *frag, int off, int len)
9961019
{
9971020
struct page *page = skb_frag_page(frag);
998-
u32 p_off, p_len, t, copied = 0;
999-
int ret = 0;
10001021

1001-
off += skb_frag_off(frag);
1002-
1003-
skb_frag_foreach_page(frag, off, len,
1004-
page, p_off, p_len, t) {
1005-
ret = io_zcrx_copy_chunk(req, ifq, NULL, page, p_off, p_len);
1006-
if (ret < 0)
1007-
return copied ? copied : ret;
1008-
copied += ret;
1009-
}
1010-
return copied;
1022+
return io_zcrx_copy_chunk(req, ifq, page, off + skb_frag_off(frag), len);
10111023
}
10121024

10131025
static int io_zcrx_recv_frag(struct io_kiocb *req, struct io_zcrx_ifq *ifq,
@@ -1064,8 +1076,9 @@ io_zcrx_recv_skb(read_descriptor_t *desc, struct sk_buff *skb,
10641076
size_t to_copy;
10651077

10661078
to_copy = min_t(size_t, skb_headlen(skb) - offset, len);
1067-
copied = io_zcrx_copy_chunk(req, ifq, skb->data, NULL,
1068-
offset, to_copy);
1079+
copied = io_zcrx_copy_chunk(req, ifq, virt_to_page(skb->data),
1080+
offset_in_page(skb->data) + offset,
1081+
to_copy);
10691082
if (copied < 0) {
10701083
ret = copied;
10711084
goto out;

io_uring/zcrx.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ struct io_zcrx_mem {
1414

1515
struct page **pages;
1616
unsigned long nr_folios;
17+
struct sg_table page_sg_table;
1718

1819
struct dma_buf_attachment *attach;
1920
struct dma_buf *dmabuf;

0 commit comments

Comments
 (0)