| From 682175a57baa3590bae406f694229aca56f2f9b0 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 9 May 2024 20:21:54 +0800 |
| Subject: fuse: clear FR_SENT when re-adding requests into pending list |
| |
| From: Hou Tao <houtao1@huawei.com> |
| |
| [ Upstream commit 246014876d782bbf2e652267482cd2e799fb5fcd ] |
| |
| The following warning was reported by lee bruce: |
| |
| ------------[ cut here ]------------ |
| WARNING: CPU: 0 PID: 8264 at fs/fuse/dev.c:300 |
| fuse_request_end+0x685/0x7e0 fs/fuse/dev.c:300 |
| Modules linked in: |
| CPU: 0 PID: 8264 Comm: ab2 Not tainted 6.9.0-rc7 |
| Hardware name: QEMU Standard PC (i440FX + PIIX, 1996) |
| RIP: 0010:fuse_request_end+0x685/0x7e0 fs/fuse/dev.c:300 |
| ...... |
| Call Trace: |
| <TASK> |
| fuse_dev_do_read.constprop.0+0xd36/0x1dd0 fs/fuse/dev.c:1334 |
| fuse_dev_read+0x166/0x200 fs/fuse/dev.c:1367 |
| call_read_iter include/linux/fs.h:2104 [inline] |
| new_sync_read fs/read_write.c:395 [inline] |
| vfs_read+0x85b/0xba0 fs/read_write.c:476 |
| ksys_read+0x12f/0x260 fs/read_write.c:619 |
| do_syscall_x64 arch/x86/entry/common.c:52 [inline] |
| do_syscall_64+0xce/0x260 arch/x86/entry/common.c:83 |
| entry_SYSCALL_64_after_hwframe+0x77/0x7f |
| ...... |
| </TASK> |
| |
| The warning is due to the FUSE_NOTIFY_RESEND notify sent by the write() |
| syscall in the reproducer program and it happens as follows: |
| |
| (1) calls fuse_dev_read() to read the INIT request |
| The read succeeds. During the read, bit FR_SENT will be set on the |
| request. |
| (2) calls fuse_dev_write() to send an USE_NOTIFY_RESEND notify |
| The resend notify will resend all processing requests, so the INIT |
| request is moved from processing list to pending list again. |
| (3) calls fuse_dev_read() with an invalid output address |
| fuse_dev_read() will try to copy the same INIT request to the output |
| address, but it will fail due to the invalid address, so the INIT |
| request is ended and triggers the warning in fuse_request_end(). |
| |
| Fix it by clearing FR_SENT when re-adding requests into pending list. |
| |
| Acked-by: Miklos Szeredi <mszeredi@redhat.com> |
| Reported-by: xingwei lee <xrivendell7@gmail.com> |
| Reported-by: yue sun <samsun1006219@gmail.com> |
| Closes: https://lore.kernel.org/linux-fsdevel/58f13e47-4765-fce4-daf4-dffcc5ae2330@huaweicloud.com/T/#m091614e5ea2af403b259e7cea6a49e51b9ee07a7 |
| Fixes: 760eac73f9f6 ("fuse: Introduce a new notification type for resend pending requests") |
| Signed-off-by: Hou Tao <houtao1@huawei.com> |
| Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| fs/fuse/dev.c | 1 + |
| 1 file changed, 1 insertion(+) |
| |
| diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c |
| index 8eb2ce7c0b012..9eb191b5c4de1 100644 |
| --- a/fs/fuse/dev.c |
| +++ b/fs/fuse/dev.c |
| @@ -1814,6 +1814,7 @@ static void fuse_resend(struct fuse_conn *fc) |
| |
| list_for_each_entry_safe(req, next, &to_queue, list) { |
| set_bit(FR_PENDING, &req->flags); |
| + clear_bit(FR_SENT, &req->flags); |
| /* mark the request as resend request */ |
| req->in.h.unique |= FUSE_UNIQUE_RESEND; |
| } |
| -- |
| 2.43.0 |
| |