On 10/25/19 3:48 AM, Pavel Begunkov wrote: > 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? Can we just look at the completion count? Ala: prev_tail = ctx->cached_cq_tail; inflight += io_submit_sqes(ctx, to_submit, cur_mm != NULL, mm_fault); if (prev_tail != ctx->cached_cq_tail) inflight -= (ctx->cached_cq_tail - prev_tail); or something like that. -- Jens Axboe