aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/trace/ftrace.c234
-rw-r--r--kernel/trace/trace.h4
2 files changed, 167 insertions, 71 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 45c965919cff..0c799d1af702 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -60,6 +60,13 @@ static int last_ftrace_enabled;
60/* Quick disabling of function tracer. */ 60/* Quick disabling of function tracer. */
61int function_trace_stop; 61int function_trace_stop;
62 62
63/* List for set_ftrace_pid's pids. */
64LIST_HEAD(ftrace_pids);
65struct ftrace_pid {
66 struct list_head list;
67 struct pid *pid;
68};
69
63/* 70/*
64 * ftrace_disabled is set when an anomaly is discovered. 71 * ftrace_disabled is set when an anomaly is discovered.
65 * ftrace_disabled is much stronger than ftrace_enabled. 72 * ftrace_disabled is much stronger than ftrace_enabled.
@@ -159,7 +166,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops)
159 else 166 else
160 func = ftrace_list_func; 167 func = ftrace_list_func;
161 168
162 if (ftrace_pid_trace) { 169 if (!list_empty(&ftrace_pids)) {
163 set_ftrace_pid_function(func); 170 set_ftrace_pid_function(func);
164 func = ftrace_pid_func; 171 func = ftrace_pid_func;
165 } 172 }
@@ -207,7 +214,7 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
207 if (ftrace_list->next == &ftrace_list_end) { 214 if (ftrace_list->next == &ftrace_list_end) {
208 ftrace_func_t func = ftrace_list->func; 215 ftrace_func_t func = ftrace_list->func;
209 216
210 if (ftrace_pid_trace) { 217 if (!list_empty(&ftrace_pids)) {
211 set_ftrace_pid_function(func); 218 set_ftrace_pid_function(func);
212 func = ftrace_pid_func; 219 func = ftrace_pid_func;
213 } 220 }
@@ -235,7 +242,7 @@ static void ftrace_update_pid_func(void)
235 func = __ftrace_trace_function; 242 func = __ftrace_trace_function;
236#endif 243#endif
237 244
238 if (ftrace_pid_trace) { 245 if (!list_empty(&ftrace_pids)) {
239 set_ftrace_pid_function(func); 246 set_ftrace_pid_function(func);
240 func = ftrace_pid_func; 247 func = ftrace_pid_func;
241 } else { 248 } else {
@@ -825,8 +832,6 @@ static __init void ftrace_profile_debugfs(struct dentry *d_tracer)
825} 832}
826#endif /* CONFIG_FUNCTION_PROFILER */ 833#endif /* CONFIG_FUNCTION_PROFILER */
827 834
828/* set when tracing only a pid */
829struct pid *ftrace_pid_trace;
830static struct pid * const ftrace_swapper_pid = &init_struct_pid; 835static struct pid * const ftrace_swapper_pid = &init_struct_pid;
831 836
832#ifdef CONFIG_DYNAMIC_FTRACE 837#ifdef CONFIG_DYNAMIC_FTRACE
@@ -2758,23 +2763,6 @@ static inline void ftrace_startup_enable(int command) { }
2758# define ftrace_shutdown_sysctl() do { } while (0) 2763# define ftrace_shutdown_sysctl() do { } while (0)
2759#endif /* CONFIG_DYNAMIC_FTRACE */ 2764#endif /* CONFIG_DYNAMIC_FTRACE */
2760 2765
2761static ssize_t
2762ftrace_pid_read(struct file *file, char __user *ubuf,
2763 size_t cnt, loff_t *ppos)
2764{
2765 char buf[64];
2766 int r;
2767
2768 if (ftrace_pid_trace == ftrace_swapper_pid)
2769 r = sprintf(buf, "swapper tasks\n");
2770 else if (ftrace_pid_trace)
2771 r = sprintf(buf, "%u\n", pid_vnr(ftrace_pid_trace));
2772 else
2773 r = sprintf(buf, "no pid\n");
2774
2775 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
2776}
2777
2778static void clear_ftrace_swapper(void) 2766static void clear_ftrace_swapper(void)
2779{ 2767{
2780 struct task_struct *p; 2768 struct task_struct *p;
@@ -2825,14 +2813,12 @@ static void set_ftrace_pid(struct pid *pid)
2825 rcu_read_unlock(); 2813 rcu_read_unlock();
2826} 2814}
2827 2815
2828static void clear_ftrace_pid_task(struct pid **pid) 2816static void clear_ftrace_pid_task(struct pid *pid)
2829{ 2817{
2830 if (*pid == ftrace_swapper_pid) 2818 if (pid == ftrace_swapper_pid)
2831 clear_ftrace_swapper(); 2819 clear_ftrace_swapper();
2832 else 2820 else
2833 clear_ftrace_pid(*pid); 2821 clear_ftrace_pid(pid);
2834
2835 *pid = NULL;
2836} 2822}
2837 2823
2838static void set_ftrace_pid_task(struct pid *pid) 2824static void set_ftrace_pid_task(struct pid *pid)
@@ -2843,11 +2829,140 @@ static void set_ftrace_pid_task(struct pid *pid)
2843 set_ftrace_pid(pid); 2829 set_ftrace_pid(pid);
2844} 2830}
2845 2831
2832static int ftrace_pid_add(int p)
2833{
2834 struct pid *pid;
2835 struct ftrace_pid *fpid;
2836 int ret = -EINVAL;
2837
2838 mutex_lock(&ftrace_lock);
2839
2840 if (!p)
2841 pid = ftrace_swapper_pid;
2842 else
2843 pid = find_get_pid(p);
2844
2845 if (!pid)
2846 goto out;
2847
2848 ret = 0;
2849
2850 list_for_each_entry(fpid, &ftrace_pids, list)
2851 if (fpid->pid == pid)
2852 goto out_put;
2853
2854 ret = -ENOMEM;
2855
2856 fpid = kmalloc(sizeof(*fpid), GFP_KERNEL);
2857 if (!fpid)
2858 goto out_put;
2859
2860 list_add(&fpid->list, &ftrace_pids);
2861 fpid->pid = pid;
2862
2863 set_ftrace_pid_task(pid);
2864
2865 ftrace_update_pid_func();
2866 ftrace_startup_enable(0);
2867
2868 mutex_unlock(&ftrace_lock);
2869 return 0;
2870
2871out_put:
2872 if (pid != ftrace_swapper_pid)
2873 put_pid(pid);
2874
2875out:
2876 mutex_unlock(&ftrace_lock);
2877 return ret;
2878}
2879
2880static void ftrace_pid_reset(void)
2881{
2882 struct ftrace_pid *fpid, *safe;
2883
2884 mutex_lock(&ftrace_lock);
2885 list_for_each_entry_safe(fpid, safe, &ftrace_pids, list) {
2886 struct pid *pid = fpid->pid;
2887
2888 clear_ftrace_pid_task(pid);
2889
2890 list_del(&fpid->list);
2891 kfree(fpid);
2892 }
2893
2894 ftrace_update_pid_func();
2895 ftrace_startup_enable(0);
2896
2897 mutex_unlock(&ftrace_lock);
2898}
2899
2900static void *fpid_start(struct seq_file *m, loff_t *pos)
2901{
2902 mutex_lock(&ftrace_lock);
2903
2904 if (list_empty(&ftrace_pids) && (!*pos))
2905 return (void *) 1;
2906
2907 return seq_list_start(&ftrace_pids, *pos);
2908}
2909
2910static void *fpid_next(struct seq_file *m, void *v, loff_t *pos)
2911{
2912 if (v == (void *)1)
2913 return NULL;
2914
2915 return seq_list_next(v, &ftrace_pids, pos);
2916}
2917
2918static void fpid_stop(struct seq_file *m, void *p)
2919{
2920 mutex_unlock(&ftrace_lock);
2921}
2922
2923static int fpid_show(struct seq_file *m, void *v)
2924{
2925 const struct ftrace_pid *fpid = list_entry(v, struct ftrace_pid, list);
2926
2927 if (v == (void *)1) {
2928 seq_printf(m, "no pid\n");
2929 return 0;
2930 }
2931
2932 if (fpid->pid == ftrace_swapper_pid)
2933 seq_printf(m, "swapper tasks\n");
2934 else
2935 seq_printf(m, "%u\n", pid_vnr(fpid->pid));
2936
2937 return 0;
2938}
2939
2940static const struct seq_operations ftrace_pid_sops = {
2941 .start = fpid_start,
2942 .next = fpid_next,
2943 .stop = fpid_stop,
2944 .show = fpid_show,
2945};
2946
2947static int
2948ftrace_pid_open(struct inode *inode, struct file *file)
2949{
2950 int ret = 0;
2951
2952 if ((file->f_mode & FMODE_WRITE) &&
2953 (file->f_flags & O_TRUNC))
2954 ftrace_pid_reset();
2955
2956 if (file->f_mode & FMODE_READ)
2957 ret = seq_open(file, &ftrace_pid_sops);
2958
2959 return ret;
2960}
2961
2846static ssize_t 2962static ssize_t
2847ftrace_pid_write(struct file *filp, const char __user *ubuf, 2963ftrace_pid_write(struct file *filp, const char __user *ubuf,
2848 size_t cnt, loff_t *ppos) 2964 size_t cnt, loff_t *ppos)
2849{ 2965{
2850 struct pid *pid;
2851 char buf[64]; 2966 char buf[64];
2852 long val; 2967 long val;
2853 int ret; 2968 int ret;
@@ -2860,57 +2975,38 @@ ftrace_pid_write(struct file *filp, const char __user *ubuf,
2860 2975
2861 buf[cnt] = 0; 2976 buf[cnt] = 0;
2862 2977
2978 /*
2979 * Allow "echo > set_ftrace_pid" or "echo -n '' > set_ftrace_pid"
2980 * to clean the filter quietly.
2981 */
2982 strstrip(buf);
2983 if (strlen(buf) == 0)
2984 return 1;
2985
2863 ret = strict_strtol(buf, 10, &val); 2986 ret = strict_strtol(buf, 10, &val);
2864 if (ret < 0) 2987 if (ret < 0)
2865 return ret; 2988 return ret;
2866 2989
2867 mutex_lock(&ftrace_lock); 2990 ret = ftrace_pid_add(val);
2868 if (val < 0) {
2869 /* disable pid tracing */
2870 if (!ftrace_pid_trace)
2871 goto out;
2872
2873 clear_ftrace_pid_task(&ftrace_pid_trace);
2874
2875 } else {
2876 /* swapper task is special */
2877 if (!val) {
2878 pid = ftrace_swapper_pid;
2879 if (pid == ftrace_pid_trace)
2880 goto out;
2881 } else {
2882 pid = find_get_pid(val);
2883
2884 if (pid == ftrace_pid_trace) {
2885 put_pid(pid);
2886 goto out;
2887 }
2888 }
2889
2890 if (ftrace_pid_trace)
2891 clear_ftrace_pid_task(&ftrace_pid_trace);
2892
2893 if (!pid)
2894 goto out;
2895
2896 ftrace_pid_trace = pid;
2897
2898 set_ftrace_pid_task(ftrace_pid_trace);
2899 }
2900 2991
2901 /* update the function call */ 2992 return ret ? ret : cnt;
2902 ftrace_update_pid_func(); 2993}
2903 ftrace_startup_enable(0);
2904 2994
2905 out: 2995static int
2906 mutex_unlock(&ftrace_lock); 2996ftrace_pid_release(struct inode *inode, struct file *file)
2997{
2998 if (file->f_mode & FMODE_READ)
2999 seq_release(inode, file);
2907 3000
2908 return cnt; 3001 return 0;
2909} 3002}
2910 3003
2911static const struct file_operations ftrace_pid_fops = { 3004static const struct file_operations ftrace_pid_fops = {
2912 .read = ftrace_pid_read, 3005 .open = ftrace_pid_open,
2913 .write = ftrace_pid_write, 3006 .write = ftrace_pid_write,
3007 .read = seq_read,
3008 .llseek = seq_lseek,
3009 .release = ftrace_pid_release,
2914}; 3010};
2915 3011
2916static __init int ftrace_init_debugfs(void) 3012static __init int ftrace_init_debugfs(void)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index f22a7ac32380..acef8b4636f0 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -496,12 +496,12 @@ print_graph_function(struct trace_iterator *iter)
496} 496}
497#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 497#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
498 498
499extern struct pid *ftrace_pid_trace; 499extern struct list_head ftrace_pids;
500 500
501#ifdef CONFIG_FUNCTION_TRACER 501#ifdef CONFIG_FUNCTION_TRACER
502static inline int ftrace_trace_task(struct task_struct *task) 502static inline int ftrace_trace_task(struct task_struct *task)
503{ 503{
504 if (!ftrace_pid_trace) 504 if (list_empty(&ftrace_pids))
505 return 1; 505 return 1;
506 506
507 return test_tsk_trace_trace(task); 507 return test_tsk_trace_trace(task);