diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-15 16:27:32 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-15 16:27:32 -0700 |
| commit | b7f84966b6f17626a8129723894dc315a076b391 (patch) | |
| tree | a22229b4fdd6f344a037f99fffe2f2f02fdb6372 | |
| parent | e4bf304f000e6fcceaf60b1455a5124b783b3a66 (diff) | |
| parent | 43cec30c44764c4b1401fdeb48bfd18c3fc7eff8 (diff) | |
Merge tag 'tracefs-v7.1-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
Pull tracefs updates from Steven Rostedt:
- Simplify error handling with guards()
Use guards() to simplify the handling of releasing locks in exit
paths.
- Use dentry name snapshots instead of allocation
Instead of allocating a temp buffer to store the dentry name to use
in mkdir() and rmdir() use take_dentry_name_snapshot().
- Fix default permissions not being applied at boot
The default permissions for tracefs was 0700 to only allow root
having access. But after a change to fix other mount options the
update to permissions ignored the defined default and used the system
default of 0755. This is a regression and is fixed.
* tag 'tracefs-v7.1-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
tracefs: Removed unused 'ret' variable in eventfs_iterate()
tracefs: Fix default permissions not being applied on initial mount
tracefs: Use dentry name snapshots instead of heap allocation
eventfs: Simplify code using guard()s
| -rw-r--r-- | fs/tracefs/event_inode.c | 98 | ||||
| -rw-r--r-- | fs/tracefs/inode.c | 40 |
2 files changed, 45 insertions, 93 deletions
diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c index 8e5ac464b328..81df94038f2e 100644 --- a/fs/tracefs/event_inode.c +++ b/fs/tracefs/event_inode.c @@ -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,8 +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,22 +586,18 @@ 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 * inode number. */ - ret = 0; /* Start at 'c' to jump over already read entries */ for (i = c; i < ei->nr_entries; i++, ctx->pos++) { @@ -622,21 +606,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 +641,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 +704,10 @@ struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode INIT_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 +853,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); } /** diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index edfdf139cb02..03f768536fd5 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -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; } @@ -491,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; |
