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 Original line Diff line number Diff line
@@ -66,9 +66,12 @@ static inline void *dereference_symbol_descriptor(void *ptr)
}
}


#ifdef CONFIG_KALLSYMS
#ifdef CONFIG_KALLSYMS
unsigned long kallsyms_sym_address(int idx);
int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
				      unsigned long),
				      unsigned long),
			    void *data);
			    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. */
/* Lookup the address for a symbol. Returns 0 if not found. */
unsigned long kallsyms_lookup_name(const char *name);
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;
	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*/
#endif /*CONFIG_KALLSYMS*/


static inline void print_ip_sym(const char *loglvl, unsigned long ip)
static inline void print_ip_sym(const char *loglvl, unsigned long ip)
+0 −1
Original line number Original line Diff line number Diff line
@@ -827,7 +827,6 @@ void *dereference_module_function_descriptor(struct module *mod, void *ptr)
#ifdef CONFIG_SYSFS
#ifdef CONFIG_SYSFS
extern struct kset *module_kset;
extern struct kset *module_kset;
extern struct kobj_type module_ktype;
extern struct kobj_type module_ktype;
extern int module_sysfs_initialized;
#endif /* CONFIG_SYSFS */
#endif /* CONFIG_SYSFS */


#define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x)
#define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x)
+13 −0
Original line number Original line Diff line number Diff line
@@ -1723,6 +1723,19 @@ config KALLSYMS
	  symbolic stack backtraces. This increases the size of the kernel
	  symbolic stack backtraces. This increases the size of the kernel
	  somewhat, as all symbols have to be loaded into the kernel image.
	  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
config KALLSYMS_ALL
	bool "Include all symbols in kallsyms"
	bool "Include all symbols in kallsyms"
	depends on DEBUG_KERNEL && KALLSYMS
	depends on DEBUG_KERNEL && KALLSYMS
+1 −0
Original line number Original line Diff line number Diff line
@@ -69,6 +69,7 @@ endif
obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULE_SIG_FORMAT) += module_signature.o
obj-$(CONFIG_MODULE_SIG_FORMAT) += module_signature.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o
obj-$(CONFIG_KALLSYMS_SELFTEST) += kallsyms_selftest.o
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
obj-$(CONFIG_CRASH_CORE) += crash_core.o
obj-$(CONFIG_CRASH_CORE) += crash_core.o
obj-$(CONFIG_KEXEC_CORE) += kexec_core.o
obj-$(CONFIG_KEXEC_CORE) += kexec_core.o
+104 −12
Original line number Original line Diff line number Diff line
@@ -146,7 +146,7 @@ static unsigned int get_symbol_offset(unsigned long pos)
	return name - kallsyms_names;
	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))
	if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
		return kallsyms_addresses[idx];
		return kallsyms_addresses[idx];
@@ -187,26 +187,100 @@ static bool cleanup_symbol_name(char *s)
	return false;
	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. */
/* Lookup the address for this symbol. Returns 0 if not found. */
unsigned long kallsyms_lookup_name(const char *name)
unsigned long kallsyms_lookup_name(const char *name)
{
{
	char namebuf[KSYM_NAME_LEN];
	int ret;
	unsigned long i;
	unsigned int i;
	unsigned int off;


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


	for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
	ret = kallsyms_lookup_names(name, &i, NULL);
		off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
	if (!ret)

		return kallsyms_sym_address(get_symbol_seq(i));
		if (strcmp(namebuf, name) == 0)
			return kallsyms_sym_address(i);


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


@@ -233,6 +307,24 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
	return 0;
	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,
static unsigned long get_symbol_pos(unsigned long addr,
				    unsigned long *symbolsize,
				    unsigned long *symbolsize,
				    unsigned long *offset)
				    unsigned long *offset)
Loading