All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/9] liblockdep: userspace lockdep
@ 2013-05-09 15:58 Sasha Levin
  2013-05-09 15:58 ` [PATCH v3 1/9] lockdep: Be nice about building from userspace Sasha Levin
                   ` (8 more replies)
  0 siblings, 9 replies; 34+ messages in thread
From: Sasha Levin @ 2013-05-09 15:58 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/


Changes from v2:
 - Fix possible build breakage due to recent changes to kernel/lockdep.c

Changes from v1:
 - Addressed Peter's comments.

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                        | 384 +++++++++++++++++++++
 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/kern_levels.h     |  25 ++
 tools/lib/lockdep/uinclude/linux/kernel.h          |  37 ++
 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         |  55 +++
 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
 61 files changed, 1451 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/kern_levels.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] 34+ messages in thread

* [PATCH v3 1/9] lockdep: Be nice about building from userspace
  2013-05-09 15:58 [PATCH v3 0/9] liblockdep: userspace lockdep Sasha Levin
@ 2013-05-09 15:58 ` Sasha Levin
  2013-05-09 15:58 ` [PATCH v3 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage " Sasha Levin
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 34+ messages in thread
From: Sasha Levin @ 2013-05-09 15:58 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 1f3186b..edb7f7e 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -590,6 +590,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,
@@ -616,6 +617,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
@@ -4116,6 +4118,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;
@@ -4173,6 +4176,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] 34+ messages in thread

* [PATCH v3 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage from userspace
  2013-05-09 15:58 [PATCH v3 0/9] liblockdep: userspace lockdep Sasha Levin
  2013-05-09 15:58 ` [PATCH v3 1/9] lockdep: Be nice about building from userspace Sasha Levin
@ 2013-05-09 15:58 ` Sasha Levin
  2013-05-10  9:18   ` Peter Zijlstra
  2013-05-10 13:58   ` Peter Zijlstra
  2013-05-09 15:58 ` [PATCH v3 3/9] liblockdep: Add public headers for pthread_mutex_t implementation Sasha Levin
                   ` (6 subsequent siblings)
  8 siblings, 2 replies; 34+ messages in thread
From: Sasha Levin @ 2013-05-09 15:58 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/kern_levels.h     |  25 ++
 tools/lib/lockdep/uinclude/linux/kernel.h          |  37 +++
 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         |  55 +++++
 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
 43 files changed, 677 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/kern_levels.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..8ef602f
--- /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 __thread 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/kern_levels.h b/tools/lib/lockdep/uinclude/linux/kern_levels.h
new file mode 100644
index 0000000..3b9bade
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/kern_levels.h
@@ -0,0 +1,25 @@
+#ifndef __KERN_LEVELS_H__
+#define __KERN_LEVELS_H__
+
+#define KERN_SOH	""		/* ASCII Start Of Header */
+#define KERN_SOH_ASCII	''
+
+#define KERN_EMERG	KERN_SOH ""	/* system is unusable */
+#define KERN_ALERT	KERN_SOH ""	/* action must be taken immediately */
+#define KERN_CRIT	KERN_SOH ""	/* critical conditions */
+#define KERN_ERR	KERN_SOH ""	/* error conditions */
+#define KERN_WARNING	KERN_SOH ""	/* warning conditions */
+#define KERN_NOTICE	KERN_SOH ""	/* normal but significant condition */
+#define KERN_INFO	KERN_SOH ""	/* informational */
+#define KERN_DEBUG	KERN_SOH ""	/* debug-level messages */
+
+#define KERN_DEFAULT	KERN_SOH ""	/* the default kernel loglevel */
+
+/*
+ * Annotation for a "continued" line of log printout (only done after a
+ * line that had no enclosing \n). Only to be used by core/arch code
+ * during early bootup (a continued line is not SMP-safe otherwise).
+ */
+#define KERN_CONT	""
+
+#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..afa8323
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/kernel.h
@@ -0,0 +1,37 @@
+#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>
+#include <linux/kern_levels.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..d0f5d6e
--- /dev/null
+++ b/tools/lib/lockdep/uinclude/linux/lockdep.h
@@ -0,0 +1,55 @@
+#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 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] 34+ messages in thread

* [PATCH v3 3/9] liblockdep: Add public headers for pthread_mutex_t implementation
  2013-05-09 15:58 [PATCH v3 0/9] liblockdep: userspace lockdep Sasha Levin
  2013-05-09 15:58 ` [PATCH v3 1/9] lockdep: Be nice about building from userspace Sasha Levin
  2013-05-09 15:58 ` [PATCH v3 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage " Sasha Levin
@ 2013-05-09 15:58 ` Sasha Levin
  2013-05-09 15:58 ` [PATCH v3 4/9] liblockdep: Add pthread_mutex_t test suite Sasha Levin
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 34+ messages in thread
From: Sasha Levin @ 2013-05-09 15:58 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] 34+ messages in thread

* [PATCH v3 4/9] liblockdep: Add pthread_mutex_t test suite
  2013-05-09 15:58 [PATCH v3 0/9] liblockdep: userspace lockdep Sasha Levin
                   ` (2 preceding siblings ...)
  2013-05-09 15:58 ` [PATCH v3 3/9] liblockdep: Add public headers for pthread_mutex_t implementation Sasha Levin
@ 2013-05-09 15:58 ` Sasha Levin
  2013-05-09 15:58 ` [PATCH v3 5/9] liblockdep: Add public headers for pthread_rwlock_t implementation Sasha Levin
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 34+ messages in thread
From: Sasha Levin @ 2013-05-09 15:58 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] 34+ messages in thread

* [PATCH v3 5/9] liblockdep: Add public headers for pthread_rwlock_t implementation
  2013-05-09 15:58 [PATCH v3 0/9] liblockdep: userspace lockdep Sasha Levin
                   ` (3 preceding siblings ...)
  2013-05-09 15:58 ` [PATCH v3 4/9] liblockdep: Add pthread_mutex_t test suite Sasha Levin
@ 2013-05-09 15:58 ` Sasha Levin
  2013-05-09 15:58 ` [PATCH v3 6/9] liblockdep: Add pthread_rwlock_t test suite Sasha Levin
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 34+ messages in thread
From: Sasha Levin @ 2013-05-09 15:58 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] 34+ messages in thread

* [PATCH v3 6/9] liblockdep: Add pthread_rwlock_t test suite
  2013-05-09 15:58 [PATCH v3 0/9] liblockdep: userspace lockdep Sasha Levin
                   ` (4 preceding siblings ...)
  2013-05-09 15:58 ` [PATCH v3 5/9] liblockdep: Add public headers for pthread_rwlock_t implementation Sasha Levin
@ 2013-05-09 15:58 ` Sasha Levin
  2013-05-09 15:58 ` [PATCH v3 7/9] liblockdep: Support using LD_PRELOAD Sasha Levin
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 34+ messages in thread
From: Sasha Levin @ 2013-05-09 15:58 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] 34+ messages in thread

* [PATCH v3 7/9] liblockdep: Support using LD_PRELOAD
  2013-05-09 15:58 [PATCH v3 0/9] liblockdep: userspace lockdep Sasha Levin
                   ` (5 preceding siblings ...)
  2013-05-09 15:58 ` [PATCH v3 6/9] liblockdep: Add pthread_rwlock_t test suite Sasha Levin
@ 2013-05-09 15:58 ` Sasha Levin
  2013-05-10 11:17   ` Peter Zijlstra
  2013-05-10 13:57   ` Peter Zijlstra
  2013-05-09 15:58 ` [PATCH v3 8/9] liblockdep: Add the 'lockdep' user-space utility Sasha Levin
  2013-05-09 15:58 ` [PATCH v3 9/9] liblockdep: Add a MAINTAINERS entry Sasha Levin
  8 siblings, 2 replies; 34+ messages in thread
From: Sasha Levin @ 2013-05-09 15:58 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 | 384 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 384 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..025cce0
--- /dev/null
+++ b/tools/lib/lockdep/preload.c
@@ -0,0 +1,384 @@
+#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;
+}
+
+static void __del_lock(struct lock_lookup *lock)
+{
+	ll_pthread_rwlock_wrlock(&locks_rwlock);
+	rb_erase(&lock->node, &locks);
+	ll_pthread_rwlock_unlock(&locks_rwlock);
+	free(lock);
+}
+
+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)
+{
+	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));
+	__del_lock(__get_lock(mutex));
+	return ll_pthread_mutex_destroy(mutex);
+}
+
+/* This is the rwlock part, very similar to what happened with mutex above */
+int pthread_rwlock_init(pthread_rwlock_t *rwlock,
+			const pthread_rwlockattr_t *attr)
+{
+	int r;
+
+	try_init_preload();
+
+	r = ll_pthread_rwlock_init(rwlock, attr);
+	if (r == 0)
+		__get_lock(rwlock);
+
+	return r;
+}
+
+int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
+{
+	try_init_preload();
+
+	debug_check_no_locks_freed(rwlock, rwlock + sizeof(*rwlock));
+	__del_lock(__get_lock(rwlock));
+	return ll_pthread_rwlock_destroy(rwlock);
+}
+
+int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
+{
+	int r;
+
+        init_preload();
+
+	lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 2, 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] 34+ messages in thread

* [PATCH v3 8/9] liblockdep: Add the 'lockdep' user-space utility
  2013-05-09 15:58 [PATCH v3 0/9] liblockdep: userspace lockdep Sasha Levin
                   ` (6 preceding siblings ...)
  2013-05-09 15:58 ` [PATCH v3 7/9] liblockdep: Support using LD_PRELOAD Sasha Levin
@ 2013-05-09 15:58 ` Sasha Levin
  2013-05-10  9:19   ` Peter Zijlstra
  2013-05-09 15:58 ` [PATCH v3 9/9] liblockdep: Add a MAINTAINERS entry Sasha Levin
  8 siblings, 1 reply; 34+ messages in thread
From: Sasha Levin @ 2013-05-09 15:58 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] 34+ messages in thread

* [PATCH v3 9/9] liblockdep: Add a MAINTAINERS entry
  2013-05-09 15:58 [PATCH v3 0/9] liblockdep: userspace lockdep Sasha Levin
                   ` (7 preceding siblings ...)
  2013-05-09 15:58 ` [PATCH v3 8/9] liblockdep: Add the 'lockdep' user-space utility Sasha Levin
@ 2013-05-09 15:58 ` Sasha Levin
  8 siblings, 0 replies; 34+ messages in thread
From: Sasha Levin @ 2013-05-09 15:58 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 5f5c895..0c822ef 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4856,6 +4856,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] 34+ messages in thread

* Re: [PATCH v3 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage from userspace
  2013-05-09 15:58 ` [PATCH v3 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage " Sasha Levin
@ 2013-05-10  9:18   ` Peter Zijlstra
  2013-05-10  9:38     ` Ingo Molnar
  2013-05-10 10:11     ` Peter Zijlstra
  2013-05-10 13:58   ` Peter Zijlstra
  1 sibling, 2 replies; 34+ messages in thread
From: Peter Zijlstra @ 2013-05-10  9:18 UTC (permalink / raw)
  To: Sasha Levin; +Cc: torvalds, mingo, linux-kernel

On Thu, May 09, 2013 at 11:58:02AM -0400, Sasha Levin wrote:
> 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>
> ---

OK, this patch is a complete fail with anything not git. Please fix it so I can
use quilt.

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

* Re: [PATCH v3 8/9] liblockdep: Add the 'lockdep' user-space utility
  2013-05-09 15:58 ` [PATCH v3 8/9] liblockdep: Add the 'lockdep' user-space utility Sasha Levin
@ 2013-05-10  9:19   ` Peter Zijlstra
  2013-05-10  9:35     ` Ingo Molnar
  0 siblings, 1 reply; 34+ messages in thread
From: Peter Zijlstra @ 2013-05-10  9:19 UTC (permalink / raw)
  To: Sasha Levin
  Cc: torvalds, mingo, linux-kernel, jamie.iles, penberg, acme, paulus,
	namhyung, Andrew Morton, Thomas Gleixner

On Thu, May 09, 2013 at 11:58:08AM -0400, Sasha Levin wrote:
> 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

That's me

> Cc: Linus Torvalds <torvalds@linux-foundation.org>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>

That too..

> 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>

I was wondering why I kept getting this particular patch twice every time..

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

* Re: [PATCH v3 8/9] liblockdep: Add the 'lockdep' user-space utility
  2013-05-10  9:19   ` Peter Zijlstra
@ 2013-05-10  9:35     ` Ingo Molnar
  2013-05-10 10:41       ` Peter Zijlstra
  0 siblings, 1 reply; 34+ messages in thread
From: Ingo Molnar @ 2013-05-10  9:35 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Sasha Levin, torvalds, linux-kernel, jamie.iles, penberg, acme,
	paulus, namhyung, Andrew Morton, Thomas Gleixner


* Peter Zijlstra <peterz@infradead.org> wrote:

> On Thu, May 09, 2013 at 11:58:08AM -0400, Sasha Levin wrote:
> > 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
> 
> That's me
> 
> > Cc: Linus Torvalds <torvalds@linux-foundation.org>
> > Cc: Andrew Morton <akpm@linux-foundation.org>
> > Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
> 
> That too..
> 
> > 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>
> 
> I was wondering why I kept getting this particular patch twice every time..

If you started acking and emailing from the same address you'd only get 
one! :-)

Thanks,

	Ingo

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

* Re: [PATCH v3 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage from userspace
  2013-05-10  9:18   ` Peter Zijlstra
@ 2013-05-10  9:38     ` Ingo Molnar
  2013-05-10 10:11     ` Peter Zijlstra
  1 sibling, 0 replies; 34+ messages in thread
From: Ingo Molnar @ 2013-05-10  9:38 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Sasha Levin, torvalds, linux-kernel


* Peter Zijlstra <peterz@infradead.org> wrote:

> On Thu, May 09, 2013 at 11:58:02AM -0400, Sasha Levin wrote:
> > 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>
> > ---
> 
> OK, this patch is a complete fail with anything not git. Please fix it so I can
> use quilt.

The way I work that around is by making empty files a single-line empty 
file, with a single \n in them.

Thanks,

	Ingo

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

* Re: [PATCH v3 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage from userspace
  2013-05-10  9:18   ` Peter Zijlstra
  2013-05-10  9:38     ` Ingo Molnar
@ 2013-05-10 10:11     ` Peter Zijlstra
  2013-05-10 13:23       ` Sasha Levin
  1 sibling, 1 reply; 34+ messages in thread
From: Peter Zijlstra @ 2013-05-10 10:11 UTC (permalink / raw)
  To: Sasha Levin; +Cc: torvalds, mingo, linux-kernel

On Fri, May 10, 2013 at 11:18:16AM +0200, Peter Zijlstra wrote:
> On Thu, May 09, 2013 at 11:58:02AM -0400, Sasha Levin wrote:
> > 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>
> > ---
> 
> OK, this patch is a complete fail with anything not git. Please fix it so I can
> use quilt.

So I tried patch --posix; but that makes patch unhappy too:

|--- /dev/null
|+++ b/tools/lib/lockdep/Makefile
--------------------------
No file to patch.  Skipping patch.
out of 1 hunk ignored
can't find file to patch at input line 393
Perhaps you used the wrong -p or --strip option?

And while patch has a --remove-empty-files it does not recognise
--no-remove-empty-files :/

I briefly read a thread from the git mailing list where Linus and others
discussed the various weirdness around empty files and the take away was that
git would act differently by default. Because as Linus put it: "patch" is a
total piece of utterly unbelievable SH*T. 

However, aside from different behaviour I don't think its that nice git-diff
creates patches that patch cannot possibly apply right...

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

* Re: [PATCH v3 8/9] liblockdep: Add the 'lockdep' user-space utility
  2013-05-10  9:35     ` Ingo Molnar
@ 2013-05-10 10:41       ` Peter Zijlstra
  2013-05-10 11:00         ` Ingo Molnar
  0 siblings, 1 reply; 34+ messages in thread
From: Peter Zijlstra @ 2013-05-10 10:41 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Sasha Levin, torvalds, linux-kernel, jamie.iles, penberg, acme,
	paulus, namhyung, Andrew Morton, Thomas Gleixner

> If you started acking and emailing from the same address you'd only get 
> one! :-)

Bah, that'd mean actually retraining my muscle memory :-)

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

* Re: [PATCH v3 8/9] liblockdep: Add the 'lockdep' user-space utility
  2013-05-10 10:41       ` Peter Zijlstra
@ 2013-05-10 11:00         ` Ingo Molnar
  2013-05-10 11:10           ` Borislav Petkov
  0 siblings, 1 reply; 34+ messages in thread
From: Ingo Molnar @ 2013-05-10 11:00 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Sasha Levin, torvalds, linux-kernel, jamie.iles, penberg, acme,
	paulus, namhyung, Andrew Morton, Thomas Gleixner


* Peter Zijlstra <peterz@infradead.org> wrote:

> > If you started acking and emailing from the same address you'd only get 
> > one! :-)
> 
> Bah, that'd mean actually retraining my muscle memory :-)

You write out your acks? Wow :-)

The way I do it is that I have two files named 'ack' and 'sob', with my 
Acked-by and Signed-off-by lines in them, so I can read them into whatever 
editing context I need them, without typing out the full thing.

Saves typing and time - and gives email address flexibility ;-)

Thanks,

	Ingo

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

* Re: [PATCH v3 8/9] liblockdep: Add the 'lockdep' user-space utility
  2013-05-10 11:10           ` Borislav Petkov
@ 2013-05-10 11:07             ` Ingo Molnar
  0 siblings, 0 replies; 34+ messages in thread
From: Ingo Molnar @ 2013-05-10 11:07 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Peter Zijlstra, Sasha Levin, torvalds, linux-kernel, jamie.iles,
	penberg, acme, paulus, namhyung, Andrew Morton, Thomas Gleixner


* Borislav Petkov <bp@alien8.de> wrote:

> On Fri, May 10, 2013 at 01:00:46PM +0200, Ingo Molnar wrote:
> > The way I do it is that I have two files named 'ack' and 'sob', with
> > my Acked-by and Signed-off-by lines in them, so I can read them into
> > whatever editing context I need them, without typing out the full
> > thing.
> 
> You must have a 'nack' one too :-) Or you rather relish typing this
> everytime by hand, with gusto?

No, I have a 'by' file which contains:

-by: Ingo Molnar <mingo@kernel.org>

Which I can then extend with rare tags like Reported-by, Tested-by or 
NAK-ed-by :-)

Thanks,

	Ingo

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

* Re: [PATCH v3 8/9] liblockdep: Add the 'lockdep' user-space utility
  2013-05-10 11:00         ` Ingo Molnar
@ 2013-05-10 11:10           ` Borislav Petkov
  2013-05-10 11:07             ` Ingo Molnar
  0 siblings, 1 reply; 34+ messages in thread
From: Borislav Petkov @ 2013-05-10 11:10 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Peter Zijlstra, Sasha Levin, torvalds, linux-kernel, jamie.iles,
	penberg, acme, paulus, namhyung, Andrew Morton, Thomas Gleixner

On Fri, May 10, 2013 at 01:00:46PM +0200, Ingo Molnar wrote:
> The way I do it is that I have two files named 'ack' and 'sob', with
> my Acked-by and Signed-off-by lines in them, so I can read them into
> whatever editing context I need them, without typing out the full
> thing.

You must have a 'nack' one too :-) Or you rather relish typing this
everytime by hand, with gusto?

:-)

-- 
Regards/Gruss,
    Boris.

Sent from a fat crate under my desk. Formatting is fine.
--

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

* Re: [PATCH v3 7/9] liblockdep: Support using LD_PRELOAD
  2013-05-09 15:58 ` [PATCH v3 7/9] liblockdep: Support using LD_PRELOAD Sasha Levin
@ 2013-05-10 11:17   ` Peter Zijlstra
  2013-05-10 11:23     ` Ingo Molnar
  2013-05-10 11:46     ` Peter Zijlstra
  2013-05-10 13:57   ` Peter Zijlstra
  1 sibling, 2 replies; 34+ messages in thread
From: Peter Zijlstra @ 2013-05-10 11:17 UTC (permalink / raw)
  To: Sasha Levin; +Cc: torvalds, mingo, linux-kernel

On Thu, May 09, 2013 at 11:58:07AM -0400, Sasha Levin 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.
> +	 */
> +	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);
> +	}


Would something like the below cure things? Obviously this hasn't been near a
compiler for the entire thing still isn't wanting to compile for me.

---
--- a/tools/lib/lockdep/preload.c
+++ b/tools/lib/lockdep/preload.c
@@ -1,4 +1,5 @@
 #define _GNU_SOURCE
+#include <sysexits.h>
 #include <pthread.h>
 #include <stdio.h>
 #include <dlfcn.h>
@@ -46,11 +47,12 @@ static int (*ll_pthread_rwlock_trywrlock
 static int (*ll_pthread_rwlock_wrlock)(pthread_rwlock_t *rwlock);
 static int (*ll_pthread_rwlock_unlock)(pthread_rwlock_t *rwlock);
 
-static bool preload_done;
+enum { none, prepare, done, } __init_state;
+
 static void init_preload(void);
 static void try_init_preload(void)
 {
-	if (!preload_done)
+	if (__init_state != done)
 		init_preload();
 }
 
@@ -76,6 +78,54 @@ static struct rb_node **__get_lock_node(
 	return node;
 }
 
+#ifndef LIBLOCKDEP_STATIC_ENTRIES
+#define LIBLOCKDEP_STATIC_ENTRIES	1024
+#endif 
+
+static struct lock_lookup __locks[LIBLOCKDEP_STATIC_ENTRIES];
+static int __locks_nr;
+
+static inline bool is_static_lock(struct lock_lookup *lock)
+{
+	return lock >= __locks && lock < __locks + ARRAY_SIZE(__locks);
+}
+
+static struct lock_lookup *alloc_lock(void)
+{
+	if (unlikely(__init_state != done)) {
+		/*
+		 * Some programs attempt to initialize and use locks in their
+		 * allocation path. This means that a call to malloc() would
+		 * result in locks being initialized and locked.
+		 *
+		 * Why is it an issue for us? dlsym() below will try allocating
+		 * to give us the original function. Since this allocation will
+		 * result in a locking operations, we have to let pthread deal
+		 * with it, but we can't! we don't have the pointer to the
+		 * original API since we're inside dlsym() trying to get it :(
+		 */
+
+		/* XXX: can we be concurrent already? if so add lock */
+
+		int idx = __locks_nr++;
+		if (idx >= ARRAY_SIZE(__locks)) {
+			fprintf(stderr,
+		"LOCKDEP error: insufficient LIBLOCKDEP_STATIC_ENTRIES\n");
+
+			exit(EX_UNAVAILABLE);
+		}
+		return __locks + idx;
+	}
+
+	return malloc(sizeof(*lock));
+}
+
+static inline void free_lock(struct lock_lookup *lock)
+{
+	if (likely(!is_static_lock(lock)))
+		free(lock);
+}
+
 /**
  * __get_lock - find or create a lock instance
  * @lock: pointer to a pthread lock function
@@ -96,7 +146,7 @@ static struct lock_lookup *__get_lock(vo
 	}
 
 	/* We didn't find the lock, let's create it */
-	l = malloc(sizeof(*l));
+	l = alloc_lock();
 	if (l == NULL)
 		return NULL;
 
@@ -125,7 +175,7 @@ static void __del_lock(struct lock_looku
 	ll_pthread_rwlock_wrlock(&locks_rwlock);
 	rb_erase(&lock->node, &locks);
 	ll_pthread_rwlock_unlock(&locks_rwlock);
-	free(lock);
+	free_lock(lock);
 }
 
 int pthread_mutex_init(pthread_mutex_t *mutex,
@@ -329,40 +379,10 @@ int pthread_rwlock_unlock(pthread_rwlock
 
 __attribute__((constructor)) static void init_preload(void)
 {
-	static bool preload_started;
-
-	if (preload_done)
+	if (__init_state != 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;
+	__init_state = prepare;
 
 	ll_pthread_mutex_init = dlsym(RTLD_NEXT, "pthread_mutex_init");
 	ll_pthread_mutex_lock = dlsym(RTLD_NEXT, "pthread_mutex_lock");
@@ -380,5 +400,5 @@ __attribute__((constructor)) static void
 
 	lockdep_init();
 
-	preload_done = true;
+	__init_state = done;
 }


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

* Re: [PATCH v3 7/9] liblockdep: Support using LD_PRELOAD
  2013-05-10 11:17   ` Peter Zijlstra
@ 2013-05-10 11:23     ` Ingo Molnar
  2013-05-10 11:46     ` Peter Zijlstra
  1 sibling, 0 replies; 34+ messages in thread
From: Ingo Molnar @ 2013-05-10 11:23 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Sasha Levin, torvalds, linux-kernel


* Peter Zijlstra <peterz@infradead.org> wrote:

> Would something like the below cure things? Obviously this hasn't been 
> near a compiler for the entire thing still isn't wanting to compile for 
> me.

this oneliner command should work it around for you on Quilt:

touch tools/lib/lockdep/uinclude/asm/hweight.h tools/lib/lockdep/uinclude/asm/sections.h tools/lib/lockdep/uinclude/linux/bitops.h tools/lib/lockdep/uinclude/linux/delay.h tools/lib/lockdep/uinclude/linux/ftrace.h tools/lib/lockdep/uinclude/linux/gfp.h tools/lib/lockdep/uinclude/linux/interrupt.h tools/lib/lockdep/uinclude/linux/linkage.h tools/lib/lockdep/uinclude/linux/mm_types.h tools/lib/lockdep/uinclude/linux/mutex.h tools/lib/lockdep/uinclude/linux/proc_fs.h tools/lib/lockdep/uinclude/linux/seq_file.h tools/lib/lockdep/uinclude/linux/system.h tools/lib/lockdep/uinclude/linux/util.h tools/lib/lockdep/uinclude/trace/events/lock.h

Thanks,

	Ingo

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

* Re: [PATCH v3 7/9] liblockdep: Support using LD_PRELOAD
  2013-05-10 11:17   ` Peter Zijlstra
  2013-05-10 11:23     ` Ingo Molnar
@ 2013-05-10 11:46     ` Peter Zijlstra
  2013-05-10 13:11       ` Peter Zijlstra
  1 sibling, 1 reply; 34+ messages in thread
From: Peter Zijlstra @ 2013-05-10 11:46 UTC (permalink / raw)
  To: Sasha Levin; +Cc: torvalds, mingo, linux-kernel

On Fri, May 10, 2013 at 01:17:19PM +0200, Peter Zijlstra wrote:
> On Thu, May 09, 2013 at 11:58:07AM -0400, Sasha Levin 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.
> > +	 */
> > +	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);
> > +	}
> 
> 
> Would something like the below cure things? Obviously this hasn't been near a
> compiler for the entire thing still isn't wanting to compile for me.

OK, that won't do indeed. Not being able to malloc is only part of the problem.

/me goes stare at it more

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

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

On Fri, May 10, 2013 at 01:46:05PM +0200, Peter Zijlstra wrote:
> OK, that won't do indeed. Not being able to malloc is only part of the problem.
> 
> /me goes stare at it more

So the below hackery actually does run with firefox -- although it generates a
metric ton of output.

It very much relies on the gnu-libc (although it should work with both the NPTL
and LinuxThread implementations).

The static allocation stuff is still there but shouldn't be needed for this.

---
--- a/tools/lib/lockdep/Makefile
+++ b/tools/lib/lockdep/Makefile
@@ -146,7 +146,7 @@ do_app_build =						\
 
 do_compile_shared_library =			\
 	($(print_shared_lib_compile)		\
-	$(CC) --shared -ldl $^ -o $@)
+	$(CC) --shared $^ -o $@ -lpthread -ldl)
 
 do_build_static_lib =				\
 	($(print_static_lib_build)		\
--- a/tools/lib/lockdep/preload.c
+++ b/tools/lib/lockdep/preload.c
@@ -1,4 +1,5 @@
 #define _GNU_SOURCE
+#include <sysexits.h>
 #include <pthread.h>
 #include <stdio.h>
 #include <dlfcn.h>
@@ -29,28 +30,63 @@ static struct rb_root locks = RB_ROOT;
 static pthread_rwlock_t locks_rwlock = PTHREAD_RWLOCK_INITIALIZER;
 
 /* pthread mutex API */
+
+#ifdef __GLIBC__
+extern int __pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
+extern int __pthread_mutex_lock(pthread_mutex_t *mutex);
+extern int __pthread_mutex_trylock(pthread_mutex_t *mutex);
+extern int __pthread_mutex_unlock(pthread_mutex_t *mutex);
+extern int __pthread_mutex_destroy(pthread_mutex_t *mutex);
+#else
+#define __pthread_mutex_init	NULL
+#define __pthread_mutex_lock	NULL
+#define __pthread_mutex_trylock	NULL
+#define __pthread_mutex_unlock	NULL
+#define __pthread_mutex_destroy	NULL
+#endif
+
 static int (*ll_pthread_mutex_init)(pthread_mutex_t *mutex,
-			const pthread_mutexattr_t *attr);
-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);
+			const pthread_mutexattr_t *attr)	= __pthread_mutex_init;
+static int (*ll_pthread_mutex_lock)(pthread_mutex_t *mutex)	= __pthread_mutex_lock;
+static int (*ll_pthread_mutex_trylock)(pthread_mutex_t *mutex)	= __pthread_mutex_trylock;
+static int (*ll_pthread_mutex_unlock)(pthread_mutex_t *mutex)	= __pthread_mutex_unlock;
+static int (*ll_pthread_mutex_destroy)(pthread_mutex_t *mutex)	= __pthread_mutex_destroy;
 
 /* pthread rwlock API */
+
+#ifdef __GLIBC__
+extern int __pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
+extern int __pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
+extern int __pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
+extern int __pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
+extern int __pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
+extern int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
+extern int __pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
+#else
+#define __pthread_rwlock_init		NULL
+#define __pthread_rwlock_destroy	NULL
+#define __pthread_rwlock_wrlock		NULL
+#define __pthread_rwlock_trywrlock	NULL
+#define __pthread_rwlock_rdlock		NULL
+#define __pthread_rwlock_tryrdlock	NULL
+#define __pthread_rwlock_unlock		NULL
+#endif
+
 static int (*ll_pthread_rwlock_init)(pthread_rwlock_t *rwlock,
-			const pthread_rwlockattr_t *attr);
-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);
+			const pthread_rwlockattr_t *attr)		= __pthread_rwlock_init;
+static int (*ll_pthread_rwlock_destroy)(pthread_rwlock_t *rwlock)	= __pthread_rwlock_destroy;
+static int (*ll_pthread_rwlock_rdlock)(pthread_rwlock_t *rwlock)	= __pthread_rwlock_rdlock;
+static int (*ll_pthread_rwlock_tryrdlock)(pthread_rwlock_t *rwlock)	= __pthread_rwlock_tryrdlock;
+static int (*ll_pthread_rwlock_trywrlock)(pthread_rwlock_t *rwlock)	= __pthread_rwlock_trywrlock;
+static int (*ll_pthread_rwlock_wrlock)(pthread_rwlock_t *rwlock)	= __pthread_rwlock_wrlock;
+static int (*ll_pthread_rwlock_unlock)(pthread_rwlock_t *rwlock)	= __pthread_rwlock_unlock;
+
+enum { none, prepare, done, } __init_state;
 
-static bool preload_done;
 static void init_preload(void);
 static void try_init_preload(void)
 {
-	if (!preload_done)
+	if (__init_state != done)
 		init_preload();
 }
 
@@ -76,6 +112,56 @@ static struct rb_node **__get_lock_node(
 	return node;
 }
 
+#ifndef LIBLOCKDEP_STATIC_ENTRIES
+#define LIBLOCKDEP_STATIC_ENTRIES	1024
+#endif
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+static struct lock_lookup __locks[LIBLOCKDEP_STATIC_ENTRIES];
+static int __locks_nr;
+
+static inline bool is_static_lock(struct lock_lookup *lock)
+{
+	return lock >= __locks && lock < __locks + ARRAY_SIZE(__locks);
+}
+
+static struct lock_lookup *alloc_lock(void)
+{
+	if (__init_state != done) {
+		/*
+		 * Some programs attempt to initialize and use locks in their
+		 * allocation path. This means that a call to malloc() would
+		 * result in locks being initialized and locked.
+		 *
+		 * Why is it an issue for us? dlsym() below will try allocating
+		 * to give us the original function. Since this allocation will
+		 * result in a locking operations, we have to let pthread deal
+		 * with it, but we can't! we don't have the pointer to the
+		 * original API since we're inside dlsym() trying to get it :(
+		 */
+
+		/* XXX: can we be concurrent already? if so add lock */
+
+		int idx = __locks_nr++;
+		if (idx >= ARRAY_SIZE(__locks)) {
+			fprintf(stderr,
+		"LOCKDEP error: insufficient LIBLOCKDEP_STATIC_ENTRIES\n");
+
+			exit(EX_UNAVAILABLE);
+		}
+		return __locks + idx;
+	}
+
+	return malloc(sizeof(struct lock_lookup));
+}
+
+static inline void free_lock(struct lock_lookup *lock)
+{
+	if (likely(!is_static_lock(lock)))
+		free(lock);
+}
+
 /**
  * __get_lock - find or create a lock instance
  * @lock: pointer to a pthread lock function
@@ -96,7 +182,7 @@ static struct lock_lookup *__get_lock(vo
 	}
 
 	/* We didn't find the lock, let's create it */
-	l = malloc(sizeof(*l));
+	l = alloc_lock();
 	if (l == NULL)
 		return NULL;
 
@@ -125,7 +211,7 @@ static void __del_lock(struct lock_looku
 	ll_pthread_rwlock_wrlock(&locks_rwlock);
 	rb_erase(&lock->node, &locks);
 	ll_pthread_rwlock_unlock(&locks_rwlock);
-	free(lock);
+	free_lock(lock);
 }
 
 int pthread_mutex_init(pthread_mutex_t *mutex,
@@ -329,40 +415,11 @@ int pthread_rwlock_unlock(pthread_rwlock
 
 __attribute__((constructor)) static void init_preload(void)
 {
-	static bool preload_started;
-
-	if (preload_done)
+	if (__init_state != 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;
+#ifndef __GLIBC__
+	__init_state = prepare;
 
 	ll_pthread_mutex_init = dlsym(RTLD_NEXT, "pthread_mutex_init");
 	ll_pthread_mutex_lock = dlsym(RTLD_NEXT, "pthread_mutex_lock");
@@ -377,8 +434,9 @@ __attribute__((constructor)) static void
 	ll_pthread_rwlock_wrlock = dlsym(RTLD_NEXT, "pthread_rwlock_wrlock");
 	ll_pthread_rwlock_trywrlock = dlsym(RTLD_NEXT, "pthread_rwlock_trywrlock");
 	ll_pthread_rwlock_unlock = dlsym(RTLD_NEXT, "pthread_rwlock_unlock");
+#endif
 
 	lockdep_init();
 
-	preload_done = true;
+	__init_state = done;
 }


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

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

On 05/10/2013 06:11 AM, Peter Zijlstra wrote:
> On Fri, May 10, 2013 at 11:18:16AM +0200, Peter Zijlstra wrote:
>> On Thu, May 09, 2013 at 11:58:02AM -0400, Sasha Levin wrote:
>>> 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>
>>> ---
>>
>> OK, this patch is a complete fail with anything not git. Please fix it so I can
>> use quilt.
> 
> So I tried patch --posix; but that makes patch unhappy too:
> 
> |--- /dev/null
> |+++ b/tools/lib/lockdep/Makefile
> --------------------------
> No file to patch.  Skipping patch.
> out of 1 hunk ignored
> can't find file to patch at input line 393
> Perhaps you used the wrong -p or --strip option?
> 
> And while patch has a --remove-empty-files it does not recognise
> --no-remove-empty-files :/
> 
> I briefly read a thread from the git mailing list where Linus and others
> discussed the various weirdness around empty files and the take away was that
> git would act differently by default. Because as Linus put it: "patch" is a
> total piece of utterly unbelievable SH*T. 
> 
> However, aside from different behaviour I don't think its that nice git-diff
> creates patches that patch cannot possibly apply right...

Wait, I'm confused. Over here, patch is fine with creating empty files:

lappy lockdep # touch test.c
lappy lockdep # git diff /dev/null test.c > test.patch
lappy lockdep # rm test.c
lappy lockdep # file test.c
test.c: ERROR: cannot open `test.c' (No such file or directory)
lappy lockdep # patch -i test.patch
patching file test.c
lappy lockdep # file test.c
test.c: empty
lappy lockdep # cat test.patch
diff --git a/tools/lib/lockdep/test.c b/tools/lib/lockdep/test.c
new file mode 100644
index 0000000..e69de29
lappy lockdep #

So it seems that here patch would cleanly create empty files, what does quilt
do differently?


Thanks,
Sasha

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

* Re: [PATCH v3 7/9] liblockdep: Support using LD_PRELOAD
  2013-05-09 15:58 ` [PATCH v3 7/9] liblockdep: Support using LD_PRELOAD Sasha Levin
  2013-05-10 11:17   ` Peter Zijlstra
@ 2013-05-10 13:57   ` Peter Zijlstra
  2013-05-10 16:06     ` Sasha Levin
  1 sibling, 1 reply; 34+ messages in thread
From: Peter Zijlstra @ 2013-05-10 13:57 UTC (permalink / raw)
  To: Sasha Levin; +Cc: torvalds, mingo, linux-kernel

On Thu, May 09, 2013 at 11:58:07AM -0400, Sasha Levin wrote:

So you're doing instance tracking and not creating classes like the kernel
lockdep does? While that reduces false positives it also greatly reduces the
effectiveness of lockdep.

The power of lock-classes is that it increases the chance of catching potential
deadlocks without there ever actually being a deadlock.

I think something like so:

> +/**
> + * 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];
> +};

> +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, unsigned long addr)

> +{
> +	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, (void *)addr, 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;

+ unsigned long addr = __RET_IP_;

> +
> +	/*
> +	 * 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, addr);
> +
> +	return r;
> +}
> +
> +int pthread_mutex_lock(pthread_mutex_t *mutex)
> +{
> +	int r;

+ struct lock_lookup *lock = __get_lock(mutex, (unsigned long)mutex);

> +
> +	try_init_preload();
> +
+	lock_acquire(&lock->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(&lock->dep_map, 0, (unsigned long)_THIS_IP_);
> +
> +	return r;
> +}

Should get classes working. It will use the return address of pthread_*_init()
for key; thus all locks initialized from the same pthread_*_init() site will
end up belonging to the same class.

Failing that, the pthread_mutex_*() functions will initialize the lock using
the 'static' address of the mutex itself -- assuming its been initialized using
PTHREAD_MUTEX_INITIALIZER or similar.




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

* Re: [PATCH v3 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage from userspace
  2013-05-09 15:58 ` [PATCH v3 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage " Sasha Levin
  2013-05-10  9:18   ` Peter Zijlstra
@ 2013-05-10 13:58   ` Peter Zijlstra
  1 sibling, 0 replies; 34+ messages in thread
From: Peter Zijlstra @ 2013-05-10 13:58 UTC (permalink / raw)
  To: Sasha Levin; +Cc: torvalds, mingo, linux-kernel

On Thu, May 09, 2013 at 11:58:02AM -0400, Sasha Levin wrote:
> +#ifndef CALLER_ADDR0
> +#define _THIS_IP_ CALLER_ADDR0
> +#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0))
> +#endif

That's wrong.. _THIS_IP_ should be the address of 'here'. What you have there is _RET_IP_.



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

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

On Fri, May 10, 2013 at 09:23:33AM -0400, Sasha Levin wrote:
> Wait, I'm confused. Over here, patch is fine with creating empty files:
> 
> lappy lockdep # touch test.c
> lappy lockdep # git diff /dev/null test.c > test.patch
> lappy lockdep # rm test.c
> lappy lockdep # file test.c
> test.c: ERROR: cannot open `test.c' (No such file or directory)
> lappy lockdep # patch -i test.patch
> patching file test.c
> lappy lockdep # file test.c
> test.c: empty
> lappy lockdep # cat test.patch
> diff --git a/tools/lib/lockdep/test.c b/tools/lib/lockdep/test.c
> new file mode 100644
> index 0000000..e69de29
> lappy lockdep #
> 
> So it seems that here patch would cleanly create empty files, what does quilt
> do differently?


root@twins:~/tmp# touch ponies
root@twins:~/tmp# git diff /dev/null ponies
diff --git a/ponies b/ponies
new file mode 100644
index 0000000..e69de29
root@twins:~/tmp# git diff /dev/null ponies > ponies.patch
root@twins:~/tmp# rm ponies
root@twins:~/tmp# patch < ponies.patch
patch: **** Only garbage was found in the patch input.

t@twins:~/tmp# patch --version
patch 2.6.1
Copyright (C) 1988 Larry Wall
Copyright (C) 2003, 2009 Free Software Foundation, Inc.

This program comes with NO WARRANTY, to the extent permitted by law.
You may redistribute copies of this program
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.

written by Larry Wall and Paul Eggert


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

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

On 05/10/2013 10:03 AM, Peter Zijlstra wrote:
> On Fri, May 10, 2013 at 09:23:33AM -0400, Sasha Levin wrote:
>> Wait, I'm confused. Over here, patch is fine with creating empty files:
>>
>> lappy lockdep # touch test.c
>> lappy lockdep # git diff /dev/null test.c > test.patch
>> lappy lockdep # rm test.c
>> lappy lockdep # file test.c
>> test.c: ERROR: cannot open `test.c' (No such file or directory)
>> lappy lockdep # patch -i test.patch
>> patching file test.c
>> lappy lockdep # file test.c
>> test.c: empty
>> lappy lockdep # cat test.patch
>> diff --git a/tools/lib/lockdep/test.c b/tools/lib/lockdep/test.c
>> new file mode 100644
>> index 0000000..e69de29
>> lappy lockdep #
>>
>> So it seems that here patch would cleanly create empty files, what does quilt
>> do differently?
> 
> 
> root@twins:~/tmp# touch ponies
> root@twins:~/tmp# git diff /dev/null ponies
> diff --git a/ponies b/ponies
> new file mode 100644
> index 0000000..e69de29
> root@twins:~/tmp# git diff /dev/null ponies > ponies.patch
> root@twins:~/tmp# rm ponies
> root@twins:~/tmp# patch < ponies.patch
> patch: **** Only garbage was found in the patch input.
> 
> t@twins:~/tmp# patch --version
> patch 2.6.1
> Copyright (C) 1988 Larry Wall
> Copyright (C) 2003, 2009 Free Software Foundation, Inc.
> 
> This program comes with NO WARRANTY, to the extent permitted by law.
> You may redistribute copies of this program
> under the terms of the GNU General Public License.
> For more information about these matters, see the file named COPYING.
> 
> written by Larry Wall and Paul Eggert
> 

Ah!

# patch --version
GNU patch 2.7.1

I've tried downgrading to 2.6.1, and now I get:

lappy lockdep # patch < test.patch
patch: **** Only garbage was found in the patch input.


Thanks,
Sasha

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

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

On Fri, May 10, 2013 at 10:11:01AM -0400, Sasha Levin wrote:
> Ah!
> 
> # patch --version
> GNU patch 2.7.1

I suppose I'd better go find me a fresher patch then! :-)

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

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

On Fri, May 10, 2013 at 04:12:27PM +0200, Peter Zijlstra wrote:
> On Fri, May 10, 2013 at 10:11:01AM -0400, Sasha Levin wrote:
> > Ah!
> > 
> > # patch --version
> > GNU patch 2.7.1
> 
> I suppose I'd better go find me a fresher patch then! :-)

*groan* all Debian based distros (with exception of Debian experimental) patch
is still 2.6.1 -- including the very latestest Ubernuts.

Means I have to go build from source on all my machines.. not happy.

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

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

On 05/10/2013 10:19 AM, Peter Zijlstra wrote:
> On Fri, May 10, 2013 at 04:12:27PM +0200, Peter Zijlstra wrote:
>> On Fri, May 10, 2013 at 10:11:01AM -0400, Sasha Levin wrote:
>>> Ah!
>>>
>>> # patch --version
>>> GNU patch 2.7.1
>>
>> I suppose I'd better go find me a fresher patch then! :-)
> 
> *groan* all Debian based distros (with exception of Debian experimental) patch
> is still 2.6.1 -- including the very latestest Ubernuts.
> 
> Means I have to go build from source on all my machines.. not happy.

That's fine, I'll just add a "this file intentionally left blank" in the empty
headers :)


Thanks,
Sasha


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

* Re: [PATCH v3 7/9] liblockdep: Support using LD_PRELOAD
  2013-05-10 13:57   ` Peter Zijlstra
@ 2013-05-10 16:06     ` Sasha Levin
  2013-05-10 16:21       ` Peter Zijlstra
  0 siblings, 1 reply; 34+ messages in thread
From: Sasha Levin @ 2013-05-10 16:06 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: torvalds, mingo, linux-kernel

On 05/10/2013 09:57 AM, Peter Zijlstra wrote:
> So you're doing instance tracking and not creating classes like the kernel
> lockdep does? While that reduces false positives it also greatly reduces the
> effectiveness of lockdep.
> 
> The power of lock-classes is that it increases the chance of catching potential
> deadlocks without there ever actually being a deadlock.

Originally I had classes working as you've pointed out, until the first time I've
tried running lockdep on qemu.

They appear to have wrappers for every api call known to man, including all the
posix locking apis.

Basically, instead of directly calling pthread_mutex_lock() for example, there's
a wrapper named qemu_mutex_lock() that calls the api above:

	void qemu_mutex_lock(QemuMutex *mutex)
	{
	    int err;
	
	    err = pthread_mutex_lock(&mutex->lock);
	    if (err)
	        error_exit(err, __func__);
	}

So as you might imagine, the first time I ran it my log exploded with warnings.

I've poked around the source of other big projects, and the example above is
somewhat common with projects that wrap everything to be compatible with different
architectures or apis - which is something that doesn't happen in the kernel.


Thanks,
Sasha

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

* Re: [PATCH v3 7/9] liblockdep: Support using LD_PRELOAD
  2013-05-10 16:06     ` Sasha Levin
@ 2013-05-10 16:21       ` Peter Zijlstra
  2013-05-10 16:42         ` Sasha Levin
  0 siblings, 1 reply; 34+ messages in thread
From: Peter Zijlstra @ 2013-05-10 16:21 UTC (permalink / raw)
  To: Sasha Levin; +Cc: torvalds, mingo, linux-kernel

On Fri, May 10, 2013 at 12:06:46PM -0400, Sasha Levin wrote:
> On 05/10/2013 09:57 AM, Peter Zijlstra wrote:
> > So you're doing instance tracking and not creating classes like the kernel
> > lockdep does? While that reduces false positives it also greatly reduces the
> > effectiveness of lockdep.
> > 
> > The power of lock-classes is that it increases the chance of catching potential
> > deadlocks without there ever actually being a deadlock.
> 
> Originally I had classes working as you've pointed out, until the first time I've
> tried running lockdep on qemu.
> 
> They appear to have wrappers for every api call known to man, including all the
> posix locking apis.
> 
> Basically, instead of directly calling pthread_mutex_lock() for example, there's
> a wrapper named qemu_mutex_lock() that calls the api above:
> 
> 	void qemu_mutex_lock(QemuMutex *mutex)
> 	{
> 	    int err;
> 	
> 	    err = pthread_mutex_lock(&mutex->lock);
> 	    if (err)
> 	        error_exit(err, __func__);
> 	}
> 
> So as you might imagine, the first time I ran it my log exploded with warnings.
> 
> I've poked around the source of other big projects, and the example above is
> somewhat common with projects that wrap everything to be compatible with different
> architectures or apis - which is something that doesn't happen in the kernel.

Urgh.. yes that might be a problem. Still it is something that should at least
be clearly stated somewhere (the Changelog for one).

Not being able to do classes sucks though :/

Hmm, we could do something like:

  $ LIBLOCKDEP_CLASS_DEPTH=n LD_PRELOAD=liblockdep.so my_app

where an @n of -1 would indicate per-instance classes and 0+ would be the
__builtin_return_address(n). That way, the above qemu thing should work with 1;
which should be the return address of the wrapper.

Of course, projects mixing different wrapper depths will be immense 'fun' :/

We could make it even worse and make the depth depend on the DSO name.. /me
runs like crazeh :-)

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

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

On 05/10/2013 12:21 PM, Peter Zijlstra wrote:
> On Fri, May 10, 2013 at 12:06:46PM -0400, Sasha Levin wrote:
>> On 05/10/2013 09:57 AM, Peter Zijlstra wrote:
>>> So you're doing instance tracking and not creating classes like the kernel
>>> lockdep does? While that reduces false positives it also greatly reduces the
>>> effectiveness of lockdep.
>>>
>>> The power of lock-classes is that it increases the chance of catching potential
>>> deadlocks without there ever actually being a deadlock.
>>
>> Originally I had classes working as you've pointed out, until the first time I've
>> tried running lockdep on qemu.
>>
>> They appear to have wrappers for every api call known to man, including all the
>> posix locking apis.
>>
>> Basically, instead of directly calling pthread_mutex_lock() for example, there's
>> a wrapper named qemu_mutex_lock() that calls the api above:
>>
>> 	void qemu_mutex_lock(QemuMutex *mutex)
>> 	{
>> 	    int err;
>> 	
>> 	    err = pthread_mutex_lock(&mutex->lock);
>> 	    if (err)
>> 	        error_exit(err, __func__);
>> 	}
>>
>> So as you might imagine, the first time I ran it my log exploded with warnings.
>>
>> I've poked around the source of other big projects, and the example above is
>> somewhat common with projects that wrap everything to be compatible with different
>> architectures or apis - which is something that doesn't happen in the kernel.
> 
> Urgh.. yes that might be a problem. Still it is something that should at least
> be clearly stated somewhere (the Changelog for one).
> 
> Not being able to do classes sucks though :/
> 
> Hmm, we could do something like:
> 
>   $ LIBLOCKDEP_CLASS_DEPTH=n LD_PRELOAD=liblockdep.so my_app
> 
> where an @n of -1 would indicate per-instance classes and 0+ would be the
> __builtin_return_address(n). That way, the above qemu thing should work with 1;
> which should be the return address of the wrapper.
> 
> Of course, projects mixing different wrapper depths will be immense 'fun' :/

Like, um, qemu? :)

You think that the only pthread_mutex_lock() calls you'd see are in the wrapper
module, right? grepping for pthread_mutex_lock will show that that's not the case...

Which is also why I'd rather leave this part out for now. I really want something
pretty simple that works for *most* cases and relies *mostly* on kernel/lockdep.c
logic instead of custom liblockdep stuff (right now the only "logic" in liblockdep
is rb-tree loockups) so that we won't scare Linus.

Also, if qemu (for example) really wants to get proper lockdep support for their
testing all it takes is just an extra call to liblockdep's mutex init api inside
their code - it means that they would need to modify their code and actually link
with liblockdep, but there's a limit to the magic that can be done from outside the code.


(I'm using qemu as an example not because I think it's horrible or something like
that, but because it's a great example for a mature big project that is still
relatively easy to work with).


Thanks,
Sasha



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

end of thread, other threads:[~2013-05-10 16:42 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-09 15:58 [PATCH v3 0/9] liblockdep: userspace lockdep Sasha Levin
2013-05-09 15:58 ` [PATCH v3 1/9] lockdep: Be nice about building from userspace Sasha Levin
2013-05-09 15:58 ` [PATCH v3 2/9] liblockdep: Wrap kernel/lockdep.c to allow usage " Sasha Levin
2013-05-10  9:18   ` Peter Zijlstra
2013-05-10  9:38     ` Ingo Molnar
2013-05-10 10:11     ` Peter Zijlstra
2013-05-10 13:23       ` Sasha Levin
2013-05-10 14:03         ` Peter Zijlstra
2013-05-10 14:11           ` Sasha Levin
2013-05-10 14:12             ` Peter Zijlstra
2013-05-10 14:19               ` Peter Zijlstra
2013-05-10 14:23                 ` Sasha Levin
2013-05-10 13:58   ` Peter Zijlstra
2013-05-09 15:58 ` [PATCH v3 3/9] liblockdep: Add public headers for pthread_mutex_t implementation Sasha Levin
2013-05-09 15:58 ` [PATCH v3 4/9] liblockdep: Add pthread_mutex_t test suite Sasha Levin
2013-05-09 15:58 ` [PATCH v3 5/9] liblockdep: Add public headers for pthread_rwlock_t implementation Sasha Levin
2013-05-09 15:58 ` [PATCH v3 6/9] liblockdep: Add pthread_rwlock_t test suite Sasha Levin
2013-05-09 15:58 ` [PATCH v3 7/9] liblockdep: Support using LD_PRELOAD Sasha Levin
2013-05-10 11:17   ` Peter Zijlstra
2013-05-10 11:23     ` Ingo Molnar
2013-05-10 11:46     ` Peter Zijlstra
2013-05-10 13:11       ` Peter Zijlstra
2013-05-10 13:57   ` Peter Zijlstra
2013-05-10 16:06     ` Sasha Levin
2013-05-10 16:21       ` Peter Zijlstra
2013-05-10 16:42         ` Sasha Levin
2013-05-09 15:58 ` [PATCH v3 8/9] liblockdep: Add the 'lockdep' user-space utility Sasha Levin
2013-05-10  9:19   ` Peter Zijlstra
2013-05-10  9:35     ` Ingo Molnar
2013-05-10 10:41       ` Peter Zijlstra
2013-05-10 11:00         ` Ingo Molnar
2013-05-10 11:10           ` Borislav Petkov
2013-05-10 11:07             ` Ingo Molnar
2013-05-09 15:58 ` [PATCH v3 9/9] liblockdep: Add a MAINTAINERS entry Sasha Levin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.