On 6/12/20 11:30 AM, Pavel Begunkov wrote: > On 12/06/2020 20:02, Jens Axboe wrote: >> On 6/11/20 9:54 AM, Pavel Begunkov wrote: >>> io_do_iopoll() can async punt a request with io_queue_async_work(), >>> so doing io_req_work_grab_env(). The problem is that iopoll() can >>> be called from who knows what context, e.g. from a completely >>> different process with its own memory space, creds, etc. >>> >>> io_do_iopoll() { >>> ret = req->poll(); >>> if (ret == -EAGAIN) >>> io_queue_async_work() >>> ... >>> } >>> >>> >>> I can't find it handled in io_uring. Can this even happen? >>> Wouldn't it be better to complete them with -EAGAIN? >> >> I don't think a plain -EAGAIN complete would be very useful, it's kind >> of a shitty thing to pass back to userspace when it can be avoided. For >> polled IO, we know we're doing O_DIRECT, or using fixed buffers. For the >> latter, there's no problem in retrying, regardless of context. For the >> former, I think we'd get -EFAULT mapping the IO at that point, which is >> probably reasonable. I'd need to double check, though. > > It's shitty, but -EFAULT is the best outcome. I care more about not > corrupting another process' memory if addresses coincide. AFAIK it can > happen because io_{read,write} will use iovecs for punted re-submission. > > > Unconditional in advance async_prep() is too heavy to be good. I'd love to > see something more clever, but with -EAGAIN users at least can handle it. So how about we just grab ->task for the initial issue, and retry if we find it through -EAGAIN and ->task == current. That'll be the most common case, by far, and it'll prevent passes back -EAGAIN when we really don't have to. If the task is different, then -EAGAIN makes more sense, because at that point we're passing back -EAGAIN because we really cannot feasibly handle it rather than just as a convenience. -- Jens Axboe