kallsyms: Add helper kallsyms_on_each_match_symbol()
authorZhen Lei <thunder.leizhen@huawei.com>
Wed, 2 Nov 2022 08:49:17 +0000 (16:49 +0800)
committerLuis Chamberlain <mcgrof@kernel.org>
Sun, 13 Nov 2022 02:47:36 +0000 (18:47 -0800)
Function kallsyms_on_each_symbol() traverses all symbols and submits each
symbol to the hook 'fn' for judgment and processing. For some cases, the
hook actually only handles the matched symbol, such as livepatch.

Because all symbols are currently sorted by name, all the symbols with the
same name are clustered together. Function kallsyms_lookup_names() gets
the start and end positions of the set corresponding to the specified
name. So we can easily and quickly traverse all the matches.

The test results are as follows (twice): (x86)
kallsyms_on_each_match_symbol:     7454,     7984
kallsyms_on_each_symbol      : 1173380911785803

kallsyms_on_each_match_symbol() consumes only 0.066% of
kallsyms_on_each_symbol()'s time. In other words, 1523x better
performance.

Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
include/linux/kallsyms.h
kernel/kallsyms.c

index 649faac31ddb162701a8b75059775f74aa45dde0..0cd33be7142ad0d8098e9c92832ff2230abc718c 100644 (file)
@@ -69,6 +69,8 @@ static inline void *dereference_symbol_descriptor(void *ptr)
 int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
                                      unsigned long),
                            void *data);
+int kallsyms_on_each_match_symbol(int (*fn)(void *, unsigned long),
+                                 const char *name, void *data);
 
 /* Lookup the address for a symbol. Returns 0 if not found. */
 unsigned long kallsyms_lookup_name(const char *name);
@@ -168,6 +170,12 @@ static inline int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct
 {
        return -EOPNOTSUPP;
 }
+
+static inline int kallsyms_on_each_match_symbol(int (*fn)(void *, unsigned long),
+                                               const char *name, void *data)
+{
+       return -EOPNOTSUPP;
+}
 #endif /*CONFIG_KALLSYMS*/
 
 static inline void print_ip_sym(const char *loglvl, unsigned long ip)
index 48f36fd7e10b95e10cede557689f17d06acf4461..0008ada2b135bef30f98797cb89d703bce81fad0 100644 (file)
@@ -307,6 +307,24 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
        return 0;
 }
 
+int kallsyms_on_each_match_symbol(int (*fn)(void *, unsigned long),
+                                 const char *name, void *data)
+{
+       int ret;
+       unsigned int i, start, end;
+
+       ret = kallsyms_lookup_names(name, &start, &end);
+       if (ret)
+               return 0;
+
+       for (i = start; !ret && i <= end; i++) {
+               ret = fn(data, kallsyms_sym_address(get_symbol_seq(i)));
+               cond_resched();
+       }
+
+       return ret;
+}
+
 static unsigned long get_symbol_pos(unsigned long addr,
                                    unsigned long *symbolsize,
                                    unsigned long *offset)