Commit 4f554e95 authored by Jiri Olsa's avatar Jiri Olsa Committed by Alexei Starovoitov

ftrace: Add ftrace_set_filter_ips function

Adding ftrace_set_filter_ips function to be able to set filter on
multiple ip addresses at once.

With the kprobe multi attach interface we have cases where we need to
initialize ftrace_ops object with thousands of functions, so having
single function diving into ftrace_hash_move_and_update_ops with
ftrace_lock is faster.

The functions ips are passed as unsigned long array with count.
Signed-off-by: default avatarJiri Olsa <jolsa@kernel.org>
Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
Tested-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/164735282673.1084943.18310504594134769804.stgit@devnote2
parent e0999c8e
...@@ -512,6 +512,8 @@ struct dyn_ftrace { ...@@ -512,6 +512,8 @@ struct dyn_ftrace {
int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip, int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip,
int remove, int reset); int remove, int reset);
int ftrace_set_filter_ips(struct ftrace_ops *ops, unsigned long *ips,
unsigned int cnt, int remove, int reset);
int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf, int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,
int len, int reset); int len, int reset);
int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf, int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
...@@ -802,6 +804,7 @@ static inline unsigned long ftrace_location(unsigned long ip) ...@@ -802,6 +804,7 @@ static inline unsigned long ftrace_location(unsigned long ip)
#define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; }) #define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; })
#define ftrace_set_early_filter(ops, buf, enable) do { } while (0) #define ftrace_set_early_filter(ops, buf, enable) do { } while (0)
#define ftrace_set_filter_ip(ops, ip, remove, reset) ({ -ENODEV; }) #define ftrace_set_filter_ip(ops, ip, remove, reset) ({ -ENODEV; })
#define ftrace_set_filter_ips(ops, ips, cnt, remove, reset) ({ -ENODEV; })
#define ftrace_set_filter(ops, buf, len, reset) ({ -ENODEV; }) #define ftrace_set_filter(ops, buf, len, reset) ({ -ENODEV; })
#define ftrace_set_notrace(ops, buf, len, reset) ({ -ENODEV; }) #define ftrace_set_notrace(ops, buf, len, reset) ({ -ENODEV; })
#define ftrace_free_filter(ops) do { } while (0) #define ftrace_free_filter(ops) do { } while (0)
......
...@@ -4958,7 +4958,7 @@ ftrace_notrace_write(struct file *file, const char __user *ubuf, ...@@ -4958,7 +4958,7 @@ ftrace_notrace_write(struct file *file, const char __user *ubuf,
} }
static int 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; struct ftrace_func_entry *entry;
...@@ -4976,9 +4976,30 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove) ...@@ -4976,9 +4976,30 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
return add_hash_entry(hash, ip); 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 static int
ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, 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 **orig_hash;
struct ftrace_hash *hash; struct ftrace_hash *hash;
...@@ -5008,8 +5029,8 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, ...@@ -5008,8 +5029,8 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
ret = -EINVAL; ret = -EINVAL;
goto out_regex_unlock; goto out_regex_unlock;
} }
if (ip) { if (ips) {
ret = ftrace_match_addr(hash, ip, remove); ret = ftrace_match_addr(hash, ips, cnt, remove);
if (ret < 0) if (ret < 0)
goto out_regex_unlock; goto out_regex_unlock;
} }
...@@ -5026,10 +5047,10 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, ...@@ -5026,10 +5047,10 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
} }
static int static int
ftrace_set_addr(struct ftrace_ops *ops, unsigned long ip, int remove, ftrace_set_addr(struct ftrace_ops *ops, unsigned long *ips, unsigned int cnt,
int reset, int enable) 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 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
...@@ -5634,10 +5655,29 @@ int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip, ...@@ -5634,10 +5655,29 @@ int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip,
int remove, int reset) int remove, int reset)
{ {
ftrace_ops_init(ops); 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); 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 * ftrace_ops_set_global_filter - setup ops to use global filters
* @ops - the ops which will use the global filters * @ops - the ops which will use the global filters
...@@ -5659,7 +5699,7 @@ static int ...@@ -5659,7 +5699,7 @@ static int
ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
int reset, int enable) 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);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment