FAILED: patch "[PATCH] io_uring/kbuf: don't charge provided buffer rings to" failed to apply to 6.18-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.18-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.18.y
git checkout FETCH_HEAD
git cherry-pick -x cde56daf4b93f474dc256dbcc5205035223ae6f5
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026101232-relieving-tacking-73ef@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From cde56daf4b93f474dc256dbcc5205035223ae6f5 Mon Sep 17 00:00:00 2001
From: Jens Axboe <[email protected]>
Date: Thu, 8 Oct 2026 13:07:38 -0600
Subject: [PATCH] io_uring/kbuf: don't charge provided buffer rings to
RLIMIT_MEMLOCK
Just like with the SQ and CQ rings, the provided buffer rings were also not charged against the memlock limit prior to the below mentioned commit. Restore that behavior.
io_uring/kbuf.c +3 -3
@@ -459,7 +459,7 @@ static int io_remove_buffers_legacy(struct io_ring_ctx *ctx,static void io_put_bl (struct io_ring_ctx *ctx,struct io_buffer_list *bl) {if (bl->flags &IOBL_BUF_RING ) -io_free_region (ctx->user, &bl->region); +io_free_region (NULL , &bl->region);else io_remove_buffers_legacy (ctx, bl,-1U );
@@ -676,7 +676,7 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg) rd.user_addr = reg.ring_addr; rd.flags |=IORING_MEM_REGION_TYPE_USER ; } - ret =io_create_region (ctx->user, &bl->region, &rd, mmap_offset); + ret =io_create_region (NULL , &bl->region, &rd, mmap_offset);if (ret) goto fail; br =io_region_get_ptr (&bl->region);
@@ -709,7 +709,7 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)if (!ret)return 0 ; fail: -io_free_region (ctx->user, &bl->region); +io_free_region (NULL , &bl->region);kfree (bl);return ret; }
Quoted 8 lines · On 10/12/26 5:43 AM, [email protected] wrote:
The patch below does not apply to the 6.18-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.To reproduce the conflict and resubmit, you may use the following commands:
Quoted 8 lines
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.18.y
git checkoutFETCH_HEAD
git cherry-pick -xcde56daf4b93f474dc256dbcc5205035223ae6f5
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026101232-relieving-tacking-73ef@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'Possible dependencies:
Here are the 2 accounting patches adopted for 6.18-stable.
Signature · 1 line
Jens Axboe
From 70fa03bac565a5046a4aec1dd50192d56329b2f9 Mon Sep 17 00:00:00 2001
From: Jens Axboe <[email protected]>
Date: Thu, 8 Oct 2026 13:07:38 -0600
Subject: [PATCH 2/2] io_uring/kbuf: don't charge provided buffer rings to
RLIMIT_MEMLOCK
commit cde56daf4b93f474dc256dbcc5205035223ae6f5 upstream.
Just like with the SQ and CQ rings, the provided buffer rings were also not charged against the memlock limit prior to the below mentioned commit. Restore that behavior.
--- io_uring/kbuf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
io_uring/kbuf.c +3 -3
@@ -444,7 +444,7 @@ static int io_remove_buffers_legacy(struct io_ring_ctx *ctx,static void io_put_bl (struct io_ring_ctx *ctx,struct io_buffer_list *bl) {if (bl->flags &IOBL_BUF_RING ) -io_free_region (ctx->user, &bl->region); +io_free_region (NULL , &bl->region);else io_remove_buffers_legacy (ctx, bl,-1U );
@@ -661,7 +661,7 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg) rd.user_addr = reg.ring_addr; rd.flags |=IORING_MEM_REGION_TYPE_USER ; } - ret =io_create_region_mmap_safe (ctx, ctx->user, &bl->region, &rd, mmap_offset); + ret =io_create_region_mmap_safe (ctx,NULL , &bl->region, &rd, mmap_offset);if (ret) goto fail; br =io_region_get_ptr (&bl->region);
@@ -695,7 +695,7 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)if (!ret)return 0 ; fail: -io_free_region (ctx->user, &bl->region); +io_free_region (NULL , &bl->region);kfree (bl);return ret; }
Signature · 1 line
2.56.0
From 82ece83ba3d1d79f9abb8c84cf6e7717145541df Mon Sep 17 00:00:00 2001
From: Hengyu Liang <[email protected]>
Date: Tue, 6 Oct 2026 08:57:32 -0400
Subject: [PATCH 1/2] io_uring: do not charge the SQ/CQ rings to RLIMIT_MEMLOCK
commit b59cabf9b4acb65f3f9968087ca0e18010d85076 upstream.
Commit 8078486e1d53 ("io_uring: use region api for SQ") and commit 81a4058e0cd0 ("io_uring: use region api for CQ") made io_uring_setup() allocate the rings with io_create_region().
However, io_create_region() charges the memory to RLIMIT_MEMLOCK, and the rings had been exempt from that limit since commit 26bfa89e25f4 ("io_uring: place ring SQ/CQ arrays under memcg memory limits"). As of now, a user without CAP_IPC_LOCK gets ENOMEM from io_uring_setup() when their rings exceed the limit, which is 8 MiB by default. PostgreSQL developers have already hit this in their io_uring tests [1].
The issue can be reproduced with a simple liburing program, run as an unprivileged user:
#include <liburing.h>
#include <stdio.h>
int main(void)
{
static struct io_uring ring[64];
int i;
for (i = 0; i < 64; i++)
if (io_uring_queue_init(4096, &ring[i], 0) < 0)
break;
printf("%d rings\n", i);
return 0;
}Before those commits (v6.13), it prints "64 rings". After those commits (v6.14), it prints "21 rings".
This patch makes io_create_region() take the user to charge, and passes no user for the SQ/CQ rings.
[axboe: 6.18 still has the ctx based region API. Convert
io_create_region() and io_free_region() to take the user_struct, and add a user argument to io_create_region_mmap_safe()]
--- io_uring/io_uring.c | 12 +++++++----- io_uring/kbuf.c | 6 +++--- io_uring/memmap.c | 29 ++++++++++++++--------------- io_uring/memmap.h | 6 +++--- io_uring/register.c | 15 ++++++++------- io_uring/zcrx.c | 4 ++-- 6 files changed, 37 insertions(+), 35 deletions(-)
io_uring/io_uring.c +7 -5
@@ -2832,8 +2832,9 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events, u32 flags,static void io_rings_free (struct io_ring_ctx *ctx) { -io_free_region (ctx, &ctx->sq_region); -io_free_region (ctx, &ctx->ring_region); +/* ring memory is not charged to RLIMIT_MEMLOCK, hence no user */ +io_free_region (NULL , &ctx->sq_region); +io_free_region (NULL , &ctx->ring_region); ctx->rings =NULL ;RCU_INIT_POINTER (ctx->rings_rcu,NULL ); ctx->sq_sqes =NULL ;
@@ -2915,7 +2916,7 @@ static __cold void io_ring_ctx_free(struct io_ring_ctx *ctx)io_eventfd_unregister (ctx);io_free_alloc_caches (ctx);io_destroy_buffers (ctx); -io_free_region (ctx, &ctx->param_region); +io_free_region (ctx->user, &ctx->param_region);mutex_unlock (&ctx->uring_lock);if (ctx->sq_creds)put_cred (ctx->sq_creds);
@@ -3688,7 +3689,8 @@ static __cold int io_allocate_scq_urings(struct io_ring_ctx *ctx, rd.user_addr = p->cq_off.user_addr; rd.flags |=IORING_MEM_REGION_TYPE_USER ; } - ret =io_create_region (ctx, &ctx->ring_region, &rd,IORING_OFF_CQ_RING ); +/* ring memory is not charged to RLIMIT_MEMLOCK, hence no user */ + ret =io_create_region (NULL , &ctx->ring_region, &rd,IORING_OFF_CQ_RING );if (ret)return ret; ctx->rings = rings =io_region_get_ptr (&ctx->ring_region);
@@ -3711,7 +3713,7 @@ static __cold int io_allocate_scq_urings(struct io_ring_ctx *ctx, rd.user_addr = p->sq_off.user_addr; rd.flags |=IORING_MEM_REGION_TYPE_USER ; } - ret =io_create_region (ctx, &ctx->sq_region, &rd,IORING_OFF_SQES ); + ret =io_create_region (NULL , &ctx->sq_region, &rd,IORING_OFF_SQES );if (ret) {io_rings_free (ctx);return ret;
io_uring/kbuf.c +3 -3
@@ -444,7 +444,7 @@ static int io_remove_buffers_legacy(struct io_ring_ctx *ctx,static void io_put_bl (struct io_ring_ctx *ctx,struct io_buffer_list *bl) {if (bl->flags &IOBL_BUF_RING ) -io_free_region (ctx, &bl->region); +io_free_region (ctx->user, &bl->region);else io_remove_buffers_legacy (ctx, bl,-1U );
@@ -661,7 +661,7 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg) rd.user_addr = reg.ring_addr; rd.flags |=IORING_MEM_REGION_TYPE_USER ; } - ret =io_create_region_mmap_safe (ctx, &bl->region, &rd, mmap_offset); + ret =io_create_region_mmap_safe (ctx, ctx->user, &bl->region, &rd, mmap_offset);if (ret) goto fail; br =io_region_get_ptr (&bl->region);
@@ -695,7 +695,7 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)if (!ret)return 0 ; fail: -io_free_region (ctx, &bl->region); +io_free_region (ctx->user, &bl->region);kfree (bl);return ret; }
io_uring/memmap.c +14 -15
@@ -88,7 +88,7 @@ enum { IO_REGION_F_SINGLE_REF = 4, }; -void io_free_region (struct io_ring_ctx *ctx,struct io_mapped_region *mr) +void io_free_region (struct user_struct *user,struct io_mapped_region *mr) {if (mr->pages) {long nr_refs = mr->nr_pages;
@@ -105,8 +105,8 @@ void io_free_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr) }if ((mr->flags &IO_REGION_F_VMAP ) && mr->ptr)vunmap (mr->ptr); -if (mr->nr_pages && ctx->user) -__io_unaccount_mem (ctx->user, mr->nr_pages); +if (mr->nr_pages && user) +__io_unaccount_mem (user, mr->nr_pages);memset (mr,0 ,sizeof (*mr)); }
@@ -131,8 +131,7 @@ static int io_region_init_ptr(struct io_mapped_region *mr)return 0 ; } -static int io_region_pin_pages (struct io_ring_ctx *ctx, -struct io_mapped_region *mr, +static int io_region_pin_pages (struct io_mapped_region *mr,struct io_uring_region_desc *reg) {unsigned long size = (size_t ) mr->nr_pages <<PAGE_SHIFT ;
@@ -150,8 +149,7 @@ static int io_region_pin_pages(struct io_ring_ctx *ctx,return 0 ; } -static int io_region_allocate_pages (struct io_ring_ctx *ctx, -struct io_mapped_region *mr, +static int io_region_allocate_pages (struct io_mapped_region *mr,struct io_uring_region_desc *reg,unsigned long mmap_offset) {
@@ -185,7 +183,7 @@ static int io_region_allocate_pages(struct io_ring_ctx *ctx,return 0 ; } -int io_create_region (struct io_ring_ctx *ctx,struct io_mapped_region *mr, +int io_create_region (struct user_struct *user,struct io_mapped_region *mr,struct io_uring_region_desc *reg,unsigned long mmap_offset) {
@@ -211,17 +209,17 @@ int io_create_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr,return -EOVERFLOW ; nr_pages = reg->size >>PAGE_SHIFT ; -if (ctx->user) { - ret =__io_account_mem (ctx->user, nr_pages); +if (user) { + ret =__io_account_mem (user, nr_pages);if (ret)return ret; } mr->nr_pages = nr_pages;if (reg->flags &IORING_MEM_REGION_TYPE_USER ) - ret =io_region_pin_pages (ctx, mr, reg); + ret =io_region_pin_pages (mr, reg);else - ret =io_region_allocate_pages (ctx, mr, reg, mmap_offset); + ret =io_region_allocate_pages (mr, reg, mmap_offset);if (ret) goto out_free;
@@ -230,11 +228,12 @@ int io_create_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr, goto out_free;return 0 ; out_free: -io_free_region (ctx, mr); +io_free_region (user, mr);return ret; } -int io_create_region_mmap_safe (struct io_ring_ctx *ctx,struct io_mapped_region *mr, +int io_create_region_mmap_safe (struct io_ring_ctx *ctx,struct user_struct *user, +struct io_mapped_region *mr,struct io_uring_region_desc *reg,unsigned long mmap_offset) {
@@ -242,7 +241,7 @@ int io_create_region_mmap_safe(struct io_ring_ctx *ctx, struct io_mapped_regionint ret;memcpy (&tmp_mr, mr,sizeof (tmp_mr)); - ret =io_create_region (ctx, &tmp_mr, reg, mmap_offset); + ret =io_create_region (user, &tmp_mr, reg, mmap_offset);if (ret)return ret;
io_uring/memmap.h +3 -3
@@ -16,12 +16,12 @@ unsigned long io_uring_get_unmapped_area(struct file *file, unsigned long addr, unsigned long flags);int io_uring_mmap (struct file *file,struct vm_area_struct *vma); -void io_free_region (struct io_ring_ctx *ctx,struct io_mapped_region *mr); -int io_create_region (struct io_ring_ctx *ctx,struct io_mapped_region *mr, +void io_free_region (struct user_struct *user,struct io_mapped_region *mr); +int io_create_region (struct user_struct *user,struct io_mapped_region *mr,struct io_uring_region_desc *reg,unsigned long mmap_offset); -int io_create_region_mmap_safe (struct io_ring_ctx *ctx, +int io_create_region_mmap_safe (struct io_ring_ctx *ctx,struct user_struct *user,struct io_mapped_region *mr,struct io_uring_region_desc *reg,unsigned long mmap_offset);
io_uring/register.c +8 -7
@@ -383,8 +383,9 @@ static void io_register_free_rings(struct io_ring_ctx *ctx,struct io_uring_params *p, struct io_ring_ctx_rings *r) { - io_free_region(ctx, &r->sq_region); -io_free_region (ctx, &r->ring_region); +/* ring memory is not charged to RLIMIT_MEMLOCK, hence no user */ + io_free_region(NULL, &r->sq_region); +io_free_region (NULL , &r->ring_region); }#define swap_old (ctx, o, n, field) \
@@ -433,7 +434,7 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg) rd.user_addr = p.cq_off.user_addr; rd.flags |=IORING_MEM_REGION_TYPE_USER ; } - ret =io_create_region_mmap_safe (ctx, &n.ring_region, &rd,IORING_OFF_CQ_RING ); + ret =io_create_region_mmap_safe (ctx,NULL , &n.ring_region, &rd,IORING_OFF_CQ_RING );if (ret) {io_register_free_rings (ctx, &p, &n);return ret;
@@ -473,7 +474,7 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg) rd.user_addr = p.sq_off.user_addr; rd.flags |=IORING_MEM_REGION_TYPE_USER ; } - ret =io_create_region_mmap_safe (ctx, &n.sq_region, &rd,IORING_OFF_SQES ); + ret =io_create_region_mmap_safe (ctx,NULL , &n.sq_region, &rd,IORING_OFF_SQES );if (ret) {io_register_free_rings (ctx, &p, &n);return ret;
@@ -633,13 +634,13 @@ static int io_register_mem_region(struct io_ring_ctx *ctx, void __user *uarg) !(ctx->flags & IORING_SETUP_R_DISABLED))return -EINVAL ; - ret =io_create_region_mmap_safe (ctx, &ctx->param_region, &rd, -IORING_MAP_OFF_PARAM_REGION ); + ret =io_create_region_mmap_safe (ctx, ctx->user, &ctx->param_region, + &rd,IORING_MAP_OFF_PARAM_REGION );if (ret)return ret;if (copy_to_user (rd_uptr, &rd,sizeof (rd))) {guard (mutex)(&ctx->mmap_lock); -io_free_region (ctx, &ctx->param_region); +io_free_region (ctx->user, &ctx->param_region);return -EFAULT ; }
io_uring/zcrx.c +2 -2
@@ -371,7 +371,7 @@ static int io_allocate_rbuf_ring(struct io_zcrx_ifq *ifq, mmap_offset =IORING_MAP_OFF_ZCRX_REGION ; mmap_offset += id <<IORING_OFF_PBUF_SHIFT ; - ret =io_create_region (ifq->ctx, &ifq->region, rd, mmap_offset); + ret =io_create_region (ifq->ctx->user, &ifq->region, rd, mmap_offset);if (ret <0 )return ret;
@@ -387,7 +387,7 @@ static int io_allocate_rbuf_ring(struct io_zcrx_ifq *ifq,static void io_free_rbuf_ring (struct io_zcrx_ifq *ifq) { -io_free_region (ifq->ctx, &ifq->region); +io_free_region (ifq->ctx->user, &ifq->region); ifq->rq_ring =NULL ; ifq->rqes =NULL ; }
Signature · 1 line
2.56.0
Quoted 1 line
Here are the 2 accounting patches adopted for 6.18-stable.
Queued for 6.18, thanks.
Signature · 2 lines
Thanks, Sasha