tracefs: Updates for v7.1
Subsystems (2)
cover tracefs: Updates for v7.1
git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git
tracefs/for-next
Head SHA1: e8368d1f4bedbb0cce4cfe33a1d2664bb0fd4f27
AnishMulay (1):
tracefs: Use dentry name snapshots instead of heap allocation
David Carlier (1):
tracefs: Fix default permissions not being applied on initial mount
Steven Rostedt (1):
eventfs: Simplify code using guard()s
----
fs/tracefs/event_inode.c | 96 ++++++++++++++++++------------------------------ fs/tracefs/inode.c | 40 +++++--------------- 2 files changed, 45 insertions(+), 91 deletions(-)
PATCH 1/3 eventfs: Simplify code using guard()s
From: Steven Rostedt <[email protected]>
Use guard(mutex), scoped_guard(mutex) and guard(src) to simplify the code and remove a lot of the jumps to "out:" labels.
--- fs/tracefs/event_inode.c | 96 +++++++++++++++------------------------- 1 file changed, 36 insertions(+), 60 deletions(-)
fs/tracefs/event_inode.c +36 -60
@@ -180,29 +180,25 @@ static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry,const char *name;int ret; -mutex_lock (&eventfs_mutex); +guard (mutex)(&eventfs_mutex); ei = dentry->d_fsdata; -if (ei->is_freed) { -/* Do not allow changes if the event is about to be removed. */ -mutex_unlock (&eventfs_mutex); +/* Do not allow changes if the event is about to be removed. */ +if (ei->is_freed)return -ENODEV ; - }/* Preallocate the children mode array if necessary */ if (!(dentry->d_inode->i_mode &S_IFDIR )) {if (!ei->entry_attrs) { ei->entry_attrs =kzalloc_objs (*ei->entry_attrs, ei->nr_entries,GFP_NOFS ); -if (!ei->entry_attrs) { - ret = -ENOMEM ; - goto out; - } +if (!ei->entry_attrs) +return -ENOMEM ; } } ret =simple_setattr (idmap, dentry, iattr);if (ret <0 ) - goto out; +return ret;/* * If this is a dir, then update the ei cache, only the file
@@ -225,8 +221,6 @@ static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry, } } } - out: -mutex_unlock (&eventfs_mutex);return ret; }
@@ -528,26 +522,24 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,struct tracefs_inode *ti;struct eventfs_inode *ei;const char *name = dentry->d_name.name; -struct dentry *result =NULL ; ti =get_tracefs (dir);if (WARN_ON_ONCE (!(ti->flags &TRACEFS_EVENT_INODE )))return ERR_PTR (-EIO ); -mutex_lock (&eventfs_mutex); +guard (mutex)(&eventfs_mutex); ei = ti->private;if (!ei || ei->is_freed) - goto out; +return NULL ;list_for_each_entry (ei_child, &ei->children, list) {if (strcmp (ei_child->name, name) !=0 )continue ;/* A child is freed and removed from the list at the same time */ if (WARN_ON_ONCE (ei_child->is_freed)) - goto out; - result =lookup_dir_entry (dentry, ei, ei_child); - goto out; +return NULL ; +return lookup_dir_entry (dentry, ei, ei_child); }for (int i =0 ; i < ei->nr_entries; i++) {
@@ -561,14 +553,12 @@ static struct dentry *eventfs_root_lookup(struct inode *dir, data = ei->data;if (entry->callback (name, &mode, &data, &fops) <=0 ) - goto out; +return NULL ; + +return lookup_file_dentry (dentry, ei, i, mode, data, fops); - result =lookup_file_dentry (dentry, ei, i, mode, data, fops); - goto out; } - out: -mutex_unlock (&eventfs_mutex); -return result; +return NULL ; }/*
@@ -584,7 +574,6 @@ static int eventfs_iterate(struct file *file, struct dir_context *ctx)struct eventfs_inode *ei;const char *name;umode_t mode; -int idx;int ret = -EINVAL ;int ino;int i, r, c;
@@ -598,16 +587,13 @@ static int eventfs_iterate(struct file *file, struct dir_context *ctx) c = ctx->pos -2 ; - idx =srcu_read_lock (&eventfs_srcu); +guard (srcu)(&eventfs_srcu); -mutex_lock (&eventfs_mutex); - ei =READ_ONCE (ti->private); -if (ei && ei->is_freed) - ei =NULL ; -mutex_unlock (&eventfs_mutex); - -if (!ei) - goto out; + scoped_guard(mutex, &eventfs_mutex) { + ei =READ_ONCE (ti->private); +if (!ei || ei->is_freed) +return -EINVAL ; + }/* * Need to create the dentries and inodes to have a consistent
@@ -622,21 +608,19 @@ static int eventfs_iterate(struct file *file, struct dir_context *ctx) entry = &ei->entries[i]; name = entry->name; -mutex_lock (&eventfs_mutex);/* If ei->is_freed then just bail here, nothing more to do */ -if (ei->is_freed) { -mutex_unlock (&eventfs_mutex); - goto out; + scoped_guard(mutex, &eventfs_mutex) { +if (ei->is_freed) +return -EINVAL ; + r = entry->callback (name, &mode, &cdata, &fops); } - r = entry->callback (name, &mode, &cdata, &fops); -mutex_unlock (&eventfs_mutex);if (r <=0 )continue ; ino =EVENTFS_FILE_INODE_INO ;if (!dir_emit (ctx, name,strlen (name), ino,DT_REG )) - goto out; +return -EINVAL ; }/* Subtract the skipped entries above */
@@ -659,19 +643,13 @@ static int eventfs_iterate(struct file *file, struct dir_context *ctx) ino =eventfs_dir_ino (ei_child); -if (!dir_emit (ctx, name,strlen (name), ino,DT_DIR )) - goto out_dec; +if (!dir_emit (ctx, name,strlen (name), ino,DT_DIR )) { +/* Incremented ctx->pos without adding something, reset it */ + ctx->pos--; +return -EINVAL ; + } } - ret =1 ; - out: -srcu_read_unlock (&eventfs_srcu, idx); - -return ret; - - out_dec: -/* Incremented ctx->pos without adding something, reset it */ - ctx->pos--; - goto out; +return 1 ; }/**
@@ -728,11 +706,10 @@ struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inodeINIT_LIST_HEAD (&ei->children);INIT_LIST_HEAD (&ei->list); -mutex_lock (&eventfs_mutex); -if (!parent->is_freed) -list_add_tail (&ei->list, &parent->children); -mutex_unlock (&eventfs_mutex); - + scoped_guard(mutex, &eventfs_mutex) { +if (!parent->is_freed) +list_add_tail (&ei->list, &parent->children); + }/* Was the parent freed? */ if (list_empty (&ei->list)) {cleanup_ei (ei);
@@ -878,9 +855,8 @@ void eventfs_remove_dir(struct eventfs_inode *ei)if (!ei)return ; -mutex_lock (&eventfs_mutex); +guard (mutex)(&eventfs_mutex);eventfs_remove_rec (ei,0 ); -mutex_unlock (&eventfs_mutex); }/**
Signature · 1 line
2.51.0
PATCH 2/3 tracefs: Use dentry name snapshots instead of heap allocation
In reply to Steven RostedtFrom: AnishMulay <[email protected]>
In fs/tracefs/inode.c, tracefs_syscall_mkdir() and tracefs_syscall_rmdir() previously used a local helper, get_dname(), which allocated a temporary buffer on the heap via kmalloc() to hold the dentry name. This introduced unnecessary overhead, an ENOMEM failure path, and required manual memory cleanup via kfree().
As suggested by Al Viro, replace this heap allocation with the VFS dentry name snapshot API. By stack-allocating a struct name_snapshot and using take_dentry_name_snapshot() and release_dentry_name_snapshot(), we safely capture the dentry name locklessly, eliminate the heap allocation entirely, and remove the now-obsolete error handling paths. The get_dname() helper is completely removed.
Testing:
Booted a custom kernel natively in virtme-ng (ARM64). Triggered tracefs inode and dentry allocation by creating and removing a custom directory under a temporary tracefs mount. Verified that the instance is created successfully and that no memory errors or warnings are emitted in dmesg.
--- fs/tracefs/inode.c | 39 ++++++++------------------------------- 1 file changed, 8 insertions(+), 31 deletions(-)
fs/tracefs/inode.c +8 -31
@@ -94,33 +94,14 @@ static struct tracefs_dir_ops {int (*rmdir)(const char *name); } tracefs_ops__ro_after_init ; -static char *get_dname (struct dentry *dentry) -{ -const char *dname; -char *name; -int len = dentry->d_name.len; - - dname = dentry->d_name.name; - name =kmalloc (len +1 ,GFP_KERNEL ); -if (!name) -return NULL ; -memcpy (name, dname, len); - name[len] =0 ; -return name; -} -static struct dentry *tracefs_syscall_mkdir (struct mnt_idmap *idmap,struct inode *inode,struct dentry *dentry,umode_t mode) {struct tracefs_inode *ti; -char *name; +struct name_snapshot name;int ret; - name =get_dname (dentry); -if (!name) -return ERR_PTR (-ENOMEM ); -/* * This is a new directory that does not take the default of * the rootfs. It becomes the default permissions for all the
@@ -135,24 +116,20 @@ static struct dentry *tracefs_syscall_mkdir(struct mnt_idmap *idmap,* the files within the tracefs system. It is up to the individual * mkdir routine to handle races. */ +take_dentry_name_snapshot (&name, dentry);inode_unlock (inode); - ret = tracefs_ops.mkdir (name); + ret = tracefs_ops.mkdir (name.name.name);inode_lock (inode); - -kfree (name); +release_dentry_name_snapshot (&name);return ERR_PTR (ret); }static int tracefs_syscall_rmdir (struct inode *inode,struct dentry *dentry) { -char *name; +struct name_snapshot name;int ret; - name =get_dname (dentry); -if (!name) -return -ENOMEM ; -/* * The rmdir call can call the generic functions that create * the files within the tracefs system. It is up to the individual
@@ -160,15 +137,15 @@ static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry)* This time we need to unlock not only the parent (inode) but * also the directory that is being deleted. */ +take_dentry_name_snapshot (&name, dentry);inode_unlock (inode);inode_unlock (d_inode (dentry)); - ret = tracefs_ops.rmdir (name); + ret = tracefs_ops.rmdir (name.name.name);inode_lock_nested (inode,I_MUTEX_PARENT );inode_lock (d_inode (dentry)); - -kfree (name); +release_dentry_name_snapshot (&name);return ret; }
Signature · 1 line
2.51.0
PATCH 3/3 tracefs: Fix default permissions not being applied on initial mount
In reply to Steven RostedtFrom: David Carlier <[email protected]>
Commit e4d32142d1de ("tracing: Fix tracefs mount options") moved the option application from tracefs_fill_super() to tracefs_reconfigure() called from tracefs_get_tree(). This fixed mount options being ignored on user-space mounts when the superblock already exists, but introduced a regression for the initial kernel-internal mount.
On the first mount (via simple_pin_fs during init), sget_fc() transfers fc->s_fs_info to sb->s_fs_info and sets fc->s_fs_info to NULL. When tracefs_get_tree() then calls tracefs_reconfigure(), it sees a NULL fc->s_fs_info and returns early without applying any options. The root inode keeps mode 0755 from simple_fill_super() instead of the intended TRACEFS_DEFAULT_MODE (0700).
Furthermore, even on subsequent user-space mounts without an explicit mode= option, tracefs_apply_options(sb, true) gates the mode behind fsi->opts & BIT(Opt_mode), which is unset for the defaults. So the mode is never corrected unless the user explicitly passes mode=0700.
Restore the tracefs_apply_options(sb, false) call in tracefs_fill_super() to apply default permissions on initial superblock creation, matching what debugfs does in debugfs_fill_super().
--- fs/tracefs/inode.c | 1 + 1 file changed, 1 insertion(+)
fs/tracefs/inode.c +1 -0
@@ -468,6 +468,7 @@ static int tracefs_fill_super(struct super_block *sb, struct fs_context *fc)return err; sb->s_op = &tracefs_super_operations; +tracefs_apply_options (sb, false);set_default_d_op (sb, &tracefs_dentry_operations);return 0 ;
Signature · 1 line
2.51.0