On Tue, 03 Nov 2026 18:51:19 +0000
[email protected] wrote:
> > + inode->i_ino = 1;
> > + inode->i_mode = S_IFDIR | 0555;
> > + simple_inode_init_ts(inode);
> > + inode->i_op = &simple_dir_inode_operations;
> > + inode->i_fop = &simple_dir_operations;
> > + set_nlink(inode, 2);
>
> [Severity: Medium]
> Should the root inode keep i_nlink at 1 rather than calling
> set_nlink(inode, 2) in eventfs_ro_fill_super()?
>
> When eventfs_create_events_ro_copy() later configures this root inode as the
> top-level eventfs directory with eventfs_ro_dir_inode_operations and
> eventfs_ro_file_operations, its subsystem subdirectories are created
> dynamically on demand in lookup_dir_entry() without incrementing the parent
> directory link count.
>
> As noted in eventfs_create_events_dir(), eventfs directories keep i_nlink == 1
> so userspace tools do not trust the link count:
>
> /*
> * Keep all eventfs directories with i_nlink == 1.
> * Due to the dynamic nature of the dentry creations and not
> * wanting to add a pointer to the parent eventfs_inode in the
> * eventfs_inode structure, keeping the i_nlink in sync with the
> * number of directories would cause too much complexity for
> * something not worth much. Keeping directory links at 1
> * tells userspace not to trust the link number.
> */
>
> With i_nlink set to 2 on /sys/kernel/events, won't userspace directory
> traversal tools such as find and fts assume the directory has no
> subdirectories (st_nlink == 2) and skip recursing into the event subsystem
> directories?
Good point. Will update.
>
> [ ... ]
>
> > @@ -308,12 +404,17 @@ void eventfs_remount(struct tracefs_inode *ti, bool
> > update_uid, bool update_gid)
> > }
> >
> > static void update_inode_attr(struct inode *inode, umode_t mode,
> > - struct eventfs_attr *attr, struct
> > eventfs_root_inode *rei)
> > + struct eventfs_attr *attr, struct
> > eventfs_root_inode *rei,
> > + bool ro)
> > {
> > + inode->i_mode = mode;
> > +
> > + /* The read-only version does not allow updates to owership or
> > permissions */
> > + if (ro)
> > + return;
> > +
> > if (attr && attr->mode & EVENTFS_SAVE_MODE)
> > inode->i_mode = attr->mode & EVENTFS_MODE_MASK;
> > - else
> > - inode->i_mode = mode;
> >
> > if (attr && attr->mode & EVENTFS_SAVE_UID)
> > inode->i_uid = attr->uid;
>
> [ ... ]
>
> > @@ -407,22 +512,28 @@ static struct dentry *lookup_file(struct
> > eventfs_inode *parent_ei,
> > * @dentry: the directory to look up
> > * @pei: Pointer to the parent eventfs_inode if available
> > * @ei: the eventfs_inode that represents the directory to create
> > + * @ro: boolean to denote if this lookup is for the read-only version
> > *
> > * This function will look up a dentry for a directory represented by
> > * a eventfs_inode.
> > */
> > static struct dentry *lookup_dir_entry(struct dentry *dentry,
> > - struct eventfs_inode *pei, struct eventfs_inode *ei)
> > + struct eventfs_inode *pei, struct eventfs_inode *ei, bool ro)
> > {
> > struct inode *inode;
> > umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
> >
> > - inode = eventfs_get_inode(dentry, &ei->attr, mode, ei);
> > + inode = eventfs_get_inode(dentry, &ei->attr, mode, ei, ro);
> > if (unlikely(!inode))
> > return ERR_PTR(-ENOMEM);
> >
> > - inode->i_op = &eventfs_dir_inode_operations;
> > - inode->i_fop = &eventfs_file_operations;
> > + if (ro) {
> > + inode->i_op = &eventfs_ro_dir_inode_operations;
> > + inode->i_fop = &eventfs_ro_file_operations;
> > + } else {
> > + inode->i_op = &eventfs_dir_inode_operations;
> > + inode->i_fop = &eventfs_file_operations;
> > + }
>
> [ ... ]
>
> > @@ -521,14 +640,16 @@ lookup_file_dentry(struct dentry *dentry,
> > * @dir: in which a lookup is being done
> > * @dentry: file/dir dentry
> > * @flags: Just passed to simple_lookup()
> > + * @ro: Denote if this is from a read-only eventfs
> > *
> > * Used to create dynamic file/dir with-in @dir, search with-in @ei
> > * list, if @dentry found go ahead and create the file/dir
> > */
> >
> > -static struct dentry *eventfs_root_lookup(struct inode *dir,
> > - struct dentry *dentry,
> > - unsigned int flags)
> > +static struct dentry *__eventfs_root_lookup(struct inode *dir,
> > + struct dentry *dentry,
> > + unsigned int flags,
> > + bool ro)
>
> [Severity: Low]
> This isn't a bug, but since eventfs_root_lookup() was renamed to
> __eventfs_root_lookup(), should the function name in the kernel-doc comment
> header above it also be updated to __eventfs_root_lookup to avoid a W=1
> kernel-doc warning?
Hmm, I rather keep it as is. Yeah, W=1 may warn, but it's still the first
function. Maybe I'll update this later as a cleanup.
>
> [ ... ]
>
> > diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
> > index f3d6188a3b7b2..dafa0d587f04c 100644
> > --- a/fs/tracefs/inode.c
> > +++ b/fs/tracefs/inode.c
> > @@ -423,6 +423,14 @@ static const struct super_operations
> > tracefs_super_operations = {
> > .show_options = tracefs_show_options,
> > };
> >
> > +const struct super_operations eventfs_ro_super_operations = {
> > + .alloc_inode = tracefs_alloc_inode,
> > + .free_inode = tracefs_free_inode,
> > + .destroy_inode = tracefs_destroy_inode,
> > + .drop_inode = tracefs_drop_inode,
> > + .statfs = simple_statfs,
> > +};
>
> [Severity: Medium]
> As reported by Sashiko on v4 [1], because eventfs_ro_super_operations uses
> tracefs_alloc_inode, all inodes allocated on the read-only eventfs
> superblock (including the pinned root inode configured by
> eventfs_create_events_ro_copy() and any cached subdirectories or files) are
> linked into the global tracefs_inodes list.
>
> While update_inode_attr() now returns early when ro is true during lookup,
> when tracefs is mounted or remounted with uid= or gid= options,
> tracefs_apply_options() still walks the global tracefs_inodes list without
> checking if the inode belongs to the tracefs superblock:
>
> fs/tracefs/inode.c:tracefs_apply_options() {
> ...
> list_for_each_entry_rcu(ti, &tracefs_inodes, list) {
> if (update_uid) {
> ti->flags &= ~TRACEFS_UID_PERM_SET;
> ti->vfs_inode.i_uid = fsi->uid;
> }
>
> if (update_gid) {
> ti->flags &= ~TRACEFS_GID_PERM_SET;
> ti->vfs_inode.i_gid = fsi->gid;
> }
>
> if (ti->flags & TRACEFS_EVENT_INODE)
> eventfs_remount(ti, update_uid, update_gid);
> }
> ...
> }
>
> Won't mounting or remounting tracefs with uid= or gid= overwrite i_uid and
> i_gid on the pinned /sys/kernel/events root inode and all currently cached
> eventfs_ro inodes, as well as invoke eventfs_remount() a second time on the
> shared eventfs_inode via the eventfs_ro root inode?
OK, I'll add a flag to skip read-only event inodes.
>
> Also, in lookup_dir_entry(), mode is initialized to:
>
> umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
>
> When ro is true, should lookup_dir_entry() clear S_IWUSR (or use 0555 to
> match the root inode in eventfs_ro_fill_super()) so subdirectories in the
> read-only eventfs mount do not report 0755 permissions?
Honestly, all of tracefs directories should be read only except for the
instances directory. I may update that as a separate patch.
-- Steve