Repository navigation
test/read-before-exit: wait for deferred ring frees on -ENOMEM - #1663
7z0423arsenova wants to merge 1 commit into
Conversation
Without CAP_IPC_LOCK, ring memory is accounted against RLIMIT_MEMLOCK. Every ring in this test exits with two timerfd reads still pending, so the kernel frees it asynchronously from the exit work. The test creates over 2000 rings back to back, faster than those frees complete, and as a regular user it runs into the limit: with the default 8 MiB limit, ring setup fails with -ENOMEM after about 1000 rings: queue_init: Cannot allocate memory Test IOPOLL failed loop 1 The test passes when run as root, since root rings are not accounted. When ring setup fails with -ENOMEM as a regular user, sleep and retry for up to a second to let the deferred frees catch up. Also print the loop index rather than the return value when the IOPOLL loop fails. Link: axboe#1611 Signed-off-by: Arsenova <7z0423arsenova@proton.me>
|
Update: the root cause is a kernel regression, not expected behavior. b59cabf9b4ac ("io_uring: do not charge the SQ/CQ rings to RLIMIT_MEMLOCK") which is tagged for stable. So this test is doing its job by failing on Two options:
Happy to respin with just the message fix, or close this, whichever |
This, the whole point of the test is to catch a regression, and it did. We should change the test case to make it pass. |
|
Thanks for the review, closing this PR! |
Run as a regular user,
read-before-exit.tfails every time on 7.3:Without
CAP_IPC_LOCK, ring memory is accounted againstRLIMIT_MEMLOCK(io_create_region()→__io_account_mem()). Every ring in this test exits with two timerfd reads still pending, so it is freed asynchronously byio_ring_exit_work(). The test creates over 2000 rings back to back, faster than those frees complete. With the default 8 MiB limit and about 8 KiB per ring, setup starts failing around ring 1000. The test passes as root because root rings are not accounted, which is presumably why CI doesn't see this.Measurements with a small reproducer (create a ring, leave a read pending, exit it, repeat):
-ENOMEMat ring ~991-996ulimit -lThis change makes the test sleep and retry for up to a second when ring setup fails with
-ENOMEMas a regular user. Root and other errors go throught_create_ring_params()exactly as before. It also prints the loop index instead of the return value when the IOPOLL loop fails; the old message's "loop 1" was reallyret.Tested on 7.3.0-9-generic as a regular user: 3 out of 3 runs pass with the default limit (0.6 to 0.9 s each), and the test also passes with
ulimit -l 512(2.3 s).This is likely also behind the
read-before-exit.tfailure in #1611. Thering setup failed: -12reported there for read-inc-* and read-mshot may be the same accounting backlog spilling over from earlier tests. I kept this change scoped to one test; retrying int_create_ring_params()itself would cover those too, if that's preferred.