* Re: [PATCH v4 00/54] tree-in-dcache stuff [not found] <20251118051604.3868588-1-viro@zeniv.linux.org.uk> @ 2026-01-27 0:56 ` Samuel Wu 2026-01-27 7:42 ` Greg KH 0 siblings, 1 reply; 26+ messages in thread From: Samuel Wu @ 2026-01-27 0:56 UTC (permalink / raw) To: Al Viro Cc: linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, gregkh, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Mon, Nov 17, 2025 at 9:15 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > > Some filesystems use a kinda-sorta controlled dentry refcount leak to pin > dentries of created objects in dcache (and undo it when removing those). > Reference is grabbed and not released, but it's not actually _stored_ > anywhere. That works, but it's hard to follow and verify; among other > things, we have no way to tell _which_ of the increments is intended > to be an unpaired one. Worse, on removal we need to decide whether > the reference had already been dropped, which can be non-trivial if > that removal is on umount and we need to figure out if this dentry is > pinned due to e.g. unlink() not done. Usually that is handled by using > kill_litter_super() as ->kill_sb(), but there are open-coded special > cases of the same (consider e.g. /proc/self). > > Things get simpler if we introduce a new dentry flag (DCACHE_PERSISTENT) > marking those "leaked" dentries. Having it set claims responsibility > for +1 in refcount. > > The end result this series is aiming for: > > * get these unbalanced dget() and dput() replaced with new primitives that > would, in addition to adjusting refcount, set and clear persistency flag. > * instead of having kill_litter_super() mess with removing the remaining > "leaked" references (e.g. for all tmpfs files that hadn't been removed > prior to umount), have the regular shrink_dcache_for_umount() strip > DCACHE_PERSISTENT of all dentries, dropping the corresponding > reference if it had been set. After that kill_litter_super() becomes > an equivalent of kill_anon_super(). > > Doing that in a single step is not feasible - it would affect too many places > in too many filesystems. It has to be split into a series. > > This work has really started early in 2024; quite a few preliminary pieces > have already gone into mainline. This chunk is finally getting to the > meat of that stuff - infrastructure and most of the conversions to it. > > Some pieces are still sitting in the local branches, but the bulk of > that stuff is here. > > Compared to v3: > * fixed a functionfs braino around ffs_epfiles_destroy() (in #40/54, > used to be #36/50). > * added fixes for a couple of UAF in functionfs (##36--39); that > does *NOT* include any fixes for dmabuf bugs Chris posted last week, though. > > The branch is -rc5-based; it lives in > git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git #work.persistency > individual patches in followups. > > Please, help with review and testing. If nobody objects, in a few days it > goes into #for-next. > > Shortlog: > fuse_ctl_add_conn(): fix nlink breakage in case of early failure > tracefs: fix a leak in eventfs_create_events_dir() > new helper: simple_remove_by_name() > new helper: simple_done_creating() > introduce a flag for explicitly marking persistently pinned dentries > primitives for maintaining persisitency > convert simple_{link,unlink,rmdir,rename,fill_super}() to new primitives > convert ramfs and tmpfs > procfs: make /self and /thread_self dentries persistent > configfs, securityfs: kill_litter_super() not needed > convert xenfs > convert smackfs > convert hugetlbfs > convert mqueue > convert bpf > convert dlmfs > convert fuse_ctl > convert pstore > convert tracefs > convert debugfs > debugfs: remove duplicate checks in callers of start_creating() > convert efivarfs > convert spufs > convert ibmasmfs > ibmasmfs: get rid of ibmasmfs_dir_ops > convert devpts > binderfs: use simple_start_creating() > binderfs_binder_ctl_create(): kill a bogus check > convert binderfs > autofs_{rmdir,unlink}: dentry->d_fsdata->dentry == dentry there > convert autofs > convert binfmt_misc > selinuxfs: don't stash the dentry of /policy_capabilities > selinuxfs: new helper for attaching files to tree > convert selinuxfs > functionfs: don't abuse ffs_data_closed() on fs shutdown > functionfs: don't bother with ffs->ref in ffs_data_{opened,closed}() > functionfs: need to cancel ->reset_work in ->kill_sb() > functionfs: fix the open/removal races > functionfs: switch to simple_remove_by_name() > convert functionfs > gadgetfs: switch to simple_remove_by_name() > convert gadgetfs > hypfs: don't pin dentries twice > hypfs: switch hypfs_create_str() to returning int > hypfs: swich hypfs_create_u64() to returning int > convert hypfs > convert rpc_pipefs > convert nfsctl > convert rust_binderfs > get rid of kill_litter_super() > convert securityfs > kill securityfs_recursive_remove() > d_make_discardable(): warn if given a non-persistent dentry > > Diffstat: > Documentation/filesystems/porting.rst | 7 ++ > arch/powerpc/platforms/cell/spufs/inode.c | 17 ++- > arch/s390/hypfs/hypfs.h | 6 +- > arch/s390/hypfs/hypfs_diag_fs.c | 60 ++++------ > arch/s390/hypfs/hypfs_vm_fs.c | 21 ++-- > arch/s390/hypfs/inode.c | 82 +++++-------- > drivers/android/binder/rust_binderfs.c | 121 ++++++------------- > drivers/android/binderfs.c | 82 +++---------- > drivers/base/devtmpfs.c | 2 +- > drivers/misc/ibmasm/ibmasmfs.c | 24 ++-- > drivers/usb/gadget/function/f_fs.c | 144 +++++++++++++---------- > drivers/usb/gadget/legacy/inode.c | 49 ++++---- > drivers/xen/xenfs/super.c | 2 +- > fs/autofs/inode.c | 2 +- > fs/autofs/root.c | 11 +- > fs/binfmt_misc.c | 69 ++++++----- > fs/configfs/dir.c | 10 +- > fs/configfs/inode.c | 3 +- > fs/configfs/mount.c | 2 +- > fs/dcache.c | 111 +++++++++++------- > fs/debugfs/inode.c | 32 ++---- > fs/devpts/inode.c | 57 ++++----- > fs/efivarfs/inode.c | 7 +- > fs/efivarfs/super.c | 5 +- > fs/fuse/control.c | 38 +++--- > fs/hugetlbfs/inode.c | 12 +- > fs/internal.h | 1 - > fs/libfs.c | 52 +++++++-- > fs/nfsd/nfsctl.c | 18 +-- > fs/ocfs2/dlmfs/dlmfs.c | 8 +- > fs/proc/base.c | 6 +- > fs/proc/internal.h | 1 + > fs/proc/root.c | 14 +-- > fs/proc/self.c | 10 +- > fs/proc/thread_self.c | 11 +- > fs/pstore/inode.c | 7 +- > fs/ramfs/inode.c | 8 +- > fs/super.c | 8 -- > fs/tracefs/event_inode.c | 7 +- > fs/tracefs/inode.c | 13 +-- > include/linux/dcache.h | 4 +- > include/linux/fs.h | 6 +- > include/linux/proc_fs.h | 2 - > include/linux/security.h | 2 - > init/do_mounts.c | 2 +- > ipc/mqueue.c | 12 +- > kernel/bpf/inode.c | 15 +-- > mm/shmem.c | 38 ++---- > net/sunrpc/rpc_pipe.c | 27 ++--- > security/apparmor/apparmorfs.c | 13 ++- > security/inode.c | 35 +++--- > security/selinux/selinuxfs.c | 185 +++++++++++++----------------- > security/smack/smackfs.c | 2 +- > 53 files changed, 649 insertions(+), 834 deletions(-) > > Overview: > > First two commits are bugfixes (fusectl and tracefs resp.) > > [1/54] fuse_ctl_add_conn(): fix nlink breakage in case of early failure > [2/54] tracefs: fix a leak in eventfs_create_events_dir() > > Next, two commits adding a couple of useful helpers, the next three adding > the infrastructure and the rest consists of per-filesystem conversions. > > [3/54] new helper: simple_remove_by_name() > [4/54] new helper: simple_done_creating() > end_creating_path() analogue for internal object creation; unlike > end_creating_path() no mount is passed to it (or guaranteed to exist, for > that matter - it might be used during the filesystem setup, before the > superblock gets attached to any mounts). > > Infrastructure: > [5/54] introduce a flag for explicitly marking persistently pinned dentries > * introduce the new flag > * teach shrink_dcache_for_umount() to handle it (i.e. remove > and drop refcount on anything that survives to umount with that flag > still set) > * teach kill_litter_super() that anything with that flag does > *not* need to be unpinned. > [6/54] primitives for maintaining persisitency > * d_make_persistent(dentry, inode) - bump refcount, mark persistent > and make hashed positive. Return value is a borrowed reference to dentry; > it can be used until something removes persistency (at the very least, > until the parent gets unlocked, but some filesystems may have stronger > exclusion). > * d_make_discardable() - remove persistency mark and drop reference. > > NOTE: at that stage d_make_discardable() does not reject dentries not > marked persistent - it acts as if the mark been set. > > Rationale: less noise in series splitup that way. We want (and on the > next commit will get) simple_unlink() to do the right thing - remove > persistency, if it's there. However, it's used by many filesystems. > We would have either to convert them all at once or split simple_unlink() > into "want persistent" and "don't want persistent" versions, the latter > being the old one. In the course of the series almost all callers > would migrate to the replacement, leaving only two pathological cases > with the old one. The same goes for simple_rmdir() (two callers left in > the end), simple_recursive_removal() (all callers gone in the end), etc. > That's a lot of noise and it's easier to start with d_make_discardable() > quietly accepting non-persistent dentries, then, in the end, add private > copies of simple_unlink() and simple_rmdir() for two weird users (configfs > and apparmorfs) and have those use dput() instead of d_make_discardable(). > At that point we'd be left with all callers of d_make_discardable() > always passing persistent dentries, allowing to add a warning in it. > > [7/54] convert simple_{link,unlink,rmdir,rename,fill_super}() to new primitives > See above re quietly accepting non-peristent dentries in > simple_unlink(), simple_rmdir(), etc. > > Converting filesystems: > [8/54] convert ramfs and tmpfs > [9/54] procfs: make /self and /thread_self dentries persistent > [10/54] configfs, securityfs: kill_litter_super() not needed > [11/54] convert xenfs > [12/54] convert smackfs > [13/54] convert hugetlbfs > [14/54] convert mqueue > [15/54] convert bpf > [16/54] convert dlmfs > [17/54] convert fuse_ctl > [18/54] convert pstore > [19/54] convert tracefs > [20/54] convert debugfs > [21/54] debugfs: remove duplicate checks in callers of start_creating() > [22/54] convert efivarfs > [23/54] convert spufs > [24/54] convert ibmasmfs > [25/54] ibmasmfs: get rid of ibmasmfs_dir_ops > [26/54] convert devpts > [27/54] binderfs: use simple_start_creating() > [28/54] binderfs_binder_ctl_create(): kill a bogus check > [29/54] convert binderfs > [30/54] autofs_{rmdir,unlink}: dentry->d_fsdata->dentry == dentry there > [31/54] convert autofs > [32/54] convert binfmt_misc > [33/54] selinuxfs: don't stash the dentry of /policy_capabilities > [34/54] selinuxfs: new helper for attaching files to tree > [35/54] convert selinuxfs > > Several functionfs fixes, before converting it, to make life > simpler for backporting: > [36/54] functionfs: don't abuse ffs_data_closed() on fs shutdown > [37/54] functionfs: don't bother with ffs->ref in ffs_data_{opened,closed}() > [38/54] functionfs: need to cancel ->reset_work in ->kill_sb() > [39/54] functionfs: fix the open/removal races > > ... and back to filesystems conversions: > > [40/54] functionfs: switch to simple_remove_by_name() > [41/54] convert functionfs > [42/54] gadgetfs: switch to simple_remove_by_name() > [43/54] convert gadgetfs > [44/54] hypfs: don't pin dentries twice > [45/54] hypfs: switch hypfs_create_str() to returning int > [46/54] hypfs: swich hypfs_create_u64() to returning int > [47/54] convert hypfs > [48/54] convert rpc_pipefs > [49/54] convert nfsctl > [50/54] convert rust_binderfs > > ... and no kill_litter_super() callers remain, so we > can take it out: > [51/54] get rid of kill_litter_super() > > Followups: > [52/54] convert securityfs > That was the last remaining user of simple_recursive_removal() > that did *not* mark things persistent. Now the only places where > d_make_discardable() is still called for dentries that are not marked > persistent are the calls of simple_{unlink,rmdir}() in configfs and > apparmorfs. > > [53/54] kill securityfs_recursive_remove() > Unused macro... > > [54/54] d_make_discardable(): warn if given a non-persistent dentry > > At this point there are very few call chains that might lead to > d_make_discardable() on a dentry that hadn't been made persistent: > calls of simple_unlink() and simple_rmdir() in configfs and > apparmorfs. > > Both filesystems do pin (part of) their contents in dcache, but > they are currently playing very unusual games with that. Converting > them to more usual patterns might be possible, but it's definitely > going to be a long series of changes in both cases. > > For now the easiest solution is to have both stop using simple_unlink() > and simple_rmdir() - that allows to make d_make_discardable() warn > when given a non-persistent dentry. > > Rather than giving them full-blown private copies (with calls of > d_make_discardable() replaced with dput()), let's pull the parts of > simple_unlink() and simple_rmdir() that deal with timestamps and link > counts into separate helpers (__simple_unlink() and __simple_rmdir() > resp.) and have those used by configfs and apparmorfs. > Hi Al, when I apply this patchset my Pixel 6 no longer enumerates on lsusb or ADB. It was quite hard to bisect to this point, as this is non-deterministic and seems to be setup specific. Note, I am using android-mainline, but my understanding is that this build does not have any out-of-tree USB patches, and that there are no vendor hooks in the build. My apologies as I can't offer any other clues; there are no obviously bad dmesg logs and I'm still working on narrowing down the exact commit(s) that started this, but just wanted to send a FYI in case something stands out as obvious. Thanks! Sam ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-27 0:56 ` [PATCH v4 00/54] tree-in-dcache stuff Samuel Wu @ 2026-01-27 7:42 ` Greg KH 2026-01-27 18:39 ` Linus Torvalds 2026-01-28 2:02 ` Samuel Wu 0 siblings, 2 replies; 26+ messages in thread From: Greg KH @ 2026-01-27 7:42 UTC (permalink / raw) To: Samuel Wu Cc: Al Viro, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Mon, Jan 26, 2026 at 04:56:42PM -0800, Samuel Wu wrote: > On Mon, Nov 17, 2025 at 9:15 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > > > > Some filesystems use a kinda-sorta controlled dentry refcount leak to pin > > dentries of created objects in dcache (and undo it when removing those). > > Reference is grabbed and not released, but it's not actually _stored_ > > anywhere. That works, but it's hard to follow and verify; among other > > things, we have no way to tell _which_ of the increments is intended > > to be an unpaired one. Worse, on removal we need to decide whether > > the reference had already been dropped, which can be non-trivial if > > that removal is on umount and we need to figure out if this dentry is > > pinned due to e.g. unlink() not done. Usually that is handled by using > > kill_litter_super() as ->kill_sb(), but there are open-coded special > > cases of the same (consider e.g. /proc/self). > > > > Things get simpler if we introduce a new dentry flag (DCACHE_PERSISTENT) > > marking those "leaked" dentries. Having it set claims responsibility > > for +1 in refcount. > > > > The end result this series is aiming for: > > > > * get these unbalanced dget() and dput() replaced with new primitives that > > would, in addition to adjusting refcount, set and clear persistency flag. > > * instead of having kill_litter_super() mess with removing the remaining > > "leaked" references (e.g. for all tmpfs files that hadn't been removed > > prior to umount), have the regular shrink_dcache_for_umount() strip > > DCACHE_PERSISTENT of all dentries, dropping the corresponding > > reference if it had been set. After that kill_litter_super() becomes > > an equivalent of kill_anon_super(). > > > > Doing that in a single step is not feasible - it would affect too many places > > in too many filesystems. It has to be split into a series. > > > > This work has really started early in 2024; quite a few preliminary pieces > > have already gone into mainline. This chunk is finally getting to the > > meat of that stuff - infrastructure and most of the conversions to it. > > > > Some pieces are still sitting in the local branches, but the bulk of > > that stuff is here. > > > > Compared to v3: > > * fixed a functionfs braino around ffs_epfiles_destroy() (in #40/54, > > used to be #36/50). > > * added fixes for a couple of UAF in functionfs (##36--39); that > > does *NOT* include any fixes for dmabuf bugs Chris posted last week, though. > > > > The branch is -rc5-based; it lives in > > git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git #work.persistency > > individual patches in followups. > > > > Please, help with review and testing. If nobody objects, in a few days it > > goes into #for-next. > > > > Shortlog: > > fuse_ctl_add_conn(): fix nlink breakage in case of early failure > > tracefs: fix a leak in eventfs_create_events_dir() > > new helper: simple_remove_by_name() > > new helper: simple_done_creating() > > introduce a flag for explicitly marking persistently pinned dentries > > primitives for maintaining persisitency > > convert simple_{link,unlink,rmdir,rename,fill_super}() to new primitives > > convert ramfs and tmpfs > > procfs: make /self and /thread_self dentries persistent > > configfs, securityfs: kill_litter_super() not needed > > convert xenfs > > convert smackfs > > convert hugetlbfs > > convert mqueue > > convert bpf > > convert dlmfs > > convert fuse_ctl > > convert pstore > > convert tracefs > > convert debugfs > > debugfs: remove duplicate checks in callers of start_creating() > > convert efivarfs > > convert spufs > > convert ibmasmfs > > ibmasmfs: get rid of ibmasmfs_dir_ops > > convert devpts > > binderfs: use simple_start_creating() > > binderfs_binder_ctl_create(): kill a bogus check > > convert binderfs > > autofs_{rmdir,unlink}: dentry->d_fsdata->dentry == dentry there > > convert autofs > > convert binfmt_misc > > selinuxfs: don't stash the dentry of /policy_capabilities > > selinuxfs: new helper for attaching files to tree > > convert selinuxfs > > functionfs: don't abuse ffs_data_closed() on fs shutdown > > functionfs: don't bother with ffs->ref in ffs_data_{opened,closed}() > > functionfs: need to cancel ->reset_work in ->kill_sb() > > functionfs: fix the open/removal races > > functionfs: switch to simple_remove_by_name() > > convert functionfs > > gadgetfs: switch to simple_remove_by_name() > > convert gadgetfs > > hypfs: don't pin dentries twice > > hypfs: switch hypfs_create_str() to returning int > > hypfs: swich hypfs_create_u64() to returning int > > convert hypfs > > convert rpc_pipefs > > convert nfsctl > > convert rust_binderfs > > get rid of kill_litter_super() > > convert securityfs > > kill securityfs_recursive_remove() > > d_make_discardable(): warn if given a non-persistent dentry > > > > Diffstat: > > Documentation/filesystems/porting.rst | 7 ++ > > arch/powerpc/platforms/cell/spufs/inode.c | 17 ++- > > arch/s390/hypfs/hypfs.h | 6 +- > > arch/s390/hypfs/hypfs_diag_fs.c | 60 ++++------ > > arch/s390/hypfs/hypfs_vm_fs.c | 21 ++-- > > arch/s390/hypfs/inode.c | 82 +++++-------- > > drivers/android/binder/rust_binderfs.c | 121 ++++++------------- > > drivers/android/binderfs.c | 82 +++---------- > > drivers/base/devtmpfs.c | 2 +- > > drivers/misc/ibmasm/ibmasmfs.c | 24 ++-- > > drivers/usb/gadget/function/f_fs.c | 144 +++++++++++++---------- > > drivers/usb/gadget/legacy/inode.c | 49 ++++---- > > drivers/xen/xenfs/super.c | 2 +- > > fs/autofs/inode.c | 2 +- > > fs/autofs/root.c | 11 +- > > fs/binfmt_misc.c | 69 ++++++----- > > fs/configfs/dir.c | 10 +- > > fs/configfs/inode.c | 3 +- > > fs/configfs/mount.c | 2 +- > > fs/dcache.c | 111 +++++++++++------- > > fs/debugfs/inode.c | 32 ++---- > > fs/devpts/inode.c | 57 ++++----- > > fs/efivarfs/inode.c | 7 +- > > fs/efivarfs/super.c | 5 +- > > fs/fuse/control.c | 38 +++--- > > fs/hugetlbfs/inode.c | 12 +- > > fs/internal.h | 1 - > > fs/libfs.c | 52 +++++++-- > > fs/nfsd/nfsctl.c | 18 +-- > > fs/ocfs2/dlmfs/dlmfs.c | 8 +- > > fs/proc/base.c | 6 +- > > fs/proc/internal.h | 1 + > > fs/proc/root.c | 14 +-- > > fs/proc/self.c | 10 +- > > fs/proc/thread_self.c | 11 +- > > fs/pstore/inode.c | 7 +- > > fs/ramfs/inode.c | 8 +- > > fs/super.c | 8 -- > > fs/tracefs/event_inode.c | 7 +- > > fs/tracefs/inode.c | 13 +-- > > include/linux/dcache.h | 4 +- > > include/linux/fs.h | 6 +- > > include/linux/proc_fs.h | 2 - > > include/linux/security.h | 2 - > > init/do_mounts.c | 2 +- > > ipc/mqueue.c | 12 +- > > kernel/bpf/inode.c | 15 +-- > > mm/shmem.c | 38 ++---- > > net/sunrpc/rpc_pipe.c | 27 ++--- > > security/apparmor/apparmorfs.c | 13 ++- > > security/inode.c | 35 +++--- > > security/selinux/selinuxfs.c | 185 +++++++++++++----------------- > > security/smack/smackfs.c | 2 +- > > 53 files changed, 649 insertions(+), 834 deletions(-) > > > > Overview: > > > > First two commits are bugfixes (fusectl and tracefs resp.) > > > > [1/54] fuse_ctl_add_conn(): fix nlink breakage in case of early failure > > [2/54] tracefs: fix a leak in eventfs_create_events_dir() > > > > Next, two commits adding a couple of useful helpers, the next three adding > > the infrastructure and the rest consists of per-filesystem conversions. > > > > [3/54] new helper: simple_remove_by_name() > > [4/54] new helper: simple_done_creating() > > end_creating_path() analogue for internal object creation; unlike > > end_creating_path() no mount is passed to it (or guaranteed to exist, for > > that matter - it might be used during the filesystem setup, before the > > superblock gets attached to any mounts). > > > > Infrastructure: > > [5/54] introduce a flag for explicitly marking persistently pinned dentries > > * introduce the new flag > > * teach shrink_dcache_for_umount() to handle it (i.e. remove > > and drop refcount on anything that survives to umount with that flag > > still set) > > * teach kill_litter_super() that anything with that flag does > > *not* need to be unpinned. > > [6/54] primitives for maintaining persisitency > > * d_make_persistent(dentry, inode) - bump refcount, mark persistent > > and make hashed positive. Return value is a borrowed reference to dentry; > > it can be used until something removes persistency (at the very least, > > until the parent gets unlocked, but some filesystems may have stronger > > exclusion). > > * d_make_discardable() - remove persistency mark and drop reference. > > > > NOTE: at that stage d_make_discardable() does not reject dentries not > > marked persistent - it acts as if the mark been set. > > > > Rationale: less noise in series splitup that way. We want (and on the > > next commit will get) simple_unlink() to do the right thing - remove > > persistency, if it's there. However, it's used by many filesystems. > > We would have either to convert them all at once or split simple_unlink() > > into "want persistent" and "don't want persistent" versions, the latter > > being the old one. In the course of the series almost all callers > > would migrate to the replacement, leaving only two pathological cases > > with the old one. The same goes for simple_rmdir() (two callers left in > > the end), simple_recursive_removal() (all callers gone in the end), etc. > > That's a lot of noise and it's easier to start with d_make_discardable() > > quietly accepting non-persistent dentries, then, in the end, add private > > copies of simple_unlink() and simple_rmdir() for two weird users (configfs > > and apparmorfs) and have those use dput() instead of d_make_discardable(). > > At that point we'd be left with all callers of d_make_discardable() > > always passing persistent dentries, allowing to add a warning in it. > > > > [7/54] convert simple_{link,unlink,rmdir,rename,fill_super}() to new primitives > > See above re quietly accepting non-peristent dentries in > > simple_unlink(), simple_rmdir(), etc. > > > > Converting filesystems: > > [8/54] convert ramfs and tmpfs > > [9/54] procfs: make /self and /thread_self dentries persistent > > [10/54] configfs, securityfs: kill_litter_super() not needed > > [11/54] convert xenfs > > [12/54] convert smackfs > > [13/54] convert hugetlbfs > > [14/54] convert mqueue > > [15/54] convert bpf > > [16/54] convert dlmfs > > [17/54] convert fuse_ctl > > [18/54] convert pstore > > [19/54] convert tracefs > > [20/54] convert debugfs > > [21/54] debugfs: remove duplicate checks in callers of start_creating() > > [22/54] convert efivarfs > > [23/54] convert spufs > > [24/54] convert ibmasmfs > > [25/54] ibmasmfs: get rid of ibmasmfs_dir_ops > > [26/54] convert devpts > > [27/54] binderfs: use simple_start_creating() > > [28/54] binderfs_binder_ctl_create(): kill a bogus check > > [29/54] convert binderfs > > [30/54] autofs_{rmdir,unlink}: dentry->d_fsdata->dentry == dentry there > > [31/54] convert autofs > > [32/54] convert binfmt_misc > > [33/54] selinuxfs: don't stash the dentry of /policy_capabilities > > [34/54] selinuxfs: new helper for attaching files to tree > > [35/54] convert selinuxfs > > > > Several functionfs fixes, before converting it, to make life > > simpler for backporting: > > [36/54] functionfs: don't abuse ffs_data_closed() on fs shutdown > > [37/54] functionfs: don't bother with ffs->ref in ffs_data_{opened,closed}() > > [38/54] functionfs: need to cancel ->reset_work in ->kill_sb() > > [39/54] functionfs: fix the open/removal races > > > > ... and back to filesystems conversions: > > > > [40/54] functionfs: switch to simple_remove_by_name() > > [41/54] convert functionfs > > [42/54] gadgetfs: switch to simple_remove_by_name() > > [43/54] convert gadgetfs > > [44/54] hypfs: don't pin dentries twice > > [45/54] hypfs: switch hypfs_create_str() to returning int > > [46/54] hypfs: swich hypfs_create_u64() to returning int > > [47/54] convert hypfs > > [48/54] convert rpc_pipefs > > [49/54] convert nfsctl > > [50/54] convert rust_binderfs > > > > ... and no kill_litter_super() callers remain, so we > > can take it out: > > [51/54] get rid of kill_litter_super() > > > > Followups: > > [52/54] convert securityfs > > That was the last remaining user of simple_recursive_removal() > > that did *not* mark things persistent. Now the only places where > > d_make_discardable() is still called for dentries that are not marked > > persistent are the calls of simple_{unlink,rmdir}() in configfs and > > apparmorfs. > > > > [53/54] kill securityfs_recursive_remove() > > Unused macro... > > > > [54/54] d_make_discardable(): warn if given a non-persistent dentry > > > > At this point there are very few call chains that might lead to > > d_make_discardable() on a dentry that hadn't been made persistent: > > calls of simple_unlink() and simple_rmdir() in configfs and > > apparmorfs. > > > > Both filesystems do pin (part of) their contents in dcache, but > > they are currently playing very unusual games with that. Converting > > them to more usual patterns might be possible, but it's definitely > > going to be a long series of changes in both cases. > > > > For now the easiest solution is to have both stop using simple_unlink() > > and simple_rmdir() - that allows to make d_make_discardable() warn > > when given a non-persistent dentry. > > > > Rather than giving them full-blown private copies (with calls of > > d_make_discardable() replaced with dput()), let's pull the parts of > > simple_unlink() and simple_rmdir() that deal with timestamps and link > > counts into separate helpers (__simple_unlink() and __simple_rmdir() > > resp.) and have those used by configfs and apparmorfs. > > > > Hi Al, when I apply this patchset my Pixel 6 no longer enumerates on > lsusb or ADB. It was quite hard to bisect to this point, as this is > non-deterministic and seems to be setup specific. Note, I am using > android-mainline, but my understanding is that this build does not > have any out-of-tree USB patches, and that there are no vendor hooks > in the build. > > My apologies as I can't offer any other clues; there are no obviously > bad dmesg logs and I'm still working on narrowing down the exact > commit(s) that started this, but just wanted to send a FYI in case > something stands out as obvious. Note that I had to revert commit e5bf5ee26663 ("functionfs: fix the open/removal races") from the stable backports, as it was causing issues on the pixel devices it got backported to. So perhaps look there? thanks, greg k-h ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-27 7:42 ` Greg KH @ 2026-01-27 18:39 ` Linus Torvalds 2026-01-27 20:14 ` Al Viro 2026-01-28 2:02 ` Samuel Wu 1 sibling, 1 reply; 26+ messages in thread From: Linus Torvalds @ 2026-01-27 18:39 UTC (permalink / raw) To: Greg KH Cc: Samuel Wu, Al Viro, linux-fsdevel, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Mon, 26 Jan 2026 at 23:42, Greg KH <gregkh@linuxfoundation.org> wrote: > > Note that I had to revert commit e5bf5ee26663 ("functionfs: fix the > open/removal races") from the stable backports, as it was causing issues > on the pixel devices it got backported to. So perhaps look there? Hmm. That commit is obviously still upstream, do we understand why it caused problems in the backports? Linus ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-27 18:39 ` Linus Torvalds @ 2026-01-27 20:14 ` Al Viro 2026-01-28 8:53 ` Greg KH 0 siblings, 1 reply; 26+ messages in thread From: Al Viro @ 2026-01-27 20:14 UTC (permalink / raw) To: Linus Torvalds Cc: Greg KH, Samuel Wu, linux-fsdevel, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Tue, Jan 27, 2026 at 10:39:04AM -0800, Linus Torvalds wrote: > On Mon, 26 Jan 2026 at 23:42, Greg KH <gregkh@linuxfoundation.org> wrote: > > > > Note that I had to revert commit e5bf5ee26663 ("functionfs: fix the > > open/removal races") from the stable backports, as it was causing issues > > on the pixel devices it got backported to. So perhaps look there? > > Hmm. That commit is obviously still upstream, do we understand why it > caused problems in the backports? This is all I've seen: | It has been reported to cause test problems in Android devices. As the | other functionfs changes were not also backported at the same time, | something is out of sync. So just revert this one for now and it can | come back in the future as a patch series if it is tested. My apologies for not following up on that one; Greg, could you give some references to those reports? ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-27 20:14 ` Al Viro @ 2026-01-28 8:53 ` Greg KH 0 siblings, 0 replies; 26+ messages in thread From: Greg KH @ 2026-01-28 8:53 UTC (permalink / raw) To: Al Viro Cc: Linus Torvalds, Samuel Wu, linux-fsdevel, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Tue, Jan 27, 2026 at 08:14:54PM +0000, Al Viro wrote: > On Tue, Jan 27, 2026 at 10:39:04AM -0800, Linus Torvalds wrote: > > On Mon, 26 Jan 2026 at 23:42, Greg KH <gregkh@linuxfoundation.org> wrote: > > > > > > Note that I had to revert commit e5bf5ee26663 ("functionfs: fix the > > > open/removal races") from the stable backports, as it was causing issues > > > on the pixel devices it got backported to. So perhaps look there? > > > > Hmm. That commit is obviously still upstream, do we understand why it > > caused problems in the backports? > > This is all I've seen: > > | It has been reported to cause test problems in Android devices. As the > | other functionfs changes were not also backported at the same time, > | something is out of sync. So just revert this one for now and it can > | come back in the future as a patch series if it is tested. > > My apologies for not following up on that one; Greg, could you give some > references to those reports? Sorry, all I got was a "this commit caused devices to fail" and was found from bisection, on the 6.18.y tree. Samuel has much more information as to exactly what is happening here as he can see the test results properly, I'll let him work through this, thanks! greg k-h ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-27 7:42 ` Greg KH 2026-01-27 18:39 ` Linus Torvalds @ 2026-01-28 2:02 ` Samuel Wu 2026-01-28 4:59 ` Al Viro 1 sibling, 1 reply; 26+ messages in thread From: Samuel Wu @ 2026-01-28 2:02 UTC (permalink / raw) To: Greg KH Cc: Al Viro, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Mon, Jan 26, 2026 at 11:42 PM Greg KH <gregkh@linuxfoundation.org> wrote: > > On Mon, Jan 26, 2026 at 04:56:42PM -0800, Samuel Wu wrote: > > On Mon, Nov 17, 2025 at 9:15 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > > > > > > Some filesystems use a kinda-sorta controlled dentry refcount leak to pin > > > dentries of created objects in dcache (and undo it when removing those). > > > Reference is grabbed and not released, but it's not actually _stored_ > > > anywhere. That works, but it's hard to follow and verify; among other > > > things, we have no way to tell _which_ of the increments is intended > > > to be an unpaired one. Worse, on removal we need to decide whether > > > the reference had already been dropped, which can be non-trivial if > > > that removal is on umount and we need to figure out if this dentry is > > > pinned due to e.g. unlink() not done. Usually that is handled by using > > > kill_litter_super() as ->kill_sb(), but there are open-coded special > > > cases of the same (consider e.g. /proc/self). > > > > > > Things get simpler if we introduce a new dentry flag (DCACHE_PERSISTENT) > > > marking those "leaked" dentries. Having it set claims responsibility > > > for +1 in refcount. > > > > > > The end result this series is aiming for: > > > > > > * get these unbalanced dget() and dput() replaced with new primitives that > > > would, in addition to adjusting refcount, set and clear persistency flag. > > > * instead of having kill_litter_super() mess with removing the remaining > > > "leaked" references (e.g. for all tmpfs files that hadn't been removed > > > prior to umount), have the regular shrink_dcache_for_umount() strip > > > DCACHE_PERSISTENT of all dentries, dropping the corresponding > > > reference if it had been set. After that kill_litter_super() becomes > > > an equivalent of kill_anon_super(). > > > > > > Doing that in a single step is not feasible - it would affect too many places > > > in too many filesystems. It has to be split into a series. > > > > > > This work has really started early in 2024; quite a few preliminary pieces > > > have already gone into mainline. This chunk is finally getting to the > > > meat of that stuff - infrastructure and most of the conversions to it. > > > > > > Some pieces are still sitting in the local branches, but the bulk of > > > that stuff is here. > > > > > > Compared to v3: > > > * fixed a functionfs braino around ffs_epfiles_destroy() (in #40/54, > > > used to be #36/50). > > > * added fixes for a couple of UAF in functionfs (##36--39); that > > > does *NOT* include any fixes for dmabuf bugs Chris posted last week, though. > > > > > > The branch is -rc5-based; it lives in > > > git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git #work.persistency > > > individual patches in followups. > > > > > > Please, help with review and testing. If nobody objects, in a few days it > > > goes into #for-next. > > > > > > Shortlog: > > > fuse_ctl_add_conn(): fix nlink breakage in case of early failure > > > tracefs: fix a leak in eventfs_create_events_dir() > > > new helper: simple_remove_by_name() > > > new helper: simple_done_creating() > > > introduce a flag for explicitly marking persistently pinned dentries > > > primitives for maintaining persisitency > > > convert simple_{link,unlink,rmdir,rename,fill_super}() to new primitives > > > convert ramfs and tmpfs > > > procfs: make /self and /thread_self dentries persistent > > > configfs, securityfs: kill_litter_super() not needed > > > convert xenfs > > > convert smackfs > > > convert hugetlbfs > > > convert mqueue > > > convert bpf > > > convert dlmfs > > > convert fuse_ctl > > > convert pstore > > > convert tracefs > > > convert debugfs > > > debugfs: remove duplicate checks in callers of start_creating() > > > convert efivarfs > > > convert spufs > > > convert ibmasmfs > > > ibmasmfs: get rid of ibmasmfs_dir_ops > > > convert devpts > > > binderfs: use simple_start_creating() > > > binderfs_binder_ctl_create(): kill a bogus check > > > convert binderfs > > > autofs_{rmdir,unlink}: dentry->d_fsdata->dentry == dentry there > > > convert autofs > > > convert binfmt_misc > > > selinuxfs: don't stash the dentry of /policy_capabilities > > > selinuxfs: new helper for attaching files to tree > > > convert selinuxfs > > > functionfs: don't abuse ffs_data_closed() on fs shutdown > > > functionfs: don't bother with ffs->ref in ffs_data_{opened,closed}() > > > functionfs: need to cancel ->reset_work in ->kill_sb() > > > functionfs: fix the open/removal races > > > functionfs: switch to simple_remove_by_name() > > > convert functionfs > > > gadgetfs: switch to simple_remove_by_name() > > > convert gadgetfs > > > hypfs: don't pin dentries twice > > > hypfs: switch hypfs_create_str() to returning int > > > hypfs: swich hypfs_create_u64() to returning int > > > convert hypfs > > > convert rpc_pipefs > > > convert nfsctl > > > convert rust_binderfs > > > get rid of kill_litter_super() > > > convert securityfs > > > kill securityfs_recursive_remove() > > > d_make_discardable(): warn if given a non-persistent dentry > > > > > > Diffstat: > > > Documentation/filesystems/porting.rst | 7 ++ > > > arch/powerpc/platforms/cell/spufs/inode.c | 17 ++- > > > arch/s390/hypfs/hypfs.h | 6 +- > > > arch/s390/hypfs/hypfs_diag_fs.c | 60 ++++------ > > > arch/s390/hypfs/hypfs_vm_fs.c | 21 ++-- > > > arch/s390/hypfs/inode.c | 82 +++++-------- > > > drivers/android/binder/rust_binderfs.c | 121 ++++++------------- > > > drivers/android/binderfs.c | 82 +++---------- > > > drivers/base/devtmpfs.c | 2 +- > > > drivers/misc/ibmasm/ibmasmfs.c | 24 ++-- > > > drivers/usb/gadget/function/f_fs.c | 144 +++++++++++++---------- > > > drivers/usb/gadget/legacy/inode.c | 49 ++++---- > > > drivers/xen/xenfs/super.c | 2 +- > > > fs/autofs/inode.c | 2 +- > > > fs/autofs/root.c | 11 +- > > > fs/binfmt_misc.c | 69 ++++++----- > > > fs/configfs/dir.c | 10 +- > > > fs/configfs/inode.c | 3 +- > > > fs/configfs/mount.c | 2 +- > > > fs/dcache.c | 111 +++++++++++------- > > > fs/debugfs/inode.c | 32 ++---- > > > fs/devpts/inode.c | 57 ++++----- > > > fs/efivarfs/inode.c | 7 +- > > > fs/efivarfs/super.c | 5 +- > > > fs/fuse/control.c | 38 +++--- > > > fs/hugetlbfs/inode.c | 12 +- > > > fs/internal.h | 1 - > > > fs/libfs.c | 52 +++++++-- > > > fs/nfsd/nfsctl.c | 18 +-- > > > fs/ocfs2/dlmfs/dlmfs.c | 8 +- > > > fs/proc/base.c | 6 +- > > > fs/proc/internal.h | 1 + > > > fs/proc/root.c | 14 +-- > > > fs/proc/self.c | 10 +- > > > fs/proc/thread_self.c | 11 +- > > > fs/pstore/inode.c | 7 +- > > > fs/ramfs/inode.c | 8 +- > > > fs/super.c | 8 -- > > > fs/tracefs/event_inode.c | 7 +- > > > fs/tracefs/inode.c | 13 +-- > > > include/linux/dcache.h | 4 +- > > > include/linux/fs.h | 6 +- > > > include/linux/proc_fs.h | 2 - > > > include/linux/security.h | 2 - > > > init/do_mounts.c | 2 +- > > > ipc/mqueue.c | 12 +- > > > kernel/bpf/inode.c | 15 +-- > > > mm/shmem.c | 38 ++---- > > > net/sunrpc/rpc_pipe.c | 27 ++--- > > > security/apparmor/apparmorfs.c | 13 ++- > > > security/inode.c | 35 +++--- > > > security/selinux/selinuxfs.c | 185 +++++++++++++----------------- > > > security/smack/smackfs.c | 2 +- > > > 53 files changed, 649 insertions(+), 834 deletions(-) > > > > > > Overview: > > > > > > First two commits are bugfixes (fusectl and tracefs resp.) > > > > > > [1/54] fuse_ctl_add_conn(): fix nlink breakage in case of early failure > > > [2/54] tracefs: fix a leak in eventfs_create_events_dir() > > > > > > Next, two commits adding a couple of useful helpers, the next three adding > > > the infrastructure and the rest consists of per-filesystem conversions. > > > > > > [3/54] new helper: simple_remove_by_name() > > > [4/54] new helper: simple_done_creating() > > > end_creating_path() analogue for internal object creation; unlike > > > end_creating_path() no mount is passed to it (or guaranteed to exist, for > > > that matter - it might be used during the filesystem setup, before the > > > superblock gets attached to any mounts). > > > > > > Infrastructure: > > > [5/54] introduce a flag for explicitly marking persistently pinned dentries > > > * introduce the new flag > > > * teach shrink_dcache_for_umount() to handle it (i.e. remove > > > and drop refcount on anything that survives to umount with that flag > > > still set) > > > * teach kill_litter_super() that anything with that flag does > > > *not* need to be unpinned. > > > [6/54] primitives for maintaining persisitency > > > * d_make_persistent(dentry, inode) - bump refcount, mark persistent > > > and make hashed positive. Return value is a borrowed reference to dentry; > > > it can be used until something removes persistency (at the very least, > > > until the parent gets unlocked, but some filesystems may have stronger > > > exclusion). > > > * d_make_discardable() - remove persistency mark and drop reference. > > > > > > NOTE: at that stage d_make_discardable() does not reject dentries not > > > marked persistent - it acts as if the mark been set. > > > > > > Rationale: less noise in series splitup that way. We want (and on the > > > next commit will get) simple_unlink() to do the right thing - remove > > > persistency, if it's there. However, it's used by many filesystems. > > > We would have either to convert them all at once or split simple_unlink() > > > into "want persistent" and "don't want persistent" versions, the latter > > > being the old one. In the course of the series almost all callers > > > would migrate to the replacement, leaving only two pathological cases > > > with the old one. The same goes for simple_rmdir() (two callers left in > > > the end), simple_recursive_removal() (all callers gone in the end), etc. > > > That's a lot of noise and it's easier to start with d_make_discardable() > > > quietly accepting non-persistent dentries, then, in the end, add private > > > copies of simple_unlink() and simple_rmdir() for two weird users (configfs > > > and apparmorfs) and have those use dput() instead of d_make_discardable(). > > > At that point we'd be left with all callers of d_make_discardable() > > > always passing persistent dentries, allowing to add a warning in it. > > > > > > [7/54] convert simple_{link,unlink,rmdir,rename,fill_super}() to new primitives > > > See above re quietly accepting non-peristent dentries in > > > simple_unlink(), simple_rmdir(), etc. > > > > > > Converting filesystems: > > > [8/54] convert ramfs and tmpfs > > > [9/54] procfs: make /self and /thread_self dentries persistent > > > [10/54] configfs, securityfs: kill_litter_super() not needed > > > [11/54] convert xenfs > > > [12/54] convert smackfs > > > [13/54] convert hugetlbfs > > > [14/54] convert mqueue > > > [15/54] convert bpf > > > [16/54] convert dlmfs > > > [17/54] convert fuse_ctl > > > [18/54] convert pstore > > > [19/54] convert tracefs > > > [20/54] convert debugfs > > > [21/54] debugfs: remove duplicate checks in callers of start_creating() > > > [22/54] convert efivarfs > > > [23/54] convert spufs > > > [24/54] convert ibmasmfs > > > [25/54] ibmasmfs: get rid of ibmasmfs_dir_ops > > > [26/54] convert devpts > > > [27/54] binderfs: use simple_start_creating() > > > [28/54] binderfs_binder_ctl_create(): kill a bogus check > > > [29/54] convert binderfs > > > [30/54] autofs_{rmdir,unlink}: dentry->d_fsdata->dentry == dentry there > > > [31/54] convert autofs > > > [32/54] convert binfmt_misc > > > [33/54] selinuxfs: don't stash the dentry of /policy_capabilities > > > [34/54] selinuxfs: new helper for attaching files to tree > > > [35/54] convert selinuxfs > > > > > > Several functionfs fixes, before converting it, to make life > > > simpler for backporting: > > > [36/54] functionfs: don't abuse ffs_data_closed() on fs shutdown > > > [37/54] functionfs: don't bother with ffs->ref in ffs_data_{opened,closed}() > > > [38/54] functionfs: need to cancel ->reset_work in ->kill_sb() > > > [39/54] functionfs: fix the open/removal races > > > > > > ... and back to filesystems conversions: > > > > > > [40/54] functionfs: switch to simple_remove_by_name() > > > [41/54] convert functionfs > > > [42/54] gadgetfs: switch to simple_remove_by_name() > > > [43/54] convert gadgetfs > > > [44/54] hypfs: don't pin dentries twice > > > [45/54] hypfs: switch hypfs_create_str() to returning int > > > [46/54] hypfs: swich hypfs_create_u64() to returning int > > > [47/54] convert hypfs > > > [48/54] convert rpc_pipefs > > > [49/54] convert nfsctl > > > [50/54] convert rust_binderfs > > > > > > ... and no kill_litter_super() callers remain, so we > > > can take it out: > > > [51/54] get rid of kill_litter_super() > > > > > > Followups: > > > [52/54] convert securityfs > > > That was the last remaining user of simple_recursive_removal() > > > that did *not* mark things persistent. Now the only places where > > > d_make_discardable() is still called for dentries that are not marked > > > persistent are the calls of simple_{unlink,rmdir}() in configfs and > > > apparmorfs. > > > > > > [53/54] kill securityfs_recursive_remove() > > > Unused macro... > > > > > > [54/54] d_make_discardable(): warn if given a non-persistent dentry > > > > > > At this point there are very few call chains that might lead to > > > d_make_discardable() on a dentry that hadn't been made persistent: > > > calls of simple_unlink() and simple_rmdir() in configfs and > > > apparmorfs. > > > > > > Both filesystems do pin (part of) their contents in dcache, but > > > they are currently playing very unusual games with that. Converting > > > them to more usual patterns might be possible, but it's definitely > > > going to be a long series of changes in both cases. > > > > > > For now the easiest solution is to have both stop using simple_unlink() > > > and simple_rmdir() - that allows to make d_make_discardable() warn > > > when given a non-persistent dentry. > > > > > > Rather than giving them full-blown private copies (with calls of > > > d_make_discardable() replaced with dput()), let's pull the parts of > > > simple_unlink() and simple_rmdir() that deal with timestamps and link > > > counts into separate helpers (__simple_unlink() and __simple_rmdir() > > > resp.) and have those used by configfs and apparmorfs. > > > > > > > Hi Al, when I apply this patchset my Pixel 6 no longer enumerates on > > lsusb or ADB. It was quite hard to bisect to this point, as this is > > non-deterministic and seems to be setup specific. Note, I am using > > android-mainline, but my understanding is that this build does not > > have any out-of-tree USB patches, and that there are no vendor hooks > > in the build. > > > > My apologies as I can't offer any other clues; there are no obviously > > bad dmesg logs and I'm still working on narrowing down the exact > > commit(s) that started this, but just wanted to send a FYI in case > > something stands out as obvious. > > Note that I had to revert commit e5bf5ee26663 ("functionfs: fix the > open/removal races") from the stable backports, as it was causing issues > on the pixel devices it got backported to. So perhaps look there? > > thanks, > > greg k-h Thanks for the suggestion. I tried a few different setups, and now I'm fairly confident e5bf5ee26663 ("functionfs: fix the open/removal races") is the culprit. I did have to revert 6ca67378d0e7 ("convert functionfs") and c7747fafaba0 ("functionfs: switch to simple_remove_by_name()") to successfully build, but reverting only those two in isolation did not fix the issue. Al, please let me know if you have any other variant of the patch(s) that you want tested, otherwise feel free to add these tags as appropriate: Reported-by: Samuel Wu <wusamuel@google.com> Tested-by: Samuel Wu <wusamuel@google.com> Thanks! ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-28 2:02 ` Samuel Wu @ 2026-01-28 4:59 ` Al Viro 2026-01-29 0:58 ` Samuel Wu 0 siblings, 1 reply; 26+ messages in thread From: Al Viro @ 2026-01-28 4:59 UTC (permalink / raw) To: Samuel Wu Cc: Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Tue, Jan 27, 2026 at 06:02:25PM -0800, Samuel Wu wrote: > Thanks for the suggestion. I tried a few different setups, and now I'm > fairly confident e5bf5ee26663 ("functionfs: fix the open/removal > races") is the culprit. I did have to revert 6ca67378d0e7 ("convert > functionfs") and c7747fafaba0 ("functionfs: switch to > simple_remove_by_name()") to successfully build, but reverting only > those two in isolation did not fix the issue. Very interesting... Does 1544775687f0 (parent of e5bf5ee26663) demonstrate that behaviour? ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-28 4:59 ` Al Viro @ 2026-01-29 0:58 ` Samuel Wu 2026-01-29 3:23 ` Al Viro 0 siblings, 1 reply; 26+ messages in thread From: Samuel Wu @ 2026-01-29 0:58 UTC (permalink / raw) To: Al Viro Cc: Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Tue, Jan 27, 2026 at 8:58 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > Very interesting... Does 1544775687f0 (parent of e5bf5ee26663) > demonstrate that behaviour? Reverting only 1544775687f0 (functionfs: need to cancel ->reset_work in ->kill_sb()) does not fix the issue. With 6.19-rc7 as baseline, the simplest working recipe at the moment is with 6ca67378d0e7, c7747fafaba0, and e5bf5ee26663 reverted. ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-29 0:58 ` Samuel Wu @ 2026-01-29 3:23 ` Al Viro 2026-01-29 22:54 ` Al Viro 0 siblings, 1 reply; 26+ messages in thread From: Al Viro @ 2026-01-29 3:23 UTC (permalink / raw) To: Samuel Wu Cc: Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Wed, Jan 28, 2026 at 04:58:57PM -0800, Samuel Wu wrote: > On Tue, Jan 27, 2026 at 8:58 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > > > Very interesting... Does 1544775687f0 (parent of e5bf5ee26663) > > demonstrate that behaviour? > > Reverting only 1544775687f0 (functionfs: need to cancel ->reset_work > in ->kill_sb()) does not fix the issue. With 6.19-rc7 as baseline, the > simplest working recipe at the moment is with 6ca67378d0e7, > c7747fafaba0, and e5bf5ee26663 reverted. Sorry, I hadn't been clear enough: if you do git switch --detach 1544775687f0 and build the resulting tree, does the breakage reproduce? What I want to do is to split e5bf5ee26663 into smaller steps and see which one introduces the breakage, but the starting point would be verify that there's no breakage prior to that. PS: v6.19-rc7 contains fc45aee66223 ("get rid of kill_litter_super()"), and reverting 6ca67378d0e7 ("convert functionfs") would reintroduce the call of that function in ffs_fs_kill_sb(), so the resulting tree won't even build on any configs with functionfs enabledd; are you sure that you'd been testing v6.19-rc7 + reverts of just these 3 commits? ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-29 3:23 ` Al Viro @ 2026-01-29 22:54 ` Al Viro 2026-01-30 1:16 ` Samuel Wu 0 siblings, 1 reply; 26+ messages in thread From: Al Viro @ 2026-01-29 22:54 UTC (permalink / raw) To: Samuel Wu Cc: Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Thu, Jan 29, 2026 at 03:23:35AM +0000, Al Viro wrote: > On Wed, Jan 28, 2026 at 04:58:57PM -0800, Samuel Wu wrote: > > On Tue, Jan 27, 2026 at 8:58 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > > > > > Very interesting... Does 1544775687f0 (parent of e5bf5ee26663) > > > demonstrate that behaviour? > > > > Reverting only 1544775687f0 (functionfs: need to cancel ->reset_work > > in ->kill_sb()) does not fix the issue. With 6.19-rc7 as baseline, the > > simplest working recipe at the moment is with 6ca67378d0e7, > > c7747fafaba0, and e5bf5ee26663 reverted. > > Sorry, I hadn't been clear enough: if you do > git switch --detach 1544775687f0 > and build the resulting tree, does the breakage reproduce? What I want > to do is to split e5bf5ee26663 into smaller steps and see which one > introduces the breakage, but the starting point would be verify that > there's no breakage prior to that. > > > PS: v6.19-rc7 contains fc45aee66223 ("get rid of kill_litter_super()"), > and reverting 6ca67378d0e7 ("convert functionfs") would reintroduce > the call of that function in ffs_fs_kill_sb(), so the resulting tree > won't even build on any configs with functionfs enabledd; are you sure > that you'd been testing v6.19-rc7 + reverts of just these 3 commits? Could you try your reproducer on mainline with the following delta applied? diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 05c6750702b6..6c6d55ba0749 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -646,12 +646,11 @@ static int ffs_ep0_open(struct inode *inode, struct file *file) if (ret < 0) return ret; - ffs_data_opened(ffs); if (ffs->state == FFS_CLOSING) { - ffs_data_closed(ffs); mutex_unlock(&ffs->mutex); return -EBUSY; } + ffs_data_opened(ffs); mutex_unlock(&ffs->mutex); file->private_data = ffs; ^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-29 22:54 ` Al Viro @ 2026-01-30 1:16 ` Samuel Wu 2026-01-30 7:04 ` Al Viro 2026-01-31 14:58 ` Krishna Kurapati PSSNV 0 siblings, 2 replies; 26+ messages in thread From: Samuel Wu @ 2026-01-30 1:16 UTC (permalink / raw) To: Al Viro Cc: Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Thu, Jan 29, 2026 at 2:52 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > > Sorry, I hadn't been clear enough: if you do > > git switch --detach 1544775687f0 > > and build the resulting tree, does the breakage reproduce? What I want > > to do is to split e5bf5ee26663 into smaller steps and see which one > > introduces the breakage, but the starting point would be verify that > > there's no breakage prior to that. Ultimately, same conclusion as before: 6.18-rc5 with patches up to 1544775687f0 works, but adding e5bf5ee26663 breaks it. > > PS: v6.19-rc7 contains fc45aee66223 ("get rid of kill_litter_super()"), > > and reverting 6ca67378d0e7 ("convert functionfs") would reintroduce > > the call of that function in ffs_fs_kill_sb(), so the resulting tree > > won't even build on any configs with functionfs enabledd; are you sure > > that you'd been testing v6.19-rc7 + reverts of just these 3 commits? I also could have been more clear- I had to s/kill_anon_super/kill_litter_super/ as part of the revert of 6ca67378d0e7 to properly build. That felt like an appropriate change, but if not, adding patches on top of 6.18-rc5 is perfectly fine for testing this. > Could you try your reproducer on mainline with the following delta applied? > > diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c > index 05c6750702b6..6c6d55ba0749 100644 > --- a/drivers/usb/gadget/function/f_fs.c > +++ b/drivers/usb/gadget/function/f_fs.c > @@ -646,12 +646,11 @@ static int ffs_ep0_open(struct inode *inode, struct file *file) > if (ret < 0) > return ret; > > - ffs_data_opened(ffs); > if (ffs->state == FFS_CLOSING) { > - ffs_data_closed(ffs); > mutex_unlock(&ffs->mutex); > return -EBUSY; > } > + ffs_data_opened(ffs); > mutex_unlock(&ffs->mutex); > file->private_data = ffs; > This didn't work on either build variant (6.18-rc5 and 6.19-rc7). I'm exploring a few other paths, but not having USB access makes traditional tools a bit difficult. One thing I'm rechecking and is worth mentioning is the lockdep below: it's been present for quite some time now, but I'm not sure if it would have some undesired interaction with your patch. [ BUG: Invalid wait context ] 6.18.0-rc5-mainline-maybe-dirty-4k ----------------------------- irq/360-dwc3/352 is trying to lock: ffffff800792deb8 (&psy->extensions_sem){.+.+}-{3:3}, at: __power_supply_set_property+0x40/0x180 other info that might help us debug this: context-{4:4} 1 lock held by irq/360-dwc3/352: #0: ffffff8017bb98f0 (&gi->spinlock){....}-{2:2}, at: configfs_composite_suspend+0x28/0x68 Call trace: show_stack+0x18/0x28 (C) __dump_stack+0x28/0x3c dump_stack_lvl+0xac/0xf0 dump_stack+0x18/0x3c __lock_acquire+0x794/0x2bec lock_acquire+0x148/0x2cc down_read+0x3c/0x194 __power_supply_set_property+0x40/0x180 power_supply_set_property+0x14/0x20 dwc3_gadget_vbus_draw+0x8c/0xcc usb_gadget_vbus_draw+0x48/0x130 composite_suspend+0xcc/0xe4 configfs_composite_suspend+0x44/0x68 dwc3_thread_interrupt+0x8f8/0xc88 irq_thread_fn+0x48/0xa8 irq_thread+0x150/0x31c kthread+0x150/0x280 ret_from_fork+0x10/0x20 ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-30 1:16 ` Samuel Wu @ 2026-01-30 7:04 ` Al Viro 2026-01-30 22:31 ` Samuel Wu 2026-01-31 14:58 ` Krishna Kurapati PSSNV 1 sibling, 1 reply; 26+ messages in thread From: Al Viro @ 2026-01-30 7:04 UTC (permalink / raw) To: Samuel Wu Cc: Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Thu, Jan 29, 2026 at 05:16:20PM -0800, Samuel Wu wrote: > On Thu, Jan 29, 2026 at 2:52 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > > > > Sorry, I hadn't been clear enough: if you do > > > git switch --detach 1544775687f0 > > > and build the resulting tree, does the breakage reproduce? What I want > > > to do is to split e5bf5ee26663 into smaller steps and see which one > > > introduces the breakage, but the starting point would be verify that > > > there's no breakage prior to that. > > Ultimately, same conclusion as before: 6.18-rc5 with patches up to > 1544775687f0 works, but adding e5bf5ee26663 breaks it. OK. Could you take a clone of mainline repository and in there run ; git fetch git://git.kernel.org:/pub/scm/linux/kernel/git/viro/vfs.git for-wsamuel:for-wsamuel then ; git diff for-wsamuel e5bf5ee26663 to verify that for-wsamuel is identical to tree you've seen breakage on ; git diff for-wsamuel-base 1544775687f0 to verify that for-wsamuel-base is the tree where the breakage did not reproduce Then bisect from for-wsamuel-base to for-wsamuel. Basically, that's the offending commit split into steps; let's try to figure out what causes the breakage with better resolution... ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-30 7:04 ` Al Viro @ 2026-01-30 22:31 ` Samuel Wu 2026-01-30 23:57 ` Al Viro 0 siblings, 1 reply; 26+ messages in thread From: Samuel Wu @ 2026-01-30 22:31 UTC (permalink / raw) To: Al Viro Cc: Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Thu, Jan 29, 2026 at 11:02 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > OK. Could you take a clone of mainline repository and in there run > ; git fetch git://git.kernel.org:/pub/scm/linux/kernel/git/viro/vfs.git for-wsamuel:for-wsamuel > then > ; git diff for-wsamuel e5bf5ee26663 > to verify that for-wsamuel is identical to tree you've seen breakage on > ; git diff for-wsamuel-base 1544775687f0 > to verify that for-wsamuel-base is the tree where the breakage did not reproduce > Then bisect from for-wsamuel-base to for-wsamuel. > > Basically, that's the offending commit split into steps; let's try to figure > out what causes the breakage with better resolution... Confirming that bisect points to this patch: 09e88dc22ea2 (serialize ffs_ep0_open() on ffs->mutex) ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-30 22:31 ` Samuel Wu @ 2026-01-30 23:57 ` Al Viro 2026-01-31 0:14 ` Linus Torvalds ` (2 more replies) 0 siblings, 3 replies; 26+ messages in thread From: Al Viro @ 2026-01-30 23:57 UTC (permalink / raw) To: Samuel Wu Cc: Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Fri, Jan 30, 2026 at 02:31:54PM -0800, Samuel Wu wrote: > On Thu, Jan 29, 2026 at 11:02 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > > OK. Could you take a clone of mainline repository and in there run > > ; git fetch git://git.kernel.org:/pub/scm/linux/kernel/git/viro/vfs.git for-wsamuel:for-wsamuel > > then > > ; git diff for-wsamuel e5bf5ee26663 > > to verify that for-wsamuel is identical to tree you've seen breakage on > > ; git diff for-wsamuel-base 1544775687f0 > > to verify that for-wsamuel-base is the tree where the breakage did not reproduce > > Then bisect from for-wsamuel-base to for-wsamuel. > > > > Basically, that's the offending commit split into steps; let's try to figure > > out what causes the breakage with better resolution... > > Confirming that bisect points to this patch: 09e88dc22ea2 (serialize > ffs_ep0_open() on ffs->mutex) So we have something that does O_NDELAY opens of ep0 *and* does not retry on EAGAIN? How lovely... Could you slap WARN_ON(ret == -EAGAIN); right before that if (ret < 0) return ret; in there and see which process is doing that? Regression is a regression, odd userland or not, but I would like to see what is that userland actually trying to do there. *grumble* IMO at that point we have two problems - one is how to avoid a revert of the tail of tree-in-dcache series, another is how to deal with quite real preexisting bugs in functionfs. Another thing to try (not as a suggestion of a fix, just an attempt to figure out how badly would the things break): in current mainline replace that ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK) in ffs_ep0_open() with ffs_mutex_lock(&ffs->mutex, false) and see how badly do the things regress for userland. Again, I'm not saying that this is a fix - just trying to get some sense of what's the userland is doing. FWIW, it might make sense to try a lighter serialization in ffs_ep0_open() - taking it there is due to the following scenario (assuming 6.18 or earlier): ffs->state is FFS_DEACTIVATED. ffs->opened is 0. Two threads attempt to open ep0. Here's what happens prior to these patches: static int ffs_ep0_open(struct inode *inode, struct file *file) { struct ffs_data *ffs = inode->i_private; if (ffs->state == FFS_CLOSING) return -EBUSY; file->private_data = ffs; ffs_data_opened(ffs); with static void ffs_data_opened(struct ffs_data *ffs) { refcount_inc(&ffs->ref); if (atomic_add_return(1, &ffs->opened) == 1 && ffs->state == FFS_DEACTIVATED) { ffs->state = FFS_CLOSING; ffs_data_reset(ffs); } } IOW, the sequence is if (state == FFS_CLOSING) return -EBUSY; n = atomic_add_return(1, &opened); if (n == 1 && state == FFS_DEACTIVATED) { state = FFS_CLOSING; ffs_data_reset(); See the race there? If the second open() comes between the increment of ffs->opened and setting the state to FFS_CLOSING, it will *not* fail with EBUSY - it will proceed to return to userland, while the first sucker is crawling through the work in ffs_data_reset()/ffs_data_clear()/ffs_epfiles_destroy(). What's more, there's nothing to stop that second opener from calling write() on the descriptor it got. No exclusion there - ffs->state = FFS_READ_DESCRIPTORS; ffs->setup_state = FFS_NO_SETUP; ffs->flags = 0; in ffs_data_reset() is *not* serialized against ffs_ep0_write(). Get preempted right after setting ->state and that write() will go just fine, only to be surprised when the first thread regains CPU and continues modifying the contents of *ffs under whatever the second thread is doing. That code obviously relies upon that kind of shit being prevented by that -EBUSY logics in ep0 open() and that logics is obviously racy as it is. Note that other callers of ffs_data_reset() have similar problem: ffs_func_set_alt(), for example has if (ffs->state == FFS_DEACTIVATED) { ffs->state = FFS_CLOSING; INIT_WORK(&ffs->reset_work, ffs_reset_work); schedule_work(&ffs->reset_work); return -ENODEV; } again, with no exclusion. Lose CPU just after seeing FFS_DEACTIVATED, then have another thread open() the sucker and start going through ffs_data_reset(), only to have us regain CPU and schedule this for execution: static void ffs_reset_work(struct work_struct *work) { struct ffs_data *ffs = container_of(work, struct ffs_data, reset_work); ffs_data_reset(ffs); } IOW, stray ffs_data_reset() coming to surprise the opener who'd just finished ffs_data_reset() during open(2) and proceeded to write to the damn thing, etc. That's obviously on the "how do we fix the preexisting bugs" side of things, though - regression needs to be dealt with ASAP anyway. ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-30 23:57 ` Al Viro @ 2026-01-31 0:14 ` Linus Torvalds 2026-01-31 1:08 ` Al Viro 2026-01-31 0:59 ` Al Viro 2026-01-31 1:05 ` Samuel Wu 2 siblings, 1 reply; 26+ messages in thread From: Linus Torvalds @ 2026-01-31 0:14 UTC (permalink / raw) To: Al Viro Cc: Samuel Wu, Greg KH, linux-fsdevel, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Fri, 30 Jan 2026 at 15:55, Al Viro <viro@zeniv.linux.org.uk> wrote: > > So we have something that does O_NDELAY opens of ep0 *and* does not retry on > EAGAIN? > > How lovely... Actually, I think that is pretty normal behavior. Generally, O_NDELAY and friends should *NOT* turn locks into trylocks - because user space has no sane way to deal with kernel lock issues, and user space simply shouldn't care. So O_NDELAY should be about avoiding IO, not about avoiding perfectly normal locks. Of course, that horrendous driver locking is broken, since it holds the lock over IO, so that driver basically conflates IO and locking, and that's arguably the fundamental problem here. But I suspect that for this case, we should just pass in zero to ffs_mutex_lock() on open, and say that the O_NONBLOCK flag is purely about the subsequent IO, not about the open() itself. That is, after all, how the driver used to work. Linus ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-31 0:14 ` Linus Torvalds @ 2026-01-31 1:08 ` Al Viro 2026-01-31 1:11 ` Linus Torvalds 0 siblings, 1 reply; 26+ messages in thread From: Al Viro @ 2026-01-31 1:08 UTC (permalink / raw) To: Linus Torvalds Cc: Samuel Wu, Greg KH, linux-fsdevel, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Fri, Jan 30, 2026 at 04:14:48PM -0800, Linus Torvalds wrote: > On Fri, 30 Jan 2026 at 15:55, Al Viro <viro@zeniv.linux.org.uk> wrote: > > > > So we have something that does O_NDELAY opens of ep0 *and* does not retry on > > EAGAIN? > > > > How lovely... > > Actually, I think that is pretty normal behavior. > > Generally, O_NDELAY and friends should *NOT* turn locks into trylocks > - because user space has no sane way to deal with kernel lock issues, > and user space simply shouldn't care. > > So O_NDELAY should be about avoiding IO, not about avoiding perfectly > normal locks. > > Of course, that horrendous driver locking is broken, since it holds > the lock over IO, so that driver basically conflates IO and locking, > and that's arguably the fundamental problem here. > > But I suspect that for this case, we should just pass in zero to > ffs_mutex_lock() on open, and say that the O_NONBLOCK flag is purely > about the subsequent IO, not about the open() itself. > > That is, after all, how the driver used to work. I'd rather go for a spinlock there, protecting these FFS_DEACTIVATED transitions; let me try and put together something along those lines. Matter of fact, I would drop the atomics for ->opened completely and do all changes under the same spinlock - it's really just ->open() and ->release(). Simpler that way... The shitty part is that ->set_alt() thing and its callers seems to be written in assumption that it can come from an interrupt, so we'd need spin_lock_irq() in open/release and spin_lock_irqsave() in set_alt/disable... Another fun part is that we need a barrier on transition from FFS_CLOSING in ffs_data_reset() - right now it's not even the last assignment in there. Same spinlock would solve that - screw explicit barriers, it's _not_ a hot path and the locking is convoluted enough as it is. ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-31 1:08 ` Al Viro @ 2026-01-31 1:11 ` Linus Torvalds 2026-02-01 0:11 ` Al Viro 0 siblings, 1 reply; 26+ messages in thread From: Linus Torvalds @ 2026-01-31 1:11 UTC (permalink / raw) To: Al Viro Cc: Samuel Wu, Greg KH, linux-fsdevel, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Fri, 30 Jan 2026 at 17:06, Al Viro <viro@zeniv.linux.org.uk> wrote: > > I'd rather go for a spinlock there, protecting these FFS_DEACTIVATED > transitions; Yes, that's the much better solution. The locking in this thing is horrendous. But judging by Samuel's recent email, there's something else than the open locking thing going on. Linus ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-31 1:11 ` Linus Torvalds @ 2026-02-01 0:11 ` Al Viro 0 siblings, 0 replies; 26+ messages in thread From: Al Viro @ 2026-02-01 0:11 UTC (permalink / raw) To: Linus Torvalds Cc: Samuel Wu, Greg KH, linux-fsdevel, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Fri, Jan 30, 2026 at 05:11:39PM -0800, Linus Torvalds wrote: > On Fri, 30 Jan 2026 at 17:06, Al Viro <viro@zeniv.linux.org.uk> wrote: > > > > I'd rather go for a spinlock there, protecting these FFS_DEACTIVATED > > transitions; > > Yes, that's the much better solution. The locking in this thing is horrendous. > > But judging by Samuel's recent email, there's something else than the > open locking thing going on. I've put the following into viro/vfs.git#fixes; diff is identical to the one that is reported to fix things on top of -rc7... Objections? commit 99a706fa47949ece1fb02b5b1206efd4fb031d25 Author: Al Viro <viro@zeniv.linux.org.uk> Date: Sat Jan 31 18:24:41 2026 -0500 functionfs: use spinlock for FFS_DEACTIVATED/FFS_CLOSING transitions When all files are closed, functionfs needs ffs_data_reset() to be done before any further opens are allowed. During that time we have ffs->state set to FFS_CLOSING; that makes ->open() fail with -EBUSY. Once ffs_data_reset() is done, it switches state (to FFS_READ_DESCRIPTORS) indicating that opening that thing is allowed again. There's a couple of additional twists: * mounting with -o no_disconnect delays ffs_data_reset() from doing that at the final ->release() to the first subsequent open(). That's indicated by ffs->state set to FFS_DEACTIVATED; if open() sees that, it immediately switches to FFS_CLOSING and proceeds with doing ffs_data_reset() before returning to userland. * a couple of usb callbacks need to force the delayed transition; unfortunately, they are done in locking environment that does not allow blocking and ffs_data_reset() can block. As the result, if these callbacks see FFS_DEACTIVATED, they change state to FFS_CLOSING and use schedule_work() to get ffs_data_reset() executed asynchronously. Unfortunately, the locking is rather insufficient. A fix attempted in e5bf5ee26663 ("functionfs: fix the open/removal races") had closed a bunch of UAF, but it didn't do anything to the callbacks, lacked barriers in transition from FFS_CLOSING to FFS_READ_DESCRIPTORS _and_ it had been too heavy-handed in open()/open() serialization - I've used ffs->mutex for that, and it's being held over actual IO on ep0, complete with copy_from_user(), etc. Even more unfortunately, the userland side is apparently racy enough to have the resulting timing changes (no failures, just a delayed return of open(2)) disrupt the things quite badly. Userland bugs or not, it's a clear regression that needs to be dealt with. Solution is to use a spinlock for serializing these state checks and transitions - unlike ffs->mutex it can be taken in these callbacks and it doesn't disrupt the timings in open(). We could introduce a new spinlock, but it's easier to use the one that is already there (ffs->eps_lock) instead - the locking environment is safe for it in all affected places. Since now it is held over all places that alter or check the open count (ffs->opened), there's no need to keep that atomic_t - int would serve just fine and it's simpler that way. Fixes: e5bf5ee26663 ("functionfs: fix the open/removal races") Fixes: 18d6b32fca38 ("usb: gadget: f_fs: add "no_disconnect" mode") # v4.0 Tested-by: Samuel Wu <wusamuel@google.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> --- diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 05c6750702b6..fa467a40949d 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -59,7 +59,6 @@ static struct ffs_data *__must_check ffs_data_new(const char *dev_name) __attribute__((malloc)); /* Opened counter handling. */ -static void ffs_data_opened(struct ffs_data *ffs); static void ffs_data_closed(struct ffs_data *ffs); /* Called with ffs->mutex held; take over ownership of data. */ @@ -636,23 +635,25 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, return ret; } + +static void ffs_data_reset(struct ffs_data *ffs); + static int ffs_ep0_open(struct inode *inode, struct file *file) { struct ffs_data *ffs = inode->i_sb->s_fs_info; - int ret; - /* Acquire mutex */ - ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); - if (ret < 0) - return ret; - - ffs_data_opened(ffs); + spin_lock_irq(&ffs->eps_lock); if (ffs->state == FFS_CLOSING) { - ffs_data_closed(ffs); - mutex_unlock(&ffs->mutex); + spin_unlock_irq(&ffs->eps_lock); return -EBUSY; } - mutex_unlock(&ffs->mutex); + if (!ffs->opened++ && ffs->state == FFS_DEACTIVATED) { + ffs->state = FFS_CLOSING; + spin_unlock_irq(&ffs->eps_lock); + ffs_data_reset(ffs); + } else { + spin_unlock_irq(&ffs->eps_lock); + } file->private_data = ffs; return stream_open(inode, file); @@ -1202,15 +1203,10 @@ ffs_epfile_open(struct inode *inode, struct file *file) { struct ffs_data *ffs = inode->i_sb->s_fs_info; struct ffs_epfile *epfile; - int ret; - - /* Acquire mutex */ - ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); - if (ret < 0) - return ret; - if (!atomic_inc_not_zero(&ffs->opened)) { - mutex_unlock(&ffs->mutex); + spin_lock_irq(&ffs->eps_lock); + if (!ffs->opened) { + spin_unlock_irq(&ffs->eps_lock); return -ENODEV; } /* @@ -1220,11 +1216,11 @@ ffs_epfile_open(struct inode *inode, struct file *file) */ epfile = smp_load_acquire(&inode->i_private); if (unlikely(ffs->state != FFS_ACTIVE || !epfile)) { - mutex_unlock(&ffs->mutex); - ffs_data_closed(ffs); + spin_unlock_irq(&ffs->eps_lock); return -ENODEV; } - mutex_unlock(&ffs->mutex); + ffs->opened++; + spin_unlock_irq(&ffs->eps_lock); file->private_data = epfile; return stream_open(inode, file); @@ -2092,8 +2088,6 @@ static int ffs_fs_init_fs_context(struct fs_context *fc) return 0; } -static void ffs_data_reset(struct ffs_data *ffs); - static void ffs_fs_kill_sb(struct super_block *sb) { @@ -2150,15 +2144,6 @@ static void ffs_data_get(struct ffs_data *ffs) refcount_inc(&ffs->ref); } -static void ffs_data_opened(struct ffs_data *ffs) -{ - if (atomic_add_return(1, &ffs->opened) == 1 && - ffs->state == FFS_DEACTIVATED) { - ffs->state = FFS_CLOSING; - ffs_data_reset(ffs); - } -} - static void ffs_data_put(struct ffs_data *ffs) { if (refcount_dec_and_test(&ffs->ref)) { @@ -2176,28 +2161,29 @@ static void ffs_data_put(struct ffs_data *ffs) static void ffs_data_closed(struct ffs_data *ffs) { - if (atomic_dec_and_test(&ffs->opened)) { - if (ffs->no_disconnect) { - struct ffs_epfile *epfiles; - unsigned long flags; - - ffs->state = FFS_DEACTIVATED; - spin_lock_irqsave(&ffs->eps_lock, flags); - epfiles = ffs->epfiles; - ffs->epfiles = NULL; - spin_unlock_irqrestore(&ffs->eps_lock, - flags); - - if (epfiles) - ffs_epfiles_destroy(ffs->sb, epfiles, - ffs->eps_count); - - if (ffs->setup_state == FFS_SETUP_PENDING) - __ffs_ep0_stall(ffs); - } else { - ffs->state = FFS_CLOSING; - ffs_data_reset(ffs); - } + spin_lock_irq(&ffs->eps_lock); + if (--ffs->opened) { // not the last opener? + spin_unlock_irq(&ffs->eps_lock); + return; + } + if (ffs->no_disconnect) { + struct ffs_epfile *epfiles; + + ffs->state = FFS_DEACTIVATED; + epfiles = ffs->epfiles; + ffs->epfiles = NULL; + spin_unlock_irq(&ffs->eps_lock); + + if (epfiles) + ffs_epfiles_destroy(ffs->sb, epfiles, + ffs->eps_count); + + if (ffs->setup_state == FFS_SETUP_PENDING) + __ffs_ep0_stall(ffs); + } else { + ffs->state = FFS_CLOSING; + spin_unlock_irq(&ffs->eps_lock); + ffs_data_reset(ffs); } } @@ -2214,7 +2200,7 @@ static struct ffs_data *ffs_data_new(const char *dev_name) } refcount_set(&ffs->ref, 1); - atomic_set(&ffs->opened, 0); + ffs->opened = 0; ffs->state = FFS_READ_DESCRIPTORS; mutex_init(&ffs->mutex); spin_lock_init(&ffs->eps_lock); @@ -2266,6 +2252,7 @@ static void ffs_data_reset(struct ffs_data *ffs) { ffs_data_clear(ffs); + spin_lock_irq(&ffs->eps_lock); ffs->raw_descs_data = NULL; ffs->raw_descs = NULL; ffs->raw_strings = NULL; @@ -2289,6 +2276,7 @@ static void ffs_data_reset(struct ffs_data *ffs) ffs->ms_os_descs_ext_prop_count = 0; ffs->ms_os_descs_ext_prop_name_len = 0; ffs->ms_os_descs_ext_prop_data_len = 0; + spin_unlock_irq(&ffs->eps_lock); } @@ -3756,6 +3744,7 @@ static int ffs_func_set_alt(struct usb_function *f, { struct ffs_function *func = ffs_func_from_usb(f); struct ffs_data *ffs = func->ffs; + unsigned long flags; int ret = 0, intf; if (alt > MAX_ALT_SETTINGS) @@ -3768,12 +3757,15 @@ static int ffs_func_set_alt(struct usb_function *f, if (ffs->func) ffs_func_eps_disable(ffs->func); + spin_lock_irqsave(&ffs->eps_lock, flags); if (ffs->state == FFS_DEACTIVATED) { ffs->state = FFS_CLOSING; + spin_unlock_irqrestore(&ffs->eps_lock, flags); INIT_WORK(&ffs->reset_work, ffs_reset_work); schedule_work(&ffs->reset_work); return -ENODEV; } + spin_unlock_irqrestore(&ffs->eps_lock, flags); if (ffs->state != FFS_ACTIVE) return -ENODEV; @@ -3791,16 +3783,20 @@ static void ffs_func_disable(struct usb_function *f) { struct ffs_function *func = ffs_func_from_usb(f); struct ffs_data *ffs = func->ffs; + unsigned long flags; if (ffs->func) ffs_func_eps_disable(ffs->func); + spin_lock_irqsave(&ffs->eps_lock, flags); if (ffs->state == FFS_DEACTIVATED) { ffs->state = FFS_CLOSING; + spin_unlock_irqrestore(&ffs->eps_lock, flags); INIT_WORK(&ffs->reset_work, ffs_reset_work); schedule_work(&ffs->reset_work); return; } + spin_unlock_irqrestore(&ffs->eps_lock, flags); if (ffs->state == FFS_ACTIVE) { ffs->func = NULL; diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h index 4b3365f23fd7..6a80182aadd7 100644 --- a/drivers/usb/gadget/function/u_fs.h +++ b/drivers/usb/gadget/function/u_fs.h @@ -176,7 +176,7 @@ struct ffs_data { /* reference counter */ refcount_t ref; /* how many files are opened (EP0 and others) */ - atomic_t opened; + int opened; /* EP0 state */ enum ffs_state state; ^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-30 23:57 ` Al Viro 2026-01-31 0:14 ` Linus Torvalds @ 2026-01-31 0:59 ` Al Viro 2026-01-31 1:05 ` Samuel Wu 2 siblings, 0 replies; 26+ messages in thread From: Al Viro @ 2026-01-31 0:59 UTC (permalink / raw) To: Samuel Wu Cc: Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Fri, Jan 30, 2026 at 11:57:43PM +0000, Al Viro wrote: > Another thing to try (not as a suggestion of a fix, just an attempt to figure > out how badly would the things break): in current mainline replace that > ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK) > in ffs_ep0_open() with > ffs_mutex_lock(&ffs->mutex, false) > and see how badly do the things regress for userland. Again, I'm not saying > that this is a fix - just trying to get some sense of what's the userland > is doing. At a guess, quite badly. ffs->mutex *is* way too heavy for that purpose - that's a geniune bug. State transitions in that thing are messy; AFAICS, the state is a combination of ->opened and ->state, and transitions assume atomicity that just isn't there. All updates of ->opened are process-synchronous; the nasty part is in the FFS_DEACTIVATED handling. We don't want it to coexist with ->opened > 0; normally decrement of ->opened to 0 gets us into FFS_CLOSING immediately and follows that with ffs_data_reset(). In -o no_disconnect mounts we switch to FFS_DEACTIVATED instead. On the next open() after that we want it to transition to the same FFS_CLOSING + the same call of ffs_data_reset(). open() running into FFS_CLOSING fails; that happens until ffs_data_reset() switches ->state to FFS_READ_DESCRIPTORS. Things are complicated by ffs_func_set_alt() and ffs_func_disable() - these can come with ->opened being zero and both contain this: if (ffs->state == FFS_DEACTIVATED) { ffs->state = FFS_CLOSING; INIT_WORK(&ffs->reset_work, ffs_reset_work); schedule_work(&ffs->reset_work); return -ENODEV; } with s/return -ENODEV;/return;/ for ffs_func_disable(). The point, AFAICT, is to avoid deadlocks from having ffs_data_reset() called in the locking environment these two are called in. At least ->set_alt() can be called under a spinlock and ffs_data_reset() is blocking. Another potentially troubling part is the check for FFS_ACTIVE in the same functions, seeing that ffs->state = FFS_ACTIVE; mutex_unlock(&ffs->mutex); ret = ffs_ready(ffs); if (ret < 0) { ffs->state = FFS_CLOSING; return ret; } in ep0 write() happens with no exclusion with those (as the matter of fact, that transition to FFS_CLOSING holds no locks at all)... ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-30 23:57 ` Al Viro 2026-01-31 0:14 ` Linus Torvalds 2026-01-31 0:59 ` Al Viro @ 2026-01-31 1:05 ` Samuel Wu 2026-01-31 1:18 ` Al Viro 2 siblings, 1 reply; 26+ messages in thread From: Samuel Wu @ 2026-01-31 1:05 UTC (permalink / raw) To: Al Viro Cc: Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Fri, Jan 30, 2026 at 3:55 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > So we have something that does O_NDELAY opens of ep0 *and* does not retry on > EAGAIN? > > How lovely... Could you slap > WARN_ON(ret == -EAGAIN); > right before that > if (ret < 0) > return ret; Surprisingly ret == 0 every time, so no difference in dmesg logs with this addition. > in there and see which process is doing that? Regression is a regression, > odd userland or not, but I would like to see what is that userland actually > trying to do there. > > *grumble* > > IMO at that point we have two problems - one is how to avoid a revert of the > tail of tree-in-dcache series, another is how to deal with quite real > preexisting bugs in functionfs. > > Another thing to try (not as a suggestion of a fix, just an attempt to figure > out how badly would the things break): in current mainline replace that > ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK) > in ffs_ep0_open() with > ffs_mutex_lock(&ffs->mutex, false) > and see how badly do the things regress for userland. Again, I'm not saying > that this is a fix - just trying to get some sense of what's the userland > is doing. Ergo this didn't make a difference either. ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-31 1:05 ` Samuel Wu @ 2026-01-31 1:18 ` Al Viro 2026-01-31 2:09 ` Samuel Wu 0 siblings, 1 reply; 26+ messages in thread From: Al Viro @ 2026-01-31 1:18 UTC (permalink / raw) To: Samuel Wu Cc: Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Fri, Jan 30, 2026 at 05:05:34PM -0800, Samuel Wu wrote: > > How lovely... Could you slap > > WARN_ON(ret == -EAGAIN); > > right before that > > if (ret < 0) > > return ret; > > Surprisingly ret == 0 every time, so no difference in dmesg logs with > this addition. What the hell? Other than that mutex_lock(), the only change in there is the order of store to file->private_data and call of ffs_data_opened(); that struct file pointer is not visible to anyone at that point... Wait, it also brings ffs_data_reset() on that transition under ffs->mutex... For a quick check: does git fetch git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git for-wsamuel2 git switch --detach FETCH_HEAD demonstrate the same breakage? ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-31 1:18 ` Al Viro @ 2026-01-31 2:09 ` Samuel Wu 2026-01-31 2:43 ` Al Viro 0 siblings, 1 reply; 26+ messages in thread From: Samuel Wu @ 2026-01-31 2:09 UTC (permalink / raw) To: Al Viro Cc: Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Fri, Jan 30, 2026 at 5:16 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > > On Fri, Jan 30, 2026 at 05:05:34PM -0800, Samuel Wu wrote: > > > > How lovely... Could you slap > > > WARN_ON(ret == -EAGAIN); > > > right before that > > > if (ret < 0) > > > return ret; > > > > Surprisingly ret == 0 every time, so no difference in dmesg logs with > > this addition. > > What the hell? Other than that mutex_lock(), the only change in there > is the order of store to file->private_data and call of ffs_data_opened(); > that struct file pointer is not visible to anyone at that point... Agree, 09e88dc22ea2 (serialize ffs_ep0_open() on ffs->mutex) in itself is quite straightforward. Not familiar with this code path so just speculating, but is there any interaction with previous patches (e.g. refcounting)? > Wait, it also brings ffs_data_reset() on that transition under ffs->mutex... > For a quick check: does > git fetch git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git for-wsamuel2 > git switch --detach FETCH_HEAD > demonstrate the same breakage? Had to adjust forward declaration of ffs_data_reset() to build, but unfortunately same breakage. ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-31 2:09 ` Samuel Wu @ 2026-01-31 2:43 ` Al Viro 2026-01-31 19:48 ` Samuel Wu 0 siblings, 1 reply; 26+ messages in thread From: Al Viro @ 2026-01-31 2:43 UTC (permalink / raw) To: Samuel Wu Cc: Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Fri, Jan 30, 2026 at 06:09:00PM -0800, Samuel Wu wrote: > On Fri, Jan 30, 2026 at 5:16 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > > > > On Fri, Jan 30, 2026 at 05:05:34PM -0800, Samuel Wu wrote: > > > > > > How lovely... Could you slap > > > > WARN_ON(ret == -EAGAIN); > > > > right before that > > > > if (ret < 0) > > > > return ret; > > > > > > Surprisingly ret == 0 every time, so no difference in dmesg logs with > > > this addition. > > > > What the hell? Other than that mutex_lock(), the only change in there > > is the order of store to file->private_data and call of ffs_data_opened(); > > that struct file pointer is not visible to anyone at that point... > > Agree, 09e88dc22ea2 (serialize ffs_ep0_open() on ffs->mutex) in itself > is quite straightforward. Not familiar with this code path so just > speculating, but is there any interaction with previous patches (e.g. > refcounting)? > > > Wait, it also brings ffs_data_reset() on that transition under ffs->mutex... > > For a quick check: does > > git fetch git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git for-wsamuel2 > > git switch --detach FETCH_HEAD > > demonstrate the same breakage? > > Had to adjust forward declaration of ffs_data_reset() to build, but > unfortunately same breakage. That really looks like a badly racy userland on top of everything else... I mean, it smells like userland open() from one process while another is in the middle of configuring that stuff getting delayed too much for the entire thing to work. Bloody wonderful... OK, let's see if a variant with serialization on spinlock works - how does the following do on top of mainline? diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 05c6750702b6..fa467a40949d 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -59,7 +59,6 @@ static struct ffs_data *__must_check ffs_data_new(const char *dev_name) __attribute__((malloc)); /* Opened counter handling. */ -static void ffs_data_opened(struct ffs_data *ffs); static void ffs_data_closed(struct ffs_data *ffs); /* Called with ffs->mutex held; take over ownership of data. */ @@ -636,23 +635,25 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, return ret; } + +static void ffs_data_reset(struct ffs_data *ffs); + static int ffs_ep0_open(struct inode *inode, struct file *file) { struct ffs_data *ffs = inode->i_sb->s_fs_info; - int ret; - /* Acquire mutex */ - ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); - if (ret < 0) - return ret; - - ffs_data_opened(ffs); + spin_lock_irq(&ffs->eps_lock); if (ffs->state == FFS_CLOSING) { - ffs_data_closed(ffs); - mutex_unlock(&ffs->mutex); + spin_unlock_irq(&ffs->eps_lock); return -EBUSY; } - mutex_unlock(&ffs->mutex); + if (!ffs->opened++ && ffs->state == FFS_DEACTIVATED) { + ffs->state = FFS_CLOSING; + spin_unlock_irq(&ffs->eps_lock); + ffs_data_reset(ffs); + } else { + spin_unlock_irq(&ffs->eps_lock); + } file->private_data = ffs; return stream_open(inode, file); @@ -1202,15 +1203,10 @@ ffs_epfile_open(struct inode *inode, struct file *file) { struct ffs_data *ffs = inode->i_sb->s_fs_info; struct ffs_epfile *epfile; - int ret; - - /* Acquire mutex */ - ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); - if (ret < 0) - return ret; - if (!atomic_inc_not_zero(&ffs->opened)) { - mutex_unlock(&ffs->mutex); + spin_lock_irq(&ffs->eps_lock); + if (!ffs->opened) { + spin_unlock_irq(&ffs->eps_lock); return -ENODEV; } /* @@ -1220,11 +1216,11 @@ ffs_epfile_open(struct inode *inode, struct file *file) */ epfile = smp_load_acquire(&inode->i_private); if (unlikely(ffs->state != FFS_ACTIVE || !epfile)) { - mutex_unlock(&ffs->mutex); - ffs_data_closed(ffs); + spin_unlock_irq(&ffs->eps_lock); return -ENODEV; } - mutex_unlock(&ffs->mutex); + ffs->opened++; + spin_unlock_irq(&ffs->eps_lock); file->private_data = epfile; return stream_open(inode, file); @@ -2092,8 +2088,6 @@ static int ffs_fs_init_fs_context(struct fs_context *fc) return 0; } -static void ffs_data_reset(struct ffs_data *ffs); - static void ffs_fs_kill_sb(struct super_block *sb) { @@ -2150,15 +2144,6 @@ static void ffs_data_get(struct ffs_data *ffs) refcount_inc(&ffs->ref); } -static void ffs_data_opened(struct ffs_data *ffs) -{ - if (atomic_add_return(1, &ffs->opened) == 1 && - ffs->state == FFS_DEACTIVATED) { - ffs->state = FFS_CLOSING; - ffs_data_reset(ffs); - } -} - static void ffs_data_put(struct ffs_data *ffs) { if (refcount_dec_and_test(&ffs->ref)) { @@ -2176,28 +2161,29 @@ static void ffs_data_put(struct ffs_data *ffs) static void ffs_data_closed(struct ffs_data *ffs) { - if (atomic_dec_and_test(&ffs->opened)) { - if (ffs->no_disconnect) { - struct ffs_epfile *epfiles; - unsigned long flags; - - ffs->state = FFS_DEACTIVATED; - spin_lock_irqsave(&ffs->eps_lock, flags); - epfiles = ffs->epfiles; - ffs->epfiles = NULL; - spin_unlock_irqrestore(&ffs->eps_lock, - flags); - - if (epfiles) - ffs_epfiles_destroy(ffs->sb, epfiles, - ffs->eps_count); - - if (ffs->setup_state == FFS_SETUP_PENDING) - __ffs_ep0_stall(ffs); - } else { - ffs->state = FFS_CLOSING; - ffs_data_reset(ffs); - } + spin_lock_irq(&ffs->eps_lock); + if (--ffs->opened) { // not the last opener? + spin_unlock_irq(&ffs->eps_lock); + return; + } + if (ffs->no_disconnect) { + struct ffs_epfile *epfiles; + + ffs->state = FFS_DEACTIVATED; + epfiles = ffs->epfiles; + ffs->epfiles = NULL; + spin_unlock_irq(&ffs->eps_lock); + + if (epfiles) + ffs_epfiles_destroy(ffs->sb, epfiles, + ffs->eps_count); + + if (ffs->setup_state == FFS_SETUP_PENDING) + __ffs_ep0_stall(ffs); + } else { + ffs->state = FFS_CLOSING; + spin_unlock_irq(&ffs->eps_lock); + ffs_data_reset(ffs); } } @@ -2214,7 +2200,7 @@ static struct ffs_data *ffs_data_new(const char *dev_name) } refcount_set(&ffs->ref, 1); - atomic_set(&ffs->opened, 0); + ffs->opened = 0; ffs->state = FFS_READ_DESCRIPTORS; mutex_init(&ffs->mutex); spin_lock_init(&ffs->eps_lock); @@ -2266,6 +2252,7 @@ static void ffs_data_reset(struct ffs_data *ffs) { ffs_data_clear(ffs); + spin_lock_irq(&ffs->eps_lock); ffs->raw_descs_data = NULL; ffs->raw_descs = NULL; ffs->raw_strings = NULL; @@ -2289,6 +2276,7 @@ static void ffs_data_reset(struct ffs_data *ffs) ffs->ms_os_descs_ext_prop_count = 0; ffs->ms_os_descs_ext_prop_name_len = 0; ffs->ms_os_descs_ext_prop_data_len = 0; + spin_unlock_irq(&ffs->eps_lock); } @@ -3756,6 +3744,7 @@ static int ffs_func_set_alt(struct usb_function *f, { struct ffs_function *func = ffs_func_from_usb(f); struct ffs_data *ffs = func->ffs; + unsigned long flags; int ret = 0, intf; if (alt > MAX_ALT_SETTINGS) @@ -3768,12 +3757,15 @@ static int ffs_func_set_alt(struct usb_function *f, if (ffs->func) ffs_func_eps_disable(ffs->func); + spin_lock_irqsave(&ffs->eps_lock, flags); if (ffs->state == FFS_DEACTIVATED) { ffs->state = FFS_CLOSING; + spin_unlock_irqrestore(&ffs->eps_lock, flags); INIT_WORK(&ffs->reset_work, ffs_reset_work); schedule_work(&ffs->reset_work); return -ENODEV; } + spin_unlock_irqrestore(&ffs->eps_lock, flags); if (ffs->state != FFS_ACTIVE) return -ENODEV; @@ -3791,16 +3783,20 @@ static void ffs_func_disable(struct usb_function *f) { struct ffs_function *func = ffs_func_from_usb(f); struct ffs_data *ffs = func->ffs; + unsigned long flags; if (ffs->func) ffs_func_eps_disable(ffs->func); + spin_lock_irqsave(&ffs->eps_lock, flags); if (ffs->state == FFS_DEACTIVATED) { ffs->state = FFS_CLOSING; + spin_unlock_irqrestore(&ffs->eps_lock, flags); INIT_WORK(&ffs->reset_work, ffs_reset_work); schedule_work(&ffs->reset_work); return; } + spin_unlock_irqrestore(&ffs->eps_lock, flags); if (ffs->state == FFS_ACTIVE) { ffs->func = NULL; diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h index 4b3365f23fd7..6a80182aadd7 100644 --- a/drivers/usb/gadget/function/u_fs.h +++ b/drivers/usb/gadget/function/u_fs.h @@ -176,7 +176,7 @@ struct ffs_data { /* reference counter */ refcount_t ref; /* how many files are opened (EP0 and others) */ - atomic_t opened; + int opened; /* EP0 state */ enum ffs_state state; ^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-31 2:43 ` Al Viro @ 2026-01-31 19:48 ` Samuel Wu 0 siblings, 0 replies; 26+ messages in thread From: Samuel Wu @ 2026-01-31 19:48 UTC (permalink / raw) To: Al Viro Cc: Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Fri, Jan 30, 2026 at 6:41 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > > On Fri, Jan 30, 2026 at 06:09:00PM -0800, Samuel Wu wrote: > > On Fri, Jan 30, 2026 at 5:16 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > > > > > > On Fri, Jan 30, 2026 at 05:05:34PM -0800, Samuel Wu wrote: > > > > > > > > How lovely... Could you slap > > > > > WARN_ON(ret == -EAGAIN); > > > > > right before that > > > > > if (ret < 0) > > > > > return ret; > > > > > > > > Surprisingly ret == 0 every time, so no difference in dmesg logs with > > > > this addition. > > > > > > What the hell? Other than that mutex_lock(), the only change in there > > > is the order of store to file->private_data and call of ffs_data_opened(); > > > that struct file pointer is not visible to anyone at that point... > > > > Agree, 09e88dc22ea2 (serialize ffs_ep0_open() on ffs->mutex) in itself > > is quite straightforward. Not familiar with this code path so just > > speculating, but is there any interaction with previous patches (e.g. > > refcounting)? > > > > > Wait, it also brings ffs_data_reset() on that transition under ffs->mutex... > > > For a quick check: does > > > git fetch git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git for-wsamuel2 > > > git switch --detach FETCH_HEAD > > > demonstrate the same breakage? > > > > Had to adjust forward declaration of ffs_data_reset() to build, but > > unfortunately same breakage. > > That really looks like a badly racy userland on top of everything else... > I mean, it smells like userland open() from one process while another > is in the middle of configuring that stuff getting delayed too much > for the entire thing to work. Bloody wonderful... > > OK, let's see if a variant with serialization on spinlock works - how does > the following do on top of mainline? Excellent, this is working consistently for me on the latest 6.19-rc7. > > diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c > index 05c6750702b6..fa467a40949d 100644 > --- a/drivers/usb/gadget/function/f_fs.c > +++ b/drivers/usb/gadget/function/f_fs.c > @@ -59,7 +59,6 @@ static struct ffs_data *__must_check ffs_data_new(const char *dev_name) > __attribute__((malloc)); > > /* Opened counter handling. */ > -static void ffs_data_opened(struct ffs_data *ffs); > static void ffs_data_closed(struct ffs_data *ffs); > > /* Called with ffs->mutex held; take over ownership of data. */ > @@ -636,23 +635,25 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, > return ret; > } > > + > +static void ffs_data_reset(struct ffs_data *ffs); > + > static int ffs_ep0_open(struct inode *inode, struct file *file) > { > struct ffs_data *ffs = inode->i_sb->s_fs_info; > - int ret; > > - /* Acquire mutex */ > - ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); > - if (ret < 0) > - return ret; > - > - ffs_data_opened(ffs); > + spin_lock_irq(&ffs->eps_lock); > if (ffs->state == FFS_CLOSING) { > - ffs_data_closed(ffs); > - mutex_unlock(&ffs->mutex); > + spin_unlock_irq(&ffs->eps_lock); > return -EBUSY; > } > - mutex_unlock(&ffs->mutex); > + if (!ffs->opened++ && ffs->state == FFS_DEACTIVATED) { > + ffs->state = FFS_CLOSING; > + spin_unlock_irq(&ffs->eps_lock); > + ffs_data_reset(ffs); > + } else { > + spin_unlock_irq(&ffs->eps_lock); > + } > file->private_data = ffs; > > return stream_open(inode, file); > @@ -1202,15 +1203,10 @@ ffs_epfile_open(struct inode *inode, struct file *file) > { > struct ffs_data *ffs = inode->i_sb->s_fs_info; > struct ffs_epfile *epfile; > - int ret; > - > - /* Acquire mutex */ > - ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); > - if (ret < 0) > - return ret; > > - if (!atomic_inc_not_zero(&ffs->opened)) { > - mutex_unlock(&ffs->mutex); > + spin_lock_irq(&ffs->eps_lock); > + if (!ffs->opened) { > + spin_unlock_irq(&ffs->eps_lock); > return -ENODEV; > } > /* > @@ -1220,11 +1216,11 @@ ffs_epfile_open(struct inode *inode, struct file *file) > */ > epfile = smp_load_acquire(&inode->i_private); > if (unlikely(ffs->state != FFS_ACTIVE || !epfile)) { > - mutex_unlock(&ffs->mutex); > - ffs_data_closed(ffs); > + spin_unlock_irq(&ffs->eps_lock); > return -ENODEV; > } > - mutex_unlock(&ffs->mutex); > + ffs->opened++; > + spin_unlock_irq(&ffs->eps_lock); > > file->private_data = epfile; > return stream_open(inode, file); > @@ -2092,8 +2088,6 @@ static int ffs_fs_init_fs_context(struct fs_context *fc) > return 0; > } > > -static void ffs_data_reset(struct ffs_data *ffs); > - > static void > ffs_fs_kill_sb(struct super_block *sb) > { > @@ -2150,15 +2144,6 @@ static void ffs_data_get(struct ffs_data *ffs) > refcount_inc(&ffs->ref); > } > > -static void ffs_data_opened(struct ffs_data *ffs) > -{ > - if (atomic_add_return(1, &ffs->opened) == 1 && > - ffs->state == FFS_DEACTIVATED) { > - ffs->state = FFS_CLOSING; > - ffs_data_reset(ffs); > - } > -} > - > static void ffs_data_put(struct ffs_data *ffs) > { > if (refcount_dec_and_test(&ffs->ref)) { > @@ -2176,28 +2161,29 @@ static void ffs_data_put(struct ffs_data *ffs) > > static void ffs_data_closed(struct ffs_data *ffs) > { > - if (atomic_dec_and_test(&ffs->opened)) { > - if (ffs->no_disconnect) { > - struct ffs_epfile *epfiles; > - unsigned long flags; > - > - ffs->state = FFS_DEACTIVATED; > - spin_lock_irqsave(&ffs->eps_lock, flags); > - epfiles = ffs->epfiles; > - ffs->epfiles = NULL; > - spin_unlock_irqrestore(&ffs->eps_lock, > - flags); > - > - if (epfiles) > - ffs_epfiles_destroy(ffs->sb, epfiles, > - ffs->eps_count); > - > - if (ffs->setup_state == FFS_SETUP_PENDING) > - __ffs_ep0_stall(ffs); > - } else { > - ffs->state = FFS_CLOSING; > - ffs_data_reset(ffs); > - } > + spin_lock_irq(&ffs->eps_lock); > + if (--ffs->opened) { // not the last opener? > + spin_unlock_irq(&ffs->eps_lock); > + return; > + } > + if (ffs->no_disconnect) { > + struct ffs_epfile *epfiles; > + > + ffs->state = FFS_DEACTIVATED; > + epfiles = ffs->epfiles; > + ffs->epfiles = NULL; > + spin_unlock_irq(&ffs->eps_lock); > + > + if (epfiles) > + ffs_epfiles_destroy(ffs->sb, epfiles, > + ffs->eps_count); > + > + if (ffs->setup_state == FFS_SETUP_PENDING) > + __ffs_ep0_stall(ffs); > + } else { > + ffs->state = FFS_CLOSING; > + spin_unlock_irq(&ffs->eps_lock); > + ffs_data_reset(ffs); > } > } > > @@ -2214,7 +2200,7 @@ static struct ffs_data *ffs_data_new(const char *dev_name) > } > > refcount_set(&ffs->ref, 1); > - atomic_set(&ffs->opened, 0); > + ffs->opened = 0; > ffs->state = FFS_READ_DESCRIPTORS; > mutex_init(&ffs->mutex); > spin_lock_init(&ffs->eps_lock); > @@ -2266,6 +2252,7 @@ static void ffs_data_reset(struct ffs_data *ffs) > { > ffs_data_clear(ffs); > > + spin_lock_irq(&ffs->eps_lock); > ffs->raw_descs_data = NULL; > ffs->raw_descs = NULL; > ffs->raw_strings = NULL; > @@ -2289,6 +2276,7 @@ static void ffs_data_reset(struct ffs_data *ffs) > ffs->ms_os_descs_ext_prop_count = 0; > ffs->ms_os_descs_ext_prop_name_len = 0; > ffs->ms_os_descs_ext_prop_data_len = 0; > + spin_unlock_irq(&ffs->eps_lock); > } > > > @@ -3756,6 +3744,7 @@ static int ffs_func_set_alt(struct usb_function *f, > { > struct ffs_function *func = ffs_func_from_usb(f); > struct ffs_data *ffs = func->ffs; > + unsigned long flags; > int ret = 0, intf; > > if (alt > MAX_ALT_SETTINGS) > @@ -3768,12 +3757,15 @@ static int ffs_func_set_alt(struct usb_function *f, > if (ffs->func) > ffs_func_eps_disable(ffs->func); > > + spin_lock_irqsave(&ffs->eps_lock, flags); > if (ffs->state == FFS_DEACTIVATED) { > ffs->state = FFS_CLOSING; > + spin_unlock_irqrestore(&ffs->eps_lock, flags); > INIT_WORK(&ffs->reset_work, ffs_reset_work); > schedule_work(&ffs->reset_work); > return -ENODEV; > } > + spin_unlock_irqrestore(&ffs->eps_lock, flags); > > if (ffs->state != FFS_ACTIVE) > return -ENODEV; > @@ -3791,16 +3783,20 @@ static void ffs_func_disable(struct usb_function *f) > { > struct ffs_function *func = ffs_func_from_usb(f); > struct ffs_data *ffs = func->ffs; > + unsigned long flags; > > if (ffs->func) > ffs_func_eps_disable(ffs->func); > > + spin_lock_irqsave(&ffs->eps_lock, flags); > if (ffs->state == FFS_DEACTIVATED) { > ffs->state = FFS_CLOSING; > + spin_unlock_irqrestore(&ffs->eps_lock, flags); > INIT_WORK(&ffs->reset_work, ffs_reset_work); > schedule_work(&ffs->reset_work); > return; > } > + spin_unlock_irqrestore(&ffs->eps_lock, flags); > > if (ffs->state == FFS_ACTIVE) { > ffs->func = NULL; > diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h > index 4b3365f23fd7..6a80182aadd7 100644 > --- a/drivers/usb/gadget/function/u_fs.h > +++ b/drivers/usb/gadget/function/u_fs.h > @@ -176,7 +176,7 @@ struct ffs_data { > /* reference counter */ > refcount_t ref; > /* how many files are opened (EP0 and others) */ > - atomic_t opened; > + int opened; > > /* EP0 state */ > enum ffs_state state; ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-30 1:16 ` Samuel Wu 2026-01-30 7:04 ` Al Viro @ 2026-01-31 14:58 ` Krishna Kurapati PSSNV 2026-01-31 20:02 ` Samuel Wu 1 sibling, 1 reply; 26+ messages in thread From: Krishna Kurapati PSSNV @ 2026-01-31 14:58 UTC (permalink / raw) To: Samuel Wu Cc: Al Viro, Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Fri, Jan 30, 2026 at 6:46 AM Samuel Wu <wusamuel@google.com> wrote: > > On Thu, Jan 29, 2026 at 2:52 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > [...] > I'm exploring a few other paths, but not having USB access makes > traditional tools a bit difficult. One thing I'm rechecking and is > worth mentioning is the lockdep below: it's been present for quite > some time now, but I'm not sure if it would have some undesired > interaction with your patch. > > [ BUG: Invalid wait context ] > 6.18.0-rc5-mainline-maybe-dirty-4k > ----------------------------- > irq/360-dwc3/352 is trying to lock: > ffffff800792deb8 (&psy->extensions_sem){.+.+}-{3:3}, at: > __power_supply_set_property+0x40/0x180 > other info that might help us debug this: > context-{4:4} > 1 lock held by irq/360-dwc3/352: > #0: ffffff8017bb98f0 (&gi->spinlock){....}-{2:2}, at: > configfs_composite_suspend+0x28/0x68 > Call trace: > show_stack+0x18/0x28 (C) > __dump_stack+0x28/0x3c > dump_stack_lvl+0xac/0xf0 > dump_stack+0x18/0x3c > __lock_acquire+0x794/0x2bec > lock_acquire+0x148/0x2cc > down_read+0x3c/0x194 > __power_supply_set_property+0x40/0x180 > power_supply_set_property+0x14/0x20 > dwc3_gadget_vbus_draw+0x8c/0xcc > usb_gadget_vbus_draw+0x48/0x130 > composite_suspend+0xcc/0xe4 > configfs_composite_suspend+0x44/0x68 > dwc3_thread_interrupt+0x8f8/0xc88 > irq_thread_fn+0x48/0xa8 > irq_thread+0x150/0x31c > kthread+0x150/0x280 > ret_from_fork+0x10/0x20 > Hi Samuel, Not sure if it helps, but Prashanth recently pushed a patch to address this vbus_draw kernel panic: https://lore.kernel.org/all/20260129111403.3081730-1-prashanth.k@oss.qualcomm.com/ Can you check if it fixes the above crash in vbus_draw. Regards, Krishna, ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v4 00/54] tree-in-dcache stuff 2026-01-31 14:58 ` Krishna Kurapati PSSNV @ 2026-01-31 20:02 ` Samuel Wu 0 siblings, 0 replies; 26+ messages in thread From: Samuel Wu @ 2026-01-31 20:02 UTC (permalink / raw) To: Krishna Kurapati PSSNV Cc: Al Viro, Greg KH, linux-fsdevel, torvalds, brauner, jack, raven, miklos, neil, a.hindborg, linux-mm, linux-efi, ocfs2-devel, kees, rostedt, linux-usb, paul, casey, linuxppc-dev, john.johansen, selinux, borntraeger, bpf, clm, android-kernel-team On Sat, Jan 31, 2026 at 6:58 AM Krishna Kurapati PSSNV <krishna.kurapati@oss.qualcomm.com> wrote: > > On Fri, Jan 30, 2026 at 6:46 AM Samuel Wu <wusamuel@google.com> wrote: > > > > On Thu, Jan 29, 2026 at 2:52 PM Al Viro <viro@zeniv.linux.org.uk> wrote: > > > > [...] > > > I'm exploring a few other paths, but not having USB access makes > > traditional tools a bit difficult. One thing I'm rechecking and is > > worth mentioning is the lockdep below: it's been present for quite > > some time now, but I'm not sure if it would have some undesired > > interaction with your patch. > > > > [ BUG: Invalid wait context ] > > 6.18.0-rc5-mainline-maybe-dirty-4k > > ----------------------------- > > irq/360-dwc3/352 is trying to lock: > > ffffff800792deb8 (&psy->extensions_sem){.+.+}-{3:3}, at: > > __power_supply_set_property+0x40/0x180 > > other info that might help us debug this: > > context-{4:4} > > 1 lock held by irq/360-dwc3/352: > > #0: ffffff8017bb98f0 (&gi->spinlock){....}-{2:2}, at: > > configfs_composite_suspend+0x28/0x68 > > Call trace: > > show_stack+0x18/0x28 (C) > > __dump_stack+0x28/0x3c > > dump_stack_lvl+0xac/0xf0 > > dump_stack+0x18/0x3c > > __lock_acquire+0x794/0x2bec > > lock_acquire+0x148/0x2cc > > down_read+0x3c/0x194 > > __power_supply_set_property+0x40/0x180 > > power_supply_set_property+0x14/0x20 > > dwc3_gadget_vbus_draw+0x8c/0xcc > > usb_gadget_vbus_draw+0x48/0x130 > > composite_suspend+0xcc/0xe4 > > configfs_composite_suspend+0x44/0x68 > > dwc3_thread_interrupt+0x8f8/0xc88 > > irq_thread_fn+0x48/0xa8 > > irq_thread+0x150/0x31c > > kthread+0x150/0x280 > > ret_from_fork+0x10/0x20 > > > > Hi Samuel, > > Not sure if it helps, but Prashanth recently pushed a patch to > address this vbus_draw kernel panic: > https://lore.kernel.org/all/20260129111403.3081730-1-prashanth.k@oss.qualcomm.com/ > > Can you check if it fixes the above crash in vbus_draw. > > Regards, > Krishna, Tested above patch, and it didn't fix the device enumerating on lsusb/ADB issue. Seems like usb dwc3 lockdep was a red herring. I'll respond on that thread with what I'm observing. ^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2026-02-01 0:09 UTC | newest]
Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20251118051604.3868588-1-viro@zeniv.linux.org.uk>
2026-01-27 0:56 ` [PATCH v4 00/54] tree-in-dcache stuff Samuel Wu
2026-01-27 7:42 ` Greg KH
2026-01-27 18:39 ` Linus Torvalds
2026-01-27 20:14 ` Al Viro
2026-01-28 8:53 ` Greg KH
2026-01-28 2:02 ` Samuel Wu
2026-01-28 4:59 ` Al Viro
2026-01-29 0:58 ` Samuel Wu
2026-01-29 3:23 ` Al Viro
2026-01-29 22:54 ` Al Viro
2026-01-30 1:16 ` Samuel Wu
2026-01-30 7:04 ` Al Viro
2026-01-30 22:31 ` Samuel Wu
2026-01-30 23:57 ` Al Viro
2026-01-31 0:14 ` Linus Torvalds
2026-01-31 1:08 ` Al Viro
2026-01-31 1:11 ` Linus Torvalds
2026-02-01 0:11 ` Al Viro
2026-01-31 0:59 ` Al Viro
2026-01-31 1:05 ` Samuel Wu
2026-01-31 1:18 ` Al Viro
2026-01-31 2:09 ` Samuel Wu
2026-01-31 2:43 ` Al Viro
2026-01-31 19:48 ` Samuel Wu
2026-01-31 14:58 ` Krishna Kurapati PSSNV
2026-01-31 20:02 ` Samuel Wu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox