* Re: FAILED: Patch "io_uring/rw: fix missing NOWAIT check for O_DIRECT start write" failed to apply to v5.10-stable tree
2024-11-06 2:13 FAILED: Patch "io_uring/rw: fix missing NOWAIT check for O_DIRECT start write" failed to apply to v5.10-stable tree Sasha Levin
@ 2024-11-06 14:53 ` Jens Axboe
0 siblings, 0 replies; 2+ messages in thread
From: Jens Axboe @ 2024-11-06 14:53 UTC (permalink / raw)
To: Sasha Levin, stable; +Cc: Peter Mann, io-uring, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 326 bytes --]
On 11/5/24 7:13 PM, Sasha Levin wrote:
> The patch below does not apply to the v5.10-stable tree.
> If someone wants it applied there, or to any other stable or longterm
> tree, then please email the backport, including the original git commit
> id to <[email protected]>.
Here's the 5.10-stable series.
--
Jens Axboe
[-- Attachment #2: 0004-io_uring-rw-fix-missing-NOWAIT-check-for-O_DIRECT-st.patch --]
[-- Type: text/x-patch, Size: 4138 bytes --]
From 51f73fe0ac32955e14b82ddc09af97a4f4a500e0 Mon Sep 17 00:00:00 2001
From: Jens Axboe <[email protected]>
Date: Thu, 31 Oct 2024 08:05:44 -0600
Subject: [PATCH 4/4] io_uring/rw: fix missing NOWAIT check for O_DIRECT start
write
Commit 1d60d74e852647255bd8e76f5a22dc42531e4389 upstream.
When io_uring starts a write, it'll call kiocb_start_write() to bump the
super block rwsem, preventing any freezes from happening while that
write is in-flight. The freeze side will grab that rwsem for writing,
excluding any new writers from happening and waiting for existing writes
to finish. But io_uring unconditionally uses kiocb_start_write(), which
will block if someone is currently attempting to freeze the mount point.
This causes a deadlock where freeze is waiting for previous writes to
complete, but the previous writes cannot complete, as the task that is
supposed to complete them is blocked waiting on starting a new write.
This results in the following stuck trace showing that dependency with
the write blocked starting a new write:
task:fio state:D stack:0 pid:886 tgid:886 ppid:876
Call trace:
__switch_to+0x1d8/0x348
__schedule+0x8e8/0x2248
schedule+0x110/0x3f0
percpu_rwsem_wait+0x1e8/0x3f8
__percpu_down_read+0xe8/0x500
io_write+0xbb8/0xff8
io_issue_sqe+0x10c/0x1020
io_submit_sqes+0x614/0x2110
__arm64_sys_io_uring_enter+0x524/0x1038
invoke_syscall+0x74/0x268
el0_svc_common.constprop.0+0x160/0x238
do_el0_svc+0x44/0x60
el0_svc+0x44/0xb0
el0t_64_sync_handler+0x118/0x128
el0t_64_sync+0x168/0x170
INFO: task fsfreeze:7364 blocked for more than 15 seconds.
Not tainted 6.12.0-rc5-00063-g76aaf945701c #7963
with the attempting freezer stuck trying to grab the rwsem:
task:fsfreeze state:D stack:0 pid:7364 tgid:7364 ppid:995
Call trace:
__switch_to+0x1d8/0x348
__schedule+0x8e8/0x2248
schedule+0x110/0x3f0
percpu_down_write+0x2b0/0x680
freeze_super+0x248/0x8a8
do_vfs_ioctl+0x149c/0x1b18
__arm64_sys_ioctl+0xd0/0x1a0
invoke_syscall+0x74/0x268
el0_svc_common.constprop.0+0x160/0x238
do_el0_svc+0x44/0x60
el0_svc+0x44/0xb0
el0t_64_sync_handler+0x118/0x128
el0t_64_sync+0x168/0x170
Fix this by having the io_uring side honor IOCB_NOWAIT, and only attempt a
blocking grab of the super block rwsem if it isn't set. For normal issue
where IOCB_NOWAIT would always be set, this returns -EAGAIN which will
have io_uring core issue a blocking attempt of the write. That will in
turn also get completions run, ensuring forward progress.
Since freezing requires CAP_SYS_ADMIN in the first place, this isn't
something that can be triggered by a regular user.
Cc: [email protected] # 5.10+
Reported-by: Peter Mann <[email protected]>
Link: https://lore.kernel.org/io-uring/[email protected]
Signed-off-by: Jens Axboe <[email protected]>
---
io_uring/io_uring.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index a6afdea5cfd8..57c51e963875 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -3719,6 +3719,25 @@ static int io_write_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
return io_prep_rw(req, sqe, WRITE);
}
+static bool io_kiocb_start_write(struct io_kiocb *req, struct kiocb *kiocb)
+{
+ struct inode *inode;
+ bool ret;
+
+ if (!(req->flags & REQ_F_ISREG))
+ return true;
+ if (!(kiocb->ki_flags & IOCB_NOWAIT)) {
+ kiocb_start_write(kiocb);
+ return true;
+ }
+
+ inode = file_inode(kiocb->ki_filp);
+ ret = sb_start_write_trylock(inode->i_sb);
+ if (ret)
+ __sb_writers_release(inode->i_sb, SB_FREEZE_WRITE);
+ return ret;
+}
+
static int io_write(struct io_kiocb *req, unsigned int issue_flags)
{
struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
@@ -3765,8 +3784,8 @@ static int io_write(struct io_kiocb *req, unsigned int issue_flags)
if (unlikely(ret))
goto out_free;
- if (req->flags & REQ_F_ISREG)
- kiocb_start_write(kiocb);
+ if (unlikely(!io_kiocb_start_write(req, kiocb)))
+ goto copy_iov;
kiocb->ki_flags |= IOCB_WRITE;
if (req->file->f_op->write_iter)
--
2.45.2
[-- Attachment #3: 0003-io_uring-use-kiocb_-start-end-_write-helpers.patch --]
[-- Type: text/x-patch, Size: 2074 bytes --]
From 7ca6b3ba89b5419ad61ae664fd319c96e81cd58e Mon Sep 17 00:00:00 2001
From: Amir Goldstein <[email protected]>
Date: Thu, 17 Aug 2023 17:13:34 +0300
Subject: [PATCH 3/4] io_uring: use kiocb_{start,end}_write() helpers
Commit e484fd73f4bdcb00c2188100c2d84e9f3f5c9f7d upstream.
Use helpers instead of the open coded dance to silence lockdep warnings.
Suggested-by: Jan Kara <[email protected]>
Signed-off-by: Amir Goldstein <[email protected]>
Reviewed-by: Jan Kara <[email protected]>
Reviewed-by: Jens Axboe <[email protected]>
Message-Id: <[email protected]>
Signed-off-by: Christian Brauner <[email protected]>
---
io_uring/io_uring.c | 23 ++++-------------------
1 file changed, 4 insertions(+), 19 deletions(-)
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index ec55f2788ac6..a6afdea5cfd8 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -2669,15 +2669,10 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, long min)
static void io_req_end_write(struct io_kiocb *req)
{
- /*
- * Tell lockdep we inherited freeze protection from submission
- * thread.
- */
if (req->flags & REQ_F_ISREG) {
- struct super_block *sb = file_inode(req->file)->i_sb;
+ struct io_rw *rw = &req->rw;
- __sb_writers_acquired(sb, SB_FREEZE_WRITE);
- sb_end_write(sb);
+ kiocb_end_write(&rw->kiocb);
}
}
@@ -3770,18 +3765,8 @@ static int io_write(struct io_kiocb *req, unsigned int issue_flags)
if (unlikely(ret))
goto out_free;
- /*
- * Open-code file_start_write here to grab freeze protection,
- * which will be released by another thread in
- * io_complete_rw(). Fool lockdep by telling it the lock got
- * released so that it doesn't complain about the held lock when
- * we return to userspace.
- */
- if (req->flags & REQ_F_ISREG) {
- sb_start_write(file_inode(req->file)->i_sb);
- __sb_writers_release(file_inode(req->file)->i_sb,
- SB_FREEZE_WRITE);
- }
+ if (req->flags & REQ_F_ISREG)
+ kiocb_start_write(kiocb);
kiocb->ki_flags |= IOCB_WRITE;
if (req->file->f_op->write_iter)
--
2.45.2
[-- Attachment #4: 0002-fs-create-kiocb_-start-end-_write-helpers.patch --]
[-- Type: text/x-patch, Size: 2351 bytes --]
From 28f855b2e34ff38516493612c74bc02def4cfdda Mon Sep 17 00:00:00 2001
From: Amir Goldstein <[email protected]>
Date: Thu, 17 Aug 2023 17:13:33 +0300
Subject: [PATCH 2/4] fs: create kiocb_{start,end}_write() helpers
Commit ed0360bbab72b829437b67ebb2f9cfac19f59dfe upstream.
aio, io_uring, cachefiles and overlayfs, all open code an ugly variant
of file_{start,end}_write() to silence lockdep warnings.
Create helpers for this lockdep dance so we can use the helpers in all
the callers.
Suggested-by: Jan Kara <[email protected]>
Signed-off-by: Amir Goldstein <[email protected]>
Reviewed-by: Jan Kara <[email protected]>
Reviewed-by: Jens Axboe <[email protected]>
Message-Id: <[email protected]>
Signed-off-by: Christian Brauner <[email protected]>
---
include/linux/fs.h | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a7d839b19606..4e475ded5cf5 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1797,6 +1797,41 @@ static inline bool sb_start_intwrite_trylock(struct super_block *sb)
return __sb_start_write_trylock(sb, SB_FREEZE_FS);
}
+/**
+ * kiocb_start_write - get write access to a superblock for async file io
+ * @iocb: the io context we want to submit the write with
+ *
+ * This is a variant of sb_start_write() for async io submission.
+ * Should be matched with a call to kiocb_end_write().
+ */
+static inline void kiocb_start_write(struct kiocb *iocb)
+{
+ struct inode *inode = file_inode(iocb->ki_filp);
+
+ sb_start_write(inode->i_sb);
+ /*
+ * Fool lockdep by telling it the lock got released so that it
+ * doesn't complain about the held lock when we return to userspace.
+ */
+ __sb_writers_release(inode->i_sb, SB_FREEZE_WRITE);
+}
+
+/**
+ * kiocb_end_write - drop write access to a superblock after async file io
+ * @iocb: the io context we sumbitted the write with
+ *
+ * Should be matched with a call to kiocb_start_write().
+ */
+static inline void kiocb_end_write(struct kiocb *iocb)
+{
+ struct inode *inode = file_inode(iocb->ki_filp);
+
+ /*
+ * Tell lockdep we inherited freeze protection from submission thread.
+ */
+ __sb_writers_acquired(inode->i_sb, SB_FREEZE_WRITE);
+ sb_end_write(inode->i_sb);
+}
extern bool inode_owner_or_capable(const struct inode *inode);
--
2.45.2
[-- Attachment #5: 0001-io_uring-rename-kiocb_end_write-local-helper.patch --]
[-- Type: text/x-patch, Size: 2129 bytes --]
From 13728704a0aa59051536327e58469269201dd79b Mon Sep 17 00:00:00 2001
From: Amir Goldstein <[email protected]>
Date: Thu, 17 Aug 2023 17:13:31 +0300
Subject: [PATCH 1/4] io_uring: rename kiocb_end_write() local helper
Commit a370167fe526123637965f60859a9f1f3e1a58b7 upstream.
This helper does not take a kiocb as input and we want to create a
common helper by that name that takes a kiocb as input.
Signed-off-by: Amir Goldstein <[email protected]>
Reviewed-by: Jan Kara <[email protected]>
Reviewed-by: Jens Axboe <[email protected]>
Message-Id: <[email protected]>
Signed-off-by: Christian Brauner <[email protected]>
---
io_uring/io_uring.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index da07fba75827..ec55f2788ac6 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -2667,7 +2667,7 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, long min)
return ret;
}
-static void kiocb_end_write(struct io_kiocb *req)
+static void io_req_end_write(struct io_kiocb *req)
{
/*
* Tell lockdep we inherited freeze protection from submission
@@ -2737,7 +2737,7 @@ static void io_req_io_end(struct io_kiocb *req)
struct io_rw *rw = &req->rw;
if (rw->kiocb.ki_flags & IOCB_WRITE) {
- kiocb_end_write(req);
+ io_req_end_write(req);
fsnotify_modify(req->file);
} else {
fsnotify_access(req->file);
@@ -2817,7 +2817,7 @@ static void io_complete_rw_iopoll(struct kiocb *kiocb, long res, long res2)
struct io_kiocb *req = container_of(kiocb, struct io_kiocb, rw.kiocb);
if (kiocb->ki_flags & IOCB_WRITE)
- kiocb_end_write(req);
+ io_req_end_write(req);
if (unlikely(res != req->result)) {
if (res == -EAGAIN && io_rw_should_reissue(req)) {
req->flags |= REQ_F_REISSUE;
@@ -3817,7 +3817,7 @@ static int io_write(struct io_kiocb *req, unsigned int issue_flags)
ret = io_setup_async_rw(req, iovec, inline_vecs, iter, false);
if (!ret) {
if (kiocb->ki_flags & IOCB_WRITE)
- kiocb_end_write(req);
+ io_req_end_write(req);
return -EAGAIN;
}
return ret;
--
2.45.2
^ permalink raw reply related [flat|nested] 2+ messages in thread