Commit 756d17ee7ee4fbc8238bdf97100af63e6ac441ef

Authored by jolsa@redhat.com
Committed by Ingo Molnar
1 parent 194ec34184

tracing: Support multiple pids in set_pid_ftrace file

Adding the possibility to set more than 1 pid in the set_pid_ftrace
file, thus allowing to trace more than 1 independent processes.

Usage:

 sh-4.0# echo 284 > ./set_ftrace_pid
 sh-4.0# cat ./set_ftrace_pid
 284
 sh-4.0# echo 1 >> ./set_ftrace_pid
 sh-4.0# echo 0 >> ./set_ftrace_pid
 sh-4.0# cat ./set_ftrace_pid
 swapper tasks
 1
 284
 sh-4.0# echo 4 > ./set_ftrace_pid
 sh-4.0# cat ./set_ftrace_pid
 4
 sh-4.0# echo > ./set_ftrace_pid
 sh-4.0# cat ./set_ftrace_pid
 no pid
 sh-4.0#

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <20091013203425.565454612@goodmis.org>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

Showing 2 changed files with 167 additions and 71 deletions Side-by-side Diff

kernel/trace/ftrace.c
... ... @@ -60,6 +60,13 @@
60 60 /* Quick disabling of function tracer. */
61 61 int function_trace_stop;
62 62  
  63 +/* List for set_ftrace_pid's pids. */
  64 +LIST_HEAD(ftrace_pids);
  65 +struct ftrace_pid {
  66 + struct list_head list;
  67 + struct pid *pid;
  68 +};
  69 +
63 70 /*
64 71 * ftrace_disabled is set when an anomaly is discovered.
65 72 * ftrace_disabled is much stronger than ftrace_enabled.
... ... @@ -159,7 +166,7 @@
159 166 else
160 167 func = ftrace_list_func;
161 168  
162   - if (ftrace_pid_trace) {
  169 + if (!list_empty(&ftrace_pids)) {
163 170 set_ftrace_pid_function(func);
164 171 func = ftrace_pid_func;
165 172 }
... ... @@ -207,7 +214,7 @@
207 214 if (ftrace_list->next == &ftrace_list_end) {
208 215 ftrace_func_t func = ftrace_list->func;
209 216  
210   - if (ftrace_pid_trace) {
  217 + if (!list_empty(&ftrace_pids)) {
211 218 set_ftrace_pid_function(func);
212 219 func = ftrace_pid_func;
213 220 }
... ... @@ -235,7 +242,7 @@
235 242 func = __ftrace_trace_function;
236 243 #endif
237 244  
238   - if (ftrace_pid_trace) {
  245 + if (!list_empty(&ftrace_pids)) {
239 246 set_ftrace_pid_function(func);
240 247 func = ftrace_pid_func;
241 248 } else {
... ... @@ -825,8 +832,6 @@
825 832 }
826 833 #endif /* CONFIG_FUNCTION_PROFILER */
827 834  
828   -/* set when tracing only a pid */
829   -struct pid *ftrace_pid_trace;
830 835 static struct pid * const ftrace_swapper_pid = &init_struct_pid;
831 836  
832 837 #ifdef CONFIG_DYNAMIC_FTRACE
... ... @@ -2758,23 +2763,6 @@
2758 2763 # define ftrace_shutdown_sysctl() do { } while (0)
2759 2764 #endif /* CONFIG_DYNAMIC_FTRACE */
2760 2765  
2761   -static ssize_t
2762   -ftrace_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   -
2778 2766 static void clear_ftrace_swapper(void)
2779 2767 {
2780 2768 struct task_struct *p;
2781 2769  
2782 2770  
... ... @@ -2825,14 +2813,12 @@
2825 2813 rcu_read_unlock();
2826 2814 }
2827 2815  
2828   -static void clear_ftrace_pid_task(struct pid **pid)
  2816 +static void clear_ftrace_pid_task(struct pid *pid)
2829 2817 {
2830   - if (*pid == ftrace_swapper_pid)
  2818 + if (pid == ftrace_swapper_pid)
2831 2819 clear_ftrace_swapper();
2832 2820 else
2833   - clear_ftrace_pid(*pid);
2834   -
2835   - *pid = NULL;
  2821 + clear_ftrace_pid(pid);
2836 2822 }
2837 2823  
2838 2824 static void set_ftrace_pid_task(struct pid *pid)
2839 2825  
... ... @@ -2843,11 +2829,140 @@
2843 2829 set_ftrace_pid(pid);
2844 2830 }
2845 2831  
  2832 +static 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 +
  2871 +out_put:
  2872 + if (pid != ftrace_swapper_pid)
  2873 + put_pid(pid);
  2874 +
  2875 +out:
  2876 + mutex_unlock(&ftrace_lock);
  2877 + return ret;
  2878 +}
  2879 +
  2880 +static 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 +
  2900 +static 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 +
  2910 +static 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 +
  2918 +static void fpid_stop(struct seq_file *m, void *p)
  2919 +{
  2920 + mutex_unlock(&ftrace_lock);
  2921 +}
  2922 +
  2923 +static 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 +
  2940 +static 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 +
  2947 +static int
  2948 +ftrace_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 +
2846 2962 static ssize_t
2847 2963 ftrace_pid_write(struct file *filp, const char __user *ubuf,
2848 2964 size_t cnt, loff_t *ppos)
2849 2965 {
2850   - struct pid *pid;
2851 2966 char buf[64];
2852 2967 long val;
2853 2968 int ret;
2854 2969  
2855 2970  
2856 2971  
2857 2972  
2858 2973  
... ... @@ -2860,57 +2975,38 @@
2860 2975  
2861 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 2986 ret = strict_strtol(buf, 10, &val);
2864 2987 if (ret < 0)
2865 2988 return ret;
2866 2989  
2867   - mutex_lock(&ftrace_lock);
2868   - if (val < 0) {
2869   - /* disable pid tracing */
2870   - if (!ftrace_pid_trace)
2871   - goto out;
  2990 + ret = ftrace_pid_add(val);
2872 2991  
2873   - clear_ftrace_pid_task(&ftrace_pid_trace);
  2992 + return ret ? ret : cnt;
  2993 +}
2874 2994  
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);
  2995 +static int
  2996 +ftrace_pid_release(struct inode *inode, struct file *file)
  2997 +{
  2998 + if (file->f_mode & FMODE_READ)
  2999 + seq_release(inode, file);
2883 3000  
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   -
2901   - /* update the function call */
2902   - ftrace_update_pid_func();
2903   - ftrace_startup_enable(0);
2904   -
2905   - out:
2906   - mutex_unlock(&ftrace_lock);
2907   -
2908   - return cnt;
  3001 + return 0;
2909 3002 }
2910 3003  
2911 3004 static const struct file_operations ftrace_pid_fops = {
2912   - .read = ftrace_pid_read,
2913   - .write = ftrace_pid_write,
  3005 + .open = ftrace_pid_open,
  3006 + .write = ftrace_pid_write,
  3007 + .read = seq_read,
  3008 + .llseek = seq_lseek,
  3009 + .release = ftrace_pid_release,
2914 3010 };
2915 3011  
2916 3012 static __init int ftrace_init_debugfs(void)
kernel/trace/trace.h
... ... @@ -496,12 +496,12 @@
496 496 }
497 497 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
498 498  
499   -extern struct pid *ftrace_pid_trace;
  499 +extern struct list_head ftrace_pids;
500 500  
501 501 #ifdef CONFIG_FUNCTION_TRACER
502 502 static inline int ftrace_trace_task(struct task_struct *task)
503 503 {
504   - if (!ftrace_pid_trace)
  504 + if (list_empty(&ftrace_pids))
505 505 return 1;
506 506  
507 507 return test_tsk_trace_trace(task);