Merge https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
[linux-2.6-microblaze.git] / kernel / trace / ftrace.c
index 6105b70..4214d6a 100644 (file)
@@ -4958,7 +4958,7 @@ ftrace_notrace_write(struct file *file, const char __user *ubuf,
 }
 
 static int
-ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
+__ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
 {
        struct ftrace_func_entry *entry;
 
@@ -4976,9 +4976,30 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
        return add_hash_entry(hash, ip);
 }
 
+static int
+ftrace_match_addr(struct ftrace_hash *hash, unsigned long *ips,
+                 unsigned int cnt, int remove)
+{
+       unsigned int i;
+       int err;
+
+       for (i = 0; i < cnt; i++) {
+               err = __ftrace_match_addr(hash, ips[i], remove);
+               if (err) {
+                       /*
+                        * This expects the @hash is a temporary hash and if this
+                        * fails the caller must free the @hash.
+                        */
+                       return err;
+               }
+       }
+       return 0;
+}
+
 static int
 ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
-               unsigned long ip, int remove, int reset, int enable)
+               unsigned long *ips, unsigned int cnt,
+               int remove, int reset, int enable)
 {
        struct ftrace_hash **orig_hash;
        struct ftrace_hash *hash;
@@ -5008,8 +5029,8 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
                ret = -EINVAL;
                goto out_regex_unlock;
        }
-       if (ip) {
-               ret = ftrace_match_addr(hash, ip, remove);
+       if (ips) {
+               ret = ftrace_match_addr(hash, ips, cnt, remove);
                if (ret < 0)
                        goto out_regex_unlock;
        }
@@ -5026,10 +5047,10 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
 }
 
 static int
-ftrace_set_addr(struct ftrace_ops *ops, unsigned long ip, int remove,
-               int reset, int enable)
+ftrace_set_addr(struct ftrace_ops *ops, unsigned long *ips, unsigned int cnt,
+               int remove, int reset, int enable)
 {
-       return ftrace_set_hash(ops, NULL, 0, ip, remove, reset, enable);
+       return ftrace_set_hash(ops, NULL, 0, ips, cnt, remove, reset, enable);
 }
 
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
@@ -5634,10 +5655,29 @@ int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip,
                         int remove, int reset)
 {
        ftrace_ops_init(ops);
-       return ftrace_set_addr(ops, ip, remove, reset, 1);
+       return ftrace_set_addr(ops, &ip, 1, remove, reset, 1);
 }
 EXPORT_SYMBOL_GPL(ftrace_set_filter_ip);
 
+/**
+ * ftrace_set_filter_ips - set functions to filter on in ftrace by addresses
+ * @ops - the ops to set the filter with
+ * @ips - the array of addresses to add to or remove from the filter.
+ * @cnt - the number of addresses in @ips
+ * @remove - non zero to remove ips from the filter
+ * @reset - non zero to reset all filters before applying this filter.
+ *
+ * Filters denote which functions should be enabled when tracing is enabled
+ * If @ips array or any ip specified within is NULL , it fails to update filter.
+ */
+int ftrace_set_filter_ips(struct ftrace_ops *ops, unsigned long *ips,
+                         unsigned int cnt, int remove, int reset)
+{
+       ftrace_ops_init(ops);
+       return ftrace_set_addr(ops, ips, cnt, remove, reset, 1);
+}
+EXPORT_SYMBOL_GPL(ftrace_set_filter_ips);
+
 /**
  * ftrace_ops_set_global_filter - setup ops to use global filters
  * @ops - the ops which will use the global filters
@@ -5659,7 +5699,7 @@ static int
 ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
                 int reset, int enable)
 {
-       return ftrace_set_hash(ops, buf, len, 0, 0, reset, enable);
+       return ftrace_set_hash(ops, buf, len, NULL, 0, 0, reset, enable);
 }
 
 /**