Commit 756d17ee7ee4fbc8238bdf97100af63e6ac441ef
Committed by
Ingo Molnar
1 parent
194ec34184
Exists in
master
and in
7 other branches
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); |