diff options
Diffstat (limited to 'tools/lib')
44 files changed, 307 insertions, 1237 deletions
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index c09cbb868c9f..725701235fd8 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -515,6 +515,7 @@ int bpf_map_lookup_and_delete_elem(int fd, const void *key, void *value) int bpf_map_lookup_and_delete_elem_flags(int fd, const void *key, void *value, __u64 flags) { union bpf_attr attr; + int ret; memset(&attr, 0, sizeof(attr)); attr.map_fd = fd; @@ -522,7 +523,8 @@ int bpf_map_lookup_and_delete_elem_flags(int fd, const void *key, void *value, _ attr.value = ptr_to_u64(value); attr.flags = flags; - return sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr)); + ret = sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr)); + return libbpf_err_errno(ret); } int bpf_map_delete_elem(int fd, const void *key) diff --git a/tools/lib/bpf/bpf_gen_internal.h b/tools/lib/bpf/bpf_gen_internal.h index d26e5472fe50..6f3df004479b 100644 --- a/tools/lib/bpf/bpf_gen_internal.h +++ b/tools/lib/bpf/bpf_gen_internal.h @@ -45,8 +45,8 @@ struct bpf_gen { int nr_fd_array; }; -void bpf_gen__init(struct bpf_gen *gen, int log_level); -int bpf_gen__finish(struct bpf_gen *gen); +void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps); +int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps); void bpf_gen__free(struct bpf_gen *gen); void bpf_gen__load_btf(struct bpf_gen *gen, const void *raw_data, __u32 raw_size); void bpf_gen__map_create(struct bpf_gen *gen, struct bpf_create_map_params *map_attr, int map_idx); diff --git a/tools/lib/bpf/gen_loader.c b/tools/lib/bpf/gen_loader.c index 502dea53a742..9934851ccde7 100644 --- a/tools/lib/bpf/gen_loader.c +++ b/tools/lib/bpf/gen_loader.c @@ -18,7 +18,7 @@ #define MAX_USED_MAPS 64 #define MAX_USED_PROGS 32 #define MAX_KFUNC_DESCS 256 -#define MAX_FD_ARRAY_SZ (MAX_USED_PROGS + MAX_KFUNC_DESCS) +#define MAX_FD_ARRAY_SZ (MAX_USED_MAPS + MAX_KFUNC_DESCS) /* The following structure describes the stack layout of the loader program. * In addition R6 contains the pointer to context. @@ -33,8 +33,8 @@ */ struct loader_stack { __u32 btf_fd; - __u32 prog_fd[MAX_USED_PROGS]; __u32 inner_map_fd; + __u32 prog_fd[MAX_USED_PROGS]; }; #define stack_off(field) \ @@ -42,6 +42,11 @@ struct loader_stack { #define attr_field(attr, field) (attr + offsetof(union bpf_attr, field)) +static int blob_fd_array_off(struct bpf_gen *gen, int index) +{ + return gen->fd_array + index * sizeof(int); +} + static int realloc_insn_buf(struct bpf_gen *gen, __u32 size) { size_t off = gen->insn_cur - gen->insn_start; @@ -102,11 +107,15 @@ static void emit2(struct bpf_gen *gen, struct bpf_insn insn1, struct bpf_insn in emit(gen, insn2); } -void bpf_gen__init(struct bpf_gen *gen, int log_level) +static int add_data(struct bpf_gen *gen, const void *data, __u32 size); +static void emit_sys_close_blob(struct bpf_gen *gen, int blob_off); + +void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps) { - size_t stack_sz = sizeof(struct loader_stack); + size_t stack_sz = sizeof(struct loader_stack), nr_progs_sz; int i; + gen->fd_array = add_data(gen, NULL, MAX_FD_ARRAY_SZ * sizeof(int)); gen->log_level = log_level; /* save ctx pointer into R6 */ emit(gen, BPF_MOV64_REG(BPF_REG_6, BPF_REG_1)); @@ -118,19 +127,27 @@ void bpf_gen__init(struct bpf_gen *gen, int log_level) emit(gen, BPF_MOV64_IMM(BPF_REG_3, 0)); emit(gen, BPF_EMIT_CALL(BPF_FUNC_probe_read_kernel)); + /* amount of stack actually used, only used to calculate iterations, not stack offset */ + nr_progs_sz = offsetof(struct loader_stack, prog_fd[nr_progs]); /* jump over cleanup code */ emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, - /* size of cleanup code below */ - (stack_sz / 4) * 3 + 2)); + /* size of cleanup code below (including map fd cleanup) */ + (nr_progs_sz / 4) * 3 + 2 + + /* 6 insns for emit_sys_close_blob, + * 6 insns for debug_regs in emit_sys_close_blob + */ + nr_maps * (6 + (gen->log_level ? 6 : 0)))); /* remember the label where all error branches will jump to */ gen->cleanup_label = gen->insn_cur - gen->insn_start; /* emit cleanup code: close all temp FDs */ - for (i = 0; i < stack_sz; i += 4) { + for (i = 0; i < nr_progs_sz; i += 4) { emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_10, -stack_sz + i)); emit(gen, BPF_JMP_IMM(BPF_JSLE, BPF_REG_1, 0, 1)); emit(gen, BPF_EMIT_CALL(BPF_FUNC_sys_close)); } + for (i = 0; i < nr_maps; i++) + emit_sys_close_blob(gen, blob_fd_array_off(gen, i)); /* R7 contains the error code from sys_bpf. Copy it into R0 and exit. */ emit(gen, BPF_MOV64_REG(BPF_REG_0, BPF_REG_7)); emit(gen, BPF_EXIT_INSN()); @@ -160,8 +177,6 @@ static int add_data(struct bpf_gen *gen, const void *data, __u32 size) */ static int add_map_fd(struct bpf_gen *gen) { - if (!gen->fd_array) - gen->fd_array = add_data(gen, NULL, MAX_FD_ARRAY_SZ * sizeof(int)); if (gen->nr_maps == MAX_USED_MAPS) { pr_warn("Total maps exceeds %d\n", MAX_USED_MAPS); gen->error = -E2BIG; @@ -174,8 +189,6 @@ static int add_kfunc_btf_fd(struct bpf_gen *gen) { int cur; - if (!gen->fd_array) - gen->fd_array = add_data(gen, NULL, MAX_FD_ARRAY_SZ * sizeof(int)); if (gen->nr_fd_array == MAX_KFUNC_DESCS) { cur = add_data(gen, NULL, sizeof(int)); return (cur - gen->fd_array) / sizeof(int); @@ -183,11 +196,6 @@ static int add_kfunc_btf_fd(struct bpf_gen *gen) return MAX_USED_MAPS + gen->nr_fd_array++; } -static int blob_fd_array_off(struct bpf_gen *gen, int index) -{ - return gen->fd_array + index * sizeof(int); -} - static int insn_bytes_to_bpf_size(__u32 sz) { switch (sz) { @@ -359,10 +367,15 @@ static void emit_sys_close_blob(struct bpf_gen *gen, int blob_off) __emit_sys_close(gen); } -int bpf_gen__finish(struct bpf_gen *gen) +int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps) { int i; + if (nr_progs != gen->nr_progs || nr_maps != gen->nr_maps) { + pr_warn("progs/maps mismatch\n"); + gen->error = -EFAULT; + return gen->error; + } emit_sys_close_stack(gen, stack_off(btf_fd)); for (i = 0; i < gen->nr_progs; i++) move_stack2ctx(gen, diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index a1bea1953df6..7c74342bb668 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -7258,7 +7258,7 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr) } if (obj->gen_loader) - bpf_gen__init(obj->gen_loader, attr->log_level); + bpf_gen__init(obj->gen_loader, attr->log_level, obj->nr_programs, obj->nr_maps); err = bpf_object__probe_loading(obj); err = err ? : bpf_object__load_vmlinux_btf(obj, false); @@ -7277,7 +7277,7 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr) for (i = 0; i < obj->nr_maps; i++) obj->maps[i].fd = -1; if (!err) - err = bpf_gen__finish(obj->gen_loader); + err = bpf_gen__finish(obj->gen_loader, obj->nr_programs, obj->nr_maps); } /* clean up fd_array */ diff --git a/tools/lib/list_sort.c b/tools/lib/list_sort.c new file mode 100644 index 000000000000..10c067e3a8d2 --- /dev/null +++ b/tools/lib/list_sort.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/kernel.h> +#include <linux/compiler.h> +#include <linux/export.h> +#include <linux/string.h> +#include <linux/list_sort.h> +#include <linux/list.h> + +/* + * Returns a list organized in an intermediate format suited + * to chaining of merge() calls: null-terminated, no reserved or + * sentinel head node, "prev" links not maintained. + */ +__attribute__((nonnull(2,3,4))) +static struct list_head *merge(void *priv, list_cmp_func_t cmp, + struct list_head *a, struct list_head *b) +{ + struct list_head *head, **tail = &head; + + for (;;) { + /* if equal, take 'a' -- important for sort stability */ + if (cmp(priv, a, b) <= 0) { + *tail = a; + tail = &a->next; + a = a->next; + if (!a) { + *tail = b; + break; + } + } else { + *tail = b; + tail = &b->next; + b = b->next; + if (!b) { + *tail = a; + break; + } + } + } + return head; +} + +/* + * Combine final list merge with restoration of standard doubly-linked + * list structure. This approach duplicates code from merge(), but + * runs faster than the tidier alternatives of either a separate final + * prev-link restoration pass, or maintaining the prev links + * throughout. + */ +__attribute__((nonnull(2,3,4,5))) +static void merge_final(void *priv, list_cmp_func_t cmp, struct list_head *head, + struct list_head *a, struct list_head *b) +{ + struct list_head *tail = head; + u8 count = 0; + + for (;;) { + /* if equal, take 'a' -- important for sort stability */ + if (cmp(priv, a, b) <= 0) { + tail->next = a; + a->prev = tail; + tail = a; + a = a->next; + if (!a) + break; + } else { + tail->next = b; + b->prev = tail; + tail = b; + b = b->next; + if (!b) { + b = a; + break; + } + } + } + + /* Finish linking remainder of list b on to tail */ + tail->next = b; + do { + /* + * If the merge is highly unbalanced (e.g. the input is + * already sorted), this loop may run many iterations. + * Continue callbacks to the client even though no + * element comparison is needed, so the client's cmp() + * routine can invoke cond_resched() periodically. + */ + if (unlikely(!++count)) + cmp(priv, b, b); + b->prev = tail; + tail = b; + b = b->next; + } while (b); + + /* And the final links to make a circular doubly-linked list */ + tail->next = head; + head->prev = tail; +} + +/** + * list_sort - sort a list + * @priv: private data, opaque to list_sort(), passed to @cmp + * @head: the list to sort + * @cmp: the elements comparison function + * + * The comparison function @cmp must return > 0 if @a should sort after + * @b ("@a > @b" if you want an ascending sort), and <= 0 if @a should + * sort before @b *or* their original order should be preserved. It is + * always called with the element that came first in the input in @a, + * and list_sort is a stable sort, so it is not necessary to distinguish + * the @a < @b and @a == @b cases. + * + * This is compatible with two styles of @cmp function: + * - The traditional style which returns <0 / =0 / >0, or + * - Returning a boolean 0/1. + * The latter offers a chance to save a few cycles in the comparison + * (which is used by e.g. plug_ctx_cmp() in block/blk-mq.c). + * + * A good way to write a multi-word comparison is:: + * + * if (a->high != b->high) + * return a->high > b->high; + * if (a->middle != b->middle) + * return a->middle > b->middle; + * return a->low > b->low; + * + * + * This mergesort is as eager as possible while always performing at least + * 2:1 balanced merges. Given two pending sublists of size 2^k, they are + * merged to a size-2^(k+1) list as soon as we have 2^k following elements. + * + * Thus, it will avoid cache thrashing as long as 3*2^k elements can + * fit into the cache. Not quite as good as a fully-eager bottom-up + * mergesort, but it does use 0.2*n fewer comparisons, so is faster in + * the common case that everything fits into L1. + * + * + * The merging is controlled by "count", the number of elements in the + * pending lists. This is beautifully simple code, but rather subtle. + * + * Each time we increment "count", we set one bit (bit k) and clear + * bits k-1 .. 0. Each time this happens (except the very first time + * for each bit, when count increments to 2^k), we merge two lists of + * size 2^k into one list of size 2^(k+1). + * + * This merge happens exactly when the count reaches an odd multiple of + * 2^k, which is when we have 2^k elements pending in smaller lists, + * so it's safe to merge away two lists of size 2^k. + * + * After this happens twice, we have created two lists of size 2^(k+1), + * which will be merged into a list of size 2^(k+2) before we create + * a third list of size 2^(k+1), so there are never more than two pending. + * + * The number of pending lists of size 2^k is determined by the + * state of bit k of "count" plus two extra pieces of information: + * + * - The state of bit k-1 (when k == 0, consider bit -1 always set), and + * - Whether the higher-order bits are zero or non-zero (i.e. + * is count >= 2^(k+1)). + * + * There are six states we distinguish. "x" represents some arbitrary + * bits, and "y" represents some arbitrary non-zero bits: + * 0: 00x: 0 pending of size 2^k; x pending of sizes < 2^k + * 1: 01x: 0 pending of size 2^k; 2^(k-1) + x pending of sizes < 2^k + * 2: x10x: 0 pending of size 2^k; 2^k + x pending of sizes < 2^k + * 3: x11x: 1 pending of size 2^k; 2^(k-1) + x pending of sizes < 2^k + * 4: y00x: 1 pending of size 2^k; 2^k + x pending of sizes < 2^k + * 5: y01x: 2 pending of size 2^k; 2^(k-1) + x pending of sizes < 2^k + * (merge and loop back to state 2) + * + * We gain lists of size 2^k in the 2->3 and 4->5 transitions (because + * bit k-1 is set while the more significant bits are non-zero) and + * merge them away in the 5->2 transition. Note in particular that just + * before the 5->2 transition, all lower-order bits are 11 (state 3), + * so there is one list of each smaller size. + * + * When we reach the end of the input, we merge all the pending + * lists, from smallest to largest. If you work through cases 2 to + * 5 above, you can see that the number of elements we merge with a list + * of size 2^k varies from 2^(k-1) (cases 3 and 5 when x == 0) to + * 2^(k+1) - 1 (second merge of case 5 when x == 2^(k-1) - 1). + */ +__attribute__((nonnull(2,3))) +void list_sort(void *priv, struct list_head *head, list_cmp_func_t cmp) +{ + struct list_head *list = head->next, *pending = NULL; + size_t count = 0; /* Count of pending */ + + if (list == head->prev) /* Zero or one elements */ + return; + + /* Convert to a null-terminated singly-linked list. */ + head->prev->next = NULL; + + /* + * Data structure invariants: + * - All lists are singly linked and null-terminated; prev + * pointers are not maintained. + * - pending is a prev-linked "list of lists" of sorted + * sublists awaiting further merging. + * - Each of the sorted sublists is power-of-two in size. + * - Sublists are sorted by size and age, smallest & newest at front. + * - There are zero to two sublists of each size. + * - A pair of pending sublists are merged as soon as the number + * of following pending elements equals their size (i.e. + * each time count reaches an odd multiple of that size). + * That ensures each later final merge will be at worst 2:1. + * - Each round consists of: + * - Merging the two sublists selected by the highest bit + * which flips when count is incremented, and + * - Adding an element from the input as a size-1 sublist. + */ + do { + size_t bits; + struct list_head **tail = &pending; + + /* Find the least-significant clear bit in count */ + for (bits = count; bits & 1; bits >>= 1) + tail = &(*tail)->prev; + /* Do the indicated merge */ + if (likely(bits)) { + struct list_head *a = *tail, *b = a->prev; + + a = merge(priv, cmp, b, a); + /* Install the merged result in place of the inputs */ + a->prev = b->prev; + *tail = a; + } + + /* Move one element from input list to pending */ + list->prev = pending; + pending = list; + list = list->next; + pending->next = NULL; + count++; + } while (list); + + /* End of input; merge together all the pending lists. */ + list = pending; + pending = pending->prev; + for (;;) { + struct list_head *next = pending->prev; + + if (!next) + break; + list = merge(priv, cmp, pending, list); + pending = next; + } + /* The final merge, rebuilding prev links */ + merge_final(priv, cmp, head, pending, list); +} +EXPORT_SYMBOL(list_sort); diff --git a/tools/lib/lockdep/.gitignore b/tools/lib/lockdep/.gitignore deleted file mode 100644 index 6c308ac4388c..000000000000 --- a/tools/lib/lockdep/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -liblockdep.so.* diff --git a/tools/lib/lockdep/Build b/tools/lib/lockdep/Build deleted file mode 100644 index 6f667355b068..000000000000 --- a/tools/lib/lockdep/Build +++ /dev/null @@ -1 +0,0 @@ -liblockdep-y += common.o lockdep.o preload.o rbtree.o diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile deleted file mode 100644 index 9dafb8cb752f..000000000000 --- a/tools/lib/lockdep/Makefile +++ /dev/null @@ -1,162 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# file format version -FILE_VERSION = 1 - -LIBLOCKDEP_VERSION=$(shell make --no-print-directory -sC ../../.. kernelversion) - -# Makefiles suck: This macro sets a default value of $(2) for the -# variable named by $(1), unless the variable has been set by -# environment or command line. This is necessary for CC and AR -# because make sets default values, so the simpler ?= approach -# won't work as expected. -define allow-override - $(if $(or $(findstring environment,$(origin $(1))),\ - $(findstring command line,$(origin $(1)))),,\ - $(eval $(1) = $(2))) -endef - -# Allow setting CC and AR and LD, or setting CROSS_COMPILE as a prefix. -$(call allow-override,CC,$(CROSS_COMPILE)gcc) -$(call allow-override,AR,$(CROSS_COMPILE)ar) -$(call allow-override,LD,$(CROSS_COMPILE)ld) - -INSTALL = install - -# Use DESTDIR for installing into a different root directory. -# This is useful for building a package. The program will be -# installed in this directory as if it was the root directory. -# Then the build tool can move it later. -DESTDIR ?= -DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))' - -prefix ?= /usr/local -libdir_relative = lib -libdir = $(prefix)/$(libdir_relative) -bindir_relative = bin -bindir = $(prefix)/$(bindir_relative) - -export DESTDIR DESTDIR_SQ INSTALL - -MAKEFLAGS += --no-print-directory - -include ../../scripts/Makefile.include - -# copy a bit from Linux kbuild - -ifeq ("$(origin V)", "command line") - VERBOSE = $(V) -endif -ifndef VERBOSE - VERBOSE = 0 -endif - -ifeq ($(srctree),) -srctree := $(patsubst %/,%,$(dir $(CURDIR))) -srctree := $(patsubst %/,%,$(dir $(srctree))) -srctree := $(patsubst %/,%,$(dir $(srctree))) -#$(info Determined 'srctree' to be $(srctree)) -endif - -# Shell quotes -libdir_SQ = $(subst ','\'',$(libdir)) -bindir_SQ = $(subst ','\'',$(bindir)) - -LIB_IN := $(OUTPUT)liblockdep-in.o - -BIN_FILE = lockdep -LIB_FILE = $(OUTPUT)liblockdep.a $(OUTPUT)liblockdep.so.$(LIBLOCKDEP_VERSION) - -CONFIG_INCLUDES = -CONFIG_LIBS = -CONFIG_FLAGS = - -OBJ = $@ -N = - -export Q VERBOSE - -INCLUDES = -I. -I./uinclude -I./include -I../../include $(CONFIG_INCLUDES) - -# Set compile option CFLAGS if not set elsewhere -CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g -CFLAGS += -fPIC -CFLAGS += -Wall - -override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ) - -ifeq ($(VERBOSE),1) - Q = - print_shared_lib_compile = - print_install = -else - Q = @ - print_shared_lib_compile = echo ' LD '$(OBJ); - print_static_lib_build = echo ' LD '$(OBJ); - print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; -endif - -all: - -export srctree OUTPUT CC LD CFLAGS V -include $(srctree)/tools/build/Makefile.include - -do_compile_shared_library = \ - ($(print_shared_lib_compile) \ - $(CC) $(LDFLAGS) --shared $^ -o $@ -lpthread -ldl -Wl,-soname='$(@F)';$(shell ln -sf $(@F) $(@D)/liblockdep.so)) - -do_build_static_lib = \ - ($(print_static_lib_build) \ - $(RM) $@; $(AR) rcs $@ $^) - -CMD_TARGETS = $(LIB_FILE) - -TARGETS = $(CMD_TARGETS) - - -all: fixdep all_cmd - -all_cmd: $(CMD_TARGETS) - -$(LIB_IN): force - $(Q)$(MAKE) $(build)=liblockdep - -$(OUTPUT)liblockdep.so.$(LIBLOCKDEP_VERSION): $(LIB_IN) - $(Q)$(do_compile_shared_library) - -$(OUTPUT)liblockdep.a: $(LIB_IN) - $(Q)$(do_build_static_lib) - -tags: force - $(RM) tags - find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ - --regex-c++='/_PE\(([^,)]*).*/TEP_ERRNO__\1/' - -TAGS: force - $(RM) TAGS - find . -name '*.[ch]' | xargs etags \ - --regex='/_PE(\([^,)]*\).*/TEP_ERRNO__\1/' - -define do_install - $(print_install) \ - if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ - $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ - fi; \ - $(INSTALL) $1 '$(DESTDIR_SQ)$2' -endef - -install_lib: all_cmd - $(Q)$(call do_install,$(LIB_FILE),$(libdir_SQ)) - $(Q)$(call do_install,$(BIN_FILE),$(bindir_SQ)) - -install: install_lib - -clean: - $(RM) $(OUTPUT)*.o *~ $(TARGETS) $(OUTPUT)*.a $(OUTPUT)*liblockdep*.so* $(VERSION_FILES) $(OUTPUT).*.d $(OUTPUT).*.cmd - $(RM) tags TAGS - -PHONY += force -force: - -# Declare the contents of the .PHONY variable as phony. We keep that -# information in a variable so we can use it in if_changed and friends. -.PHONY: $(PHONY) diff --git a/tools/lib/lockdep/common.c b/tools/lib/lockdep/common.c deleted file mode 100644 index 5c3b58cce8a9..000000000000 --- a/tools/lib/lockdep/common.c +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <stddef.h> -#include <stdbool.h> -#include <linux/compiler.h> -#include <linux/lockdep.h> -#include <unistd.h> -#include <sys/syscall.h> - -static __thread struct task_struct current_obj; - -/* lockdep wants these */ -bool debug_locks = true; -bool debug_locks_silent; - -__attribute__((destructor)) static void liblockdep_exit(void) -{ - debug_check_no_locks_held(); -} - -struct task_struct *__curr(void) -{ - if (current_obj.pid == 0) { - /* Makes lockdep output pretty */ - prctl(PR_GET_NAME, current_obj.comm); - current_obj.pid = syscall(__NR_gettid); - } - - return ¤t_obj; -} diff --git a/tools/lib/lockdep/include/liblockdep/common.h b/tools/lib/lockdep/include/liblockdep/common.h deleted file mode 100644 index a6d7ee5f18ba..000000000000 --- a/tools/lib/lockdep/include/liblockdep/common.h +++ /dev/null @@ -1,54 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _LIBLOCKDEP_COMMON_H -#define _LIBLOCKDEP_COMMON_H - -#include <pthread.h> - -#define NR_LOCKDEP_CACHING_CLASSES 2 -#define MAX_LOCKDEP_SUBCLASSES 8UL - -#ifndef CALLER_ADDR0 -#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0)) -#endif - -#ifndef _RET_IP_ -#define _RET_IP_ CALLER_ADDR0 -#endif - -#ifndef _THIS_IP_ -#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; }) -#endif - -struct lockdep_subclass_key { - char __one_byte; -}; - -struct lock_class_key { - struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES]; -}; - -struct lockdep_map { - struct lock_class_key *key; - struct lock_class *class_cache[NR_LOCKDEP_CACHING_CLASSES]; - const char *name; -#ifdef CONFIG_LOCK_STAT - int cpu; - unsigned long ip; -#endif -}; - -void lockdep_init_map(struct lockdep_map *lock, const char *name, - struct lock_class_key *key, int subclass); -void lock_acquire(struct lockdep_map *lock, unsigned int subclass, - int trylock, int read, int check, - struct lockdep_map *nest_lock, unsigned long ip); -void lock_release(struct lockdep_map *lock, unsigned long ip); -void lockdep_reset_lock(struct lockdep_map *lock); -void lockdep_register_key(struct lock_class_key *key); -void lockdep_unregister_key(struct lock_class_key *key); -extern void debug_check_no_locks_freed(const void *from, unsigned long len); - -#define STATIC_LOCKDEP_MAP_INIT(_name, _key) \ - { .name = (_name), .key = (void *)(_key), } - -#endif diff --git a/tools/lib/lockdep/include/liblockdep/mutex.h b/tools/lib/lockdep/include/liblockdep/mutex.h deleted file mode 100644 index bd106b82759b..000000000000 --- a/tools/lib/lockdep/include/liblockdep/mutex.h +++ /dev/null @@ -1,73 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _LIBLOCKDEP_MUTEX_H -#define _LIBLOCKDEP_MUTEX_H - -#include <pthread.h> -#include "common.h" - -struct liblockdep_pthread_mutex { - pthread_mutex_t mutex; - struct lock_class_key key; - struct lockdep_map dep_map; -}; - -typedef struct liblockdep_pthread_mutex liblockdep_pthread_mutex_t; - -#define LIBLOCKDEP_PTHREAD_MUTEX_INITIALIZER(mtx) \ - (const struct liblockdep_pthread_mutex) { \ - .mutex = PTHREAD_MUTEX_INITIALIZER, \ - .dep_map = STATIC_LOCKDEP_MAP_INIT(#mtx, &((&(mtx))->dep_map)), \ -} - -static inline int __mutex_init(liblockdep_pthread_mutex_t *lock, - const char *name, - struct lock_class_key *key, - const pthread_mutexattr_t *__mutexattr) -{ - lockdep_init_map(&lock->dep_map, name, key, 0); - return pthread_mutex_init(&lock->mutex, __mutexattr); -} - -#define liblockdep_pthread_mutex_init(mutex, mutexattr) \ -({ \ - lockdep_register_key(&(mutex)->key); \ - __mutex_init((mutex), #mutex, &(mutex)->key, (mutexattr)); \ -}) - -static inline int liblockdep_pthread_mutex_lock(liblockdep_pthread_mutex_t *lock) -{ - lock_acquire(&lock->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_); - return pthread_mutex_lock(&lock->mutex); -} - -static inline int liblockdep_pthread_mutex_unlock(liblockdep_pthread_mutex_t *lock) -{ - lock_release(&lock->dep_map, (unsigned long)_RET_IP_); - return pthread_mutex_unlock(&lock->mutex); -} - -static inline int liblockdep_pthread_mutex_trylock(liblockdep_pthread_mutex_t *lock) -{ - lock_acquire(&lock->dep_map, 0, 1, 0, 1, NULL, (unsigned long)_RET_IP_); - return pthread_mutex_trylock(&lock->mutex) == 0 ? 1 : 0; -} - -static inline int liblockdep_pthread_mutex_destroy(liblockdep_pthread_mutex_t *lock) -{ - lockdep_reset_lock(&lock->dep_map); - lockdep_unregister_key(&lock->key); - return pthread_mutex_destroy(&lock->mutex); -} - -#ifdef __USE_LIBLOCKDEP - -#define pthread_mutex_t liblockdep_pthread_mutex_t -#define pthread_mutex_init liblockdep_pthread_mutex_init -#define pthread_mutex_lock liblockdep_pthread_mutex_lock -#define pthread_mutex_unlock liblockdep_pthread_mutex_unlock -#define pthread_mutex_trylock liblockdep_pthread_mutex_trylock -#define pthread_mutex_destroy liblockdep_pthread_mutex_destroy - -#endif - -#endif diff --git a/tools/lib/lockdep/include/liblockdep/rwlock.h b/tools/lib/lockdep/include/liblockdep/rwlock.h deleted file mode 100644 index 6d5d2932bf4d..000000000000 --- a/tools/lib/lockdep/include/liblockdep/rwlock.h +++ /dev/null @@ -1,87 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _LIBLOCKDEP_RWLOCK_H -#define _LIBLOCKDEP_RWLOCK_H - -#include <pthread.h> -#include "common.h" - -struct liblockdep_pthread_rwlock { - pthread_rwlock_t rwlock; - struct lockdep_map dep_map; -}; - -typedef struct liblockdep_pthread_rwlock liblockdep_pthread_rwlock_t; - -#define LIBLOCKDEP_PTHREAD_RWLOCK_INITIALIZER(rwl) \ - (struct liblockdep_pthread_rwlock) { \ - .rwlock = PTHREAD_RWLOCK_INITIALIZER, \ - .dep_map = STATIC_LOCKDEP_MAP_INIT(#rwl, &((&(rwl))->dep_map)), \ -} - -static inline int __rwlock_init(liblockdep_pthread_rwlock_t *lock, - const char *name, - struct lock_class_key *key, - const pthread_rwlockattr_t *attr) -{ - lockdep_init_map(&lock->dep_map, name, key, 0); - - return pthread_rwlock_init(&lock->rwlock, attr); -} - -#define liblockdep_pthread_rwlock_init(lock, attr) \ -({ \ - static struct lock_class_key __key; \ - \ - __rwlock_init((lock), #lock, &__key, (attr)); \ -}) - -static inline int liblockdep_pthread_rwlock_rdlock(liblockdep_pthread_rwlock_t *lock) -{ - lock_acquire(&lock->dep_map, 0, 0, 2, 1, NULL, (unsigned long)_RET_IP_); - return pthread_rwlock_rdlock(&lock->rwlock); - -} - -static inline int liblockdep_pthread_rwlock_unlock(liblockdep_pthread_rwlock_t *lock) -{ - lock_release(&lock->dep_map, (unsigned long)_RET_IP_); - return pthread_rwlock_unlock(&lock->rwlock); -} - -static inline int liblockdep_pthread_rwlock_wrlock(liblockdep_pthread_rwlock_t *lock) -{ - lock_acquire(&lock->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_); - return pthread_rwlock_wrlock(&lock->rwlock); -} - -static inline int liblockdep_pthread_rwlock_tryrdlock(liblockdep_pthread_rwlock_t *lock) -{ - lock_acquire(&lock->dep_map, 0, 1, 2, 1, NULL, (unsigned long)_RET_IP_); - return pthread_rwlock_tryrdlock(&lock->rwlock) == 0 ? 1 : 0; -} - -static inline int liblockdep_pthread_rwlock_trywrlock(liblockdep_pthread_rwlock_t *lock) -{ - lock_acquire(&lock->dep_map, 0, 1, 0, 1, NULL, (unsigned long)_RET_IP_); - return pthread_rwlock_trywrlock(&lock->rwlock) == 0 ? 1 : 0; -} - -static inline int liblockdep_rwlock_destroy(liblockdep_pthread_rwlock_t *lock) -{ - return pthread_rwlock_destroy(&lock->rwlock); -} - -#ifdef __USE_LIBLOCKDEP - -#define pthread_rwlock_t liblockdep_pthread_rwlock_t -#define pthread_rwlock_init liblockdep_pthread_rwlock_init -#define pthread_rwlock_rdlock liblockdep_pthread_rwlock_rdlock -#define pthread_rwlock_unlock liblockdep_pthread_rwlock_unlock -#define pthread_rwlock_wrlock liblockdep_pthread_rwlock_wrlock -#define pthread_rwlock_tryrdlock liblockdep_pthread_rwlock_tryrdlock -#define pthread_rwlock_trywrlock liblockdep_pthread_rwlock_trywrlock -#define pthread_rwlock_destroy liblockdep_rwlock_destroy - -#endif - -#endif diff --git a/tools/lib/lockdep/lockdep b/tools/lib/lockdep/lockdep deleted file mode 100755 index 49af9fe19f5b..000000000000 --- a/tools/lib/lockdep/lockdep +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -LD_PRELOAD="./liblockdep.so $LD_PRELOAD" "$@" diff --git a/tools/lib/lockdep/lockdep.c b/tools/lib/lockdep/lockdep.c deleted file mode 100644 index 348a9d0fb766..000000000000 --- a/tools/lib/lockdep/lockdep.c +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/lockdep.h> -#include <stdlib.h> - -/* Trivial API wrappers, we don't (yet) have RCU in user-space: */ -#define hlist_for_each_entry_rcu hlist_for_each_entry -#define hlist_add_head_rcu hlist_add_head -#define hlist_del_rcu hlist_del -#define list_for_each_entry_rcu list_for_each_entry -#define list_add_tail_rcu list_add_tail - -u32 prandom_u32(void) -{ - /* Used only by lock_pin_lock() which is dead code */ - abort(); -} - -void print_irqtrace_events(struct task_struct *curr) -{ - abort(); -} - -static struct new_utsname *init_utsname(void) -{ - static struct new_utsname n = (struct new_utsname) { - .release = "liblockdep", - .version = LIBLOCKDEP_VERSION, - }; - - return &n; -} - -#include "../../../kernel/locking/lockdep.c" diff --git a/tools/lib/lockdep/lockdep_internals.h b/tools/lib/lockdep/lockdep_internals.h deleted file mode 100644 index 29d0c954cc24..000000000000 --- a/tools/lib/lockdep/lockdep_internals.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../../kernel/locking/lockdep_internals.h" diff --git a/tools/lib/lockdep/lockdep_states.h b/tools/lib/lockdep/lockdep_states.h deleted file mode 100644 index 248d235efda9..000000000000 --- a/tools/lib/lockdep/lockdep_states.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../../kernel/locking/lockdep_states.h" diff --git a/tools/lib/lockdep/preload.c b/tools/lib/lockdep/preload.c deleted file mode 100644 index 8f1adbe887b2..000000000000 --- a/tools/lib/lockdep/preload.c +++ /dev/null @@ -1,443 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#define _GNU_SOURCE -#include <pthread.h> -#include <stdio.h> -#include <dlfcn.h> -#include <stdlib.h> -#include <sysexits.h> -#include <unistd.h> -#include "include/liblockdep/mutex.h" -#include "../../include/linux/rbtree.h" - -/** - * struct lock_lookup - liblockdep's view of a single unique lock - * @orig: pointer to the original pthread lock, used for lookups - * @dep_map: lockdep's dep_map structure - * @key: lockdep's key structure - * @node: rb-tree node used to store the lock in a global tree - * @name: a unique name for the lock - */ -struct lock_lookup { - void *orig; /* Original pthread lock, used for lookups */ - struct lockdep_map dep_map; /* Since all locks are dynamic, we need - * a dep_map and a key for each lock */ - /* - * Wait, there's no support for key classes? Yup :( - * Most big projects wrap the pthread api with their own calls to - * be compatible with different locking methods. This means that - * "classes" will be brokes since the function that creates all - * locks will point to a generic locking function instead of the - * actual code that wants to do the locking. - */ - struct lock_class_key key; - struct rb_node node; -#define LIBLOCKDEP_MAX_LOCK_NAME 22 - char name[LIBLOCKDEP_MAX_LOCK_NAME]; -}; - -/* This is where we store our locks */ -static struct rb_root locks = RB_ROOT; -static pthread_rwlock_t locks_rwlock = PTHREAD_RWLOCK_INITIALIZER; - -/* pthread mutex API */ - -#ifdef __GLIBC__ -extern int __pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); -extern int __pthread_mutex_lock(pthread_mutex_t *mutex); -extern int __pthread_mutex_trylock(pthread_mutex_t *mutex); -extern int __pthread_mutex_unlock(pthread_mutex_t *mutex); -extern int __pthread_mutex_destroy(pthread_mutex_t *mutex); -#else -#define __pthread_mutex_init NULL -#define __pthread_mutex_lock NULL -#define __pthread_mutex_trylock NULL -#define __pthread_mutex_unlock NULL -#define __pthread_mutex_destroy NULL -#endif -static int (*ll_pthread_mutex_init)(pthread_mutex_t *mutex, - const pthread_mutexattr_t *attr) = __pthread_mutex_init; -static int (*ll_pthread_mutex_lock)(pthread_mutex_t *mutex) = __pthread_mutex_lock; -static int (*ll_pthread_mutex_trylock)(pthread_mutex_t *mutex) = __pthread_mutex_trylock; -static int (*ll_pthread_mutex_unlock)(pthread_mutex_t *mutex) = __pthread_mutex_unlock; -static int (*ll_pthread_mutex_destroy)(pthread_mutex_t *mutex) = __pthread_mutex_destroy; - -/* pthread rwlock API */ - -#ifdef __GLIBC__ -extern int __pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); -extern int __pthread_rwlock_destroy(pthread_rwlock_t *rwlock); -extern int __pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); -extern int __pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); -extern int __pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); -extern int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); -extern int __pthread_rwlock_unlock(pthread_rwlock_t *rwlock); -#else -#define __pthread_rwlock_init NULL -#define __pthread_rwlock_destroy NULL -#define __pthread_rwlock_wrlock NULL -#define __pthread_rwlock_trywrlock NULL -#define __pthread_rwlock_rdlock NULL -#define __pthread_rwlock_tryrdlock NULL -#define __pthread_rwlock_unlock NULL -#endif - -static int (*ll_pthread_rwlock_init)(pthread_rwlock_t *rwlock, - const pthread_rwlockattr_t *attr) = __pthread_rwlock_init; -static int (*ll_pthread_rwlock_destroy)(pthread_rwlock_t *rwlock) = __pthread_rwlock_destroy; -static int (*ll_pthread_rwlock_rdlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_rdlock; -static int (*ll_pthread_rwlock_tryrdlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_tryrdlock; -static int (*ll_pthread_rwlock_trywrlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_trywrlock; -static int (*ll_pthread_rwlock_wrlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_wrlock; -static int (*ll_pthread_rwlock_unlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_unlock; - -enum { none, prepare, done, } __init_state; -static void init_preload(void); -static void try_init_preload(void) -{ - if (__init_state != done) - init_preload(); -} - -static struct rb_node **__get_lock_node(void *lock, struct rb_node **parent) -{ - struct rb_node **node = &locks.rb_node; - struct lock_lookup *l; - - *parent = NULL; - - while (*node) { - l = rb_entry(*node, struct lock_lookup, node); - - *parent = *node; - if (lock < l->orig) - node = &l->node.rb_left; - else if (lock > l->orig) - node = &l->node.rb_right; - else - return node; - } - - return node; -} - -#ifndef LIBLOCKDEP_STATIC_ENTRIES -#define LIBLOCKDEP_STATIC_ENTRIES 1024 -#endif - -static struct lock_lookup __locks[LIBLOCKDEP_STATIC_ENTRIES]; -static int __locks_nr; - -static inline bool is_static_lock(struct lock_lookup *lock) -{ - return lock >= __locks && lock < __locks + ARRAY_SIZE(__locks); -} - -static struct lock_lookup *alloc_lock(void) -{ - if (__init_state != done) { - /* - * Some programs attempt to initialize and use locks in their - * allocation path. This means that a call to malloc() would - * result in locks being initialized and locked. - * - * Why is it an issue for us? dlsym() below will try allocating - * to give us the original function. Since this allocation will - * result in a locking operations, we have to let pthread deal - * with it, but we can't! we don't have the pointer to the - * original API since we're inside dlsym() trying to get it - */ - - int idx = __locks_nr++; - if (idx >= ARRAY_SIZE(__locks)) { - dprintf(STDERR_FILENO, - "LOCKDEP error: insufficient LIBLOCKDEP_STATIC_ENTRIES\n"); - exit(EX_UNAVAILABLE); - } - return __locks + idx; - } - - return malloc(sizeof(struct lock_lookup)); -} - -static inline void free_lock(struct lock_lookup *lock) -{ - if (likely(!is_static_lock(lock))) - free(lock); -} - -/** - * __get_lock - find or create a lock instance - * @lock: pointer to a pthread lock function - * - * Try to find an existing lock in the rbtree using the provided pointer. If - * one wasn't found - create it. - */ -static struct lock_lookup *__get_lock(void *lock) -{ - struct rb_node **node, *parent; - struct lock_lookup *l; - - ll_pthread_rwlock_rdlock(&locks_rwlock); - node = __get_lock_node(lock, &parent); - ll_pthread_rwlock_unlock(&locks_rwlock); - if (*node) { - return rb_entry(*node, struct lock_lookup, node); - } - - /* We didn't find the lock, let's create it */ - l = alloc_lock(); - if (l == NULL) - return NULL; - - l->orig = lock; - /* - * Currently the name of the lock is the ptr value of the pthread lock, - * while not optimal, it makes debugging a bit easier. - * - * TODO: Get the real name of the lock using libdwarf - */ - sprintf(l->name, "%p", lock); - lockdep_init_map(&l->dep_map, l->name, &l->key, 0); - - ll_pthread_rwlock_wrlock(&locks_rwlock); - /* This might have changed since the last time we fetched it */ - node = __get_lock_node(lock, &parent); - rb_link_node(&l->node, parent, node); - rb_insert_color(&l->node, &locks); - ll_pthread_rwlock_unlock(&locks_rwlock); - - return l; -} - -static void __del_lock(struct lock_lookup *lock) -{ - ll_pthread_rwlock_wrlock(&locks_rwlock); - rb_erase(&lock->node, &locks); - ll_pthread_rwlock_unlock(&locks_rwlock); - free_lock(lock); -} - -int pthread_mutex_init(pthread_mutex_t *mutex, - const pthread_mutexattr_t *attr) -{ - int r; - - /* - * We keep trying to init our preload module because there might be - * code in init sections that tries to touch locks before we are - * initialized, in that case we'll need to manually call preload - * to get us going. - * - * Funny enough, kernel's lockdep had the same issue, and used - * (almost) the same solution. See look_up_lock_class() in - * kernel/locking/lockdep.c for details. - */ - try_init_preload(); - - r = ll_pthread_mutex_init(mutex, attr); - if (r == 0) - /* - * We do a dummy initialization here so that lockdep could - * warn us if something fishy is going on - such as - * initializing a held lock. - */ - __get_lock(mutex); - - return r; -} - -int pthread_mutex_lock(pthread_mutex_t *mutex) -{ - int r; - - try_init_preload(); - - lock_acquire(&__get_lock(mutex)->dep_map, 0, 0, 0, 1, NULL, - (unsigned long)_RET_IP_); - /* - * Here's the thing with pthread mutexes: unlike the kernel variant, - * they can fail. - * - * This means that the behaviour here is a bit different from what's - * going on in the kernel: there we just tell lockdep that we took the - * lock before actually taking it, but here we must deal with the case - * that locking failed. - * - * To do that we'll "release" the lock if locking failed - this way - * we'll get lockdep doing the correct checks when we try to take - * the lock, and if that fails - we'll be back to the correct - * state by releasing it. - */ - r = ll_pthread_mutex_lock(mutex); - if (r) - lock_release(&__get_lock(mutex)->dep_map, (unsigned long)_RET_IP_); - - return r; -} - -int pthread_mutex_trylock(pthread_mutex_t *mutex) -{ - int r; - - try_init_preload(); - - lock_acquire(&__get_lock(mutex)->dep_map, 0, 1, 0, 1, NULL, (unsigned long)_RET_IP_); - r = ll_pthread_mutex_trylock(mutex); - if (r) - lock_release(&__get_lock(mutex)->dep_map, (unsigned long)_RET_IP_); - - return r; -} - -int pthread_mutex_unlock(pthread_mutex_t *mutex) -{ - int r; - - try_init_preload(); - - lock_release(&__get_lock(mutex)->dep_map, (unsigned long)_RET_IP_); - /* - * Just like taking a lock, only in reverse! - * - * If we fail releasing the lock, tell lockdep we're holding it again. - */ - r = ll_pthread_mutex_unlock(mutex); - if (r) - lock_acquire(&__get_lock(mutex)->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_); - - return r; -} - -int pthread_mutex_destroy(pthread_mutex_t *mutex) -{ - try_init_preload(); - - /* - * Let's see if we're releasing a lock that's held. - * - * TODO: Hook into free() and add that check there as well. - */ - debug_check_no_locks_freed(mutex, sizeof(*mutex)); - __del_lock(__get_lock(mutex)); - return ll_pthread_mutex_destroy(mutex); -} - -/* This is the rwlock part, very similar to what happened with mutex above */ -int pthread_rwlock_init(pthread_rwlock_t *rwlock, - const pthread_rwlockattr_t *attr) -{ - int r; - - try_init_preload(); - - r = ll_pthread_rwlock_init(rwlock, attr); - if (r == 0) - __get_lock(rwlock); - - return r; -} - -int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) -{ - try_init_preload(); - - debug_check_no_locks_freed(rwlock, sizeof(*rwlock)); - __del_lock(__get_lock(rwlock)); - return ll_pthread_rwlock_destroy(rwlock); -} - -int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) -{ - int r; - - init_preload(); - - lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 2, 1, NULL, (unsigned long)_RET_IP_); - r = ll_pthread_rwlock_rdlock(rwlock); - if (r) - lock_release(&__get_lock(rwlock)->dep_map, (unsigned long)_RET_IP_); - - return r; -} - -int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) -{ - int r; - - init_preload(); - - lock_acquire(&__get_lock(rwlock)->dep_map, 0, 1, 2, 1, NULL, (unsigned long)_RET_IP_); - r = ll_pthread_rwlock_tryrdlock(rwlock); - if (r) - lock_release(&__get_lock(rwlock)->dep_map, (unsigned long)_RET_IP_); - - return r; -} - -int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) -{ - int r; - - init_preload(); - - lock_acquire(&__get_lock(rwlock)->dep_map, 0, 1, 0, 1, NULL, (unsigned long)_RET_IP_); - r = ll_pthread_rwlock_trywrlock(rwlock); - if (r) - lock_release(&__get_lock(rwlock)->dep_map, (unsigned long)_RET_IP_); - - return r; -} - -int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) -{ - int r; - - init_preload(); - - lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_); - r = ll_pthread_rwlock_wrlock(rwlock); - if (r) - lock_release(&__get_lock(rwlock)->dep_map, (unsigned long)_RET_IP_); - - return r; -} - -int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) -{ - int r; - - init_preload(); - - lock_release(&__get_lock(rwlock)->dep_map, (unsigned long)_RET_IP_); - r = ll_pthread_rwlock_unlock(rwlock); - if (r) - lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_); - - return r; -} - -__attribute__((constructor)) static void init_preload(void) -{ - if (__init_state == done) - return; - -#ifndef __GLIBC__ - __init_state = prepare; - - ll_pthread_mutex_init = dlsym(RTLD_NEXT, "pthread_mutex_init"); - ll_pthread_mutex_lock = dlsym(RTLD_NEXT, "pthread_mutex_lock"); - ll_pthread_mutex_trylock = dlsym(RTLD_NEXT, "pthread_mutex_trylock"); - ll_pthread_mutex_unlock = dlsym(RTLD_NEXT, "pthread_mutex_unlock"); - ll_pthread_mutex_destroy = dlsym(RTLD_NEXT, "pthread_mutex_destroy"); - - ll_pthread_rwlock_init = dlsym(RTLD_NEXT, "pthread_rwlock_init"); - ll_pthread_rwlock_destroy = dlsym(RTLD_NEXT, "pthread_rwlock_destroy"); - ll_pthread_rwlock_rdlock = dlsym(RTLD_NEXT, "pthread_rwlock_rdlock"); - ll_pthread_rwlock_tryrdlock = dlsym(RTLD_NEXT, "pthread_rwlock_tryrdlock"); - ll_pthread_rwlock_wrlock = dlsym(RTLD_NEXT, "pthread_rwlock_wrlock"); - ll_pthread_rwlock_trywrlock = dlsym(RTLD_NEXT, "pthread_rwlock_trywrlock"); - ll_pthread_rwlock_unlock = dlsym(RTLD_NEXT, "pthread_rwlock_unlock"); -#endif - - __init_state = done; -} diff --git a/tools/lib/lockdep/rbtree.c b/tools/lib/lockdep/rbtree.c deleted file mode 100644 index 297c304571f8..000000000000 --- a/tools/lib/lockdep/rbtree.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../lib/rbtree.c" diff --git a/tools/lib/lockdep/run_tests.sh b/tools/lib/lockdep/run_tests.sh deleted file mode 100755 index 11f425662b43..000000000000 --- a/tools/lib/lockdep/run_tests.sh +++ /dev/null @@ -1,47 +0,0 @@ -#! /bin/bash -# SPDX-License-Identifier: GPL-2.0 - -if ! make >/dev/null; then - echo "Building liblockdep failed." - echo "FAILED!" - exit 1 -fi - -find tests -name '*.c' | sort | while read -r i; do - testname=$(basename "$i" .c) - echo -ne "$testname... " - if gcc -o "tests/$testname" -pthread "$i" liblockdep.a -Iinclude -D__USE_LIBLOCKDEP && - timeout 1 "tests/$testname" 2>&1 | /bin/bash "tests/${testname}.sh"; then - echo "PASSED!" - else - echo "FAILED!" - fi - rm -f "tests/$testname" -done - -find tests -name '*.c' | sort | while read -r i; do - testname=$(basename "$i" .c) - echo -ne "(PRELOAD) $testname... " - if gcc -o "tests/$testname" -pthread -Iinclude "$i" && - timeout 1 ./lockdep "tests/$testname" 2>&1 | - /bin/bash "tests/${testname}.sh"; then - echo "PASSED!" - else - echo "FAILED!" - fi - rm -f "tests/$testname" -done - -find tests -name '*.c' | sort | while read -r i; do - testname=$(basename "$i" .c) - echo -ne "(PRELOAD + Valgrind) $testname... " - if gcc -o "tests/$testname" -pthread -Iinclude "$i" && - { timeout 10 valgrind --read-var-info=yes ./lockdep "./tests/$testname" >& "tests/${testname}.vg.out"; true; } && - /bin/bash "tests/${testname}.sh" < "tests/${testname}.vg.out" && - ! grep -Eq '(^==[0-9]*== (Invalid |Uninitialised ))|Mismatched free|Source and destination overlap| UME ' "tests/${testname}.vg.out"; then - echo "PASSED!" - else - echo "FAILED!" - fi - rm -f "tests/$testname" -done diff --git a/tools/lib/lockdep/tests/AA.c b/tools/lib/lockdep/tests/AA.c deleted file mode 100644 index 63c7ce97bda3..000000000000 --- a/tools/lib/lockdep/tests/AA.c +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <liblockdep/mutex.h> - -int main(void) -{ - pthread_mutex_t a; - - pthread_mutex_init(&a, NULL); - - pthread_mutex_lock(&a); - pthread_mutex_lock(&a); - - return 0; -} diff --git a/tools/lib/lockdep/tests/AA.sh b/tools/lib/lockdep/tests/AA.sh deleted file mode 100644 index f39b32865074..000000000000 --- a/tools/lib/lockdep/tests/AA.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -grep -q 'WARNING: possible recursive locking detected' diff --git a/tools/lib/lockdep/tests/ABA.c b/tools/lib/lockdep/tests/ABA.c deleted file mode 100644 index efa39b23f05d..000000000000 --- a/tools/lib/lockdep/tests/ABA.c +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <liblockdep/mutex.h> - -void main(void) -{ - pthread_mutex_t a, b; - - pthread_mutex_init(&a, NULL); - pthread_mutex_init(&b, NULL); - - pthread_mutex_lock(&a); - pthread_mutex_lock(&b); - pthread_mutex_lock(&a); -} diff --git a/tools/lib/lockdep/tests/ABA.sh b/tools/lib/lockdep/tests/ABA.sh deleted file mode 100644 index f39b32865074..000000000000 --- a/tools/lib/lockdep/tests/ABA.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -grep -q 'WARNING: possible recursive locking detected' diff --git a/tools/lib/lockdep/tests/ABBA.c b/tools/lib/lockdep/tests/ABBA.c deleted file mode 100644 index 543789bc3e37..000000000000 --- a/tools/lib/lockdep/tests/ABBA.c +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <liblockdep/mutex.h> -#include "common.h" - -void main(void) -{ - pthread_mutex_t a, b; - - pthread_mutex_init(&a, NULL); - pthread_mutex_init(&b, NULL); - - LOCK_UNLOCK_2(a, b); - LOCK_UNLOCK_2(b, a); - - pthread_mutex_destroy(&b); - pthread_mutex_destroy(&a); - - pthread_mutex_init(&a, NULL); - pthread_mutex_init(&b, NULL); - - LOCK_UNLOCK_2(a, b); - LOCK_UNLOCK_2(b, a); - - pthread_mutex_destroy(&b); - pthread_mutex_destroy(&a); -} diff --git a/tools/lib/lockdep/tests/ABBA.sh b/tools/lib/lockdep/tests/ABBA.sh deleted file mode 100644 index fc31c607a5a8..000000000000 --- a/tools/lib/lockdep/tests/ABBA.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -grep -q 'WARNING: possible circular locking dependency detected' diff --git a/tools/lib/lockdep/tests/ABBA_2threads.c b/tools/lib/lockdep/tests/ABBA_2threads.c deleted file mode 100644 index 39325ef8a2ac..000000000000 --- a/tools/lib/lockdep/tests/ABBA_2threads.c +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <stdio.h> -#include <pthread.h> - -pthread_mutex_t a = PTHREAD_MUTEX_INITIALIZER; -pthread_mutex_t b = PTHREAD_MUTEX_INITIALIZER; -pthread_barrier_t bar; - -void *ba_lock(void *arg) -{ - int ret, i; - - pthread_mutex_lock(&b); - - if (pthread_barrier_wait(&bar) == PTHREAD_BARRIER_SERIAL_THREAD) - pthread_barrier_destroy(&bar); - - pthread_mutex_lock(&a); - - pthread_mutex_unlock(&a); - pthread_mutex_unlock(&b); -} - -int main(void) -{ - pthread_t t; - - pthread_barrier_init(&bar, NULL, 2); - - if (pthread_create(&t, NULL, ba_lock, NULL)) { - fprintf(stderr, "pthread_create() failed\n"); - return 1; - } - pthread_mutex_lock(&a); - - if (pthread_barrier_wait(&bar) == PTHREAD_BARRIER_SERIAL_THREAD) - pthread_barrier_destroy(&bar); - - pthread_mutex_lock(&b); - - pthread_mutex_unlock(&b); - pthread_mutex_unlock(&a); - - pthread_join(t, NULL); - - return 0; -} diff --git a/tools/lib/lockdep/tests/ABBA_2threads.sh b/tools/lib/lockdep/tests/ABBA_2threads.sh deleted file mode 100644 index fc31c607a5a8..000000000000 --- a/tools/lib/lockdep/tests/ABBA_2threads.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -grep -q 'WARNING: possible circular locking dependency detected' diff --git a/tools/lib/lockdep/tests/ABBCCA.c b/tools/lib/lockdep/tests/ABBCCA.c deleted file mode 100644 index 48446129d496..000000000000 --- a/tools/lib/lockdep/tests/ABBCCA.c +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <liblockdep/mutex.h> -#include "common.h" - -void main(void) -{ - pthread_mutex_t a, b, c; - - pthread_mutex_init(&a, NULL); - pthread_mutex_init(&b, NULL); - pthread_mutex_init(&c, NULL); - - LOCK_UNLOCK_2(a, b); - LOCK_UNLOCK_2(b, c); - LOCK_UNLOCK_2(c, a); - - pthread_mutex_destroy(&c); - pthread_mutex_destroy(&b); - pthread_mutex_destroy(&a); -} diff --git a/tools/lib/lockdep/tests/ABBCCA.sh b/tools/lib/lockdep/tests/ABBCCA.sh deleted file mode 100644 index fc31c607a5a8..000000000000 --- a/tools/lib/lockdep/tests/ABBCCA.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -grep -q 'WARNING: possible circular locking dependency detected' diff --git a/tools/lib/lockdep/tests/ABBCCDDA.c b/tools/lib/lockdep/tests/ABBCCDDA.c deleted file mode 100644 index 3570bf7b3804..000000000000 --- a/tools/lib/lockdep/tests/ABBCCDDA.c +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <liblockdep/mutex.h> -#include "common.h" - -void main(void) -{ - pthread_mutex_t a, b, c, d; - - pthread_mutex_init(&a, NULL); - pthread_mutex_init(&b, NULL); - pthread_mutex_init(&c, NULL); - pthread_mutex_init(&d, NULL); - - LOCK_UNLOCK_2(a, b); - LOCK_UNLOCK_2(b, c); - LOCK_UNLOCK_2(c, d); - LOCK_UNLOCK_2(d, a); - - pthread_mutex_destroy(&d); - pthread_mutex_destroy(&c); - pthread_mutex_destroy(&b); - pthread_mutex_destroy(&a); -} diff --git a/tools/lib/lockdep/tests/ABBCCDDA.sh b/tools/lib/lockdep/tests/ABBCCDDA.sh deleted file mode 100644 index fc31c607a5a8..000000000000 --- a/tools/lib/lockdep/tests/ABBCCDDA.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -grep -q 'WARNING: possible circular locking dependency detected' diff --git a/tools/lib/lockdep/tests/ABCABC.c b/tools/lib/lockdep/tests/ABCABC.c deleted file mode 100644 index a1c4659894cd..000000000000 --- a/tools/lib/lockdep/tests/ABCABC.c +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <liblockdep/mutex.h> -#include "common.h" - -void main(void) -{ - pthread_mutex_t a, b, c; - - pthread_mutex_init(&a, NULL); - pthread_mutex_init(&b, NULL); - pthread_mutex_init(&c, NULL); - - LOCK_UNLOCK_2(a, b); - LOCK_UNLOCK_2(c, a); - LOCK_UNLOCK_2(b, c); - - pthread_mutex_destroy(&c); - pthread_mutex_destroy(&b); - pthread_mutex_destroy(&a); -} diff --git a/tools/lib/lockdep/tests/ABCABC.sh b/tools/lib/lockdep/tests/ABCABC.sh deleted file mode 100644 index fc31c607a5a8..000000000000 --- a/tools/lib/lockdep/tests/ABCABC.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -grep -q 'WARNING: possible circular locking dependency detected' diff --git a/tools/lib/lockdep/tests/ABCDBCDA.c b/tools/lib/lockdep/tests/ABCDBCDA.c deleted file mode 100644 index 335af1c90ab5..000000000000 --- a/tools/lib/lockdep/tests/ABCDBCDA.c +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <liblockdep/mutex.h> -#include "common.h" - -void main(void) -{ - pthread_mutex_t a, b, c, d; - - pthread_mutex_init(&a, NULL); - pthread_mutex_init(&b, NULL); - pthread_mutex_init(&c, NULL); - pthread_mutex_init(&d, NULL); - - LOCK_UNLOCK_2(a, b); - LOCK_UNLOCK_2(c, d); - LOCK_UNLOCK_2(b, c); - LOCK_UNLOCK_2(d, a); - - pthread_mutex_destroy(&d); - pthread_mutex_destroy(&c); - pthread_mutex_destroy(&b); - pthread_mutex_destroy(&a); -} diff --git a/tools/lib/lockdep/tests/ABCDBCDA.sh b/tools/lib/lockdep/tests/ABCDBCDA.sh deleted file mode 100644 index fc31c607a5a8..000000000000 --- a/tools/lib/lockdep/tests/ABCDBCDA.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -grep -q 'WARNING: possible circular locking dependency detected' diff --git a/tools/lib/lockdep/tests/ABCDBDDA.c b/tools/lib/lockdep/tests/ABCDBDDA.c deleted file mode 100644 index 3c5972863049..000000000000 --- a/tools/lib/lockdep/tests/ABCDBDDA.c +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <liblockdep/mutex.h> -#include "common.h" - -void main(void) -{ - pthread_mutex_t a, b, c, d; - - pthread_mutex_init(&a, NULL); - pthread_mutex_init(&b, NULL); - pthread_mutex_init(&c, NULL); - pthread_mutex_init(&d, NULL); - - LOCK_UNLOCK_2(a, b); - LOCK_UNLOCK_2(c, d); - LOCK_UNLOCK_2(b, d); - LOCK_UNLOCK_2(d, a); - - pthread_mutex_destroy(&d); - pthread_mutex_destroy(&c); - pthread_mutex_destroy(&b); - pthread_mutex_destroy(&a); -} diff --git a/tools/lib/lockdep/tests/ABCDBDDA.sh b/tools/lib/lockdep/tests/ABCDBDDA.sh deleted file mode 100644 index fc31c607a5a8..000000000000 --- a/tools/lib/lockdep/tests/ABCDBDDA.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -grep -q 'WARNING: possible circular locking dependency detected' diff --git a/tools/lib/lockdep/tests/WW.c b/tools/lib/lockdep/tests/WW.c deleted file mode 100644 index eee88df7fc41..000000000000 --- a/tools/lib/lockdep/tests/WW.c +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <liblockdep/rwlock.h> - -void main(void) -{ - pthread_rwlock_t a, b; - - pthread_rwlock_init(&a, NULL); - pthread_rwlock_init(&b, NULL); - - pthread_rwlock_wrlock(&a); - pthread_rwlock_rdlock(&b); - pthread_rwlock_wrlock(&a); -} diff --git a/tools/lib/lockdep/tests/WW.sh b/tools/lib/lockdep/tests/WW.sh deleted file mode 100644 index f39b32865074..000000000000 --- a/tools/lib/lockdep/tests/WW.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -grep -q 'WARNING: possible recursive locking detected' diff --git a/tools/lib/lockdep/tests/common.h b/tools/lib/lockdep/tests/common.h deleted file mode 100644 index 3026c29ccb5c..000000000000 --- a/tools/lib/lockdep/tests/common.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _LIBLOCKDEP_TEST_COMMON_H -#define _LIBLOCKDEP_TEST_COMMON_H - -#define LOCK_UNLOCK_2(a, b) \ - do { \ - pthread_mutex_lock(&(a)); \ - pthread_mutex_lock(&(b)); \ - pthread_mutex_unlock(&(b)); \ - pthread_mutex_unlock(&(a)); \ - } while(0) - -#endif diff --git a/tools/lib/lockdep/tests/unlock_balance.c b/tools/lib/lockdep/tests/unlock_balance.c deleted file mode 100644 index dba25064b50a..000000000000 --- a/tools/lib/lockdep/tests/unlock_balance.c +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <liblockdep/mutex.h> - -void main(void) -{ - pthread_mutex_t a; - - pthread_mutex_init(&a, NULL); - - pthread_mutex_lock(&a); - pthread_mutex_unlock(&a); - pthread_mutex_unlock(&a); - - pthread_mutex_destroy(&a); -} diff --git a/tools/lib/lockdep/tests/unlock_balance.sh b/tools/lib/lockdep/tests/unlock_balance.sh deleted file mode 100644 index c6e3952303fe..000000000000 --- a/tools/lib/lockdep/tests/unlock_balance.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -grep -q 'WARNING: bad unlock balance detected' diff --git a/tools/lib/perf/cpumap.c b/tools/lib/perf/cpumap.c index 6d8e521c59e1..adaad3dddf6e 100644 --- a/tools/lib/perf/cpumap.c +++ b/tools/lib/perf/cpumap.c @@ -270,11 +270,19 @@ bool perf_cpu_map__empty(const struct perf_cpu_map *map) int perf_cpu_map__idx(struct perf_cpu_map *cpus, int cpu) { - int i; + int low = 0, high = cpus->nr; - for (i = 0; i < cpus->nr; ++i) { - if (cpus->map[i] == cpu) - return i; + while (low < high) { + int idx = (low + high) / 2, + cpu_at_idx = cpus->map[idx]; + + if (cpu_at_idx == cpu) + return idx; + + if (cpu_at_idx > cpu) + high = idx; + else + low = idx + 1; } return -1; diff --git a/tools/lib/perf/include/perf/event.h b/tools/lib/perf/include/perf/event.h index 4d0c02ba3f7d..75ee385fb078 100644 --- a/tools/lib/perf/include/perf/event.h +++ b/tools/lib/perf/include/perf/event.h @@ -289,6 +289,11 @@ struct perf_record_itrace_start { __u32 tid; }; +struct perf_record_aux_output_hw_id { + struct perf_event_header header; + __u64 hw_id; +}; + struct perf_record_thread_map_entry { __u64 pid; char comm[16]; @@ -414,6 +419,7 @@ union perf_event { struct perf_record_auxtrace_error auxtrace_error; struct perf_record_aux aux; struct perf_record_itrace_start itrace_start; + struct perf_record_aux_output_hw_id aux_output_hw_id; struct perf_record_switch context_switch; struct perf_record_thread_map thread_map; struct perf_record_cpu_map cpu_map; |