[PATCH RFC] usb: gadget: mass_storage: defer file open to workqueue
"syzbot" <[email protected]>
| Newsgroups | dev.linux.lists.syzbot |
|---|---|
| Message-ID | <[email protected]> |
When a user writes a file path to a configfs attribute (e.g., the
lun.0/file attribute of the USB mass storage gadget) and the provided path
happens to reside on the same configfs filesystem, it triggers a lockdep
warning about a possible recursive locking on the sb_writers percpu rwsem.
Because configfs attributes are regular files, the VFS layer acquires the
sb_writers freeze protection lock for the configfs superblock when the
write() syscall is issued. When the driver's store method subsequently
calls filp_open() to open the backing file, filp_open() attempts to acquire
the sb_writers lock again for the target path's superblock. If the target
path is also on configfs, it results in a recursive lock on the same
superblock, which lockdep correctly flags as a potential deadlock.
Fix this lock inversion by deferring the execution of fsg_lun_open() to a
system workqueue. By executing the file opening in a separate worker
thread, it escapes the lockdep context of the write() syscall and does not
inherit the sb_writers lock held by vfs_write(). The store method uses
flush_work() to wait for completion and return the synchronous error code,
preserving the existing API behavior.
The lockdep warning is as follows:
WARNING: possible recursive locking detected
task is trying to acquire lock:
ffff8881899b0500 (sb_writers#12){.+.+}-{0:0}, at: mnt_want_write+0x41/0x90
fs/namespace.c:494
but task is already holding lock:
ffff8881899b0500 (sb_writers#12){.+.+}-{0:0}, at: file_start_write
include/linux/fs.h:2733 [inline]
ffff8881899b0500 (sb_writers#12){.+.+}-{0:0}, at: vfs_write+0x231/0xbb0
fs/read_write.c:683
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
lock(sb_writers#12);
lock(sb_writers#12);
*** DEADLOCK ***
Call Trace:
<TASK>
sb_start_write+0x4d/0x1c0 include/linux/fs/super.h:125
mnt_want_write+0x41/0x90 fs/namespace.c:494
path_openat+0xa7b/0x3850 fs/namei.c:4860
do_file_open+0x23e/0x4a0 fs/namei.c:4892
filp_open+0x16d/0x1d0 fs/open.c:1343
fsg_lun_open+0x6c/0xe00 drivers/usb/gadget/function/storage_common.c:194
fsg_store_file+0x19e/0x400
drivers/usb/gadget/function/storage_common.c:455
configfs_write_iter+0x33a/0x430 fs/configfs/file.c:229
vfs_write+0x61e/0xbb0 fs/read_write.c:687
ksys_write+0x156/0x270 fs/read_write.c:739
do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
</TASK>
Fixes: ef0aa4b92cf1 ("usb: gadget: f_mass_storage: add configfs support")
Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=da381387152f0dd8bedf
Link: https://syzkaller.appspot.com/ai_job?id=43881a07-9f58-4a9b-b110-6696a48ed088
To: "Greg Kroah-Hartman" <[email protected]>
To: <[email protected]>
To: "Andrzej Pietrasiewicz" <[email protected]>
Cc: <[email protected]>
---
diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c
index 75831f2c7..45842f8e0 100644
--- a/drivers/usb/gadget/function/storage_common.c
+++ b/drivers/usb/gadget/function/storage_common.c
@@ -24,6 +24,7 @@
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/kstrtox.h>
+#include <linux/workqueue.h>
#include <linux/usb/composite.h>
#include "storage_common.h"
@@ -434,6 +435,21 @@ ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count)
}
EXPORT_SYMBOL_GPL(fsg_store_nofua);
+struct fsg_lun_open_work {
+ struct work_struct work;
+ struct fsg_lun *curlun;
+ const char *filename;
+ int rc;
+};
+
+static void fsg_lun_open_work_func(struct work_struct *work)
+{
+ struct fsg_lun_open_work *fwork;
+
+ fwork = container_of(work, struct fsg_lun_open_work, work);
+ fwork->rc = fsg_lun_open(fwork->curlun, fwork->filename);
+}
+
ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
const char *buf, size_t count)
{
@@ -451,8 +467,17 @@ ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
/* Load new medium */
down_write(filesem);
if (count > 0 && buf[0]) {
+ struct fsg_lun_open_work fwork;
+
+ fwork.curlun = curlun;
+ fwork.filename = buf;
+ INIT_WORK_ONSTACK(&fwork.work, fsg_lun_open_work_func);
+ schedule_work(&fwork.work);
+ flush_work(&fwork.work);
+ destroy_work_on_stack(&fwork.work);
+ rc = fwork.rc;
+
/* fsg_lun_open() will close existing file if any. */
- rc = fsg_lun_open(curlun, buf);
if (rc == 0)
curlun->unit_attention_data =
SS_NOT_READY_TO_READY_TRANSITION;
base-commit: 075b74841bd0065a3bda3440873c747938e69b68
--
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).
See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at [email protected].