public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] liblockdep: userspace lockdep
@ 2013-04-30 18:54 Sasha Levin
  2013-04-30 18:54 ` [PATCH 1/9] lockdep: Be nice about building from userspace Sasha Levin
                   ` (9 more replies)
  0 siblings, 10 replies; 17+ messages in thread
From: Sasha Levin @ 2013-04-30 18:54 UTC (permalink / raw)
  To: torvalds; +Cc: mingo, peterz, linux-kernel, Sasha Levin

liblockdep is a tiny wrapper built around kernel/lockdep.c. The aim is to
provide the same functionality the kernel gets from lockdep to userspace.

The bulk of the code here is the LD_PRELOAD support which provides users
an easy way to test their code without having to integrate liblockdep into
said code. Simply doing:

	lockdep my_app

Would provide lockdep support to my_app.

There is also a small test suite to test both mutexes and rwlocks, it's
based on the tests in lib/locking-selftest.c.

This entire patch series was reviewed by lockdep maintainers and accepted to
the tip tree previously. It was pulled out so that the potential merge of
liblockdep won't delay the rest of the commits in the tip locking tree.

For some more background about this entire thing, the folks at LWN did
an awesome overview: http://lwn.net/Articles/536363/


Sasha Levin (9):
  lockdep: Be nice about building from userspace
  liblockdep: Wrap kernel/lockdep.c to allow usage from userspace
  liblockdep: Add public headers for pthread_mutex_t implementation
  liblockdep: Add pthread_mutex_t test suite
  liblockdep: Add public headers for pthread_rwlock_t implementation
  liblockdep: Add pthread_rwlock_t test suite
  liblockdep: Support using LD_PRELOAD
  liblockdep: Add the 'lockdep' user-space utility
  liblockdep: Add a MAINTAINERS entry

 MAINTAINERS                                        |   5 +
 kernel/lockdep.c                                   |   4 +
 tools/lib/lockdep/Makefile                         | 251 ++++++++++++++
 tools/lib/lockdep/common.c                         |  33 ++
 tools/lib/lockdep/include/liblockdep/common.h      |  43 +++
 tools/lib/lockdep/include/liblockdep/mutex.h       |  73 ++++
 tools/lib/lockdep/include/liblockdep/rwlock.h      |  91 +++++
 tools/lib/lockdep/lockdep                          |   3 +
 tools/lib/lockdep/lockdep.c                        |   2 +
 tools/lib/lockdep/lockdep_internals.h              |   1 +
 tools/lib/lockdep/lockdep_states.h                 |   1 +
 tools/lib/lockdep/preload.c                        | 386 +++++++++++++++++++++
 tools/lib/lockdep/rbtree.c                         |   1 +
 tools/lib/lockdep/run_tests.sh                     |  27 ++
 tools/lib/lockdep/tests/AA.c                       |  13 +
 tools/lib/lockdep/tests/ABBA.c                     |  13 +
 tools/lib/lockdep/tests/ABBCCA.c                   |  15 +
 tools/lib/lockdep/tests/ABBCCDDA.c                 |  17 +
 tools/lib/lockdep/tests/ABCABC.c                   |  15 +
 tools/lib/lockdep/tests/ABCDBCDA.c                 |  17 +
 tools/lib/lockdep/tests/ABCDBDDA.c                 |  17 +
 tools/lib/lockdep/tests/WW.c                       |  13 +
 tools/lib/lockdep/tests/common.h                   |  12 +
 tools/lib/lockdep/tests/unlock_balance.c           |  12 +
 tools/lib/lockdep/uinclude/asm/hweight.h           |   0
 tools/lib/lockdep/uinclude/asm/sections.h          |   0
 tools/lib/lockdep/uinclude/linux/bitops.h          |   0
 tools/lib/lockdep/uinclude/linux/compiler.h        |   7 +
 tools/lib/lockdep/uinclude/linux/debug_locks.h     |  12 +
 tools/lib/lockdep/uinclude/linux/delay.h           |   0
 tools/lib/lockdep/uinclude/linux/export.h          |   7 +
 tools/lib/lockdep/uinclude/linux/ftrace.h          |   0
 tools/lib/lockdep/uinclude/linux/gfp.h             |   0
 tools/lib/lockdep/uinclude/linux/hardirq.h         |  11 +
 tools/lib/lockdep/uinclude/linux/hash.h            |   1 +
 tools/lib/lockdep/uinclude/linux/interrupt.h       |   0
 tools/lib/lockdep/uinclude/linux/irqflags.h        |  38 ++
 tools/lib/lockdep/uinclude/linux/kallsyms.h        |  32 ++
 tools/lib/lockdep/uinclude/linux/kernel.h          |  36 ++
 tools/lib/lockdep/uinclude/linux/kmemcheck.h       |   8 +
 tools/lib/lockdep/uinclude/linux/linkage.h         |   0
 tools/lib/lockdep/uinclude/linux/list.h            |   1 +
 tools/lib/lockdep/uinclude/linux/lockdep.h         |  58 ++++
 tools/lib/lockdep/uinclude/linux/mm_types.h        |   0
 tools/lib/lockdep/uinclude/linux/module.h          |   6 +
 tools/lib/lockdep/uinclude/linux/mutex.h           |   0
 tools/lib/lockdep/uinclude/linux/poison.h          |   1 +
 tools/lib/lockdep/uinclude/linux/prefetch.h        |   6 +
 tools/lib/lockdep/uinclude/linux/proc_fs.h         |   0
 tools/lib/lockdep/uinclude/linux/rbtree.h          |   1 +
 .../lib/lockdep/uinclude/linux/rbtree_augmented.h  |   2 +
 tools/lib/lockdep/uinclude/linux/rcu.h             |  16 +
 tools/lib/lockdep/uinclude/linux/seq_file.h        |   0
 tools/lib/lockdep/uinclude/linux/spinlock.h        |  25 ++
 tools/lib/lockdep/uinclude/linux/stacktrace.h      |  32 ++
 tools/lib/lockdep/uinclude/linux/stringify.h       |   7 +
 tools/lib/lockdep/uinclude/linux/system.h          |   0
 tools/lib/lockdep/uinclude/linux/types.h           |  58 ++++
 tools/lib/lockdep/uinclude/linux/util.h            |   0
 tools/lib/lockdep/uinclude/trace/events/lock.h     |   0
 60 files changed, 1430 insertions(+)
 create mode 100644 tools/lib/lockdep/Makefile
 create mode 100644 tools/lib/lockdep/common.c
 create mode 100644 tools/lib/lockdep/include/liblockdep/common.h
 create mode 100644 tools/lib/lockdep/include/liblockdep/mutex.h
 create mode 100644 tools/lib/lockdep/include/liblockdep/rwlock.h
 create mode 100755 tools/lib/lockdep/lockdep
 create mode 100644 tools/lib/lockdep/lockdep.c
 create mode 100644 tools/lib/lockdep/lockdep_internals.h
 create mode 100644 tools/lib/lockdep/lockdep_states.h
 create mode 100644 tools/lib/lockdep/preload.c
 create mode 100644 tools/lib/lockdep/rbtree.c
 create mode 100755 tools/lib/lockdep/run_tests.sh
 create mode 100644 tools/lib/lockdep/tests/AA.c
 create mode 100644 tools/lib/lockdep/tests/ABBA.c
 create mode 100644 tools/lib/lockdep/tests/ABBCCA.c
 create mode 100644 tools/lib/lockdep/tests/ABBCCDDA.c
 create mode 100644 tools/lib/lockdep/tests/ABCABC.c
 create mode 100644 tools/lib/lockdep/tests/ABCDBCDA.c
 create mode 100644 tools/lib/lockdep/tests/ABCDBDDA.c
 create mode 100644 tools/lib/lockdep/tests/WW.c
 create mode 100644 tools/lib/lockdep/tests/common.h
 create mode 100644 tools/lib/lockdep/tests/unlock_balance.c
 create mode 100644 tools/lib/lockdep/uinclude/asm/hweight.h
 create mode 100644 tools/lib/lockdep/uinclude/asm/sections.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/bitops.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/compiler.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/debug_locks.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/delay.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/export.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/ftrace.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/gfp.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/hardirq.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/hash.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/interrupt.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/irqflags.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/kallsyms.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/kernel.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/kmemcheck.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/linkage.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/list.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/lockdep.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/mm_types.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/module.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/mutex.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/poison.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/prefetch.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/proc_fs.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/rbtree.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/rbtree_augmented.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/rcu.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/seq_file.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/spinlock.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/stacktrace.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/stringify.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/system.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/types.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/util.h
 create mode 100644 tools/lib/lockdep/uinclude/trace/events/lock.h

-- 
1.8.2.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/9] lockdep: Be nice about building from userspace
  2013-04-30 18:54 [PATCH 0/9] liblockdep: userspace lockdep Sasha Levin
@ 2013-04-30 18:54 ` Sasha Levin
  2013-04-30 18:54 ` [PATCH 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage " Sasha Levin
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Sasha Levin @ 2013-04-30 18:54 UTC (permalink / raw)
  To: torvalds; +Cc: mingo, peterz, linux-kernel, Sasha Levin, penberg

Lockdep is an awesome piece of code which detects locking issues
which are relevant both to userspace and kernelspace. We can
easily make lockdep work in userspace since there is really no
kernel spacific magic going on in the code.

All we need is to wrap two functions which are used by lockdep
and are very kernel specific.

Doing that will allow tools located in tools/ to easily utilize
lockdep's code for their own use.

Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
Cc: penberg@kernel.org
Cc: peterz@infradead.org
Link: http://lkml.kernel.org/r/1352753446-24109-1-git-send-email-sasha.levin@oracle.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
 kernel/lockdep.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 8a0efac..1966746 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -584,6 +584,7 @@ static int very_verbose(struct lock_class *class)
 /*
  * Is this the address of a static object:
  */
+#ifdef __KERNEL__
 static int static_obj(void *obj)
 {
 	unsigned long start = (unsigned long) &_stext,
@@ -610,6 +611,7 @@ static int static_obj(void *obj)
 	 */
 	return is_module_address(addr) || is_module_percpu_address(addr);
 }
+#endif
 
 /*
  * To make lock name printouts unique, we calculate a unique
@@ -4114,6 +4116,7 @@ void debug_check_no_locks_held(struct task_struct *task)
 		print_held_locks_bug(task);
 }
 
+#ifdef __KERNEL__
 void debug_show_all_locks(void)
 {
 	struct task_struct *g, *p;
@@ -4171,6 +4174,7 @@ retry:
 		read_unlock(&tasklist_lock);
 }
 EXPORT_SYMBOL_GPL(debug_show_all_locks);
+#endif
 
 /*
  * Careful: only use this function if you are sure that
-- 
1.8.2.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage from userspace
  2013-04-30 18:54 [PATCH 0/9] liblockdep: userspace lockdep Sasha Levin
  2013-04-30 18:54 ` [PATCH 1/9] lockdep: Be nice about building from userspace Sasha Levin
@ 2013-04-30 18:54 ` Sasha Levin
  2013-05-08 10:01   ` Peter Zijlstra
  2013-04-30 18:54 ` [PATCH 3/9] liblockdep: Add public headers for pthread_mutex_t implementation Sasha Levin
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: Sasha Levin @ 2013-04-30 18:54 UTC (permalink / raw)
  To: torvalds; +Cc: mingo, peterz, linux-kernel, Sasha Levin

kernel/lockdep.c deals with validating locking scenarios for
various architectures supported by the kernel. There isn't
anything kernel specific going on in lockdep, and when we
compare userspace to other architectures that don't have to deal
with irqs such as s390, they become all too similar.

We wrap kernel/lockdep.c and include/linux/lockdep.h with
several headers which allow us to build and use lockdep from
userspace. We don't touch the kernel code itself which means
that any work done on lockdep in the kernel will automatically
benefit userspace lockdep as well!

Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
 tools/lib/lockdep/Makefile                         | 251 +++++++++++++++++++++
 tools/lib/lockdep/common.c                         |  33 +++
 tools/lib/lockdep/lockdep.c                        |   2 +
 tools/lib/lockdep/lockdep_internals.h              |   1 +
 tools/lib/lockdep/lockdep_states.h                 |   1 +
 tools/lib/lockdep/rbtree.c                         |   1 +
 tools/lib/lockdep/uinclude/asm/hweight.h           |   0
 tools/lib/lockdep/uinclude/asm/sections.h          |   0
 tools/lib/lockdep/uinclude/linux/bitops.h          |   0
 tools/lib/lockdep/uinclude/linux/compiler.h        |   7 +
 tools/lib/lockdep/uinclude/linux/debug_locks.h     |  12 +
 tools/lib/lockdep/uinclude/linux/delay.h           |   0
 tools/lib/lockdep/uinclude/linux/export.h          |   7 +
 tools/lib/lockdep/uinclude/linux/ftrace.h          |   0
 tools/lib/lockdep/uinclude/linux/gfp.h             |   0
 tools/lib/lockdep/uinclude/linux/hardirq.h         |  11 +
 tools/lib/lockdep/uinclude/linux/hash.h            |   1 +
 tools/lib/lockdep/uinclude/linux/interrupt.h       |   0
 tools/lib/lockdep/uinclude/linux/irqflags.h        |  38 ++++
 tools/lib/lockdep/uinclude/linux/kallsyms.h        |  32 +++
 tools/lib/lockdep/uinclude/linux/kernel.h          |  36 +++
 tools/lib/lockdep/uinclude/linux/kmemcheck.h       |   8 +
 tools/lib/lockdep/uinclude/linux/linkage.h         |   0
 tools/lib/lockdep/uinclude/linux/list.h            |   1 +
 tools/lib/lockdep/uinclude/linux/lockdep.h         |  58 +++++
 tools/lib/lockdep/uinclude/linux/mm_types.h        |   0
 tools/lib/lockdep/uinclude/linux/module.h          |   6 +
 tools/lib/lockdep/uinclude/linux/mutex.h           |   0
 tools/lib/lockdep/uinclude/linux/poison.h          |   1 +
 tools/lib/lockdep/uinclude/linux/prefetch.h        |   6 +
 tools/lib/lockdep/uinclude/linux/proc_fs.h         |   0
 tools/lib/lockdep/uinclude/linux/rbtree.h          |   1 +
 .../lib/lockdep/uinclude/linux/rbtree_augmented.h  |   2 +
 tools/lib/lockdep/uinclude/linux/rcu.h             |  16 ++
 tools/lib/lockdep/uinclude/linux/seq_file.h        |   0
 tools/lib/lockdep/uinclude/linux/spinlock.h        |  25 ++
 tools/lib/lockdep/uinclude/linux/stacktrace.h      |  32 +++
 tools/lib/lockdep/uinclude/linux/stringify.h       |   7 +
 tools/lib/lockdep/uinclude/linux/system.h          |   0
 tools/lib/lockdep/uinclude/linux/types.h           |  58 +++++
 tools/lib/lockdep/uinclude/linux/util.h            |   0
 tools/lib/lockdep/uinclude/trace/events/lock.h     |   0
 42 files changed, 654 insertions(+)
 create mode 100644 tools/lib/lockdep/Makefile
 create mode 100644 tools/lib/lockdep/common.c
 create mode 100644 tools/lib/lockdep/lockdep.c
 create mode 100644 tools/lib/lockdep/lockdep_internals.h
 create mode 100644 tools/lib/lockdep/lockdep_states.h
 create mode 100644 tools/lib/lockdep/rbtree.c
 create mode 100644 tools/lib/lockdep/uinclude/asm/hweight.h
 create mode 100644 tools/lib/lockdep/uinclude/asm/sections.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/bitops.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/compiler.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/debug_locks.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/delay.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/export.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/ftrace.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/gfp.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/hardirq.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/hash.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/interrupt.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/irqflags.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/kallsyms.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/kernel.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/kmemcheck.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/linkage.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/list.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/lockdep.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/mm_types.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/module.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/mutex.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/poison.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/prefetch.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/proc_fs.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/rbtree.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/rbtree_augmented.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/rcu.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/seq_file.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/spinlock.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/stacktrace.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/stringify.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/system.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/types.h
 create mode 100644 tools/lib/lockdep/uinclude/linux/util.h
 create mode 100644 tools/lib/lockdep/uinclude/trace/events/lock.h

diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile
new file mode 100644
index 0000000..9500b00
--- /dev/null
+++ b/tools/lib/lockdep/Makefile
@@ -0,0 +1,251 @@
+# liblockdep version
+LL_VERSION = 0
+LL_PATCHLEVEL = 0
+LL_EXTRAVERSION = 1
+
+# file format version
+FILE_VERSION = 1
+
+MAKEFLAGS += --no-print-directory
+
+
+# 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, or setting CROSS_COMPILE as a prefix.
+$(call allow-override,CC,$(CROSS_COMPILE)gcc)
+$(call allow-override,AR,$(CROSS_COMPILE)ar)
+
+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
+
+# copy a bit from Linux kbuild
+
+ifeq ("$(origin V)", "command line")
+  VERBOSE = $(V)
+endif
+ifndef VERBOSE
+  VERBOSE = 0
+endif
+
+ifeq ("$(origin O)", "command line")
+  BUILD_OUTPUT := $(O)
+endif
+
+ifeq ($(BUILD_SRC),)
+ifneq ($(BUILD_OUTPUT),)
+
+define build_output
+	$(if $(VERBOSE:1=),@)$(MAKE) -C $(BUILD_OUTPUT) 	\
+	BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1
+endef
+
+saved-output := $(BUILD_OUTPUT)
+BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd)
+$(if $(BUILD_OUTPUT),, \
+     $(error output directory "$(saved-output)" does not exist))
+
+all: sub-make
+
+gui: force
+	$(call build_output, all_cmd)
+
+$(filter-out gui,$(MAKECMDGOALS)): sub-make
+
+sub-make: force
+	$(call build_output, $(MAKECMDGOALS))
+
+
+# Leave processing to above invocation of make
+skip-makefile := 1
+
+endif # BUILD_OUTPUT
+endif # BUILD_SRC
+
+# We process the rest of the Makefile if this is the final invocation of make
+ifeq ($(skip-makefile),)
+
+srctree		:= $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))
+objtree		:= $(CURDIR)
+src		:= $(srctree)
+obj		:= $(objtree)
+
+export prefix libdir bindir src obj
+
+# Shell quotes
+libdir_SQ = $(subst ','\'',$(libdir))
+bindir_SQ = $(subst ','\'',$(bindir))
+
+LIB_FILE = liblockdep.a liblockdep.so
+BIN_FILE = lockdep
+
+CONFIG_INCLUDES =
+CONFIG_LIBS	=
+CONFIG_FLAGS	=
+
+OBJ		= $@
+N		=
+
+export Q VERBOSE
+
+LIBLOCKDEP_VERSION = $(LL_VERSION).$(LL_PATCHLEVEL).$(LL_EXTRAVERSION)
+
+INCLUDES = -I. -I/usr/local/include -I./uinclude $(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
+
+override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
+
+ifeq ($(VERBOSE),1)
+  Q =
+  print_compile =
+  print_app_build =
+  print_fpic_compile =
+  print_shared_lib_compile =
+  print_install =
+else
+  Q = @
+  print_compile =		echo '  CC                 '$(OBJ);
+  print_app_build =		echo '  BUILD              '$(OBJ);
+  print_fpic_compile =		echo '  CC FPIC            '$(OBJ);
+  print_shared_lib_compile =	echo '  BUILD SHARED LIB   '$(OBJ);
+  print_static_lib_build =	echo '  BUILD STATIC LIB   '$(OBJ);
+  print_install =		echo '  INSTALL     '$1'	to	$(DESTDIR_SQ)$2';
+endif
+
+do_fpic_compile =					\
+	($(print_fpic_compile)				\
+	$(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@)
+
+do_app_build =						\
+	($(print_app_build)				\
+	$(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS))
+
+do_compile_shared_library =			\
+	($(print_shared_lib_compile)		\
+	$(CC) --shared -ldl $^ -o $@)
+
+do_build_static_lib =				\
+	($(print_static_lib_build)		\
+	$(RM) $@;  $(AR) rcs $@ $^)
+
+
+define do_compile
+	$(print_compile)						\
+	$(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
+endef
+
+$(obj)/%.o: $(src)/%.c
+	$(Q)$(call do_compile)
+
+%.o: $(src)/%.c
+	$(Q)$(call do_compile)
+
+PEVENT_LIB_OBJS = common.o lockdep.o preload.o rbtree.o
+
+ALL_OBJS = $(PEVENT_LIB_OBJS)
+
+CMD_TARGETS = $(LIB_FILE)
+
+TARGETS = $(CMD_TARGETS)
+
+
+all: all_cmd
+
+all_cmd: $(CMD_TARGETS)
+
+liblockdep.so: $(PEVENT_LIB_OBJS)
+	$(Q)$(do_compile_shared_library)
+
+liblockdep.a: $(PEVENT_LIB_OBJS)
+	$(Q)$(do_build_static_lib)
+
+$(PEVENT_LIB_OBJS): %.o: $(src)/%.c
+	$(Q)$(do_fpic_compile)
+
+## make deps
+
+all_objs := $(sort $(ALL_OBJS))
+all_deps := $(all_objs:%.o=.%.d)
+
+# let .d file also depends on the source and header files
+define check_deps
+		@set -e; $(RM) $@; \
+		$(CC) -MM $(CFLAGS) $< > $@.$$$$; \
+		sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+		$(RM) $@.$$$$
+endef
+
+$(all_deps): .%.d: $(src)/%.c
+	$(Q)$(call check_deps)
+
+$(all_objs) : %.o : .%.d
+
+dep_includes := $(wildcard $(all_deps))
+
+ifneq ($(dep_includes),)
+ include $(dep_includes)
+endif
+
+### Detect environment changes
+TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE)
+
+tags:	force
+	$(RM) tags
+	find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
+	--regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'
+
+TAGS:	force
+	$(RM) TAGS
+	find . -name '*.[ch]' | xargs etags \
+	--regex='/_PE(\([^,)]*\).*/PEVENT_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) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d
+	$(RM) tags TAGS
+
+endif # skip-makefile
+
+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
new file mode 100644
index 0000000..eb5e481
--- /dev/null
+++ b/tools/lib/lockdep/common.c
@@ -0,0 +1,33 @@
+#include <stddef.h>
+#include <stdbool.h>
+#include <linux/compiler.h>
+#include <linux/lockdep.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+static struct task_struct current_obj;
+
+/* lockdep wants these */
+bool debug_locks = true;
+bool debug_locks_silent;
+
+__attribute__((constructor)) static void liblockdep_init(void)
+{
+	lockdep_init();
+}
+
+__attribute__((destructor)) static void liblockdep_exit(void)
+{
+	debug_check_no_locks_held(&current_obj);
+}
+
+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 &current_obj;
+}
diff --git a/tools/lib/lockdep/lockdep.c b/tools/lib/lockdep/lockdep.c
new file mode 100644
index 0000000..8ddd0ff
--- /dev/null
+++ b/tools/lib/lockdep/lockdep.c
@@ -0,0 +1,2 @@
+#include <linux/lockdep.h>
+#include "../../../kernel/lockdep.c"
diff --git a/tools/lib/lockdep/lockdep_internals.h b/tools/lib/lockdep/lockdep_internals.h
new file mode 100644
index 0000000..109e96f
--- /dev/null
+++ b/tools/lib/lockdep/lockdep_internals.h
@@ -0,0 +1 @@
+#include "../../../kernel/lockdep_internals.h"
diff --git a/tools/lib/lockdep/lockdep_states.h b/tools/lib/lockdep/lockdep_states.h
new file mode 100644
index 0000000..6b75423
--- /dev/null
+++ b/tools/lib/lockdep/lockdep_states.h
@@ -0,0 +1 @@
+#include "../../../kernel/lockdep_states.h"
diff --git a/tools/lib/lockdep/rbtree.c b/tools/lib/lockdep/rbtree.c
new file mode 100644
index 0000000..f7f4303
--- /dev/null
+++ b/tools/lib/lockdep/rbtree.c
@@ -0,0 +1 @@
+#include "../../../lib/rbtree.c"
diff --git a/tools/lib/lockdep/uinclude/asm/hweight.h b/tools/lib/lockdep/uinclude/asm/hweight.h
new file mode 100644
index 0000000..e69de29
diff --git a/tools/lib/lockdep/uinclude/asm/sections.h b/tools/lib/lockdep/uinclude/asm/sections.h
new file mode 100644
index 0000000..e69de29
diff --git a/tools/lib/lockdep/uinclude/linux/bitops.h b/tools/lib/lockdep/uinclude/linux/bitops.h
new file mode 100644
index 0000000..e69de29
diff --git a/tools/lib/lockdep/uinclude/linux/compiler.h b/tools/lib/lockdep/uinclude/linux/compiler.h
new file mode 100644
index 0000000..7ac838a
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/compiler.h
@@ -0,0 +1,7 @@
+#ifndef _LIBLOCKDEP_LINUX_COMPILER_H_
+#define _LIBLOCKDEP_LINUX_COMPILER_H_
+
+#define __used		__attribute__((__unused__))
+#define unlikely
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/debug_locks.h b/tools/lib/lockdep/uinclude/linux/debug_locks.h
new file mode 100644
index 0000000..f38eb64
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/debug_locks.h
@@ -0,0 +1,12 @@
+#ifndef _LIBLOCKDEP_DEBUG_LOCKS_H_
+#define _LIBLOCKDEP_DEBUG_LOCKS_H_
+
+#include <stddef.h>
+#include <linux/compiler.h>
+
+#define DEBUG_LOCKS_WARN_ON(x) (x)
+
+extern bool debug_locks;
+extern bool debug_locks_silent;
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/delay.h b/tools/lib/lockdep/uinclude/linux/delay.h
new file mode 100644
index 0000000..e69de29
diff --git a/tools/lib/lockdep/uinclude/linux/export.h b/tools/lib/lockdep/uinclude/linux/export.h
new file mode 100644
index 0000000..6bdf349
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/export.h
@@ -0,0 +1,7 @@
+#ifndef _LIBLOCKDEP_LINUX_EXPORT_H_
+#define _LIBLOCKDEP_LINUX_EXPORT_H_
+
+#define EXPORT_SYMBOL(sym)
+#define EXPORT_SYMBOL_GPL(sym)
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/ftrace.h b/tools/lib/lockdep/uinclude/linux/ftrace.h
new file mode 100644
index 0000000..e69de29
diff --git a/tools/lib/lockdep/uinclude/linux/gfp.h b/tools/lib/lockdep/uinclude/linux/gfp.h
new file mode 100644
index 0000000..e69de29
diff --git a/tools/lib/lockdep/uinclude/linux/hardirq.h b/tools/lib/lockdep/uinclude/linux/hardirq.h
new file mode 100644
index 0000000..c8f3f8f
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/hardirq.h
@@ -0,0 +1,11 @@
+#ifndef _LIBLOCKDEP_LINUX_HARDIRQ_H_
+#define _LIBLOCKDEP_LINUX_HARDIRQ_H_
+
+#define SOFTIRQ_BITS	0UL
+#define HARDIRQ_BITS	0UL
+#define SOFTIRQ_SHIFT	0UL
+#define HARDIRQ_SHIFT	0UL
+#define hardirq_count()	0UL
+#define softirq_count()	0UL
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/hash.h b/tools/lib/lockdep/uinclude/linux/hash.h
new file mode 100644
index 0000000..0f84798
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/hash.h
@@ -0,0 +1 @@
+#include "../../../include/linux/hash.h"
diff --git a/tools/lib/lockdep/uinclude/linux/interrupt.h b/tools/lib/lockdep/uinclude/linux/interrupt.h
new file mode 100644
index 0000000..e69de29
diff --git a/tools/lib/lockdep/uinclude/linux/irqflags.h b/tools/lib/lockdep/uinclude/linux/irqflags.h
new file mode 100644
index 0000000..6cc296f
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/irqflags.h
@@ -0,0 +1,38 @@
+#ifndef _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_
+#define _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_
+
+# define trace_hardirq_context(p)	0
+# define trace_softirq_context(p)	0
+# define trace_hardirqs_enabled(p)	0
+# define trace_softirqs_enabled(p)	0
+# define trace_hardirq_enter()		do { } while (0)
+# define trace_hardirq_exit()		do { } while (0)
+# define lockdep_softirq_enter()	do { } while (0)
+# define lockdep_softirq_exit()		do { } while (0)
+# define INIT_TRACE_IRQFLAGS
+
+# define stop_critical_timings() do { } while (0)
+# define start_critical_timings() do { } while (0)
+
+#define raw_local_irq_disable() do { } while (0)
+#define raw_local_irq_enable() do { } while (0)
+#define raw_local_irq_save(flags) ((flags) = 0)
+#define raw_local_irq_restore(flags) do { } while (0)
+#define raw_local_save_flags(flags) ((flags) = 0)
+#define raw_irqs_disabled_flags(flags) do { } while (0)
+#define raw_irqs_disabled() 0
+#define raw_safe_halt()
+
+#define local_irq_enable() do { } while (0)
+#define local_irq_disable() do { } while (0)
+#define local_irq_save(flags) ((flags) = 0)
+#define local_irq_restore(flags) do { } while (0)
+#define local_save_flags(flags)	((flags) = 0)
+#define irqs_disabled() (1)
+#define irqs_disabled_flags(flags) (0)
+#define safe_halt() do { } while (0)
+
+#define trace_lock_release(x, y)
+#define trace_lock_acquire(a, b, c, d, e, f, g)
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/kallsyms.h b/tools/lib/lockdep/uinclude/linux/kallsyms.h
new file mode 100644
index 0000000..b0f2dbd
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/kallsyms.h
@@ -0,0 +1,32 @@
+#ifndef _LIBLOCKDEP_LINUX_KALLSYMS_H_
+#define _LIBLOCKDEP_LINUX_KALLSYMS_H_
+
+#include <linux/kernel.h>
+#include <stdio.h>
+
+#define KSYM_NAME_LEN 128
+
+struct module;
+
+static inline const char *kallsyms_lookup(unsigned long addr,
+					  unsigned long *symbolsize,
+					  unsigned long *offset,
+					  char **modname, char *namebuf)
+{
+	return NULL;
+}
+
+#include <execinfo.h>
+#include <stdlib.h>
+static inline void print_ip_sym(unsigned long ip)
+{
+	char **name;
+
+	name = backtrace_symbols((void **)&ip, 1);
+
+	printf("%s\n", *name);
+
+	free(name);
+}
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/kernel.h b/tools/lib/lockdep/uinclude/linux/kernel.h
new file mode 100644
index 0000000..af02ac1
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/kernel.h
@@ -0,0 +1,36 @@
+#ifndef _LIBLOCKDEP_LINUX_KERNEL_H_
+#define _LIBLOCKDEP_LINUX_KERNEL_H_
+
+#include <linux/export.h>
+#include <linux/types.h>
+#include <linux/rcu.h>
+#include <linux/hardirq.h>
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({			\
+	const typeof(((type *)0)->member) * __mptr = (ptr);	\
+	(type *)((char *)__mptr - offsetof(type, member)); })
+#endif
+
+#define max(x, y) ({				\
+	typeof(x) _max1 = (x);			\
+	typeof(y) _max2 = (y);			\
+	(void) (&_max1 == &_max2);		\
+	_max1 > _max2 ? _max1 : _max2; })
+
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+#define WARN_ON(x) (x)
+#define WARN_ON_ONCE(x) (x)
+#define likely(x) (x)
+#define WARN(x, y, z) (x)
+#define uninitialized_var(x) x
+#define __init
+#define noinline
+#define list_add_tail_rcu list_add_tail
+
+#ifndef CALLER_ADDR0
+#define _THIS_IP_ CALLER_ADDR0
+#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0))
+#endif
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/kmemcheck.h b/tools/lib/lockdep/uinclude/linux/kmemcheck.h
new file mode 100644
index 0000000..94d598b
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/kmemcheck.h
@@ -0,0 +1,8 @@
+#ifndef _LIBLOCKDEP_LINUX_KMEMCHECK_H_
+#define _LIBLOCKDEP_LINUX_KMEMCHECK_H_
+
+static inline void kmemcheck_mark_initialized(void *address, unsigned int n)
+{
+}
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/linkage.h b/tools/lib/lockdep/uinclude/linux/linkage.h
new file mode 100644
index 0000000..e69de29
diff --git a/tools/lib/lockdep/uinclude/linux/list.h b/tools/lib/lockdep/uinclude/linux/list.h
new file mode 100644
index 0000000..6e9ef31
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/list.h
@@ -0,0 +1 @@
+#include "../../../include/linux/list.h"
diff --git a/tools/lib/lockdep/uinclude/linux/lockdep.h b/tools/lib/lockdep/uinclude/linux/lockdep.h
new file mode 100644
index 0000000..8e9a5c4
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/lockdep.h
@@ -0,0 +1,58 @@
+#ifndef _LIBLOCKDEP_LOCKDEP_H_
+#define _LIBLOCKDEP_LOCKDEP_H_
+
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <string.h>
+#include <limits.h>
+#include <linux/utsname.h>
+
+
+#define MAX_LOCK_DEPTH 2000UL
+
+#include "../../../include/linux/lockdep.h"
+
+struct task_struct {
+	u64 curr_chain_key;
+	int lockdep_depth;
+	unsigned int lockdep_recursion;
+	struct held_lock held_locks[MAX_LOCK_DEPTH];
+	gfp_t lockdep_reclaim_gfp;
+	int pid;
+	char comm[17];
+};
+
+extern struct task_struct *__curr(void);
+
+#define current (__curr())
+
+#define debug_locks_off() 1
+#define task_pid_nr(tsk) ((tsk)->pid)
+
+#define KSYM_NAME_LEN 128
+#define printk printf
+
+#define KERN_ERR
+#define KERN_CONT
+
+#define list_del_rcu list_del
+
+#define atomic_t unsigned long
+#define atomic_inc(x) ((*(x))++)
+
+static struct new_utsname *init_utsname(void)
+{
+	static struct new_utsname n = (struct new_utsname) {
+		.release = "liblockdep",
+		.version = LIBLOCKDEP_VERSION,
+	};
+
+	return &n;
+}
+
+#define print_tainted() ""
+#define static_obj(x) 1
+
+#define debug_show_all_locks()
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/mm_types.h b/tools/lib/lockdep/uinclude/linux/mm_types.h
new file mode 100644
index 0000000..e69de29
diff --git a/tools/lib/lockdep/uinclude/linux/module.h b/tools/lib/lockdep/uinclude/linux/module.h
new file mode 100644
index 0000000..09c7a7b
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/module.h
@@ -0,0 +1,6 @@
+#ifndef _LIBLOCKDEP_LINUX_MODULE_H_
+#define _LIBLOCKDEP_LINUX_MODULE_H_
+
+#define module_param(name, type, perm)
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/mutex.h b/tools/lib/lockdep/uinclude/linux/mutex.h
new file mode 100644
index 0000000..e69de29
diff --git a/tools/lib/lockdep/uinclude/linux/poison.h b/tools/lib/lockdep/uinclude/linux/poison.h
new file mode 100644
index 0000000..0c27bdf
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/poison.h
@@ -0,0 +1 @@
+#include "../../../include/linux/poison.h"
diff --git a/tools/lib/lockdep/uinclude/linux/prefetch.h b/tools/lib/lockdep/uinclude/linux/prefetch.h
new file mode 100644
index 0000000..d73fe6f
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/prefetch.h
@@ -0,0 +1,6 @@
+#ifndef _LIBLOCKDEP_LINUX_PREFETCH_H_
+#define _LIBLOCKDEP_LINUX_PREFETCH_H
+
+static inline void prefetch(void *a __attribute__((unused))) { }
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/proc_fs.h b/tools/lib/lockdep/uinclude/linux/proc_fs.h
new file mode 100644
index 0000000..e69de29
diff --git a/tools/lib/lockdep/uinclude/linux/rbtree.h b/tools/lib/lockdep/uinclude/linux/rbtree.h
new file mode 100644
index 0000000..965901d
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/rbtree.h
@@ -0,0 +1 @@
+#include "../../../include/linux/rbtree.h"
diff --git a/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h b/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h
new file mode 100644
index 0000000..c375947
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h
@@ -0,0 +1,2 @@
+#define __always_inline
+#include "../../../include/linux/rbtree_augmented.h"
diff --git a/tools/lib/lockdep/uinclude/linux/rcu.h b/tools/lib/lockdep/uinclude/linux/rcu.h
new file mode 100644
index 0000000..4c99fcb
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/rcu.h
@@ -0,0 +1,16 @@
+#ifndef _LIBLOCKDEP_RCU_H_
+#define _LIBLOCKDEP_RCU_H_
+
+int rcu_scheduler_active;
+
+static inline int rcu_lockdep_current_cpu_online(void)
+{
+	return 1;
+}
+
+static inline int rcu_is_cpu_idle(void)
+{
+	return 1;
+}
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/seq_file.h b/tools/lib/lockdep/uinclude/linux/seq_file.h
new file mode 100644
index 0000000..e69de29
diff --git a/tools/lib/lockdep/uinclude/linux/spinlock.h b/tools/lib/lockdep/uinclude/linux/spinlock.h
new file mode 100644
index 0000000..68c1aa2
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/spinlock.h
@@ -0,0 +1,25 @@
+#ifndef _LIBLOCKDEP_SPINLOCK_H_
+#define _LIBLOCKDEP_SPINLOCK_H_
+
+#include <pthread.h>
+#include <stdbool.h>
+
+#define arch_spinlock_t pthread_mutex_t
+#define __ARCH_SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER
+
+static inline void arch_spin_lock(arch_spinlock_t *mutex)
+{
+	pthread_mutex_lock(mutex);
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *mutex)
+{
+	pthread_mutex_unlock(mutex);
+}
+
+static inline bool arch_spin_is_locked(arch_spinlock_t *mutex)
+{
+	return true;
+}
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/stacktrace.h b/tools/lib/lockdep/uinclude/linux/stacktrace.h
new file mode 100644
index 0000000..39aecc6
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/stacktrace.h
@@ -0,0 +1,32 @@
+#ifndef _LIBLOCKDEP_LINUX_STACKTRACE_H_
+#define _LIBLOCKDEP_LINUX_STACKTRACE_H_
+
+#include <execinfo.h>
+
+struct stack_trace {
+	unsigned int nr_entries, max_entries;
+	unsigned long *entries;
+	int skip;
+};
+
+static inline void print_stack_trace(struct stack_trace *trace, int spaces)
+{
+	backtrace_symbols_fd((void **)trace->entries, trace->nr_entries, 1);
+}
+
+#define save_stack_trace(trace)	\
+	((trace)->nr_entries =	\
+		backtrace((void **)(trace)->entries, (trace)->max_entries))
+
+static inline int dump_stack(void)
+{
+	void *array[64];
+	size_t size;
+
+	size = backtrace(array, 64);
+	backtrace_symbols_fd(array, size, 1);
+
+	return 0;
+}
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/stringify.h b/tools/lib/lockdep/uinclude/linux/stringify.h
new file mode 100644
index 0000000..05dfcd1
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/stringify.h
@@ -0,0 +1,7 @@
+#ifndef _LIBLOCKDEP_LINUX_STRINGIFY_H_
+#define _LIBLOCKDEP_LINUX_STRINGIFY_H_
+
+#define __stringify_1(x...)	#x
+#define __stringify(x...)	__stringify_1(x)
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/system.h b/tools/lib/lockdep/uinclude/linux/system.h
new file mode 100644
index 0000000..e69de29
diff --git a/tools/lib/lockdep/uinclude/linux/types.h b/tools/lib/lockdep/uinclude/linux/types.h
new file mode 100644
index 0000000..929938f
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/types.h
@@ -0,0 +1,58 @@
+#ifndef _LIBLOCKDEP_LINUX_TYPES_H_
+#define _LIBLOCKDEP_LINUX_TYPES_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#define __SANE_USERSPACE_TYPES__	/* For PPC64, to get LL64 types */
+#include <asm/types.h>
+
+struct page;
+struct kmem_cache;
+
+typedef unsigned gfp_t;
+
+typedef __u64 u64;
+typedef __s64 s64;
+
+typedef __u32 u32;
+typedef __s32 s32;
+
+typedef __u16 u16;
+typedef __s16 s16;
+
+typedef __u8  u8;
+typedef __s8  s8;
+
+#ifdef __CHECKER__
+#define __bitwise__ __attribute__((bitwise))
+#else
+#define __bitwise__
+#endif
+#ifdef __CHECK_ENDIAN__
+#define __bitwise __bitwise__
+#else
+#define __bitwise
+#endif
+
+
+typedef __u16 __bitwise __le16;
+typedef __u16 __bitwise __be16;
+typedef __u32 __bitwise __le32;
+typedef __u32 __bitwise __be32;
+typedef __u64 __bitwise __le64;
+typedef __u64 __bitwise __be64;
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+struct hlist_head {
+	struct hlist_node *first;
+};
+
+struct hlist_node {
+	struct hlist_node *next, **pprev;
+};
+
+#endif
diff --git a/tools/lib/lockdep/uinclude/linux/util.h b/tools/lib/lockdep/uinclude/linux/util.h
new file mode 100644
index 0000000..e69de29
diff --git a/tools/lib/lockdep/uinclude/trace/events/lock.h b/tools/lib/lockdep/uinclude/trace/events/lock.h
new file mode 100644
index 0000000..e69de29
-- 
1.8.2.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 3/9] liblockdep: Add public headers for pthread_mutex_t implementation
  2013-04-30 18:54 [PATCH 0/9] liblockdep: userspace lockdep Sasha Levin
  2013-04-30 18:54 ` [PATCH 1/9] lockdep: Be nice about building from userspace Sasha Levin
  2013-04-30 18:54 ` [PATCH 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage " Sasha Levin
@ 2013-04-30 18:54 ` Sasha Levin
  2013-04-30 18:54 ` [PATCH 4/9] liblockdep: Add pthread_mutex_t test suite Sasha Levin
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Sasha Levin @ 2013-04-30 18:54 UTC (permalink / raw)
  To: torvalds; +Cc: mingo, peterz, linux-kernel, Sasha Levin

These headers provide the same API as their pthread mutex
counterparts.

The design here is to allow to easily switch to liblockdep lock
validation just by adding a "liblockdep_" to pthread_mutex_*()
calls, which means that it's easy to integrate liblockdep into
existing codebases.

Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
 tools/lib/lockdep/include/liblockdep/common.h | 43 ++++++++++++++++
 tools/lib/lockdep/include/liblockdep/mutex.h  | 73 +++++++++++++++++++++++++++
 2 files changed, 116 insertions(+)
 create mode 100644 tools/lib/lockdep/include/liblockdep/common.h
 create mode 100644 tools/lib/lockdep/include/liblockdep/mutex.h

diff --git a/tools/lib/lockdep/include/liblockdep/common.h b/tools/lib/lockdep/include/liblockdep/common.h
new file mode 100644
index 0000000..1bad66c
--- /dev/null
+++ b/tools/lib/lockdep/include/liblockdep/common.h
@@ -0,0 +1,43 @@
+#ifndef _LIBLOCKDEP_COMMON_H
+#define _LIBLOCKDEP_COMMON_H
+
+#include <pthread.h>
+
+#ifndef CALLER_ADDR0
+#define CALLER_ADDR0 (__builtin_return_address(0))
+#define _THIS_IP_ CALLER_ADDR0
+#endif
+
+#define NR_LOCKDEP_CACHING_CLASSES 2
+#define MAX_LOCKDEP_SUBCLASSES 8UL
+
+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, int nested,
+			unsigned long ip);
+
+#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
new file mode 100644
index 0000000..6ebe733
--- /dev/null
+++ b/tools/lib/lockdep/include/liblockdep/mutex.h
@@ -0,0 +1,73 @@
+#ifndef _LIBLOCKDEP_MUTEX_H
+#define _LIBLOCKDEP_MUTEX_H
+
+#include <pthread.h>
+#include "common.h"
+
+struct liblockdep_pthread_mutex {
+	pthread_mutex_t mutex;
+	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)		\
+({								\
+	static struct lock_class_key __key;			\
+								\
+	__mutex_init((mutex), #mutex, &__key, (mutexattr));	\
+})
+
+static inline int liblockdep_pthread_mutex_lock(liblockdep_pthread_mutex_t *lock)
+{
+	void *ip = _THIS_IP_;
+	lock_acquire(&lock->dep_map, 0, 0, 0, 2, NULL, (unsigned long)ip);
+	return pthread_mutex_lock(&lock->mutex);
+}
+
+static inline int liblockdep_pthread_mutex_unlock(liblockdep_pthread_mutex_t *lock)
+{
+	void *ip = _THIS_IP_;
+	lock_release(&lock->dep_map, 0, (unsigned long)ip);
+	return pthread_mutex_unlock(&lock->mutex);
+}
+
+static inline int liblockdep_pthread_mutex_trylock(liblockdep_pthread_mutex_t *lock)
+{
+	void *ip = _THIS_IP_;
+	lock_acquire(&lock->dep_map, 0, 1, 0, 2, NULL, (unsigned long)ip);
+	return pthread_mutex_trylock(&lock->mutex) == 0 ? 1 : 0;
+}
+
+static inline int liblockdep_pthread_mutex_destroy(liblockdep_pthread_mutex_t *lock)
+{
+	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
-- 
1.8.2.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 4/9] liblockdep: Add pthread_mutex_t test suite
  2013-04-30 18:54 [PATCH 0/9] liblockdep: userspace lockdep Sasha Levin
                   ` (2 preceding siblings ...)
  2013-04-30 18:54 ` [PATCH 3/9] liblockdep: Add public headers for pthread_mutex_t implementation Sasha Levin
@ 2013-04-30 18:54 ` Sasha Levin
  2013-04-30 18:54 ` [PATCH 5/9] liblockdep: Add public headers for pthread_rwlock_t implementation Sasha Levin
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Sasha Levin @ 2013-04-30 18:54 UTC (permalink / raw)
  To: torvalds; +Cc: mingo, peterz, linux-kernel, Sasha Levin

This is a rather simple and basic test suite to test common
locking issues.

Beyond tests, it also shows how to use the library.

Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
 tools/lib/lockdep/run_tests.sh           | 27 +++++++++++++++++++++++++++
 tools/lib/lockdep/tests/AA.c             | 13 +++++++++++++
 tools/lib/lockdep/tests/ABBA.c           | 13 +++++++++++++
 tools/lib/lockdep/tests/ABBCCA.c         | 15 +++++++++++++++
 tools/lib/lockdep/tests/ABBCCDDA.c       | 17 +++++++++++++++++
 tools/lib/lockdep/tests/ABCABC.c         | 15 +++++++++++++++
 tools/lib/lockdep/tests/ABCDBCDA.c       | 17 +++++++++++++++++
 tools/lib/lockdep/tests/ABCDBDDA.c       | 17 +++++++++++++++++
 tools/lib/lockdep/tests/common.h         | 12 ++++++++++++
 tools/lib/lockdep/tests/unlock_balance.c | 12 ++++++++++++
 10 files changed, 158 insertions(+)
 create mode 100755 tools/lib/lockdep/run_tests.sh
 create mode 100644 tools/lib/lockdep/tests/AA.c
 create mode 100644 tools/lib/lockdep/tests/ABBA.c
 create mode 100644 tools/lib/lockdep/tests/ABBCCA.c
 create mode 100644 tools/lib/lockdep/tests/ABBCCDDA.c
 create mode 100644 tools/lib/lockdep/tests/ABCABC.c
 create mode 100644 tools/lib/lockdep/tests/ABCDBCDA.c
 create mode 100644 tools/lib/lockdep/tests/ABCDBDDA.c
 create mode 100644 tools/lib/lockdep/tests/common.h
 create mode 100644 tools/lib/lockdep/tests/unlock_balance.c

diff --git a/tools/lib/lockdep/run_tests.sh b/tools/lib/lockdep/run_tests.sh
new file mode 100755
index 0000000..240a93c
--- /dev/null
+++ b/tools/lib/lockdep/run_tests.sh
@@ -0,0 +1,27 @@
+#! /bin/bash
+
+make &> /dev/null
+
+for i in `ls tests/*.c`; do
+	testname=$(basename -s .c "$i")
+	gcc -o tests/$testname -lpthread $i liblockdep.a -Iinclude -D__USE_LIBLOCKDEP &> /dev/null
+	echo -ne "$testname... "
+	if [ $(timeout 1 ./tests/$testname | wc -l) -gt 0 ]; then
+		echo "PASSED!"
+	else
+		echo "FAILED!"
+	fi
+	rm tests/$testname
+done
+
+for i in `ls tests/*.c`; do
+	testname=$(basename -s .c "$i")
+	gcc -o tests/$testname -lpthread -Iinclude $i &> /dev/null
+	echo -ne "(PRELOAD) $testname... "
+	if [ $(timeout 1 ./lockdep ./tests/$testname | wc -l) -gt 0 ]; then
+		echo "PASSED!"
+	else
+		echo "FAILED!"
+	fi
+	rm tests/$testname
+done
diff --git a/tools/lib/lockdep/tests/AA.c b/tools/lib/lockdep/tests/AA.c
new file mode 100644
index 0000000..0f782ff
--- /dev/null
+++ b/tools/lib/lockdep/tests/AA.c
@@ -0,0 +1,13 @@
+#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/ABBA.c b/tools/lib/lockdep/tests/ABBA.c
new file mode 100644
index 0000000..07f0e29
--- /dev/null
+++ b/tools/lib/lockdep/tests/ABBA.c
@@ -0,0 +1,13 @@
+#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);
+}
diff --git a/tools/lib/lockdep/tests/ABBCCA.c b/tools/lib/lockdep/tests/ABBCCA.c
new file mode 100644
index 0000000..843db09
--- /dev/null
+++ b/tools/lib/lockdep/tests/ABBCCA.c
@@ -0,0 +1,15 @@
+#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);
+}
diff --git a/tools/lib/lockdep/tests/ABBCCDDA.c b/tools/lib/lockdep/tests/ABBCCDDA.c
new file mode 100644
index 0000000..33620e2
--- /dev/null
+++ b/tools/lib/lockdep/tests/ABBCCDDA.c
@@ -0,0 +1,17 @@
+#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);
+}
diff --git a/tools/lib/lockdep/tests/ABCABC.c b/tools/lib/lockdep/tests/ABCABC.c
new file mode 100644
index 0000000..3fee51e
--- /dev/null
+++ b/tools/lib/lockdep/tests/ABCABC.c
@@ -0,0 +1,15 @@
+#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);
+}
diff --git a/tools/lib/lockdep/tests/ABCDBCDA.c b/tools/lib/lockdep/tests/ABCDBCDA.c
new file mode 100644
index 0000000..427ba56
--- /dev/null
+++ b/tools/lib/lockdep/tests/ABCDBCDA.c
@@ -0,0 +1,17 @@
+#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);
+}
diff --git a/tools/lib/lockdep/tests/ABCDBDDA.c b/tools/lib/lockdep/tests/ABCDBDDA.c
new file mode 100644
index 0000000..680c6cf
--- /dev/null
+++ b/tools/lib/lockdep/tests/ABCDBDDA.c
@@ -0,0 +1,17 @@
+#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);
+}
diff --git a/tools/lib/lockdep/tests/common.h b/tools/lib/lockdep/tests/common.h
new file mode 100644
index 0000000..d89e94d
--- /dev/null
+++ b/tools/lib/lockdep/tests/common.h
@@ -0,0 +1,12 @@
+#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
new file mode 100644
index 0000000..0bc62de
--- /dev/null
+++ b/tools/lib/lockdep/tests/unlock_balance.c
@@ -0,0 +1,12 @@
+#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);
+}
-- 
1.8.2.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 5/9] liblockdep: Add public headers for pthread_rwlock_t implementation
  2013-04-30 18:54 [PATCH 0/9] liblockdep: userspace lockdep Sasha Levin
                   ` (3 preceding siblings ...)
  2013-04-30 18:54 ` [PATCH 4/9] liblockdep: Add pthread_mutex_t test suite Sasha Levin
@ 2013-04-30 18:54 ` Sasha Levin
  2013-04-30 18:54 ` [PATCH 6/9] liblockdep: Add pthread_rwlock_t test suite Sasha Levin
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Sasha Levin @ 2013-04-30 18:54 UTC (permalink / raw)
  To: torvalds; +Cc: mingo, peterz, linux-kernel, Sasha Levin

Both pthreads and lockdep support dealing with rwlocks, so
here's the liblockdep implementation for those.

Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
 tools/lib/lockdep/include/liblockdep/rwlock.h | 91 +++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)
 create mode 100644 tools/lib/lockdep/include/liblockdep/rwlock.h

diff --git a/tools/lib/lockdep/include/liblockdep/rwlock.h b/tools/lib/lockdep/include/liblockdep/rwlock.h
new file mode 100644
index 0000000..a1d820b
--- /dev/null
+++ b/tools/lib/lockdep/include/liblockdep/rwlock.h
@@ -0,0 +1,91 @@
+#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)
+{
+	void *ip = _THIS_IP_;
+	lock_acquire(&lock->dep_map, 0, 0, 2, 2, NULL, (unsigned long)ip);
+	return pthread_rwlock_rdlock(&lock->rwlock);
+
+}
+
+static inline int liblockdep_pthread_rwlock_unlock(liblockdep_pthread_rwlock_t *lock)
+{
+	void *ip = _THIS_IP_;
+	lock_release(&lock->dep_map, 0, (unsigned long)ip);
+	return pthread_rwlock_unlock(&lock->rwlock);
+}
+
+static inline int liblockdep_pthread_rwlock_wrlock(liblockdep_pthread_rwlock_t *lock)
+{
+	void *ip = _THIS_IP_;
+	lock_acquire(&lock->dep_map, 0, 0, 0, 2, NULL, (unsigned long)ip);
+	return pthread_rwlock_wrlock(&lock->rwlock);
+}
+
+static inline int liblockdep_pthread_rwlock_tryrdlock(liblockdep_pthread_rwlock_t *lock)
+{
+	void *ip = _THIS_IP_;
+	lock_acquire(&lock->dep_map, 0, 1, 2, 2, NULL, (unsigned long)ip);
+	return pthread_rwlock_tryrdlock(&lock->rwlock) == 0 ? 1 : 0;
+}
+
+static inline int liblockdep_pthread_rwlock_trywlock(liblockdep_pthread_rwlock_t *lock)
+{
+	void *ip = _THIS_IP_;
+	lock_acquire(&lock->dep_map, 0, 1, 0, 2, NULL, (unsigned long)ip);
+	return pthread_rwlock_trywlock(&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_trywlock		liblockdep_pthread_rwlock_trywlock
+#define pthread_rwlock_destroy		liblockdep_rwlock_destroy
+
+#endif
+
+#endif
-- 
1.8.2.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 6/9] liblockdep: Add pthread_rwlock_t test suite
  2013-04-30 18:54 [PATCH 0/9] liblockdep: userspace lockdep Sasha Levin
                   ` (4 preceding siblings ...)
  2013-04-30 18:54 ` [PATCH 5/9] liblockdep: Add public headers for pthread_rwlock_t implementation Sasha Levin
@ 2013-04-30 18:54 ` Sasha Levin
  2013-04-30 18:54 ` [PATCH 7/9] liblockdep: Support using LD_PRELOAD Sasha Levin
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Sasha Levin @ 2013-04-30 18:54 UTC (permalink / raw)
  To: torvalds; +Cc: mingo, peterz, linux-kernel, Sasha Levin

A simple test to make sure we handle rwlocks correctly.

Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
 tools/lib/lockdep/tests/WW.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 tools/lib/lockdep/tests/WW.c

diff --git a/tools/lib/lockdep/tests/WW.c b/tools/lib/lockdep/tests/WW.c
new file mode 100644
index 0000000..d44f77d
--- /dev/null
+++ b/tools/lib/lockdep/tests/WW.c
@@ -0,0 +1,13 @@
+#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);
+}
-- 
1.8.2.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 7/9] liblockdep: Support using LD_PRELOAD
  2013-04-30 18:54 [PATCH 0/9] liblockdep: userspace lockdep Sasha Levin
                   ` (5 preceding siblings ...)
  2013-04-30 18:54 ` [PATCH 6/9] liblockdep: Add pthread_rwlock_t test suite Sasha Levin
@ 2013-04-30 18:54 ` Sasha Levin
  2013-05-08 10:22   ` Peter Zijlstra
  2013-04-30 18:54 ` [PATCH 8/9] liblockdep: Add the 'lockdep' user-space utility Sasha Levin
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: Sasha Levin @ 2013-04-30 18:54 UTC (permalink / raw)
  To: torvalds; +Cc: mingo, peterz, linux-kernel, Sasha Levin

This allows lockdep to be used without being compiled in the
original program.

Usage is quite simple:

	LD_PRELOAD=/path/to/liblockdep.so /path/to/my/program

And magically, you'll have lockdep checking in your program!

Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
 tools/lib/lockdep/preload.c | 386 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 386 insertions(+)
 create mode 100644 tools/lib/lockdep/preload.c

diff --git a/tools/lib/lockdep/preload.c b/tools/lib/lockdep/preload.c
new file mode 100644
index 0000000..6ae71c6
--- /dev/null
+++ b/tools/lib/lockdep/preload.c
@@ -0,0 +1,386 @@
+#define _GNU_SOURCE
+#include <pthread.h>
+#include <stdio.h>
+#include <dlfcn.h>
+#include <stdlib.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 */
+	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 */
+static int (*ll_pthread_mutex_init)(pthread_mutex_t *mutex,
+			const pthread_mutexattr_t *attr);
+static int (*ll_pthread_mutex_lock)(pthread_mutex_t *mutex);
+static int (*ll_pthread_mutex_trylock)(pthread_mutex_t *mutex);
+static int (*ll_pthread_mutex_unlock)(pthread_mutex_t *mutex);
+static int (*ll_pthread_mutex_destroy)(pthread_mutex_t *mutex);
+
+/* pthread rwlock API */
+static int (*ll_pthread_rwlock_init)(pthread_rwlock_t *rwlock,
+			const pthread_rwlockattr_t *attr);
+static int (*ll_pthread_rwlock_destroy)(pthread_rwlock_t *rwlock);
+static int (*ll_pthread_rwlock_rdlock)(pthread_rwlock_t *rwlock);
+static int (*ll_pthread_rwlock_tryrdlock)(pthread_rwlock_t *rwlock);
+static int (*ll_pthread_rwlock_trywrlock)(pthread_rwlock_t *rwlock);
+static int (*ll_pthread_rwlock_wrlock)(pthread_rwlock_t *rwlock);
+static int (*ll_pthread_rwlock_unlock)(pthread_rwlock_t *rwlock);
+
+static bool preload_done;
+static void init_preload(void);
+static void try_init_preload(void)
+{
+	if (!preload_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;
+}
+
+/**
+ * __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 = malloc(sizeof(*l));
+	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;
+}
+
+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/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, 2, NULL,
+			(unsigned long)_THIS_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, 0, (unsigned long)_THIS_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, 2, NULL, (unsigned long)_THIS_IP_);
+	r = ll_pthread_mutex_trylock(mutex);
+	if (r)
+		lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_THIS_IP_);
+
+	return r;
+}
+
+int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+	int r;
+
+        try_init_preload();
+
+	lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_THIS_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, 2, NULL, (unsigned long)_THIS_IP_);
+
+	return r;
+}
+
+int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+	struct lock_lookup *l = __get_lock(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, mutex + sizeof(*mutex));
+	ll_pthread_rwlock_wrlock(&locks_rwlock);
+	rb_erase(&l->node, &locks);
+	ll_pthread_rwlock_unlock(&locks_rwlock);
+	free(l);
+	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)
+{
+	struct lock_lookup *l = __get_lock(rwlock);
+
+        try_init_preload();
+
+	debug_check_no_locks_freed(rwlock, rwlock + sizeof(*rwlock));
+	ll_pthread_rwlock_wrlock(&locks_rwlock);
+	rb_erase(&l->node, &locks);
+	ll_pthread_rwlock_unlock(&locks_rwlock);
+	free(l);
+	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, 2, NULL, (unsigned long)_THIS_IP_);
+	r = ll_pthread_rwlock_rdlock(rwlock);
+	if (r)
+		lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_THIS_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, 2, NULL, (unsigned long)_THIS_IP_);
+	r = ll_pthread_rwlock_tryrdlock(rwlock);
+	if (r)
+		lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_THIS_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, 2, NULL, (unsigned long)_THIS_IP_);
+	r = ll_pthread_rwlock_trywrlock(rwlock);
+	if (r)
+                lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_THIS_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, 2, NULL, (unsigned long)_THIS_IP_);
+	r = ll_pthread_rwlock_wrlock(rwlock);
+	if (r)
+		lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_THIS_IP_);
+
+	return r;
+}
+
+int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
+{
+	int r;
+
+        init_preload();
+
+	lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_THIS_IP_);
+	r = ll_pthread_rwlock_unlock(rwlock);
+	if (r)
+		lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 0, 2, NULL, (unsigned long)_THIS_IP_);
+
+	return r;
+}
+
+__attribute__((constructor)) static void init_preload(void)
+{
+	static bool preload_started;
+
+	if (preload_done)
+		return;
+
+	/*
+	 * 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 :(
+	 *
+	 * We can work around it by telling the program that locking was
+	 * really okay, and just initialize those locks when we're fully
+	 * up and running (this is ok because this all happens during
+	 * initialization phase, when we have just one thread). But
+	 * this is a big TODO at this point.
+	 */
+	if (preload_started) {
+		printf(
+		"LOCKDEP error: It seems that the program you are trying to "
+		"debug is initializing locks in it's allocation path.\n"
+		"This means that liblockdep cannot reliably analyze this "
+		"program since we need the allocator to work before we can "
+		"debug locks.\nSorry!\n");
+
+		exit(1);
+	}
+
+	preload_started = true;
+
+	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");
+
+	lockdep_init();
+
+	preload_done = true;
+}
-- 
1.8.2.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 8/9] liblockdep: Add the 'lockdep' user-space utility
  2013-04-30 18:54 [PATCH 0/9] liblockdep: userspace lockdep Sasha Levin
                   ` (6 preceding siblings ...)
  2013-04-30 18:54 ` [PATCH 7/9] liblockdep: Support using LD_PRELOAD Sasha Levin
@ 2013-04-30 18:54 ` Sasha Levin
  2013-04-30 18:54 ` [PATCH 9/9] liblockdep: Add a MAINTAINERS entry Sasha Levin
  2013-05-07 16:15 ` [PATCH 0/9] liblockdep: userspace lockdep Sasha Levin
  9 siblings, 0 replies; 17+ messages in thread
From: Sasha Levin @ 2013-04-30 18:54 UTC (permalink / raw)
  To: torvalds
  Cc: mingo, peterz, linux-kernel, Sasha Levin, jamie.iles, penberg,
	acme, paulus, namhyung, Andrew Morton, Peter Zijlstra,
	Thomas Gleixner

This is a simple wrapper to make using liblockdep on existing
applications much easier.

After running 'make && make install', it becomes quite simple to
test things with liblockdep. For example, to try it on perf:

	lockdep perf

No other integration required.

Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
Cc: jamie.iles@oracle.com
Cc: penberg@kernel.org
Cc: acme@ghostprotocols.net
Cc: paulus@samba.org
Cc: namhyung@kernel.org
Cc: peterz@infradead.org
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1360456781-32462-11-git-send-email-sasha.levin@oracle.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
 tools/lib/lockdep/lockdep | 3 +++
 1 file changed, 3 insertions(+)
 create mode 100755 tools/lib/lockdep/lockdep

diff --git a/tools/lib/lockdep/lockdep b/tools/lib/lockdep/lockdep
new file mode 100755
index 0000000..a805c81
--- /dev/null
+++ b/tools/lib/lockdep/lockdep
@@ -0,0 +1,3 @@
+#! /bin/bash
+
+LD_PRELOAD="liblockdep.so $LD_PRELOAD" "$@"
-- 
1.8.2.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 9/9] liblockdep: Add a MAINTAINERS entry
  2013-04-30 18:54 [PATCH 0/9] liblockdep: userspace lockdep Sasha Levin
                   ` (7 preceding siblings ...)
  2013-04-30 18:54 ` [PATCH 8/9] liblockdep: Add the 'lockdep' user-space utility Sasha Levin
@ 2013-04-30 18:54 ` Sasha Levin
  2013-05-07 16:15 ` [PATCH 0/9] liblockdep: userspace lockdep Sasha Levin
  9 siblings, 0 replies; 17+ messages in thread
From: Sasha Levin @ 2013-04-30 18:54 UTC (permalink / raw)
  To: torvalds; +Cc: mingo, peterz, linux-kernel, Sasha Levin

Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
 MAINTAINERS | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 8bdd7a7..e39345e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4784,6 +4784,11 @@ F:	drivers/lguest/
 F:	include/linux/lguest*.h
 F:	tools/lguest/
 
+LIBLOCK
+M:	Sasha Levin <sasha.levin@oracle.com>
+S:	Maintained
+F:	tools/lib/lockdep/
+
 LINUX FOR IBM pSERIES (RS/6000)
 M:	Paul Mackerras <paulus@au.ibm.com>
 W:	http://www.ibm.com/linux/ltc/projects/ppc
-- 
1.8.2.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/9] liblockdep: userspace lockdep
  2013-04-30 18:54 [PATCH 0/9] liblockdep: userspace lockdep Sasha Levin
                   ` (8 preceding siblings ...)
  2013-04-30 18:54 ` [PATCH 9/9] liblockdep: Add a MAINTAINERS entry Sasha Levin
@ 2013-05-07 16:15 ` Sasha Levin
  9 siblings, 0 replies; 17+ messages in thread
From: Sasha Levin @ 2013-05-07 16:15 UTC (permalink / raw)
  To: torvalds; +Cc: Sasha Levin, mingo, peterz, linux-kernel

Ping?


Thanks,
Sasha

On 04/30/2013 02:54 PM, Sasha Levin wrote:
> liblockdep is a tiny wrapper built around kernel/lockdep.c. The aim is to
> provide the same functionality the kernel gets from lockdep to userspace.
> 
> The bulk of the code here is the LD_PRELOAD support which provides users
> an easy way to test their code without having to integrate liblockdep into
> said code. Simply doing:
> 
> 	lockdep my_app
> 
> Would provide lockdep support to my_app.
> 
> There is also a small test suite to test both mutexes and rwlocks, it's
> based on the tests in lib/locking-selftest.c.
> 
> This entire patch series was reviewed by lockdep maintainers and accepted to
> the tip tree previously. It was pulled out so that the potential merge of
> liblockdep won't delay the rest of the commits in the tip locking tree.
> 
> For some more background about this entire thing, the folks at LWN did
> an awesome overview: http://lwn.net/Articles/536363/
> 
> 
> Sasha Levin (9):
>   lockdep: Be nice about building from userspace
>   liblockdep: Wrap kernel/lockdep.c to allow usage from userspace
>   liblockdep: Add public headers for pthread_mutex_t implementation
>   liblockdep: Add pthread_mutex_t test suite
>   liblockdep: Add public headers for pthread_rwlock_t implementation
>   liblockdep: Add pthread_rwlock_t test suite
>   liblockdep: Support using LD_PRELOAD
>   liblockdep: Add the 'lockdep' user-space utility
>   liblockdep: Add a MAINTAINERS entry
> 
>  MAINTAINERS                                        |   5 +
>  kernel/lockdep.c                                   |   4 +
>  tools/lib/lockdep/Makefile                         | 251 ++++++++++++++
>  tools/lib/lockdep/common.c                         |  33 ++
>  tools/lib/lockdep/include/liblockdep/common.h      |  43 +++
>  tools/lib/lockdep/include/liblockdep/mutex.h       |  73 ++++
>  tools/lib/lockdep/include/liblockdep/rwlock.h      |  91 +++++
>  tools/lib/lockdep/lockdep                          |   3 +
>  tools/lib/lockdep/lockdep.c                        |   2 +
>  tools/lib/lockdep/lockdep_internals.h              |   1 +
>  tools/lib/lockdep/lockdep_states.h                 |   1 +
>  tools/lib/lockdep/preload.c                        | 386 +++++++++++++++++++++
>  tools/lib/lockdep/rbtree.c                         |   1 +
>  tools/lib/lockdep/run_tests.sh                     |  27 ++
>  tools/lib/lockdep/tests/AA.c                       |  13 +
>  tools/lib/lockdep/tests/ABBA.c                     |  13 +
>  tools/lib/lockdep/tests/ABBCCA.c                   |  15 +
>  tools/lib/lockdep/tests/ABBCCDDA.c                 |  17 +
>  tools/lib/lockdep/tests/ABCABC.c                   |  15 +
>  tools/lib/lockdep/tests/ABCDBCDA.c                 |  17 +
>  tools/lib/lockdep/tests/ABCDBDDA.c                 |  17 +
>  tools/lib/lockdep/tests/WW.c                       |  13 +
>  tools/lib/lockdep/tests/common.h                   |  12 +
>  tools/lib/lockdep/tests/unlock_balance.c           |  12 +
>  tools/lib/lockdep/uinclude/asm/hweight.h           |   0
>  tools/lib/lockdep/uinclude/asm/sections.h          |   0
>  tools/lib/lockdep/uinclude/linux/bitops.h          |   0
>  tools/lib/lockdep/uinclude/linux/compiler.h        |   7 +
>  tools/lib/lockdep/uinclude/linux/debug_locks.h     |  12 +
>  tools/lib/lockdep/uinclude/linux/delay.h           |   0
>  tools/lib/lockdep/uinclude/linux/export.h          |   7 +
>  tools/lib/lockdep/uinclude/linux/ftrace.h          |   0
>  tools/lib/lockdep/uinclude/linux/gfp.h             |   0
>  tools/lib/lockdep/uinclude/linux/hardirq.h         |  11 +
>  tools/lib/lockdep/uinclude/linux/hash.h            |   1 +
>  tools/lib/lockdep/uinclude/linux/interrupt.h       |   0
>  tools/lib/lockdep/uinclude/linux/irqflags.h        |  38 ++
>  tools/lib/lockdep/uinclude/linux/kallsyms.h        |  32 ++
>  tools/lib/lockdep/uinclude/linux/kernel.h          |  36 ++
>  tools/lib/lockdep/uinclude/linux/kmemcheck.h       |   8 +
>  tools/lib/lockdep/uinclude/linux/linkage.h         |   0
>  tools/lib/lockdep/uinclude/linux/list.h            |   1 +
>  tools/lib/lockdep/uinclude/linux/lockdep.h         |  58 ++++
>  tools/lib/lockdep/uinclude/linux/mm_types.h        |   0
>  tools/lib/lockdep/uinclude/linux/module.h          |   6 +
>  tools/lib/lockdep/uinclude/linux/mutex.h           |   0
>  tools/lib/lockdep/uinclude/linux/poison.h          |   1 +
>  tools/lib/lockdep/uinclude/linux/prefetch.h        |   6 +
>  tools/lib/lockdep/uinclude/linux/proc_fs.h         |   0
>  tools/lib/lockdep/uinclude/linux/rbtree.h          |   1 +
>  .../lib/lockdep/uinclude/linux/rbtree_augmented.h  |   2 +
>  tools/lib/lockdep/uinclude/linux/rcu.h             |  16 +
>  tools/lib/lockdep/uinclude/linux/seq_file.h        |   0
>  tools/lib/lockdep/uinclude/linux/spinlock.h        |  25 ++
>  tools/lib/lockdep/uinclude/linux/stacktrace.h      |  32 ++
>  tools/lib/lockdep/uinclude/linux/stringify.h       |   7 +
>  tools/lib/lockdep/uinclude/linux/system.h          |   0
>  tools/lib/lockdep/uinclude/linux/types.h           |  58 ++++
>  tools/lib/lockdep/uinclude/linux/util.h            |   0
>  tools/lib/lockdep/uinclude/trace/events/lock.h     |   0
>  60 files changed, 1430 insertions(+)
>  create mode 100644 tools/lib/lockdep/Makefile
>  create mode 100644 tools/lib/lockdep/common.c
>  create mode 100644 tools/lib/lockdep/include/liblockdep/common.h
>  create mode 100644 tools/lib/lockdep/include/liblockdep/mutex.h
>  create mode 100644 tools/lib/lockdep/include/liblockdep/rwlock.h
>  create mode 100755 tools/lib/lockdep/lockdep
>  create mode 100644 tools/lib/lockdep/lockdep.c
>  create mode 100644 tools/lib/lockdep/lockdep_internals.h
>  create mode 100644 tools/lib/lockdep/lockdep_states.h
>  create mode 100644 tools/lib/lockdep/preload.c
>  create mode 100644 tools/lib/lockdep/rbtree.c
>  create mode 100755 tools/lib/lockdep/run_tests.sh
>  create mode 100644 tools/lib/lockdep/tests/AA.c
>  create mode 100644 tools/lib/lockdep/tests/ABBA.c
>  create mode 100644 tools/lib/lockdep/tests/ABBCCA.c
>  create mode 100644 tools/lib/lockdep/tests/ABBCCDDA.c
>  create mode 100644 tools/lib/lockdep/tests/ABCABC.c
>  create mode 100644 tools/lib/lockdep/tests/ABCDBCDA.c
>  create mode 100644 tools/lib/lockdep/tests/ABCDBDDA.c
>  create mode 100644 tools/lib/lockdep/tests/WW.c
>  create mode 100644 tools/lib/lockdep/tests/common.h
>  create mode 100644 tools/lib/lockdep/tests/unlock_balance.c
>  create mode 100644 tools/lib/lockdep/uinclude/asm/hweight.h
>  create mode 100644 tools/lib/lockdep/uinclude/asm/sections.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/bitops.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/compiler.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/debug_locks.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/delay.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/export.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/ftrace.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/gfp.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/hardirq.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/hash.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/interrupt.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/irqflags.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/kallsyms.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/kernel.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/kmemcheck.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/linkage.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/list.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/lockdep.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/mm_types.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/module.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/mutex.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/poison.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/prefetch.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/proc_fs.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/rbtree.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/rbtree_augmented.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/rcu.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/seq_file.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/spinlock.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/stacktrace.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/stringify.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/system.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/types.h
>  create mode 100644 tools/lib/lockdep/uinclude/linux/util.h
>  create mode 100644 tools/lib/lockdep/uinclude/trace/events/lock.h
> 


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage from userspace
  2013-04-30 18:54 ` [PATCH 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage " Sasha Levin
@ 2013-05-08 10:01   ` Peter Zijlstra
  2013-05-08 13:27     ` Sasha Levin
  0 siblings, 1 reply; 17+ messages in thread
From: Peter Zijlstra @ 2013-05-08 10:01 UTC (permalink / raw)
  To: Sasha Levin; +Cc: torvalds, mingo, linux-kernel

On Tue, Apr 30, 2013 at 02:54:33PM -0400, Sasha Levin wrote:
> diff --git a/tools/lib/lockdep/common.c b/tools/lib/lockdep/common.c
> new file mode 100644
> index 0000000..eb5e481
> --- /dev/null
> +++ b/tools/lib/lockdep/common.c
> @@ -0,0 +1,33 @@
> +#include <stddef.h>
> +#include <stdbool.h>
> +#include <linux/compiler.h>
> +#include <linux/lockdep.h>
> +#include <unistd.h>
> +#include <sys/syscall.h>
> +
> +static struct task_struct current_obj;
> +
> +/* lockdep wants these */
> +bool debug_locks = true;
> +bool debug_locks_silent;
> +
> +__attribute__((constructor)) static void liblockdep_init(void)
> +{
> +	lockdep_init();
> +}
> +
> +__attribute__((destructor)) static void liblockdep_exit(void)
> +{
> +	debug_check_no_locks_held(&current_obj);
> +}
> +
> +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 &current_obj;
> +}

> diff --git a/tools/lib/lockdep/uinclude/linux/lockdep.h b/tools/lib/lockdep/uinclude/linux/lockdep.h
> new file mode 100644
> index 0000000..8e9a5c4
> --- /dev/null
> +++ b/tools/lib/lockdep/uinclude/linux/lockdep.h
> @@ -0,0 +1,58 @@
> +#ifndef _LIBLOCKDEP_LOCKDEP_H_
> +#define _LIBLOCKDEP_LOCKDEP_H_
> +
> +#include <sys/prctl.h>
> +#include <sys/syscall.h>
> +#include <string.h>
> +#include <limits.h>
> +#include <linux/utsname.h>
> +
> +
> +#define MAX_LOCK_DEPTH 2000UL
> +
> +#include "../../../include/linux/lockdep.h"
> +
> +struct task_struct {
> +	u64 curr_chain_key;
> +	int lockdep_depth;
> +	unsigned int lockdep_recursion;
> +	struct held_lock held_locks[MAX_LOCK_DEPTH];
> +	gfp_t lockdep_reclaim_gfp;
> +	int pid;
> +	char comm[17];
> +};
> +
> +extern struct task_struct *__curr(void);
> +
> +#define current (__curr())
> +
> +#define debug_locks_off() 1
> +#define task_pid_nr(tsk) ((tsk)->pid)
> +
> +#define KSYM_NAME_LEN 128
> +#define printk printf
> +
> +#define KERN_ERR
> +#define KERN_CONT
> +
> +#define list_del_rcu list_del
> +
> +#define atomic_t unsigned long
> +#define atomic_inc(x) ((*(x))++)
> +
> +static struct new_utsname *init_utsname(void)
> +{
> +	static struct new_utsname n = (struct new_utsname) {
> +		.release = "liblockdep",
> +		.version = LIBLOCKDEP_VERSION,
> +	};
> +
> +	return &n;
> +}
> +
> +#define print_tainted() ""
> +#define static_obj(x) 1
> +
> +#define debug_show_all_locks()
> +
> +#endif

I don't see how this could possible work for threaded programs; you only have a
single task_struct instance. Wouldn't you need something like the below?

---

static int (*pthread_create_orig)(pthread_t *__restrict,
		__const pthread_attr_t *__restrict,
		void *(*)(void *),
		void *__restrict) = NULL;


static __thread struct task_struct __current;

#define current (&__current)

static void sched_fork(void)
{
	/* init __current */
}

__attribute__((constructor)) static void sched_init(void) 
{
	pthread_create_orig = dlsym(RTLD_NEXT, "pthread_create");
	if (!pthread_create_orig) {
		char *error = dlerror();
		if (!error)
			error = "pthread_create is NULL";
		die("%s\n", error);
	}

	sched_fork(); /* main thread */
}

__attribute__((destructor)) static void sched_exit(void)
{
	/* */
}

struct tramp_data {

	void *(*func)(void *);
	void *arg;

	pthread_mutex_t lock;
	pthread_cond_t  wait;
};

static void *tramp_func(void *data)
{
	struct tramp_data *tramp_data = data;
	void *(*func)(void *) = tramp_data->func;
	void *arg = tramp_data->arg;

	sched_fork();

	pthread_mutex_lock(&tramp_data->lock);
	pthread_cond_signal(&tramp_data->wait);
	pthread_mutex_unlock(&tramp_data->lock);

	return func(arg);
}

/* hijack pthread_create() */
int pthread_create(pthread_t *__restrict thread,
		__const pthread_attr_t *__restrict attr,
		void *(*func)(void *),
		void *__restrict arg)
{
	struct tramp_data tramp_data = {
		.func = func,
		.arg = arg,
	};
	int ret;

	pthread_cond_init(&tramp_data.wait, NULL);
	pthread_mutex_init(&tramp_data.lock, NULL);

	pthread_mutex_lock(&tramp_data.lock);

	ret = pthread_create_orig(thread, attr, &tramp_func, &tramp_data);
	if (!ret)
		pthread_cond_wait(&tramp_data.wait, &tramp_data.lock);

	pthread_mutex_unlock(&tramp_data.lock);

	pthread_mutex_destroy(&tramp_data.lock);
	pthread_cond_destroy(&tramp_data.wait);

	return ret;
} 


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 7/9] liblockdep: Support using LD_PRELOAD
  2013-04-30 18:54 ` [PATCH 7/9] liblockdep: Support using LD_PRELOAD Sasha Levin
@ 2013-05-08 10:22   ` Peter Zijlstra
  2013-05-08 13:29     ` Sasha Levin
  0 siblings, 1 reply; 17+ messages in thread
From: Peter Zijlstra @ 2013-05-08 10:22 UTC (permalink / raw)
  To: Sasha Levin; +Cc: torvalds, mingo, linux-kernel

On Tue, Apr 30, 2013 at 02:54:38PM -0400, Sasha Levin wrote:
> +
> +static struct rb_node **__get_lock_node(void *lock, struct rb_node **parent)
> +{

> +}
> +
> +/**
> + * __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)
> +{

> +}

This needs something like:

static void __del_lock(void *lock);

Since now you're repeating yourself in pthread_{rwlock,mutex}_destroy() :-)

> +int pthread_mutex_lock(pthread_mutex_t *mutex)
> +{
> +	int r;
> +
> +        try_init_preload();

You seem consistently whitespace challenged on this line.

> +
> +	lock_acquire(&__get_lock(mutex)->dep_map, 0, 0, 0, 2, NULL,
> +			(unsigned long)_THIS_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.

mutex_lock_{interruptible,killable}() could be argued to be able to fail too.
And if you look at __mutex_lock_common() you'll see that it does the exact same
thing -- that is release on fail.

> +	 * 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, 0, (unsigned long)_THIS_IP_);
> +
> +	return r;
> +}
> +
> +int pthread_mutex_trylock(pthread_mutex_t *mutex)
> +{
> +	int r;
> +
> +        try_init_preload();

See..

> +	lock_acquire(&__get_lock(mutex)->dep_map, 0, 1, 0, 2, NULL, (unsigned long)_THIS_IP_);
> +	r = ll_pthread_mutex_trylock(mutex);
> +	if (r)
> +		lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_THIS_IP_);
> +
> +	return r;
> +}

> +__attribute__((constructor)) static void init_preload(void)
> +{
> +	static bool preload_started;
> +
> +	if (preload_done)
> +		return;
> +
> +	/*
> +	 * 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 :(
> +	 *
> +	 * We can work around it by telling the program that locking was
> +	 * really okay, and just initialize those locks when we're fully
> +	 * up and running (this is ok because this all happens during
> +	 * initialization phase, when we have just one thread). But
> +	 * this is a big TODO at this point.
> +	 */

Fun.. got any example programs that trigger this?

> +	if (preload_started) {
> +		printf(
> +		"LOCKDEP error: It seems that the program you are trying to "
> +		"debug is initializing locks in it's allocation path.\n"
> +		"This means that liblockdep cannot reliably analyze this "
> +		"program since we need the allocator to work before we can "
> +		"debug locks.\nSorry!\n");
> +
> +		exit(1);
> +	}
> +
> +	preload_started = true;
> +
> +	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");
> +
> +	lockdep_init();
> +
> +	preload_done = true;
> +}

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage from userspace
  2013-05-08 10:01   ` Peter Zijlstra
@ 2013-05-08 13:27     ` Sasha Levin
  2013-05-08 13:35       ` Peter Zijlstra
  0 siblings, 1 reply; 17+ messages in thread
From: Sasha Levin @ 2013-05-08 13:27 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: torvalds, mingo, linux-kernel

On 05/08/2013 06:01 AM, Peter Zijlstra wrote:
> On Tue, Apr 30, 2013 at 02:54:33PM -0400, Sasha Levin wrote:
>> diff --git a/tools/lib/lockdep/common.c b/tools/lib/lockdep/common.c
>> new file mode 100644
>> index 0000000..eb5e481
>> --- /dev/null
>> +++ b/tools/lib/lockdep/common.c
>> @@ -0,0 +1,33 @@
>> +#include <stddef.h>
>> +#include <stdbool.h>
>> +#include <linux/compiler.h>
>> +#include <linux/lockdep.h>
>> +#include <unistd.h>
>> +#include <sys/syscall.h>
>> +
>> +static struct task_struct current_obj;
>> +
>> +/* lockdep wants these */
>> +bool debug_locks = true;
>> +bool debug_locks_silent;
>> +
>> +__attribute__((constructor)) static void liblockdep_init(void)
>> +{
>> +	lockdep_init();
>> +}
>> +
>> +__attribute__((destructor)) static void liblockdep_exit(void)
>> +{
>> +	debug_check_no_locks_held(&current_obj);
>> +}
>> +
>> +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 &current_obj;
>> +}
> 
>> diff --git a/tools/lib/lockdep/uinclude/linux/lockdep.h b/tools/lib/lockdep/uinclude/linux/lockdep.h
>> new file mode 100644
>> index 0000000..8e9a5c4
>> --- /dev/null
>> +++ b/tools/lib/lockdep/uinclude/linux/lockdep.h
>> @@ -0,0 +1,58 @@
>> +#ifndef _LIBLOCKDEP_LOCKDEP_H_
>> +#define _LIBLOCKDEP_LOCKDEP_H_
>> +
>> +#include <sys/prctl.h>
>> +#include <sys/syscall.h>
>> +#include <string.h>
>> +#include <limits.h>
>> +#include <linux/utsname.h>
>> +
>> +
>> +#define MAX_LOCK_DEPTH 2000UL
>> +
>> +#include "../../../include/linux/lockdep.h"
>> +
>> +struct task_struct {
>> +	u64 curr_chain_key;
>> +	int lockdep_depth;
>> +	unsigned int lockdep_recursion;
>> +	struct held_lock held_locks[MAX_LOCK_DEPTH];
>> +	gfp_t lockdep_reclaim_gfp;
>> +	int pid;
>> +	char comm[17];
>> +};
>> +
>> +extern struct task_struct *__curr(void);
>> +
>> +#define current (__curr())
>> +
>> +#define debug_locks_off() 1
>> +#define task_pid_nr(tsk) ((tsk)->pid)
>> +
>> +#define KSYM_NAME_LEN 128
>> +#define printk printf
>> +
>> +#define KERN_ERR
>> +#define KERN_CONT
>> +
>> +#define list_del_rcu list_del
>> +
>> +#define atomic_t unsigned long
>> +#define atomic_inc(x) ((*(x))++)
>> +
>> +static struct new_utsname *init_utsname(void)
>> +{
>> +	static struct new_utsname n = (struct new_utsname) {
>> +		.release = "liblockdep",
>> +		.version = LIBLOCKDEP_VERSION,
>> +	};
>> +
>> +	return &n;
>> +}
>> +
>> +#define print_tainted() ""
>> +#define static_obj(x) 1
>> +
>> +#define debug_show_all_locks()
>> +
>> +#endif
> 
> I don't see how this could possible work for threaded programs; you only have a
> single task_struct instance. Wouldn't you need something like the below?

[snip]

Hi Peter,

You're right - I broke multithreading for some odd reason (mostly me being stupid)
after having it working :/

It's enough to set the __thread flag on current_obj:

	diff --git a/tools/lib/lockdep/common.c b/tools/lib/lockdep/common.c
	index eb5e481..8ef602f 100644
	--- a/tools/lib/lockdep/common.c
	+++ b/tools/lib/lockdep/common.c
	@@ -5,7 +5,7 @@
	 #include <unistd.h>
	 #include <sys/syscall.h>
	
	-static struct task_struct current_obj;
	+static __thread struct task_struct current_obj;
	
	 /* lockdep wants these */
	 bool debug_locks = true;

Since we don't need any special initialization of the struct at any point. This
means that the patch above is enough and we don't need to hook pthread_create.

I've tested it by adding the following test to the tests dir:

	#include <pthread.h>

	#include <liblockdep/mutex.h>
	#include "common.h"

	pthread_mutex_t a, b;

	static void *thread_a(void *arg)
	{
	        LOCK_UNLOCK_2(a, b);

	        return NULL;
	}

	static void *thread_b(void *arg)
	{
	        LOCK_UNLOCK_2(b, a);

	        return NULL;
	}

	void main(void)
	{
	        pthread_t ta, tb;

	        pthread_mutex_init(&a, NULL);
	        pthread_mutex_init(&b, NULL);

	        pthread_create(&ta, NULL, thread_a, NULL);
	        pthread_create(&tb, NULL, thread_b, NULL);

	        pthread_join(ta, NULL);
	        pthread_join(tb, NULL);
	}

Which, as expected, produced the following spew:

======================================================
[ INFO: possible circular locking dependency detected ]
liblockdep 0.0.1
-------------------------------------------------------
ABBA_MT/30105 is trying to acquire lock:
 (&a){......}, at: /lib64/libpthread.so.0(+0x8f3b) [0x7ffa7d2f1f3b]

but task is already holding lock:
 (&b){......}, at: /lib64/libpthread.so.0(+0x8f3b) [0x7ffa7d2f1f3b]

which lock already depends on the new lock.


the existing dependency chain (in reverse order) is:

-> #1 (&b){......}:
tests/ABBA_MT[0x4017e4]
tests/ABBA_MT[0x403381]
tests/ABBA_MT[0x40361b]
tests/ABBA_MT[0x403cb1]
tests/ABBA_MT[0x40476e]
tests/ABBA_MT[0x40522d]
tests/ABBA_MT[0x4012d2]
/lib64/libpthread.so.0(+0x8f3b)[0x7ffa7d2f1f3b]
/lib64/libc.so.6(clone+0x6d)[0x7ffa7d02d26d]

-> #0 (&a){......}:
tests/ABBA_MT[0x4017e4]
tests/ABBA_MT[0x402c95]
tests/ABBA_MT[0x403267]
tests/ABBA_MT[0x40361b]
tests/ABBA_MT[0x403cb1]
tests/ABBA_MT[0x40476e]
tests/ABBA_MT[0x40522d]
tests/ABBA_MT[0x401372]
/lib64/libpthread.so.0(+0x8f3b)[0x7ffa7d2f1f3b]
/lib64/libc.so.6(clone+0x6d)[0x7ffa7d02d26d]

other info that might help us debug this:

 Possible unsafe locking scenario:

       CPU0                    CPU1
       ----                    ----
  lock(&b);
                               lock(&a);
                               lock(&b);
  lock(&a);

 *** DEADLOCK ***

1 lock held by ABBA_MT/30105:
 #0:  (&b){......}, at: /lib64/libpthread.so.0(+0x8f3b) [0x7ffa7d2f1f3b]

stack backtrace:
tests/ABBA_MT[0x401518]
tests/ABBA_MT[0x402d4f]
tests/ABBA_MT[0x403267]
tests/ABBA_MT[0x40361b]
tests/ABBA_MT[0x403cb1]
tests/ABBA_MT[0x40476e]
tests/ABBA_MT[0x40522d]
tests/ABBA_MT[0x401372]
/lib64/libpthread.so.0(+0x8f3b)[0x7ffa7d2f1f3b]
/lib64/libc.so.6(clone+0x6d)[0x7ffa7d02d26d]


Thanks,
Sasha

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 7/9] liblockdep: Support using LD_PRELOAD
  2013-05-08 10:22   ` Peter Zijlstra
@ 2013-05-08 13:29     ` Sasha Levin
  0 siblings, 0 replies; 17+ messages in thread
From: Sasha Levin @ 2013-05-08 13:29 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: torvalds, mingo, linux-kernel

Peter,

Thanks for your comments! I'll address them and re-send the patch series.

On 05/08/2013 06:22 AM, Peter Zijlstra wrote:
>> +	/*
>> > +	 * 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 :(
>> > +	 *
>> > +	 * We can work around it by telling the program that locking was
>> > +	 * really okay, and just initialize those locks when we're fully
>> > +	 * up and running (this is ok because this all happens during
>> > +	 * initialization phase, when we have just one thread). But
>> > +	 * this is a big TODO at this point.
>> > +	 */
> Fun.. got any example programs that trigger this?

firefox.

The problem there is that it uses jemalloc, which tries to do what I've
described in the blurb above.


Thanks,
Sasha

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage from userspace
  2013-05-08 13:27     ` Sasha Levin
@ 2013-05-08 13:35       ` Peter Zijlstra
  2013-05-08 13:53         ` Sasha Levin
  0 siblings, 1 reply; 17+ messages in thread
From: Peter Zijlstra @ 2013-05-08 13:35 UTC (permalink / raw)
  To: Sasha Levin; +Cc: torvalds, mingo, linux-kernel

On Wed, May 08, 2013 at 09:27:46AM -0400, Sasha Levin wrote:
> [snip]
> 
> Hi Peter,
> 
> You're right - I broke multithreading for some odd reason (mostly me being stupid)
> after having it working :/
> 
> It's enough to set the __thread flag on current_obj:
> 
> 	diff --git a/tools/lib/lockdep/common.c b/tools/lib/lockdep/common.c
> 	index eb5e481..8ef602f 100644
> 	--- a/tools/lib/lockdep/common.c
> 	+++ b/tools/lib/lockdep/common.c
> 	@@ -5,7 +5,7 @@
> 	 #include <unistd.h>
> 	 #include <sys/syscall.h>
> 	
> 	-static struct task_struct current_obj;
> 	+static __thread struct task_struct current_obj;
> 	
> 	 /* lockdep wants these */
> 	 bool debug_locks = true;
> 
> Since we don't need any special initialization of the struct at any point. This
> means that the patch above is enough and we don't need to hook pthread_create.
> 

I tried googling but failed to find the TLS initialization rules. Are they
zero'd for each thread or copied about or what? And is this documented or
implementation behaviour?

If its consistently zero'd then I suppose you're right and we can get away with
just adding __thread; *phew*.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage from userspace
  2013-05-08 13:35       ` Peter Zijlstra
@ 2013-05-08 13:53         ` Sasha Levin
  0 siblings, 0 replies; 17+ messages in thread
From: Sasha Levin @ 2013-05-08 13:53 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: torvalds, mingo, linux-kernel

On 05/08/2013 09:35 AM, Peter Zijlstra wrote:
> On Wed, May 08, 2013 at 09:27:46AM -0400, Sasha Levin wrote:
>> [snip]
>>
>> Hi Peter,
>>
>> You're right - I broke multithreading for some odd reason (mostly me being stupid)
>> after having it working :/
>>
>> It's enough to set the __thread flag on current_obj:
>>
>> 	diff --git a/tools/lib/lockdep/common.c b/tools/lib/lockdep/common.c
>> 	index eb5e481..8ef602f 100644
>> 	--- a/tools/lib/lockdep/common.c
>> 	+++ b/tools/lib/lockdep/common.c
>> 	@@ -5,7 +5,7 @@
>> 	 #include <unistd.h>
>> 	 #include <sys/syscall.h>
>> 	
>> 	-static struct task_struct current_obj;
>> 	+static __thread struct task_struct current_obj;
>> 	
>> 	 /* lockdep wants these */
>> 	 bool debug_locks = true;
>>
>> Since we don't need any special initialization of the struct at any point. This
>> means that the patch above is enough and we don't need to hook pthread_create.
>>
> 
> I tried googling but failed to find the TLS initialization rules. Are they
> zero'd for each thread or copied about or what? And is this documented or
> implementation behaviour?
> 
> If its consistently zero'd then I suppose you're right and we can get away with
> just adding __thread; *phew*.

I assumed that they are zero'd because it is a global variable, and those are
supposed to be zero'd.

Running a quick test confirmed that they are indeed zero'd for each thread, so
we're safe to just add that __thread.


Thanks,
Sasha


^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2013-05-08 13:53 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-04-30 18:54 [PATCH 0/9] liblockdep: userspace lockdep Sasha Levin
2013-04-30 18:54 ` [PATCH 1/9] lockdep: Be nice about building from userspace Sasha Levin
2013-04-30 18:54 ` [PATCH 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage " Sasha Levin
2013-05-08 10:01   ` Peter Zijlstra
2013-05-08 13:27     ` Sasha Levin
2013-05-08 13:35       ` Peter Zijlstra
2013-05-08 13:53         ` Sasha Levin
2013-04-30 18:54 ` [PATCH 3/9] liblockdep: Add public headers for pthread_mutex_t implementation Sasha Levin
2013-04-30 18:54 ` [PATCH 4/9] liblockdep: Add pthread_mutex_t test suite Sasha Levin
2013-04-30 18:54 ` [PATCH 5/9] liblockdep: Add public headers for pthread_rwlock_t implementation Sasha Levin
2013-04-30 18:54 ` [PATCH 6/9] liblockdep: Add pthread_rwlock_t test suite Sasha Levin
2013-04-30 18:54 ` [PATCH 7/9] liblockdep: Support using LD_PRELOAD Sasha Levin
2013-05-08 10:22   ` Peter Zijlstra
2013-05-08 13:29     ` Sasha Levin
2013-04-30 18:54 ` [PATCH 8/9] liblockdep: Add the 'lockdep' user-space utility Sasha Levin
2013-04-30 18:54 ` [PATCH 9/9] liblockdep: Add a MAINTAINERS entry Sasha Levin
2013-05-07 16:15 ` [PATCH 0/9] liblockdep: userspace lockdep Sasha Levin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox