Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
[linux-2.6-microblaze.git] / kernel / trace / trace_events_filter.c
index 0dceb77..5574e86 100644 (file)
@@ -1,20 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * trace_events_filter - generic event filtering
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
  * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
  */
 
@@ -583,11 +570,13 @@ predicate_parse(const char *str, int nr_parens, int nr_preds,
                }
        }
 
+       kfree(op_stack);
+       kfree(inverts);
        return prog;
 out_free:
        kfree(op_stack);
-       kfree(prog_stack);
        kfree(inverts);
+       kfree(prog_stack);
        return ERR_PTR(ret);
 }
 
@@ -899,7 +888,8 @@ int filter_match_preds(struct event_filter *filter, void *rec)
        if (!filter)
                return 1;
 
-       prog = rcu_dereference_sched(filter->prog);
+       /* Protected by either SRCU(tracepoint_srcu) or preempt_disable */
+       prog = rcu_dereference_raw(filter->prog);
        if (!prog)
                return 1;
 
@@ -1626,10 +1616,10 @@ static int process_system_preds(struct trace_subsystem_dir *dir,
 
        /*
         * The calls can still be using the old filters.
-        * Do a synchronize_sched() to ensure all calls are
+        * Do a synchronize_sched() and to ensure all calls are
         * done with them before we free them.
         */
-       synchronize_sched();
+       tracepoint_synchronize_unregister();
        list_for_each_entry_safe(filter_item, tmp, &filter_list, list) {
                __free_filter(filter_item->filter);
                list_del(&filter_item->list);
@@ -1648,7 +1638,7 @@ static int process_system_preds(struct trace_subsystem_dir *dir,
        kfree(filter);
        /* If any call succeeded, we still need to sync */
        if (!fail)
-               synchronize_sched();
+               tracepoint_synchronize_unregister();
        list_for_each_entry_safe(filter_item, tmp, &filter_list, list) {
                __free_filter(filter_item->filter);
                list_del(&filter_item->list);
@@ -1701,6 +1691,7 @@ static void create_filter_finish(struct filter_parse_error *pe)
  * @filter_str: filter string
  * @set_str: remember @filter_str and enable detailed error in filter
  * @filterp: out param for created filter (always updated on return)
+ *           Must be a pointer that references a NULL pointer.
  *
  * Creates a filter for @call with @filter_str.  If @set_str is %true,
  * @filter_str is copied and recorded in the new filter.
@@ -1718,6 +1709,10 @@ static int create_filter(struct trace_event_call *call,
        struct filter_parse_error *pe = NULL;
        int err;
 
+       /* filterp must point to NULL */
+       if (WARN_ON(*filterp))
+               *filterp = NULL;
+
        err = create_filter_start(filter_string, set_str, &pe, filterp);
        if (err)
                return err;
@@ -1725,6 +1720,7 @@ static int create_filter(struct trace_event_call *call,
        err = process_preds(call, filter_string, *filterp, pe);
        if (err && set_str)
                append_filter_err(pe, *filterp);
+       create_filter_finish(pe);
 
        return err;
 }
@@ -1785,7 +1781,7 @@ int apply_event_filter(struct trace_event_file *file, char *filter_string)
                event_clear_filter(file);
 
                /* Make sure the filter is not being used */
-               synchronize_sched();
+               tracepoint_synchronize_unregister();
                __free_filter(filter);
 
                return 0;
@@ -1812,7 +1808,7 @@ int apply_event_filter(struct trace_event_file *file, char *filter_string)
 
                if (tmp) {
                        /* Make sure the call is done with the filter */
-                       synchronize_sched();
+                       tracepoint_synchronize_unregister();
                        __free_filter(tmp);
                }
        }
@@ -1842,7 +1838,7 @@ int apply_subsystem_event_filter(struct trace_subsystem_dir *dir,
                filter = system->filter;
                system->filter = NULL;
                /* Ensure all filters are no longer used */
-               synchronize_sched();
+               tracepoint_synchronize_unregister();
                filter_free_subsystem_filters(dir, tr);
                __free_filter(filter);
                goto out_unlock;