In case of IORING_SETUP_SQPOLL | IORING_SETUP_IOPOLL: @inflight count returned by io_submit_sqes() is the number of entries picked up from a sqring including already completed/failed. And completed but not failed requests will be placed into @poll_list. Then io_sq_thread() tries to poll @inflight events, even though failed won't appear in @poll_list. Thus, it will think that there are always something to poll (i.e. @inflight > 0) There are several issues with this: 1. io_sq_thread won't ever sleep 2. io_sq_thread() may be left running and actively polling even after user process is destroyed 3. the same goes for mm_struct with all vmas of the user process TL;DR; awhile @inflight > 0, io_sq_thread won't put @cur_mm, so locking recycling of vmas used for rings' mapping, which hold refcount of io_uring's struct file. Thus, io_uring_release() won't be called, as well as kthread_{park,stop}(). That's all in case when the user process haven't unmapped rings. I'm not sure how to fix it better: 1. try to put failed into poll_list (grabbing mutex). 2. test for zero-inflight case with comparing sq and cq. something like ``` if (nr_polled == 0) { lock(comp_lock); if (cached_cq_head == cached_sq_tail) inflight = 0; unlock(comp_lock); } ``` But that's adds extra spinlock locking in fast-path. And that's unsafe to use non-cached heads/tails, as it could be maliciously changed by userspace. 3. Do some counting of failed (probably needs atomic or synchronisation) 4. something else? -- Yours sincerely, Pavel Begunkov
Attachment:
signature.asc
Description: OpenPGP digital signature