From: Jens Axboe <ax...@kernel.dk>

[ Upstream commit 944d1444d53f5a213457e5096db370cfd06923d4 ]

Any attempt to do path resolution on /proc/self from an async worker will
yield -EOPNOTSUPP. We can safely do that resolution from the task itself,
and without blocking, so retry it from there.

Ideally io_uring would know this upfront and not have to go through the
worker thread to find out, but that doesn't currently seem feasible.

Signed-off-by: Jens Axboe <ax...@kernel.dk>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 fs/io_uring.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/fs/io_uring.c b/fs/io_uring.c
index e74a56f6915c0..46a68a8439895 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -435,6 +435,7 @@ struct io_sr_msg {
 struct io_open {
        struct file                     *file;
        int                             dfd;
+       bool                            ignore_nonblock;
        struct filename                 *filename;
        struct open_how                 how;
        unsigned long                   nofile;
@@ -3590,6 +3591,7 @@ static int __io_openat_prep(struct io_kiocb *req, const 
struct io_uring_sqe *sqe
                return ret;
        }
        req->open.nofile = rlimit(RLIMIT_NOFILE);
+       req->open.ignore_nonblock = false;
        req->flags |= REQ_F_NEED_CLEANUP;
        return 0;
 }
@@ -3637,7 +3639,7 @@ static int io_openat2(struct io_kiocb *req, bool 
force_nonblock)
        struct file *file;
        int ret;
 
-       if (force_nonblock)
+       if (force_nonblock && !req->open.ignore_nonblock)
                return -EAGAIN;
 
        ret = build_open_flags(&req->open.how, &op);
@@ -3652,6 +3654,21 @@ static int io_openat2(struct io_kiocb *req, bool 
force_nonblock)
        if (IS_ERR(file)) {
                put_unused_fd(ret);
                ret = PTR_ERR(file);
+               /*
+                * A work-around to ensure that /proc/self works that way
+                * that it should - if we get -EOPNOTSUPP back, then assume
+                * that proc_self_get_link() failed us because we're in async
+                * context. We should be safe to retry this from the task
+                * itself with force_nonblock == false set, as it should not
+                * block on lookup. Would be nice to know this upfront and
+                * avoid the async dance, but doesn't seem feasible.
+                */
+               if (ret == -EOPNOTSUPP && io_wq_current_is_worker()) {
+                       req->open.ignore_nonblock = true;
+                       refcount_inc(&req->refs);
+                       io_req_task_queue(req);
+                       return 0;
+               }
        } else {
                fsnotify_open(file);
                fd_install(ret, file);
-- 
2.27.0

Reply via email to