diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/rseq.c | 73 |
1 files changed, 69 insertions, 4 deletions
diff --git a/kernel/rseq.c b/kernel/rseq.c index c0dbe2ed26a8..679ab8ebdfd3 100644 --- a/kernel/rseq.c +++ b/kernel/rseq.c @@ -95,6 +95,27 @@ RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL | \ RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE) +DEFINE_STATIC_KEY_MAYBE(CONFIG_RSEQ_DEBUG_DEFAULT_ENABLE, rseq_debug_enabled); + +static inline void rseq_control_debug(bool on) +{ + if (on) + static_branch_enable(&rseq_debug_enabled); + else + static_branch_disable(&rseq_debug_enabled); +} + +static int __init rseq_setup_debug(char *str) +{ + bool on; + + if (kstrtobool(str, &on)) + return -EINVAL; + rseq_control_debug(on); + return 1; +} +__setup("rseq_debug=", rseq_setup_debug); + #ifdef CONFIG_TRACEPOINTS /* * Out of line, so the actual update functions can be in a header to be @@ -112,10 +133,11 @@ void __rseq_trace_ip_fixup(unsigned long ip, unsigned long start_ip, } #endif /* CONFIG_TRACEPOINTS */ +#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_RSEQ_STATS DEFINE_PER_CPU(struct rseq_stats, rseq_stats); -static int rseq_debug_show(struct seq_file *m, void *p) +static int rseq_stats_show(struct seq_file *m, void *p) { struct rseq_stats stats = { }; unsigned int cpu; @@ -140,14 +162,56 @@ static int rseq_debug_show(struct seq_file *m, void *p) return 0; } +static int rseq_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, rseq_stats_show, inode->i_private); +} + +static const struct file_operations stat_ops = { + .open = rseq_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init rseq_stats_init(struct dentry *root_dir) +{ + debugfs_create_file("stats", 0444, root_dir, NULL, &stat_ops); + return 0; +} +#else +static inline void rseq_stats_init(struct dentry *root_dir) { } +#endif /* CONFIG_RSEQ_STATS */ + +static int rseq_debug_show(struct seq_file *m, void *p) +{ + bool on = static_branch_unlikely(&rseq_debug_enabled); + + seq_printf(m, "%d\n", on); + return 0; +} + +static ssize_t rseq_debug_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + bool on; + + if (kstrtobool_from_user(ubuf, count, &on)) + return -EINVAL; + + rseq_control_debug(on); + return count; +} + static int rseq_debug_open(struct inode *inode, struct file *file) { return single_open(file, rseq_debug_show, inode->i_private); } -static const struct file_operations dfs_ops = { +static const struct file_operations debug_ops = { .open = rseq_debug_open, .read = seq_read, + .write = rseq_debug_write, .llseek = seq_lseek, .release = single_release, }; @@ -156,11 +220,12 @@ static int __init rseq_debugfs_init(void) { struct dentry *root_dir = debugfs_create_dir("rseq", NULL); - debugfs_create_file("stats", 0444, root_dir, NULL, &dfs_ops); + debugfs_create_file("debug", 0644, root_dir, NULL, &debug_ops); + rseq_stats_init(root_dir); return 0; } __initcall(rseq_debugfs_init); -#endif /* CONFIG_RSEQ_STATS */ +#endif /* CONFIG_DEBUG_FS */ #ifdef CONFIG_DEBUG_RSEQ static struct rseq *rseq_kernel_fields(struct task_struct *t) |
