Commit 3ba2c3ff authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull modules updates from Luis Chamberlain:
 "Tux gets for xmas an improvement to the average lookup performance of
  kallsyms_lookup_name() by 715x thanks to the work by Zhen Lei, which
  upgraded our old implementation from being O(n) to O(log(n)), while
  also retaining the old implementation support on /proc/kallsyms.

  The only penalty was increasing the memory footprint by 3 *
  kallsyms_num_syms. Folks who want to improve this further now also
  have a dedicated selftest facility through KALLSYMS_SELFTEST.

  Stephen Boyd added zstd in-kernel decompression support, but the only
  users of this would be folks using the load-pin LSM because otherwise
  we do module decompression in userspace.

  The only other thing with mentioning is a minor boot time optimization
  by Rasmus Villemoes which deferes param_sysfs_init() to late init. The
  rest is cleanups and minor fixes"

* tag 'modules-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux:
  livepatch: Call klp_match_callback() in klp_find_callback() to avoid code duplication
  module/decompress: Support zstd in-kernel decompression
  kallsyms: Remove unneeded semicolon
  kallsyms: Add self-test facility
  livepatch: Use kallsyms_on_each_match_symbol() to improve performance
  kallsyms: Add helper kallsyms_on_each_match_symbol()
  kallsyms: Reduce the memory occupied by kallsyms_seqs_of_names[]
  kallsyms: Correctly sequence symbols when CONFIG_LTO_CLANG=y
  kallsyms: Improve the performance of kallsyms_lookup_name()
  scripts/kallsyms: rename build_initial_tok_table()
  module: Fix NULL vs IS_ERR checking for module_get_next_page
  kernel/params.c: defer most of param_sysfs_init() to late_initcall time
  module: Remove unused macros module_addr_min/max
  module: remove redundant module_sysfs_initialized variable
parents 0015edd6 4f1354d5
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -66,9 +66,12 @@ static inline void *dereference_symbol_descriptor(void *ptr)
}

#ifdef CONFIG_KALLSYMS
unsigned long kallsyms_sym_address(int idx);
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 +171,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)
+0 −1
Original line number Diff line number Diff line
@@ -827,7 +827,6 @@ void *dereference_module_function_descriptor(struct module *mod, void *ptr)
#ifdef CONFIG_SYSFS
extern struct kset *module_kset;
extern struct kobj_type module_ktype;
extern int module_sysfs_initialized;
#endif /* CONFIG_SYSFS */

#define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x)
+13 −0
Original line number Diff line number Diff line
@@ -1723,6 +1723,19 @@ config KALLSYMS
	  symbolic stack backtraces. This increases the size of the kernel
	  somewhat, as all symbols have to be loaded into the kernel image.

config KALLSYMS_SELFTEST
	bool "Test the basic functions and performance of kallsyms"
	depends on KALLSYMS
	default n
	help
	  Test the basic functions and performance of some interfaces, such as
	  kallsyms_lookup_name. It also calculates the compression rate of the
	  kallsyms compression algorithm for the current symbol set.

	  Start self-test automatically after system startup. Suggest executing
	  "dmesg | grep kallsyms_selftest" to collect test results. "finish" is
	  displayed in the last line, indicating that the test is complete.

config KALLSYMS_ALL
	bool "Include all symbols in kallsyms"
	depends on DEBUG_KERNEL && KALLSYMS
+1 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ endif
obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULE_SIG_FORMAT) += module_signature.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o
obj-$(CONFIG_KALLSYMS_SELFTEST) += kallsyms_selftest.o
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
obj-$(CONFIG_CRASH_CORE) += crash_core.o
obj-$(CONFIG_KEXEC_CORE) += kexec_core.o
+104 −12
Original line number Diff line number Diff line
@@ -146,7 +146,7 @@ static unsigned int get_symbol_offset(unsigned long pos)
	return name - kallsyms_names;
}

static unsigned long kallsyms_sym_address(int idx)
unsigned long kallsyms_sym_address(int idx)
{
	if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
		return kallsyms_addresses[idx];
@@ -187,26 +187,100 @@ static bool cleanup_symbol_name(char *s)
	return false;
}

static int compare_symbol_name(const char *name, char *namebuf)
{
	int ret;

	ret = strcmp(name, namebuf);
	if (!ret)
		return ret;

	if (cleanup_symbol_name(namebuf) && !strcmp(name, namebuf))
		return 0;

	return ret;
}

static unsigned int get_symbol_seq(int index)
{
	unsigned int i, seq = 0;

	for (i = 0; i < 3; i++)
		seq = (seq << 8) | kallsyms_seqs_of_names[3 * index + i];

	return seq;
}

static int kallsyms_lookup_names(const char *name,
				 unsigned int *start,
				 unsigned int *end)
{
	int ret;
	int low, mid, high;
	unsigned int seq, off;
	char namebuf[KSYM_NAME_LEN];

	low = 0;
	high = kallsyms_num_syms - 1;

	while (low <= high) {
		mid = low + (high - low) / 2;
		seq = get_symbol_seq(mid);
		off = get_symbol_offset(seq);
		kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
		ret = compare_symbol_name(name, namebuf);
		if (ret > 0)
			low = mid + 1;
		else if (ret < 0)
			high = mid - 1;
		else
			break;
	}

	if (low > high)
		return -ESRCH;

	low = mid;
	while (low) {
		seq = get_symbol_seq(low - 1);
		off = get_symbol_offset(seq);
		kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
		if (compare_symbol_name(name, namebuf))
			break;
		low--;
	}
	*start = low;

	if (end) {
		high = mid;
		while (high < kallsyms_num_syms - 1) {
			seq = get_symbol_seq(high + 1);
			off = get_symbol_offset(seq);
			kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
			if (compare_symbol_name(name, namebuf))
				break;
			high++;
		}
		*end = high;
	}

	return 0;
}

/* Lookup the address for this symbol. Returns 0 if not found. */
unsigned long kallsyms_lookup_name(const char *name)
{
	char namebuf[KSYM_NAME_LEN];
	unsigned long i;
	unsigned int off;
	int ret;
	unsigned int i;

	/* Skip the search for empty string. */
	if (!*name)
		return 0;

	for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
		off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));

		if (strcmp(namebuf, name) == 0)
			return kallsyms_sym_address(i);
	ret = kallsyms_lookup_names(name, &i, NULL);
	if (!ret)
		return kallsyms_sym_address(get_symbol_seq(i));

		if (cleanup_symbol_name(namebuf) && strcmp(namebuf, name) == 0)
			return kallsyms_sym_address(i);
	}
	return module_kallsyms_lookup_name(name);
}

@@ -233,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)
Loading