diff options
author | Steven Rostedt <srostedt@redhat.com> | 2011-02-03 23:25:46 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2011-02-07 20:56:20 -0500 |
commit | 75b8e98263fdb0bfbdeba60d4db463259f1fe8a2 (patch) | |
tree | fdd1e66316b049523c76e34c816a812598d07a3c /kernel/trace | |
parent | bf93f9ed3a2cb89eb7e58851139d3be375b98027 (diff) |
tracing/filter: Swap entire filter of events
When creating a new filter, instead of allocating the filter to the
event call first and then processing the filter, it is easier to
process a temporary filter and then just swap it with the call filter.
By doing this, it simplifies the code.
A filter is allocated and processed, when it is done, it is
swapped with the call filter, synchronize_sched() is called to make
sure all callers are done with the old filter (filters are called
with premption disabled), and then the old filter is freed.
Cc: Tom Zanussi <tzanussi@gmail.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/trace_events_filter.c | 251 |
1 files changed, 146 insertions, 105 deletions
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 2403ce5b6507..f5d335d28d0b 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
@@ -425,10 +425,15 @@ int filter_match_preds(struct event_filter *filter, void *rec) | |||
425 | struct filter_pred *preds; | 425 | struct filter_pred *preds; |
426 | struct filter_pred *pred; | 426 | struct filter_pred *pred; |
427 | struct filter_pred *root; | 427 | struct filter_pred *root; |
428 | int n_preds = ACCESS_ONCE(filter->n_preds); | 428 | int n_preds; |
429 | int done = 0; | 429 | int done = 0; |
430 | 430 | ||
431 | /* no filter is considered a match */ | 431 | /* no filter is considered a match */ |
432 | if (!filter) | ||
433 | return 1; | ||
434 | |||
435 | n_preds = filter->n_preds; | ||
436 | |||
432 | if (!n_preds) | 437 | if (!n_preds) |
433 | return 1; | 438 | return 1; |
434 | 439 | ||
@@ -509,6 +514,9 @@ static void parse_error(struct filter_parse_state *ps, int err, int pos) | |||
509 | 514 | ||
510 | static void remove_filter_string(struct event_filter *filter) | 515 | static void remove_filter_string(struct event_filter *filter) |
511 | { | 516 | { |
517 | if (!filter) | ||
518 | return; | ||
519 | |||
512 | kfree(filter->filter_string); | 520 | kfree(filter->filter_string); |
513 | filter->filter_string = NULL; | 521 | filter->filter_string = NULL; |
514 | } | 522 | } |
@@ -568,9 +576,10 @@ static void append_filter_err(struct filter_parse_state *ps, | |||
568 | 576 | ||
569 | void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s) | 577 | void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s) |
570 | { | 578 | { |
571 | struct event_filter *filter = call->filter; | 579 | struct event_filter *filter; |
572 | 580 | ||
573 | mutex_lock(&event_mutex); | 581 | mutex_lock(&event_mutex); |
582 | filter = call->filter; | ||
574 | if (filter && filter->filter_string) | 583 | if (filter && filter->filter_string) |
575 | trace_seq_printf(s, "%s\n", filter->filter_string); | 584 | trace_seq_printf(s, "%s\n", filter->filter_string); |
576 | else | 585 | else |
@@ -581,9 +590,10 @@ void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s) | |||
581 | void print_subsystem_event_filter(struct event_subsystem *system, | 590 | void print_subsystem_event_filter(struct event_subsystem *system, |
582 | struct trace_seq *s) | 591 | struct trace_seq *s) |
583 | { | 592 | { |
584 | struct event_filter *filter = system->filter; | 593 | struct event_filter *filter; |
585 | 594 | ||
586 | mutex_lock(&event_mutex); | 595 | mutex_lock(&event_mutex); |
596 | filter = system->filter; | ||
587 | if (filter && filter->filter_string) | 597 | if (filter && filter->filter_string) |
588 | trace_seq_printf(s, "%s\n", filter->filter_string); | 598 | trace_seq_printf(s, "%s\n", filter->filter_string); |
589 | else | 599 | else |
@@ -745,26 +755,9 @@ static void __free_preds(struct event_filter *filter) | |||
745 | filter->n_preds = 0; | 755 | filter->n_preds = 0; |
746 | } | 756 | } |
747 | 757 | ||
748 | static void reset_preds(struct event_filter *filter) | 758 | static void filter_disable(struct ftrace_event_call *call) |
749 | { | ||
750 | int n_preds = filter->n_preds; | ||
751 | int i; | ||
752 | |||
753 | filter->n_preds = 0; | ||
754 | filter->root = NULL; | ||
755 | if (!filter->preds) | ||
756 | return; | ||
757 | |||
758 | for (i = 0; i < n_preds; i++) | ||
759 | filter->preds[i].fn = filter_pred_none; | ||
760 | } | ||
761 | |||
762 | static void filter_disable_preds(struct ftrace_event_call *call) | ||
763 | { | 759 | { |
764 | struct event_filter *filter = call->filter; | ||
765 | |||
766 | call->flags &= ~TRACE_EVENT_FL_FILTERED; | 760 | call->flags &= ~TRACE_EVENT_FL_FILTERED; |
767 | reset_preds(filter); | ||
768 | } | 761 | } |
769 | 762 | ||
770 | static void __free_filter(struct event_filter *filter) | 763 | static void __free_filter(struct event_filter *filter) |
@@ -777,11 +770,16 @@ static void __free_filter(struct event_filter *filter) | |||
777 | kfree(filter); | 770 | kfree(filter); |
778 | } | 771 | } |
779 | 772 | ||
773 | /* | ||
774 | * Called when destroying the ftrace_event_call. | ||
775 | * The call is being freed, so we do not need to worry about | ||
776 | * the call being currently used. This is for module code removing | ||
777 | * the tracepoints from within it. | ||
778 | */ | ||
780 | void destroy_preds(struct ftrace_event_call *call) | 779 | void destroy_preds(struct ftrace_event_call *call) |
781 | { | 780 | { |
782 | __free_filter(call->filter); | 781 | __free_filter(call->filter); |
783 | call->filter = NULL; | 782 | call->filter = NULL; |
784 | call->flags &= ~TRACE_EVENT_FL_FILTERED; | ||
785 | } | 783 | } |
786 | 784 | ||
787 | static struct event_filter *__alloc_filter(void) | 785 | static struct event_filter *__alloc_filter(void) |
@@ -789,11 +787,6 @@ static struct event_filter *__alloc_filter(void) | |||
789 | struct event_filter *filter; | 787 | struct event_filter *filter; |
790 | 788 | ||
791 | filter = kzalloc(sizeof(*filter), GFP_KERNEL); | 789 | filter = kzalloc(sizeof(*filter), GFP_KERNEL); |
792 | if (!filter) | ||
793 | return ERR_PTR(-ENOMEM); | ||
794 | |||
795 | filter->n_preds = 0; | ||
796 | |||
797 | return filter; | 790 | return filter; |
798 | } | 791 | } |
799 | 792 | ||
@@ -838,46 +831,28 @@ static int __alloc_preds(struct event_filter *filter, int n_preds) | |||
838 | return 0; | 831 | return 0; |
839 | } | 832 | } |
840 | 833 | ||
841 | static int init_filter(struct ftrace_event_call *call) | 834 | static void filter_free_subsystem_preds(struct event_subsystem *system) |
842 | { | ||
843 | if (call->filter) | ||
844 | return 0; | ||
845 | |||
846 | call->flags &= ~TRACE_EVENT_FL_FILTERED; | ||
847 | call->filter = __alloc_filter(); | ||
848 | if (IS_ERR(call->filter)) | ||
849 | return PTR_ERR(call->filter); | ||
850 | |||
851 | return 0; | ||
852 | } | ||
853 | |||
854 | static int init_subsystem_preds(struct event_subsystem *system) | ||
855 | { | 835 | { |
856 | struct ftrace_event_call *call; | 836 | struct ftrace_event_call *call; |
857 | int err; | ||
858 | 837 | ||
859 | list_for_each_entry(call, &ftrace_events, list) { | 838 | list_for_each_entry(call, &ftrace_events, list) { |
860 | if (strcmp(call->class->system, system->name) != 0) | 839 | if (strcmp(call->class->system, system->name) != 0) |
861 | continue; | 840 | continue; |
862 | 841 | ||
863 | err = init_filter(call); | 842 | filter_disable(call); |
864 | if (err) | 843 | remove_filter_string(call->filter); |
865 | return err; | ||
866 | } | 844 | } |
867 | |||
868 | return 0; | ||
869 | } | 845 | } |
870 | 846 | ||
871 | static void filter_free_subsystem_preds(struct event_subsystem *system) | 847 | static void filter_free_subsystem_filters(struct event_subsystem *system) |
872 | { | 848 | { |
873 | struct ftrace_event_call *call; | 849 | struct ftrace_event_call *call; |
874 | 850 | ||
875 | list_for_each_entry(call, &ftrace_events, list) { | 851 | list_for_each_entry(call, &ftrace_events, list) { |
876 | if (strcmp(call->class->system, system->name) != 0) | 852 | if (strcmp(call->class->system, system->name) != 0) |
877 | continue; | 853 | continue; |
878 | 854 | __free_filter(call->filter); | |
879 | filter_disable_preds(call); | 855 | call->filter = NULL; |
880 | remove_filter_string(call->filter); | ||
881 | } | 856 | } |
882 | } | 857 | } |
883 | 858 | ||
@@ -1743,88 +1718,129 @@ fail: | |||
1743 | return err; | 1718 | return err; |
1744 | } | 1719 | } |
1745 | 1720 | ||
1721 | struct filter_list { | ||
1722 | struct list_head list; | ||
1723 | struct event_filter *filter; | ||
1724 | }; | ||
1725 | |||
1746 | static int replace_system_preds(struct event_subsystem *system, | 1726 | static int replace_system_preds(struct event_subsystem *system, |
1747 | struct filter_parse_state *ps, | 1727 | struct filter_parse_state *ps, |
1748 | char *filter_string) | 1728 | char *filter_string) |
1749 | { | 1729 | { |
1750 | struct ftrace_event_call *call; | 1730 | struct ftrace_event_call *call; |
1731 | struct filter_list *filter_item; | ||
1732 | struct filter_list *tmp; | ||
1733 | LIST_HEAD(filter_list); | ||
1751 | bool fail = true; | 1734 | bool fail = true; |
1752 | int err; | 1735 | int err; |
1753 | 1736 | ||
1754 | list_for_each_entry(call, &ftrace_events, list) { | 1737 | list_for_each_entry(call, &ftrace_events, list) { |
1755 | struct event_filter *filter = call->filter; | ||
1756 | 1738 | ||
1757 | if (strcmp(call->class->system, system->name) != 0) | 1739 | if (strcmp(call->class->system, system->name) != 0) |
1758 | continue; | 1740 | continue; |
1759 | 1741 | ||
1760 | /* try to see if the filter can be applied */ | 1742 | /* |
1761 | err = replace_preds(call, filter, ps, filter_string, true); | 1743 | * Try to see if the filter can be applied |
1744 | * (filter arg is ignored on dry_run) | ||
1745 | */ | ||
1746 | err = replace_preds(call, NULL, ps, filter_string, true); | ||
1762 | if (err) | 1747 | if (err) |
1763 | goto fail; | 1748 | goto fail; |
1764 | } | 1749 | } |
1765 | 1750 | ||
1766 | /* set all filter pred counts to zero */ | ||
1767 | list_for_each_entry(call, &ftrace_events, list) { | 1751 | list_for_each_entry(call, &ftrace_events, list) { |
1768 | struct event_filter *filter = call->filter; | 1752 | struct event_filter *filter; |
1769 | 1753 | ||
1770 | if (strcmp(call->class->system, system->name) != 0) | 1754 | if (strcmp(call->class->system, system->name) != 0) |
1771 | continue; | 1755 | continue; |
1772 | 1756 | ||
1773 | reset_preds(filter); | 1757 | filter_item = kzalloc(sizeof(*filter_item), GFP_KERNEL); |
1774 | } | 1758 | if (!filter_item) |
1759 | goto fail_mem; | ||
1775 | 1760 | ||
1776 | /* | 1761 | list_add_tail(&filter_item->list, &filter_list); |
1777 | * Since some of the preds may be used under preemption | ||
1778 | * we need to wait for them to finish before we may | ||
1779 | * reallocate them. | ||
1780 | */ | ||
1781 | synchronize_sched(); | ||
1782 | 1762 | ||
1783 | list_for_each_entry(call, &ftrace_events, list) { | 1763 | filter_item->filter = __alloc_filter(); |
1784 | struct event_filter *filter = call->filter; | 1764 | if (!filter_item->filter) |
1765 | goto fail_mem; | ||
1766 | filter = filter_item->filter; | ||
1785 | 1767 | ||
1786 | if (strcmp(call->class->system, system->name) != 0) | 1768 | /* Can only fail on no memory */ |
1787 | continue; | 1769 | err = replace_filter_string(filter, filter_string); |
1770 | if (err) | ||
1771 | goto fail_mem; | ||
1788 | 1772 | ||
1789 | /* really apply the filter */ | ||
1790 | filter_disable_preds(call); | ||
1791 | err = replace_preds(call, filter, ps, filter_string, false); | 1773 | err = replace_preds(call, filter, ps, filter_string, false); |
1792 | if (err) | 1774 | if (err) { |
1793 | filter_disable_preds(call); | 1775 | filter_disable(call); |
1794 | else { | 1776 | parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); |
1777 | append_filter_err(ps, filter); | ||
1778 | } else | ||
1795 | call->flags |= TRACE_EVENT_FL_FILTERED; | 1779 | call->flags |= TRACE_EVENT_FL_FILTERED; |
1796 | replace_filter_string(filter, filter_string); | 1780 | /* |
1797 | } | 1781 | * Regardless of if this returned an error, we still |
1782 | * replace the filter for the call. | ||
1783 | */ | ||
1784 | filter = call->filter; | ||
1785 | call->filter = filter_item->filter; | ||
1786 | filter_item->filter = filter; | ||
1787 | |||
1798 | fail = false; | 1788 | fail = false; |
1799 | } | 1789 | } |
1800 | 1790 | ||
1801 | if (fail) | 1791 | if (fail) |
1802 | goto fail; | 1792 | goto fail; |
1803 | 1793 | ||
1794 | /* | ||
1795 | * The calls can still be using the old filters. | ||
1796 | * Do a synchronize_sched() to ensure all calls are | ||
1797 | * done with them before we free them. | ||
1798 | */ | ||
1799 | synchronize_sched(); | ||
1800 | list_for_each_entry_safe(filter_item, tmp, &filter_list, list) { | ||
1801 | __free_filter(filter_item->filter); | ||
1802 | list_del(&filter_item->list); | ||
1803 | kfree(filter_item); | ||
1804 | } | ||
1804 | return 0; | 1805 | return 0; |
1805 | fail: | 1806 | fail: |
1807 | /* No call succeeded */ | ||
1808 | list_for_each_entry_safe(filter_item, tmp, &filter_list, list) { | ||
1809 | list_del(&filter_item->list); | ||
1810 | kfree(filter_item); | ||
1811 | } | ||
1806 | parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); | 1812 | parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); |
1807 | return -EINVAL; | 1813 | return -EINVAL; |
1814 | fail_mem: | ||
1815 | /* If any call succeeded, we still need to sync */ | ||
1816 | if (!fail) | ||
1817 | synchronize_sched(); | ||
1818 | list_for_each_entry_safe(filter_item, tmp, &filter_list, list) { | ||
1819 | __free_filter(filter_item->filter); | ||
1820 | list_del(&filter_item->list); | ||
1821 | kfree(filter_item); | ||
1822 | } | ||
1823 | return -ENOMEM; | ||
1808 | } | 1824 | } |
1809 | 1825 | ||
1810 | int apply_event_filter(struct ftrace_event_call *call, char *filter_string) | 1826 | int apply_event_filter(struct ftrace_event_call *call, char *filter_string) |
1811 | { | 1827 | { |
1812 | int err; | ||
1813 | struct filter_parse_state *ps; | 1828 | struct filter_parse_state *ps; |
1829 | struct event_filter *filter; | ||
1830 | struct event_filter *tmp; | ||
1831 | int err = 0; | ||
1814 | 1832 | ||
1815 | mutex_lock(&event_mutex); | 1833 | mutex_lock(&event_mutex); |
1816 | 1834 | ||
1817 | err = init_filter(call); | ||
1818 | if (err) | ||
1819 | goto out_unlock; | ||
1820 | |||
1821 | if (!strcmp(strstrip(filter_string), "0")) { | 1835 | if (!strcmp(strstrip(filter_string), "0")) { |
1822 | filter_disable_preds(call); | 1836 | filter_disable(call); |
1823 | reset_preds(call->filter); | 1837 | filter = call->filter; |
1838 | if (!filter) | ||
1839 | goto out_unlock; | ||
1840 | call->filter = NULL; | ||
1824 | /* Make sure the filter is not being used */ | 1841 | /* Make sure the filter is not being used */ |
1825 | synchronize_sched(); | 1842 | synchronize_sched(); |
1826 | __free_preds(call->filter); | 1843 | __free_filter(filter); |
1827 | remove_filter_string(call->filter); | ||
1828 | goto out_unlock; | 1844 | goto out_unlock; |
1829 | } | 1845 | } |
1830 | 1846 | ||
@@ -1833,29 +1849,41 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) | |||
1833 | if (!ps) | 1849 | if (!ps) |
1834 | goto out_unlock; | 1850 | goto out_unlock; |
1835 | 1851 | ||
1836 | filter_disable_preds(call); | 1852 | filter = __alloc_filter(); |
1837 | replace_filter_string(call->filter, filter_string); | 1853 | if (!filter) { |
1854 | kfree(ps); | ||
1855 | goto out_unlock; | ||
1856 | } | ||
1857 | |||
1858 | replace_filter_string(filter, filter_string); | ||
1838 | 1859 | ||
1839 | parse_init(ps, filter_ops, filter_string); | 1860 | parse_init(ps, filter_ops, filter_string); |
1840 | err = filter_parse(ps); | 1861 | err = filter_parse(ps); |
1841 | if (err) { | 1862 | if (err) { |
1842 | append_filter_err(ps, call->filter); | 1863 | append_filter_err(ps, filter); |
1843 | goto out; | 1864 | goto out; |
1844 | } | 1865 | } |
1845 | 1866 | ||
1846 | /* | 1867 | err = replace_preds(call, filter, ps, filter_string, false); |
1847 | * Make sure all the pred counts are zero so that | 1868 | if (err) { |
1848 | * no task is using it when we reallocate the preds array. | 1869 | filter_disable(call); |
1849 | */ | 1870 | append_filter_err(ps, filter); |
1850 | reset_preds(call->filter); | 1871 | } else |
1851 | synchronize_sched(); | ||
1852 | |||
1853 | err = replace_preds(call, call->filter, ps, filter_string, false); | ||
1854 | if (err) | ||
1855 | append_filter_err(ps, call->filter); | ||
1856 | else | ||
1857 | call->flags |= TRACE_EVENT_FL_FILTERED; | 1872 | call->flags |= TRACE_EVENT_FL_FILTERED; |
1858 | out: | 1873 | out: |
1874 | /* | ||
1875 | * Always swap the call filter with the new filter | ||
1876 | * even if there was an error. If there was an error | ||
1877 | * in the filter, we disable the filter and show the error | ||
1878 | * string | ||
1879 | */ | ||
1880 | tmp = call->filter; | ||
1881 | call->filter = filter; | ||
1882 | if (tmp) { | ||
1883 | /* Make sure the call is done with the filter */ | ||
1884 | synchronize_sched(); | ||
1885 | __free_filter(tmp); | ||
1886 | } | ||
1859 | filter_opstack_clear(ps); | 1887 | filter_opstack_clear(ps); |
1860 | postfix_clear(ps); | 1888 | postfix_clear(ps); |
1861 | kfree(ps); | 1889 | kfree(ps); |
@@ -1868,18 +1896,21 @@ out_unlock: | |||
1868 | int apply_subsystem_event_filter(struct event_subsystem *system, | 1896 | int apply_subsystem_event_filter(struct event_subsystem *system, |
1869 | char *filter_string) | 1897 | char *filter_string) |
1870 | { | 1898 | { |
1871 | int err; | ||
1872 | struct filter_parse_state *ps; | 1899 | struct filter_parse_state *ps; |
1900 | struct event_filter *filter; | ||
1901 | int err = 0; | ||
1873 | 1902 | ||
1874 | mutex_lock(&event_mutex); | 1903 | mutex_lock(&event_mutex); |
1875 | 1904 | ||
1876 | err = init_subsystem_preds(system); | ||
1877 | if (err) | ||
1878 | goto out_unlock; | ||
1879 | |||
1880 | if (!strcmp(strstrip(filter_string), "0")) { | 1905 | if (!strcmp(strstrip(filter_string), "0")) { |
1881 | filter_free_subsystem_preds(system); | 1906 | filter_free_subsystem_preds(system); |
1882 | remove_filter_string(system->filter); | 1907 | remove_filter_string(system->filter); |
1908 | filter = system->filter; | ||
1909 | system->filter = NULL; | ||
1910 | /* Ensure all filters are no longer used */ | ||
1911 | synchronize_sched(); | ||
1912 | filter_free_subsystem_filters(system); | ||
1913 | __free_filter(filter); | ||
1883 | goto out_unlock; | 1914 | goto out_unlock; |
1884 | } | 1915 | } |
1885 | 1916 | ||
@@ -1888,7 +1919,17 @@ int apply_subsystem_event_filter(struct event_subsystem *system, | |||
1888 | if (!ps) | 1919 | if (!ps) |
1889 | goto out_unlock; | 1920 | goto out_unlock; |
1890 | 1921 | ||
1891 | replace_filter_string(system->filter, filter_string); | 1922 | filter = __alloc_filter(); |
1923 | if (!filter) | ||
1924 | goto out; | ||
1925 | |||
1926 | replace_filter_string(filter, filter_string); | ||
1927 | /* | ||
1928 | * No event actually uses the system filter | ||
1929 | * we can free it without synchronize_sched(). | ||
1930 | */ | ||
1931 | __free_filter(system->filter); | ||
1932 | system->filter = filter; | ||
1892 | 1933 | ||
1893 | parse_init(ps, filter_ops, filter_string); | 1934 | parse_init(ps, filter_ops, filter_string); |
1894 | err = filter_parse(ps); | 1935 | err = filter_parse(ps); |
@@ -1945,7 +1986,7 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id, | |||
1945 | goto out_unlock; | 1986 | goto out_unlock; |
1946 | 1987 | ||
1947 | filter = __alloc_filter(); | 1988 | filter = __alloc_filter(); |
1948 | if (IS_ERR(filter)) { | 1989 | if (!filter) { |
1949 | err = PTR_ERR(filter); | 1990 | err = PTR_ERR(filter); |
1950 | goto out_unlock; | 1991 | goto out_unlock; |
1951 | } | 1992 | } |