Commit 56897d51 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'trace-v6.8-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull tracing and eventfs fixes from Steven Rostedt:

 - Fix the return code for ring_buffer_poll_wait()

   It was returing a -EINVAL instead of EPOLLERR.

 - Zero out the tracefs_inode so that all fields are initialized.

   The ti->private could have had stale data, but instead of just
   initializing it to NULL, clear out the entire structure when it is
   allocated.

 - Fix a crash in timerlat

   The hrtimer was initialized at read and not open, but is canceled at
   close. If the file was opened and never read the close will pass a
   NULL pointer to hrtime_cancel().

 - Rewrite of eventfs.

   Linus wrote a patch series to remove the dentry references in the
   eventfs_inode and to use ref counting and more of proper VFS
   interfaces to make it work.

 - Add warning to put_ei() if ei is not set to free. That means
   something is about to free it when it shouldn't.

 - Restructure the eventfs_inode to make it more compact, and remove the
   unused llist field.

 - Remove the fsnotify*() funtions for when the inodes were being
   created in the lookup code. It doesn't make sense to notify about
   creation just because something is being looked up.

 - The inode hard link count was not accurate.

   It was being updated when a file was looked up. The inodes of
   directories were updating their parent inode hard link count every
   time the inode was created. That means if memory reclaim cleaned a
   stale directory inode and the inode was lookup up again, it would
   increment the parent inode again as well. Al Viro said to just have
   all eventfs directories have a hard link count of 1. That tells user
   space not to trust it.

* tag 'trace-v6.8-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
  eventfs: Keep all directory links at 1
  eventfs: Remove fsnotify*() functions from lookup()
  eventfs: Restructure eventfs_inode structure to be more condensed
  eventfs: Warn if an eventfs_inode is freed without is_freed being set
  tracing/timerlat: Move hrtimer_init to timerlat_fd open()
  eventfs: Get rid of dentry pointers without refcounts
  eventfs: Clean up dentry ops and add revalidate function
  eventfs: Remove unused d_parent pointer field
  tracefs: dentry lookup crapectomy
  tracefs: Avoid using the ei->dentry pointer unnecessarily
  eventfs: Initialize the tracefs inode properly
  tracefs: Zero out the tracefs_inode when allocating it
  ring-buffer: Clean ring_buffer_poll_wait() error return
parents 6b89b6af ca185770
This diff is collapsed.
......@@ -38,8 +38,6 @@ static struct inode *tracefs_alloc_inode(struct super_block *sb)
if (!ti)
return NULL;
ti->flags = 0;
return &ti->vfs_inode;
}
......@@ -379,21 +377,30 @@ static const struct super_operations tracefs_super_operations = {
.show_options = tracefs_show_options,
};
static void tracefs_dentry_iput(struct dentry *dentry, struct inode *inode)
/*
* It would be cleaner if eventfs had its own dentry ops.
*
* Note that d_revalidate is called potentially under RCU,
* so it can't take the eventfs mutex etc. It's fine - if
* we open a file just as it's marked dead, things will
* still work just fine, and just see the old stale case.
*/
static void tracefs_d_release(struct dentry *dentry)
{
struct tracefs_inode *ti;
if (dentry->d_fsdata)
eventfs_d_release(dentry);
}
if (!dentry || !inode)
return;
static int tracefs_d_revalidate(struct dentry *dentry, unsigned int flags)
{
struct eventfs_inode *ei = dentry->d_fsdata;
ti = get_tracefs(inode);
if (ti && ti->flags & TRACEFS_EVENT_INODE)
eventfs_set_ei_status_free(ti, dentry);
iput(inode);
return !(ei && ei->is_freed);
}
static const struct dentry_operations tracefs_dentry_operations = {
.d_iput = tracefs_dentry_iput,
.d_revalidate = tracefs_d_revalidate,
.d_release = tracefs_d_release,
};
static int trace_fill_super(struct super_block *sb, void *data, int silent)
......@@ -497,75 +504,6 @@ struct dentry *tracefs_end_creating(struct dentry *dentry)
return dentry;
}
/**
* eventfs_start_creating - start the process of creating a dentry
* @name: Name of the file created for the dentry
* @parent: The parent dentry where this dentry will be created
*
* This is a simple helper function for the dynamically created eventfs
* files. When the directory of the eventfs files are accessed, their
* dentries are created on the fly. This function is used to start that
* process.
*/
struct dentry *eventfs_start_creating(const char *name, struct dentry *parent)
{
struct dentry *dentry;
int error;
/* Must always have a parent. */
if (WARN_ON_ONCE(!parent))
return ERR_PTR(-EINVAL);
error = simple_pin_fs(&trace_fs_type, &tracefs_mount,
&tracefs_mount_count);
if (error)
return ERR_PTR(error);
if (unlikely(IS_DEADDIR(parent->d_inode)))
dentry = ERR_PTR(-ENOENT);
else
dentry = lookup_one_len(name, parent, strlen(name));
if (!IS_ERR(dentry) && dentry->d_inode) {
dput(dentry);
dentry = ERR_PTR(-EEXIST);
}
if (IS_ERR(dentry))
simple_release_fs(&tracefs_mount, &tracefs_mount_count);
return dentry;
}
/**
* eventfs_failed_creating - clean up a failed eventfs dentry creation
* @dentry: The dentry to clean up
*
* If after calling eventfs_start_creating(), a failure is detected, the
* resources created by eventfs_start_creating() needs to be cleaned up. In
* that case, this function should be called to perform that clean up.
*/
struct dentry *eventfs_failed_creating(struct dentry *dentry)
{
dput(dentry);
simple_release_fs(&tracefs_mount, &tracefs_mount_count);
return NULL;
}
/**
* eventfs_end_creating - Finish the process of creating a eventfs dentry
* @dentry: The dentry that has successfully been created.
*
* This function is currently just a place holder to match
* eventfs_start_creating(). In case any synchronization needs to be added,
* this function will be used to implement that without having to modify
* the callers of eventfs_start_creating().
*/
struct dentry *eventfs_end_creating(struct dentry *dentry)
{
return dentry;
}
/* Find the inode that this will use for default */
static struct inode *instance_inode(struct dentry *parent, struct inode *inode)
{
......@@ -779,7 +717,11 @@ static void init_once(void *foo)
{
struct tracefs_inode *ti = (struct tracefs_inode *) foo;
/* inode_init_once() calls memset() on the vfs_inode portion */
inode_init_once(&ti->vfs_inode);
/* Zero out the rest */
memset_after(ti, 0, vfs_inode);
}
static int __init tracefs_init(void)
......
......@@ -11,9 +11,10 @@ enum {
};
struct tracefs_inode {
struct inode vfs_inode;
/* The below gets initialized with memset_after(ti, 0, vfs_inode) */
unsigned long flags;
void *private;
struct inode vfs_inode;
};
/*
......@@ -31,43 +32,37 @@ struct eventfs_attr {
/*
* struct eventfs_inode - hold the properties of the eventfs directories.
* @list: link list into the parent directory
* @rcu: Union with @list for freeing
* @children: link list into the child eventfs_inode
* @entries: the array of entries representing the files in the directory
* @name: the name of the directory to create
* @children: link list into the child eventfs_inode
* @dentry: the dentry of the directory
* @d_parent: pointer to the parent's dentry
* @d_children: The array of dentries to represent the files when created
* @events_dir: the dentry of the events directory
* @entry_attrs: Saved mode and ownership of the @d_children
* @attr: Saved mode and ownership of eventfs_inode itself
* @data: The private data to pass to the callbacks
* @attr: Saved mode and ownership of eventfs_inode itself
* @is_freed: Flag set if the eventfs is on its way to be freed
* Note if is_freed is set, then dentry is corrupted.
* @is_events: Flag set for only the top level "events" directory
* @nr_entries: The number of items in @entries
* @ino: The saved inode number
*/
struct eventfs_inode {
struct list_head list;
union {
struct list_head list;
struct rcu_head rcu;
};
struct list_head children;
const struct eventfs_entry *entries;
const char *name;
struct list_head children;
struct dentry *dentry; /* Check is_freed to access */
struct dentry *d_parent;
struct dentry **d_children;
struct dentry *events_dir;
struct eventfs_attr *entry_attrs;
struct eventfs_attr attr;
void *data;
struct eventfs_attr attr;
struct kref kref;
unsigned int is_freed:1;
unsigned int is_events:1;
unsigned int nr_entries:30;
unsigned int ino;
/*
* Union - used for deletion
* @llist: for calling dput() if needed after RCU
* @rcu: eventfs_inode to delete in RCU
*/
union {
struct llist_node llist;
struct rcu_head rcu;
};
};
static inline struct tracefs_inode *get_tracefs(const struct inode *inode)
......@@ -79,9 +74,7 @@ struct dentry *tracefs_start_creating(const char *name, struct dentry *parent);
struct dentry *tracefs_end_creating(struct dentry *dentry);
struct dentry *tracefs_failed_creating(struct dentry *dentry);
struct inode *tracefs_get_inode(struct super_block *sb);
struct dentry *eventfs_start_creating(const char *name, struct dentry *parent);
struct dentry *eventfs_failed_creating(struct dentry *dentry);
struct dentry *eventfs_end_creating(struct dentry *dentry);
void eventfs_set_ei_status_free(struct tracefs_inode *ti, struct dentry *dentry);
void eventfs_d_release(struct dentry *dentry);
#endif /* _TRACEFS_INTERNAL_H */
......@@ -944,7 +944,7 @@ __poll_t ring_buffer_poll_wait(struct trace_buffer *buffer, int cpu,
full = 0;
} else {
if (!cpumask_test_cpu(cpu, buffer->cpumask))
return -EINVAL;
return EPOLLERR;
cpu_buffer = buffer->buffers[cpu];
work = &cpu_buffer->irq_work;
......
......@@ -2444,6 +2444,9 @@ static int timerlat_fd_open(struct inode *inode, struct file *file)
tlat = this_cpu_tmr_var();
tlat->count = 0;
hrtimer_init(&tlat->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED_HARD);
tlat->timer.function = timerlat_irq;
migrate_enable();
return 0;
};
......@@ -2526,9 +2529,6 @@ timerlat_fd_read(struct file *file, char __user *ubuf, size_t count,
tlat->tracing_thread = false;
tlat->kthread = current;
hrtimer_init(&tlat->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED_HARD);
tlat->timer.function = timerlat_irq;
/* Annotate now to drift new period */
tlat->abs_period = hrtimer_cb_get_time(&tlat->timer);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment