diff options
-rw-r--r-- | include/linux/ftrace.h | 4 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 527 |
2 files changed, 513 insertions, 18 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index b0dd0093058f..f5911d2d42c3 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -43,7 +43,9 @@ extern void mcount(void); | |||
43 | # define FTRACE_HASHSIZE (1<<FTRACE_HASHBITS) | 43 | # define FTRACE_HASHSIZE (1<<FTRACE_HASHBITS) |
44 | 44 | ||
45 | enum { | 45 | enum { |
46 | FTRACE_FL_FAILED = (1<<0), | 46 | FTRACE_FL_FAILED = (1 << 0), |
47 | FTRACE_FL_FILTER = (1 << 1), | ||
48 | FTRACE_FL_ENABLED = (1 << 2), | ||
47 | }; | 49 | }; |
48 | 50 | ||
49 | struct dyn_ftrace { | 51 | struct dyn_ftrace { |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 88544f9bc0ed..97d5cb7b7e75 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -16,12 +16,15 @@ | |||
16 | #include <linux/stop_machine.h> | 16 | #include <linux/stop_machine.h> |
17 | #include <linux/clocksource.h> | 17 | #include <linux/clocksource.h> |
18 | #include <linux/kallsyms.h> | 18 | #include <linux/kallsyms.h> |
19 | #include <linux/seq_file.h> | ||
20 | #include <linux/debugfs.h> | ||
19 | #include <linux/kthread.h> | 21 | #include <linux/kthread.h> |
20 | #include <linux/hardirq.h> | 22 | #include <linux/hardirq.h> |
21 | #include <linux/ftrace.h> | 23 | #include <linux/ftrace.h> |
22 | #include <linux/module.h> | 24 | #include <linux/uaccess.h> |
23 | #include <linux/sysctl.h> | 25 | #include <linux/sysctl.h> |
24 | #include <linux/hash.h> | 26 | #include <linux/hash.h> |
27 | #include <linux/ctype.h> | ||
25 | #include <linux/list.h> | 28 | #include <linux/list.h> |
26 | 29 | ||
27 | #include "trace.h" | 30 | #include "trace.h" |
@@ -151,12 +154,15 @@ enum { | |||
151 | FTRACE_DISABLE_MCOUNT = (1 << 4), | 154 | FTRACE_DISABLE_MCOUNT = (1 << 4), |
152 | }; | 155 | }; |
153 | 156 | ||
157 | static int ftrace_filtered; | ||
158 | |||
154 | static struct hlist_head ftrace_hash[FTRACE_HASHSIZE]; | 159 | static struct hlist_head ftrace_hash[FTRACE_HASHSIZE]; |
155 | 160 | ||
156 | static DEFINE_PER_CPU(int, ftrace_shutdown_disable_cpu); | 161 | static DEFINE_PER_CPU(int, ftrace_shutdown_disable_cpu); |
157 | 162 | ||
158 | static DEFINE_SPINLOCK(ftrace_shutdown_lock); | 163 | static DEFINE_SPINLOCK(ftrace_shutdown_lock); |
159 | static DEFINE_MUTEX(ftraced_lock); | 164 | static DEFINE_MUTEX(ftraced_lock); |
165 | static DEFINE_MUTEX(ftrace_filter_lock); | ||
160 | 166 | ||
161 | struct ftrace_page { | 167 | struct ftrace_page { |
162 | struct ftrace_page *next; | 168 | struct ftrace_page *next; |
@@ -282,16 +288,82 @@ ftrace_record_ip(unsigned long ip) | |||
282 | #define FTRACE_ADDR ((long)(&ftrace_caller)) | 288 | #define FTRACE_ADDR ((long)(&ftrace_caller)) |
283 | #define MCOUNT_ADDR ((long)(&mcount)) | 289 | #define MCOUNT_ADDR ((long)(&mcount)) |
284 | 290 | ||
285 | static void notrace ftrace_replace_code(int saved) | 291 | static void notrace |
292 | __ftrace_replace_code(struct dyn_ftrace *rec, | ||
293 | unsigned char *old, unsigned char *new, int enable) | ||
294 | { | ||
295 | unsigned long ip; | ||
296 | int failed; | ||
297 | |||
298 | ip = rec->ip; | ||
299 | |||
300 | if (ftrace_filtered && enable) { | ||
301 | unsigned long fl; | ||
302 | /* | ||
303 | * If filtering is on: | ||
304 | * | ||
305 | * If this record is set to be filtered and | ||
306 | * is enabled then do nothing. | ||
307 | * | ||
308 | * If this record is set to be filtered and | ||
309 | * it is not enabled, enable it. | ||
310 | * | ||
311 | * If this record is not set to be filtered | ||
312 | * and it is not enabled do nothing. | ||
313 | * | ||
314 | * If this record is not set to be filtered and | ||
315 | * it is enabled, disable it. | ||
316 | */ | ||
317 | fl = rec->flags & (FTRACE_FL_FILTER | FTRACE_FL_ENABLED); | ||
318 | |||
319 | if ((fl == (FTRACE_FL_FILTER | FTRACE_FL_ENABLED)) || | ||
320 | (fl == 0)) | ||
321 | return; | ||
322 | |||
323 | /* | ||
324 | * If it is enabled disable it, | ||
325 | * otherwise enable it! | ||
326 | */ | ||
327 | if (fl == FTRACE_FL_ENABLED) { | ||
328 | /* swap new and old */ | ||
329 | new = old; | ||
330 | old = ftrace_call_replace(ip, FTRACE_ADDR); | ||
331 | rec->flags &= ~FTRACE_FL_ENABLED; | ||
332 | } else { | ||
333 | new = ftrace_call_replace(ip, FTRACE_ADDR); | ||
334 | rec->flags |= FTRACE_FL_ENABLED; | ||
335 | } | ||
336 | } else { | ||
337 | |||
338 | if (enable) | ||
339 | new = ftrace_call_replace(ip, FTRACE_ADDR); | ||
340 | else | ||
341 | old = ftrace_call_replace(ip, FTRACE_ADDR); | ||
342 | |||
343 | if (enable) { | ||
344 | if (rec->flags & FTRACE_FL_ENABLED) | ||
345 | return; | ||
346 | rec->flags |= FTRACE_FL_ENABLED; | ||
347 | } else { | ||
348 | if (!(rec->flags & FTRACE_FL_ENABLED)) | ||
349 | return; | ||
350 | rec->flags &= ~FTRACE_FL_ENABLED; | ||
351 | } | ||
352 | } | ||
353 | |||
354 | failed = ftrace_modify_code(ip, old, new); | ||
355 | if (failed) | ||
356 | rec->flags |= FTRACE_FL_FAILED; | ||
357 | } | ||
358 | |||
359 | static void notrace ftrace_replace_code(int enable) | ||
286 | { | 360 | { |
287 | unsigned char *new = NULL, *old = NULL; | 361 | unsigned char *new = NULL, *old = NULL; |
288 | struct dyn_ftrace *rec; | 362 | struct dyn_ftrace *rec; |
289 | struct ftrace_page *pg; | 363 | struct ftrace_page *pg; |
290 | unsigned long ip; | ||
291 | int failed; | ||
292 | int i; | 364 | int i; |
293 | 365 | ||
294 | if (saved) | 366 | if (enable) |
295 | old = ftrace_nop_replace(); | 367 | old = ftrace_nop_replace(); |
296 | else | 368 | else |
297 | new = ftrace_nop_replace(); | 369 | new = ftrace_nop_replace(); |
@@ -304,16 +376,7 @@ static void notrace ftrace_replace_code(int saved) | |||
304 | if (rec->flags & FTRACE_FL_FAILED) | 376 | if (rec->flags & FTRACE_FL_FAILED) |
305 | continue; | 377 | continue; |
306 | 378 | ||
307 | ip = rec->ip; | 379 | __ftrace_replace_code(rec, old, new, enable); |
308 | |||
309 | if (saved) | ||
310 | new = ftrace_call_replace(ip, FTRACE_ADDR); | ||
311 | else | ||
312 | old = ftrace_call_replace(ip, FTRACE_ADDR); | ||
313 | |||
314 | failed = ftrace_modify_code(ip, old, new); | ||
315 | if (failed) | ||
316 | rec->flags |= FTRACE_FL_FAILED; | ||
317 | } | 380 | } |
318 | } | 381 | } |
319 | } | 382 | } |
@@ -580,6 +643,436 @@ static int __init ftrace_dyn_table_alloc(void) | |||
580 | return 0; | 643 | return 0; |
581 | } | 644 | } |
582 | 645 | ||
646 | enum { | ||
647 | FTRACE_ITER_FILTER = (1 << 0), | ||
648 | FTRACE_ITER_CONT = (1 << 1), | ||
649 | }; | ||
650 | |||
651 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ | ||
652 | |||
653 | struct ftrace_iterator { | ||
654 | loff_t pos; | ||
655 | struct ftrace_page *pg; | ||
656 | unsigned idx; | ||
657 | unsigned flags; | ||
658 | unsigned char buffer[FTRACE_BUFF_MAX+1]; | ||
659 | unsigned buffer_idx; | ||
660 | unsigned filtered; | ||
661 | }; | ||
662 | |||
663 | static void notrace * | ||
664 | t_next(struct seq_file *m, void *v, loff_t *pos) | ||
665 | { | ||
666 | struct ftrace_iterator *iter = m->private; | ||
667 | struct dyn_ftrace *rec = NULL; | ||
668 | |||
669 | (*pos)++; | ||
670 | |||
671 | retry: | ||
672 | if (iter->idx >= iter->pg->index) { | ||
673 | if (iter->pg->next) { | ||
674 | iter->pg = iter->pg->next; | ||
675 | iter->idx = 0; | ||
676 | goto retry; | ||
677 | } | ||
678 | } else { | ||
679 | rec = &iter->pg->records[iter->idx++]; | ||
680 | if ((rec->flags & FTRACE_FL_FAILED) || | ||
681 | ((iter->flags & FTRACE_ITER_FILTER) && | ||
682 | !(rec->flags & FTRACE_FL_FILTER))) { | ||
683 | rec = NULL; | ||
684 | goto retry; | ||
685 | } | ||
686 | } | ||
687 | |||
688 | iter->pos = *pos; | ||
689 | |||
690 | return rec; | ||
691 | } | ||
692 | |||
693 | static void *t_start(struct seq_file *m, loff_t *pos) | ||
694 | { | ||
695 | struct ftrace_iterator *iter = m->private; | ||
696 | void *p = NULL; | ||
697 | loff_t l = -1; | ||
698 | |||
699 | if (*pos != iter->pos) { | ||
700 | for (p = t_next(m, p, &l); p && l < *pos; p = t_next(m, p, &l)) | ||
701 | ; | ||
702 | } else { | ||
703 | l = *pos; | ||
704 | p = t_next(m, p, &l); | ||
705 | } | ||
706 | |||
707 | return p; | ||
708 | } | ||
709 | |||
710 | static void t_stop(struct seq_file *m, void *p) | ||
711 | { | ||
712 | } | ||
713 | |||
714 | static int t_show(struct seq_file *m, void *v) | ||
715 | { | ||
716 | struct dyn_ftrace *rec = v; | ||
717 | char str[KSYM_SYMBOL_LEN]; | ||
718 | |||
719 | if (!rec) | ||
720 | return 0; | ||
721 | |||
722 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); | ||
723 | |||
724 | seq_printf(m, "%s\n", str); | ||
725 | |||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | static struct seq_operations show_ftrace_seq_ops = { | ||
730 | .start = t_start, | ||
731 | .next = t_next, | ||
732 | .stop = t_stop, | ||
733 | .show = t_show, | ||
734 | }; | ||
735 | |||
736 | static int notrace | ||
737 | ftrace_avail_open(struct inode *inode, struct file *file) | ||
738 | { | ||
739 | struct ftrace_iterator *iter; | ||
740 | int ret; | ||
741 | |||
742 | iter = kzalloc(sizeof(*iter), GFP_KERNEL); | ||
743 | if (!iter) | ||
744 | return -ENOMEM; | ||
745 | |||
746 | iter->pg = ftrace_pages_start; | ||
747 | iter->pos = -1; | ||
748 | |||
749 | ret = seq_open(file, &show_ftrace_seq_ops); | ||
750 | if (!ret) { | ||
751 | struct seq_file *m = file->private_data; | ||
752 | m->private = iter; | ||
753 | } else | ||
754 | kfree(iter); | ||
755 | |||
756 | return ret; | ||
757 | } | ||
758 | |||
759 | int ftrace_avail_release(struct inode *inode, struct file *file) | ||
760 | { | ||
761 | struct seq_file *m = (struct seq_file *)file->private_data; | ||
762 | struct ftrace_iterator *iter = m->private; | ||
763 | |||
764 | seq_release(inode, file); | ||
765 | kfree(iter); | ||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | static void notrace ftrace_filter_reset(void) | ||
770 | { | ||
771 | struct ftrace_page *pg; | ||
772 | struct dyn_ftrace *rec; | ||
773 | unsigned i; | ||
774 | |||
775 | /* keep kstop machine from running */ | ||
776 | preempt_disable(); | ||
777 | ftrace_filtered = 0; | ||
778 | pg = ftrace_pages_start; | ||
779 | while (pg) { | ||
780 | for (i = 0; i < pg->index; i++) { | ||
781 | rec = &pg->records[i]; | ||
782 | if (rec->flags & FTRACE_FL_FAILED) | ||
783 | continue; | ||
784 | rec->flags &= ~FTRACE_FL_FILTER; | ||
785 | } | ||
786 | pg = pg->next; | ||
787 | } | ||
788 | preempt_enable(); | ||
789 | } | ||
790 | |||
791 | static int notrace | ||
792 | ftrace_filter_open(struct inode *inode, struct file *file) | ||
793 | { | ||
794 | struct ftrace_iterator *iter; | ||
795 | int ret = 0; | ||
796 | |||
797 | iter = kzalloc(sizeof(*iter), GFP_KERNEL); | ||
798 | if (!iter) | ||
799 | return -ENOMEM; | ||
800 | |||
801 | mutex_lock(&ftrace_filter_lock); | ||
802 | if ((file->f_mode & FMODE_WRITE) && | ||
803 | !(file->f_flags & O_APPEND)) | ||
804 | ftrace_filter_reset(); | ||
805 | |||
806 | if (file->f_mode & FMODE_READ) { | ||
807 | iter->pg = ftrace_pages_start; | ||
808 | iter->pos = -1; | ||
809 | iter->flags = FTRACE_ITER_FILTER; | ||
810 | |||
811 | ret = seq_open(file, &show_ftrace_seq_ops); | ||
812 | if (!ret) { | ||
813 | struct seq_file *m = file->private_data; | ||
814 | m->private = iter; | ||
815 | } else | ||
816 | kfree(iter); | ||
817 | } else | ||
818 | file->private_data = iter; | ||
819 | mutex_unlock(&ftrace_filter_lock); | ||
820 | |||
821 | return ret; | ||
822 | } | ||
823 | |||
824 | static ssize_t notrace | ||
825 | ftrace_filter_read(struct file *file, char __user *ubuf, | ||
826 | size_t cnt, loff_t *ppos) | ||
827 | { | ||
828 | if (file->f_mode & FMODE_READ) | ||
829 | return seq_read(file, ubuf, cnt, ppos); | ||
830 | else | ||
831 | return -EPERM; | ||
832 | } | ||
833 | |||
834 | static loff_t notrace | ||
835 | ftrace_filter_lseek(struct file *file, loff_t offset, int origin) | ||
836 | { | ||
837 | loff_t ret; | ||
838 | |||
839 | if (file->f_mode & FMODE_READ) | ||
840 | ret = seq_lseek(file, offset, origin); | ||
841 | else | ||
842 | file->f_pos = ret = 1; | ||
843 | |||
844 | return ret; | ||
845 | } | ||
846 | |||
847 | enum { | ||
848 | MATCH_FULL, | ||
849 | MATCH_FRONT_ONLY, | ||
850 | MATCH_MIDDLE_ONLY, | ||
851 | MATCH_END_ONLY, | ||
852 | }; | ||
853 | |||
854 | static void notrace | ||
855 | ftrace_match(unsigned char *buff, int len) | ||
856 | { | ||
857 | char str[KSYM_SYMBOL_LEN]; | ||
858 | char *search = NULL; | ||
859 | struct ftrace_page *pg; | ||
860 | struct dyn_ftrace *rec; | ||
861 | int type = MATCH_FULL; | ||
862 | unsigned i, match = 0, search_len = 0; | ||
863 | |||
864 | for (i = 0; i < len; i++) { | ||
865 | if (buff[i] == '*') { | ||
866 | if (!i) { | ||
867 | search = buff + i + 1; | ||
868 | type = MATCH_END_ONLY; | ||
869 | search_len = len - (i + 1); | ||
870 | } else { | ||
871 | if (type == MATCH_END_ONLY) { | ||
872 | type = MATCH_MIDDLE_ONLY; | ||
873 | } else { | ||
874 | match = i; | ||
875 | type = MATCH_FRONT_ONLY; | ||
876 | } | ||
877 | buff[i] = 0; | ||
878 | break; | ||
879 | } | ||
880 | } | ||
881 | } | ||
882 | |||
883 | /* keep kstop machine from running */ | ||
884 | preempt_disable(); | ||
885 | ftrace_filtered = 1; | ||
886 | pg = ftrace_pages_start; | ||
887 | while (pg) { | ||
888 | for (i = 0; i < pg->index; i++) { | ||
889 | int matched = 0; | ||
890 | char *ptr; | ||
891 | |||
892 | rec = &pg->records[i]; | ||
893 | if (rec->flags & FTRACE_FL_FAILED) | ||
894 | continue; | ||
895 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); | ||
896 | switch (type) { | ||
897 | case MATCH_FULL: | ||
898 | if (strcmp(str, buff) == 0) | ||
899 | matched = 1; | ||
900 | break; | ||
901 | case MATCH_FRONT_ONLY: | ||
902 | if (memcmp(str, buff, match) == 0) | ||
903 | matched = 1; | ||
904 | break; | ||
905 | case MATCH_MIDDLE_ONLY: | ||
906 | if (strstr(str, search)) | ||
907 | matched = 1; | ||
908 | break; | ||
909 | case MATCH_END_ONLY: | ||
910 | ptr = strstr(str, search); | ||
911 | if (ptr && (ptr[search_len] == 0)) | ||
912 | matched = 1; | ||
913 | break; | ||
914 | } | ||
915 | if (matched) | ||
916 | rec->flags |= FTRACE_FL_FILTER; | ||
917 | } | ||
918 | pg = pg->next; | ||
919 | } | ||
920 | preempt_enable(); | ||
921 | } | ||
922 | |||
923 | static ssize_t notrace | ||
924 | ftrace_filter_write(struct file *file, const char __user *ubuf, | ||
925 | size_t cnt, loff_t *ppos) | ||
926 | { | ||
927 | struct ftrace_iterator *iter; | ||
928 | char ch; | ||
929 | size_t read = 0; | ||
930 | ssize_t ret; | ||
931 | |||
932 | if (!cnt || cnt < 0) | ||
933 | return 0; | ||
934 | |||
935 | mutex_lock(&ftrace_filter_lock); | ||
936 | |||
937 | if (file->f_mode & FMODE_READ) { | ||
938 | struct seq_file *m = file->private_data; | ||
939 | iter = m->private; | ||
940 | } else | ||
941 | iter = file->private_data; | ||
942 | |||
943 | if (!*ppos) { | ||
944 | iter->flags &= ~FTRACE_ITER_CONT; | ||
945 | iter->buffer_idx = 0; | ||
946 | } | ||
947 | |||
948 | ret = get_user(ch, ubuf++); | ||
949 | if (ret) | ||
950 | goto out; | ||
951 | read++; | ||
952 | cnt--; | ||
953 | |||
954 | if (!(iter->flags & ~FTRACE_ITER_CONT)) { | ||
955 | /* skip white space */ | ||
956 | while (cnt && isspace(ch)) { | ||
957 | ret = get_user(ch, ubuf++); | ||
958 | if (ret) | ||
959 | goto out; | ||
960 | read++; | ||
961 | cnt--; | ||
962 | } | ||
963 | |||
964 | |||
965 | if (isspace(ch)) { | ||
966 | file->f_pos += read; | ||
967 | ret = read; | ||
968 | goto out; | ||
969 | } | ||
970 | |||
971 | iter->buffer_idx = 0; | ||
972 | } | ||
973 | |||
974 | while (cnt && !isspace(ch)) { | ||
975 | if (iter->buffer_idx < FTRACE_BUFF_MAX) | ||
976 | iter->buffer[iter->buffer_idx++] = ch; | ||
977 | else { | ||
978 | ret = -EINVAL; | ||
979 | goto out; | ||
980 | } | ||
981 | ret = get_user(ch, ubuf++); | ||
982 | if (ret) | ||
983 | goto out; | ||
984 | read++; | ||
985 | cnt--; | ||
986 | } | ||
987 | |||
988 | if (isspace(ch)) { | ||
989 | iter->filtered++; | ||
990 | iter->buffer[iter->buffer_idx] = 0; | ||
991 | ftrace_match(iter->buffer, iter->buffer_idx); | ||
992 | iter->buffer_idx = 0; | ||
993 | } else | ||
994 | iter->flags |= FTRACE_ITER_CONT; | ||
995 | |||
996 | |||
997 | file->f_pos += read; | ||
998 | |||
999 | ret = read; | ||
1000 | out: | ||
1001 | mutex_unlock(&ftrace_filter_lock); | ||
1002 | |||
1003 | return ret; | ||
1004 | } | ||
1005 | |||
1006 | static int notrace | ||
1007 | ftrace_filter_release(struct inode *inode, struct file *file) | ||
1008 | { | ||
1009 | struct seq_file *m = (struct seq_file *)file->private_data; | ||
1010 | struct ftrace_iterator *iter; | ||
1011 | |||
1012 | mutex_lock(&ftrace_filter_lock); | ||
1013 | if (file->f_mode & FMODE_READ) { | ||
1014 | iter = m->private; | ||
1015 | |||
1016 | seq_release(inode, file); | ||
1017 | } else | ||
1018 | iter = file->private_data; | ||
1019 | |||
1020 | if (iter->buffer_idx) { | ||
1021 | iter->filtered++; | ||
1022 | iter->buffer[iter->buffer_idx] = 0; | ||
1023 | ftrace_match(iter->buffer, iter->buffer_idx); | ||
1024 | } | ||
1025 | |||
1026 | mutex_lock(&ftrace_sysctl_lock); | ||
1027 | mutex_lock(&ftraced_lock); | ||
1028 | if (iter->filtered && ftraced_suspend && ftrace_enabled) | ||
1029 | ftrace_run_update_code(FTRACE_ENABLE_CALLS); | ||
1030 | mutex_unlock(&ftraced_lock); | ||
1031 | mutex_unlock(&ftrace_sysctl_lock); | ||
1032 | |||
1033 | kfree(iter); | ||
1034 | mutex_unlock(&ftrace_filter_lock); | ||
1035 | return 0; | ||
1036 | } | ||
1037 | |||
1038 | static struct file_operations ftrace_avail_fops = { | ||
1039 | .open = ftrace_avail_open, | ||
1040 | .read = seq_read, | ||
1041 | .llseek = seq_lseek, | ||
1042 | .release = ftrace_avail_release, | ||
1043 | }; | ||
1044 | |||
1045 | static struct file_operations ftrace_filter_fops = { | ||
1046 | .open = ftrace_filter_open, | ||
1047 | .read = ftrace_filter_read, | ||
1048 | .write = ftrace_filter_write, | ||
1049 | .llseek = ftrace_filter_lseek, | ||
1050 | .release = ftrace_filter_release, | ||
1051 | }; | ||
1052 | |||
1053 | static __init int ftrace_init_debugfs(void) | ||
1054 | { | ||
1055 | struct dentry *d_tracer; | ||
1056 | struct dentry *entry; | ||
1057 | |||
1058 | d_tracer = tracing_init_dentry(); | ||
1059 | |||
1060 | entry = debugfs_create_file("available_filter_functions", 0444, | ||
1061 | d_tracer, NULL, &ftrace_avail_fops); | ||
1062 | if (!entry) | ||
1063 | pr_warning("Could not create debugfs " | ||
1064 | "'available_filter_functions' entry\n"); | ||
1065 | |||
1066 | entry = debugfs_create_file("set_ftrace_filter", 0644, d_tracer, | ||
1067 | NULL, &ftrace_filter_fops); | ||
1068 | if (!entry) | ||
1069 | pr_warning("Could not create debugfs " | ||
1070 | "'set_ftrace_filter' entry\n"); | ||
1071 | return 0; | ||
1072 | } | ||
1073 | |||
1074 | fs_initcall(ftrace_init_debugfs); | ||
1075 | |||
583 | static int __init notrace ftrace_dynamic_init(void) | 1076 | static int __init notrace ftrace_dynamic_init(void) |
584 | { | 1077 | { |
585 | struct task_struct *p; | 1078 | struct task_struct *p; |
@@ -657,14 +1150,14 @@ int unregister_ftrace_function(struct ftrace_ops *ops) | |||
657 | 1150 | ||
658 | notrace int | 1151 | notrace int |
659 | ftrace_enable_sysctl(struct ctl_table *table, int write, | 1152 | ftrace_enable_sysctl(struct ctl_table *table, int write, |
660 | struct file *filp, void __user *buffer, size_t *lenp, | 1153 | struct file *file, void __user *buffer, size_t *lenp, |
661 | loff_t *ppos) | 1154 | loff_t *ppos) |
662 | { | 1155 | { |
663 | int ret; | 1156 | int ret; |
664 | 1157 | ||
665 | mutex_lock(&ftrace_sysctl_lock); | 1158 | mutex_lock(&ftrace_sysctl_lock); |
666 | 1159 | ||
667 | ret = proc_dointvec(table, write, filp, buffer, lenp, ppos); | 1160 | ret = proc_dointvec(table, write, file, buffer, lenp, ppos); |
668 | 1161 | ||
669 | if (ret || !write || (last_ftrace_enabled == ftrace_enabled)) | 1162 | if (ret || !write || (last_ftrace_enabled == ftrace_enabled)) |
670 | goto out; | 1163 | goto out; |