Skip to contentSkip to conversation

lockdep: Implement crossrelease feature

PATCH Superseded Byungchul Park 5 participants 49 messages Sep 13, 2016 – Nov 8, 2016

Subsystems (11)

v3 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

v3 cover lockdep: Implement crossrelease feature

I checked if crossrelease feature works well on my qemu-i386 machine. There's no problem at all to work on mine. But I wonder if it's also true even on other machines. Especially, on large system. Could you let me know if it doesn't work on yours? Or Could you let me know if crossrelease feature is useful? Please let me know if you need to backport it to another version but it's not easy. Then I can provide the backported version after working it.

I added output text of 'cat /proc/lockdep' on my machine applying crossrelease feature, showing dependencies of lockdep. You can check what kind of dependencies are added by crossrelease feature. Please use '(complete)' or '(PG_locked)' as a keyword to find dependencies added by this patch set.

-----8<-----

Change from v2
- rebase on vanilla v4.7 tag
- move lockdep data for page lock from struct page to page_ext
- allocate plocks buffer via vmalloc instead of in struct task
- enhanced comments and document
- optimize performance
- make reporting function crossrelease-aware

Change from v1
- enhanced the document
- removed save_stack_trace() optimizing patch
- made this based on the seperated save_stack_trace patchset
https://www.mail-archive.com/[email protected]/msg1182242.html

Can we detect deadlocks below with original lockdep?

Example 1)

PROCESS X PROCESS Y
-------------- --------------
mutext_lock A
lock_page B
lock_page B
mutext_lock A // DEADLOCK
unlock_page B
mutext_unlock A
mutex_unlock A
unlock_page B

where A and B are different lock classes.

No, we cannot.

Example 2)

PROCESS X PROCESS Y PROCESS Z
-------------- -------------- --------------
mutex_lock A
lock_page B
lock_page B
mutext_lock A // DEADLOCK mutext_unlock A unlock_page B (B was held by PROCESS X)
unlock_page B
mutex_unlock A

where A and B are different lock classes.

No, we cannot.

Example 3)

PROCESS X PROCESS Y
-------------- --------------
mutex_lock A
mutex_lock A
mutex_unlock A
wait_for_complete B // DEADLOCK
complete B
mutex_unlock A

where A is a lock class and B is a completion variable.

No, we cannot.

Not only lock operations, but also any operations causing to wait or spin for something can cause deadlock unless it's eventually *released* by someone. The important point here is that the waiting or spinning must be *released* by someone.

Using crossrelease feature, we can check dependency and detect deadlock possibility not only for typical lock, but also for lock_page(), wait_for_xxx() and so on, which might be released in any context.

See the last patch including the document for more information.

Byungchul Park (15):
x86/dumpstack: Optimize save_stack_trace x86/dumpstack: Add save_stack_trace()_fast()
lockdep: Refactor lookup_chain_cache()
lockdep: Add a function building a chain between two classes
lockdep: Make check_prev_add can use a separate stack_trace
lockdep: Make save_trace can skip stack tracing of the current
lockdep: Implement crossrelease feature
lockdep: Make crossrelease use save_stack_trace_fast()
lockdep: Make print_circular_bug() crosslock-aware
lockdep: Apply crossrelease to completion operation pagemap.h: Remove trailing white space
lockdep: Apply crossrelease to PG_locked lock
lockdep: Apply lock_acquire(release) on __Set(__Clear)PageLocked
lockdep: Move data used in CONFIG_LOCKDEP_PAGELOCK from page to
page_ext
lockdep: Crossrelease feature documentation

 Documentation/locking/crossrelease.txt | 785 ++++++++++++++++++++++++++++++++
 arch/x86/include/asm/stacktrace.h      |   1 +
 arch/x86/kernel/dumpstack.c            |   4 +
 arch/x86/kernel/dumpstack_32.c         |   2 +
 arch/x86/kernel/stacktrace.c           |  32 ++
 include/linux/completion.h             | 121 ++++-
 include/linux/irqflags.h               |  12 +-
 include/linux/lockdep.h                | 122 +++++
 include/linux/mm_types.h               |   4 +
 include/linux/page-flags.h             |  43 +-
 include/linux/page_ext.h               |   5 +
 include/linux/pagemap.h                | 124 ++++-
 include/linux/sched.h                  |   5 +
 include/linux/stacktrace.h             |   2 +
 kernel/exit.c                          |   9 +
 kernel/fork.c                          |  20 +
 kernel/locking/lockdep.c               | 804 +++++++++++++++++++++++++++++----
 kernel/sched/completion.c              |  54 ++-
 lib/Kconfig.debug                      |  30 ++
 mm/filemap.c                           |  76 +++-
 mm/page_ext.c                          |   4 +
 21 files changed, 2124 insertions(+), 135 deletions(-)
 create mode 100644 Documentation/locking/crossrelease.txt
Signature · 7 lines
1.9.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#1 lore raw

PATCH v3 1/15 x86/dumpstack: Optimize save_stack_trace

Currently, x86 implementation of save_stack_trace() is walking all stack region word by word regardless of what the trace->max_entries is. However, it's unnecessary to walk after already fulfilling caller's requirement, say, if trace->nr_entries >= trace->max_entries is true.

I measured its overhead and printed its difference of sched_clock() with my QEMU x86 machine. The latency was improved over 70% when trace->max_entries = 5.

Before this patch:

[    2.329573] save_stack_trace() takes 76820 ns
[    2.329863] save_stack_trace() takes 62131 ns
[    2.330000] save_stack_trace() takes 99476 ns
[    2.329846] save_stack_trace() takes 62419 ns
[    2.330000] save_stack_trace() takes 88918 ns
[    2.330253] save_stack_trace() takes 73669 ns
[    2.330520] save_stack_trace() takes 67876 ns
[    2.330671] save_stack_trace() takes 75963 ns
[    2.330983] save_stack_trace() takes 95079 ns
[    2.330451] save_stack_trace() takes 62352 ns

After this patch:

[    2.795000] save_stack_trace() takes 21147 ns
[    2.795397] save_stack_trace() takes 20230 ns
[    2.795397] save_stack_trace() takes 31274 ns
[    2.795739] save_stack_trace() takes 19706 ns
[    2.796484] save_stack_trace() takes 20266 ns
[    2.796484] save_stack_trace() takes 20902 ns
[    2.797000] save_stack_trace() takes 38110 ns
[    2.797510] save_stack_trace() takes 20224 ns
[    2.798181] save_stack_trace() takes 20172 ns
[    2.798837] save_stack_trace() takes 20824 ns
---
 arch/x86/include/asm/stacktrace.h | 1 +
 arch/x86/kernel/dumpstack.c       | 4 ++++
 arch/x86/kernel/dumpstack_32.c    | 2 ++
 arch/x86/kernel/stacktrace.c      | 7 +++++++
 4 files changed, 14 insertions(+)
arch/x86/include/asm/stacktrace.h +1 -0
index 0944218..f6d0694 100644
@@ -41,6 +41,7 @@ struct stacktrace_ops {
 	/* On negative return stop dumping */
 	int (*stack)(void *data, char *name);
 	walk_stack_t	walk_stack;
+	int (*end_walk)(void *data);
 };
 
 void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
arch/x86/kernel/dumpstack.c +4 -0
index ef8017c..274d42a 100644
@@ -113,6 +113,8 @@ print_context_stack(struct task_struct *task,
 			print_ftrace_graph_addr(addr, data, ops, task, graph);
 		}
 		stack++;
+		if (ops->end_walk && ops->end_walk(data))
+			break;
 	}
 	return bp;
 }
@@ -138,6 +140,8 @@ print_context_stack_bp(struct task_struct *task,
 		frame = frame->next_frame;
 		ret_addr = &frame->return_address;
 		print_ftrace_graph_addr(addr, data, ops, task, graph);
+		if (ops->end_walk && ops->end_walk(data))
+			break;
 	}
 
 	return (unsigned long)frame;
arch/x86/kernel/dumpstack_32.c +2 -0
index fef917e..762d1fd 100644
@@ -69,6 +69,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
 
 		bp = ops->walk_stack(task, stack, bp, ops, data,
 				     end_stack, &graph);
+		if (ops->end_walk && ops->end_walk(data))
+			break;
 
 		/* Stop if not on irq stack */
 		if (!end_stack)
arch/x86/kernel/stacktrace.c +7 -0
index 9ee98ee..a44de4d 100644
@@ -47,10 +47,17 @@ save_stack_address_nosched(void *data, unsigned long addr, int reliable)
 	return __save_stack_address(data, addr, reliable, true);
 }
 
+static int save_stack_end(void *data)
+{
+	struct stack_trace *trace = data;
+	return trace->nr_entries >= trace->max_entries;
+}
+
 static const struct stacktrace_ops save_stack_ops = {
 	.stack		= save_stack_stack,
 	.address	= save_stack_address,
 	.walk_stack	= print_context_stack,
+	.end_walk	= save_stack_end,
 };
 
 static const struct stacktrace_ops save_stack_ops_nosched = {
Signature · 7 lines
1.9.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#2 lore raw

Re: [PATCH v3 01/15] x86/dumpstack: Optimize save_stack_trace

Quoted 8 lines · Byungchul Park

Currently, x86 implementation of save_stack_trace() is walking all stack region word by word regardless of what the trace->max_entries is. However, it's unnecessary to walk after already fulfilling caller's requirement, say, if trace->nr_entries >= trace->max_entries is true.

I measured its overhead and printed its difference of sched_clock() with my QEMU x86 machine. The latency was improved over 70% when trace->max_entries = 5.

This code will (probably) be obsoleted soon with my new unwinder.

Also, my previous comment was ignored:

Instead of adding a new callback, why not just check the ops->address() return value? It already returns an error if the array is full.

I think that would be cleaner and would help prevent more callback sprawl.

Signature · 7 lines
Josh

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#3 lore raw

Re: [PATCH v3 01/15] x86/dumpstack: Optimize save_stack_trace

Quoted 11 lines · Josh Poimboeuf
Quoted 8 lines · Byungchul Park

Currently, x86 implementation of save_stack_trace() is walking all stack region word by word regardless of what the trace->max_entries is. However, it's unnecessary to walk after already fulfilling caller's requirement, say, if trace->nr_entries >= trace->max_entries is true.

I measured its overhead and printed its difference of sched_clock() with my QEMU x86 machine. The latency was improved over 70% when trace->max_entries = 5.

This code will (probably) be obsoleted soon with my new unwinder.

Hello,

You are right.

I also think this will probably be obsoleted with yours. So I didn't modify any details of the patch.
I will take your comment into account if it becomes necessary.

Anyway, crossrelease needs this patch to work smoothly. That's only reason why I included this patch in the thread.

Thank you,
Byungchul

Quoted 10 lines

Also, my previous comment was ignored:

Instead of adding a new callback, why not just check the ops->address() return value? It already returns an error if the array is full.

I think that would be cleaner and would help prevent more callback sprawl.

--
Josh

Signature · 8 lines
Thanks,
Byungchul

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#4 lore raw

PATCH v3 2/15 x86/dumpstack: Add save_stack_trace()_fast()

In reply to Byungchul Park

In non-oops case, it's usually not necessary to check all words of stack area to extract backtrace. Instead, we can achieve it by tracking frame pointer. So made it possible to save stack trace lightly in normal case.

I measured its ovehead and printed its difference of sched_clock() with my QEMU x86 machine. The latency was improved over 80% when trace->max_entries = 5.

Before this patch:

[    2.795000] save_stack_trace() takes 21147 ns
[    2.795397] save_stack_trace() takes 20230 ns
[    2.795397] save_stack_trace() takes 31274 ns
[    2.795739] save_stack_trace() takes 19706 ns
[    2.796484] save_stack_trace() takes 20266 ns
[    2.796484] save_stack_trace() takes 20902 ns
[    2.797000] save_stack_trace() takes 38110 ns
[    2.797510] save_stack_trace() takes 20224 ns
[    2.798181] save_stack_trace() takes 20172 ns
[    2.798837] save_stack_trace() takes 20824 ns

After this patch:

[    3.133807] save_stack_trace() takes 3297 ns
[    3.133954] save_stack_trace() takes 3330 ns
[    3.134235] save_stack_trace() takes 3517 ns
[    3.134711] save_stack_trace() takes 3773 ns
[    3.135000] save_stack_trace() takes 3685 ns
[    3.135541] save_stack_trace() takes 4757 ns
[    3.135865] save_stack_trace() takes 3420 ns
[    3.136000] save_stack_trace() takes 3329 ns
[    3.137000] save_stack_trace() takes 4058 ns
[    3.137000] save_stack_trace() takes 3499 ns
---
 arch/x86/kernel/stacktrace.c | 25 +++++++++++++++++++++++++
 include/linux/stacktrace.h   |  2 ++
 2 files changed, 27 insertions(+)
arch/x86/kernel/stacktrace.c +25 -0
index a44de4d..d8da90f 100644
@@ -53,6 +53,10 @@ static int save_stack_end(void *data)
 	return trace->nr_entries >= trace->max_entries;
 }
 
+/*
+ * This operation should be used in the oops case where
+ * stack might be broken.
+ */
 static const struct stacktrace_ops save_stack_ops = {
 	.stack		= save_stack_stack,
 	.address	= save_stack_address,
@@ -60,6 +64,13 @@ static const struct stacktrace_ops save_stack_ops = {
 	.end_walk	= save_stack_end,
 };
 
+static const struct stacktrace_ops save_stack_ops_fast = {
+	.stack		= save_stack_stack,
+	.address	= save_stack_address,
+	.walk_stack	= print_context_stack_bp,
+	.end_walk	= save_stack_end,
+};
+
 static const struct stacktrace_ops save_stack_ops_nosched = {
 	.stack		= save_stack_stack,
 	.address	= save_stack_address_nosched,
@@ -68,6 +79,7 @@ static const struct stacktrace_ops save_stack_ops_nosched = {
 
 /*
  * Save stack-backtrace addresses into a stack_trace buffer.
+ * It works even in oops.
  */
 void save_stack_trace(struct stack_trace *trace)
 {
@@ -77,6 +89,19 @@ void save_stack_trace(struct stack_trace *trace)
 }
 EXPORT_SYMBOL_GPL(save_stack_trace);
 
+/*
+ * Save stack-backtrace addresses into a stack_trace buffer.
+ * This is perfered in normal case where we expect the stack is
+ * reliable.
+ */
+void save_stack_trace_fast(struct stack_trace *trace)
+{
+	dump_trace(current, NULL, NULL, 0, &save_stack_ops_fast, trace);
+	if (trace->nr_entries < trace->max_entries)
+		trace->entries[trace->nr_entries++] = ULONG_MAX;
+}
+EXPORT_SYMBOL_GPL(save_stack_trace_fast);
+
 void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
 {
 	dump_trace(current, regs, NULL, 0, &save_stack_ops, trace);
include/linux/stacktrace.h +2 -0
index 0a34489..ddef1d0 100644
@@ -14,6 +14,7 @@ struct stack_trace {
 };
 
 extern void save_stack_trace(struct stack_trace *trace);
+extern void save_stack_trace_fast(struct stack_trace *trace);
 extern void save_stack_trace_regs(struct pt_regs *regs,
 				  struct stack_trace *trace);
 extern void save_stack_trace_tsk(struct task_struct *tsk,
@@ -31,6 +32,7 @@ extern void save_stack_trace_user(struct stack_trace *trace);
 
 #else
 # define save_stack_trace(trace)			do { } while (0)
+# define save_stack_trace_fast(trace)			do { } while (0)
 # define save_stack_trace_tsk(tsk, trace)		do { } while (0)
 # define save_stack_trace_user(trace)			do { } while (0)
 # define print_stack_trace(trace, spaces)		do { } while (0)
Signature · 7 lines
1.9.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#5 lore raw

Re: [PATCH v3 02/15] x86/dumpstack: Add save_stack_trace()_fast()

Quoted 7 lines · Byungchul Park

In non-oops case, it's usually not necessary to check all words of stack area to extract backtrace. Instead, we can achieve it by tracking frame pointer. So made it possible to save stack trace lightly in normal case.

I measured its ovehead and printed its difference of sched_clock() with my QEMU x86 machine. The latency was improved over 80% when trace->max_entries = 5.

Again this code will (probably) be obsolete soon. And another quote from my previous review:

So how about we change save_stack_trace() to use print_context_stack() for CONFIG_FRAME_POINTER=n and print_context_stack_bp() for CONFIG_FRAME_POINTER=y? That would preserve the existing behavior, no?

Signature · 7 lines
Josh

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#6 lore raw

PATCH v3 3/15 lockdep: Refactor lookup_chain_cache()

In reply to Byungchul Park

Currently, lookup_chain_cache() provides both 'lookup' and 'add' functionalities in a function. However, each one is useful. So this patch makes lookup_chain_cache() only do lookup functionality and makes add_chain_cahce() only do add functionality. And it's more readable than these functionalities are mixed in a function.

Crossrelease feature also needs to use each one separately.

---
 kernel/locking/lockdep.c | 129 +++++++++++++++++++++++++++++------------------
 1 file changed, 81 insertions(+), 48 deletions(-)
kernel/locking/lockdep.c +81 -48
index 81f1a71..5df56aa 100644
@@ -2105,15 +2105,9 @@ static int check_no_collision(struct task_struct *curr,
 	return 1;
 }
 
-/*
- * Look up a dependency chain. If the key is not present yet then
- * add it and return 1 - in this case the new dependency chain is
- * validated. If the key is already hashed, return 0.
- * (On return with 1 graph_lock is held.)
- */
-static inline int lookup_chain_cache(struct task_struct *curr,
-				     struct held_lock *hlock,
-				     u64 chain_key)
+static inline int add_chain_cache(struct task_struct *curr,
+				  struct held_lock *hlock,
+				  u64 chain_key)
 {
 	struct lock_class *class = hlock_class(hlock);
 	struct hlist_head *hash_head = chainhashentry(chain_key);
@@ -2121,49 +2115,18 @@ static inline int lookup_chain_cache(struct task_struct *curr,
 	int i, j;
 
 	/*
+	 * Allocate a new chain entry from the static array, and add
+	 * it to the hash:
+	 */
+
+	/*
 	 * We might need to take the graph lock, ensure we've got IRQs
 	 * disabled to make this an IRQ-safe lock.. for recursion reasons
 	 * lockdep won't complain about its own locking errors.
 	 */
 	if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
 		return 0;
-	/*
-	 * We can walk it lock-free, because entries only get added
-	 * to the hash:
-	 */
-	hlist_for_each_entry_rcu(chain, hash_head, entry) {
-		if (chain->chain_key == chain_key) {
-cache_hit:
-			debug_atomic_inc(chain_lookup_hits);
-			if (!check_no_collision(curr, hlock, chain))
-				return 0;
 
-			if (very_verbose(class))
-				printk("\nhash chain already cached, key: "
-					"%016Lx tail class: [%p] %s\n",
-					(unsigned long long)chain_key,
-					class->key, class->name);
-			return 0;
-		}
-	}
-	if (very_verbose(class))
-		printk("\nnew hash chain, key: %016Lx tail class: [%p] %s\n",
-			(unsigned long long)chain_key, class->key, class->name);
-	/*
-	 * Allocate a new chain entry from the static array, and add
-	 * it to the hash:
-	 */
-	if (!graph_lock())
-		return 0;
-	/*
-	 * We have to walk the chain again locked - to avoid duplicates:
-	 */
-	hlist_for_each_entry(chain, hash_head, entry) {
-		if (chain->chain_key == chain_key) {
-			graph_unlock();
-			goto cache_hit;
-		}
-	}
 	if (unlikely(nr_lock_chains >= MAX_LOCKDEP_CHAINS)) {
 		if (!debug_locks_off_graph_unlock())
 			return 0;
@@ -2215,6 +2178,75 @@ cache_hit:
 	return 1;
 }
 
+/*
+ * Look up a dependency chain.
+ */
+static inline struct lock_chain *lookup_chain_cache(u64 chain_key)
+{
+	struct hlist_head *hash_head = chainhashentry(chain_key);
+	struct lock_chain *chain;
+
+	/*
+	 * We can walk it lock-free, because entries only get added
+	 * to the hash:
+	 */
+	hlist_for_each_entry_rcu(chain, hash_head, entry) {
+		if (chain->chain_key == chain_key) {
+			debug_atomic_inc(chain_lookup_hits);
+			return chain;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * If the key is not present yet in dependency chain cache then
+ * add it and return 1 - in this case the new dependency chain is
+ * validated. If the key is already hashed, return 0.
+ * (On return with 1 graph_lock is held.)
+ */
+static inline int lookup_chain_cache_add(struct task_struct *curr,
+					 struct held_lock *hlock,
+					 u64 chain_key)
+{
+	struct lock_class *class = hlock_class(hlock);
+	struct lock_chain *chain = lookup_chain_cache(chain_key);
+
+	if (chain) {
+cache_hit:
+		if (!check_no_collision(curr, hlock, chain))
+			return 0;
+
+		if (very_verbose(class))
+			printk("\nhash chain already cached, key: "
+					"%016Lx tail class: [%p] %s\n",
+					(unsigned long long)chain_key,
+					class->key, class->name);
+		return 0;
+	}
+
+	if (very_verbose(class))
+		printk("\nnew hash chain, key: %016Lx tail class: [%p] %s\n",
+			(unsigned long long)chain_key, class->key, class->name);
+
+	if (!graph_lock())
+		return 0;
+
+	/*
+	 * We have to walk the chain again locked - to avoid duplicates:
+	 */
+	chain = lookup_chain_cache(chain_key);
+	if (chain) {
+		graph_unlock();
+		goto cache_hit;
+	}
+
+	if (!add_chain_cache(curr, hlock, chain_key))
+		return 0;
+
+	return 1;
+}
+
 static int validate_chain(struct task_struct *curr, struct lockdep_map *lock,
 		struct held_lock *hlock, int chain_head, u64 chain_key)
 {
@@ -2225,11 +2257,11 @@ static int validate_chain(struct task_struct *curr, struct lockdep_map *lock,
 	 *
 	 * We look up the chain_key and do the O(N^2) check and update of
 	 * the dependencies only if this is a new dependency chain.
-	 * (If lookup_chain_cache() returns with 1 it acquires
+	 * (If lookup_chain_cache_add() return with 1 it acquires
 	 * graph_lock for us)
 	 */
 	if (!hlock->trylock && hlock->check &&
-	    lookup_chain_cache(curr, hlock, chain_key)) {
+	    lookup_chain_cache_add(curr, hlock, chain_key)) {
 		/*
 		 * Check whether last held lock:
 		 *
@@ -2260,9 +2292,10 @@ static int validate_chain(struct task_struct *curr, struct lockdep_map *lock,
 		if (!chain_head && ret != 2)
 			if (!check_prevs_add(curr, hlock))
 				return 0;
+
 		graph_unlock();
 	} else
-		/* after lookup_chain_cache(): */
+		/* after lookup_chain_cache_add(): */
 		if (unlikely(!debug_locks))
 			return 0;
 
Signature · 7 lines
1.9.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#7 lore raw

Re: [PATCH v3 03/15] lockdep: Refactor lookup_chain_cache()

Quoted 14 lines · Byungchul Park
kernel/locking/lockdep.c +10 -0
@@ -2215,6 +2178,75 @@ cache_hit:
        return 1;
 }
 
+/*
+ * Look up a dependency chain.
+ */
+static inline struct lock_chain *lookup_chain_cache(u64 chain_key)
+{
+       struct hlist_head *hash_head = chainhashentry(chain_key);
+       struct lock_chain *chain;
+
+       /*
+        * We can walk it lock-free, because entries only get added

kernel/locking/lockdep.c cache_hit: · line 2200

Quoted 10 lines
kernel/locking/lockdep.c +10 -0
+        * to the hash:
+        */
+       hlist_for_each_entry_rcu(chain, hash_head, entry) {
+               if (chain->chain_key == chain_key) {
+                       debug_atomic_inc(chain_lookup_hits);
+                       return chain;
+               }
+       }
+       return NULL;
+}

Byungchul, do you think we should increment chain_lookup_misses before returning NULL from the above function?

--
Nilay

#8 lore raw

Re: [PATCH v3 03/15] lockdep: Refactor lookup_chain_cache()

Quoted 20 lines · Nilay Vaish
Quoted 19 lines · Byungchul Park
kernel/locking/lockdep.c +15 -0
@@ -2215,6 +2178,75 @@ cache_hit:
        return 1;
 }
 
+/*
+ * Look up a dependency chain.
+ */
+static inline struct lock_chain *lookup_chain_cache(u64 chain_key)
+{
+       struct hlist_head *hash_head = chainhashentry(chain_key);
+       struct lock_chain *chain;
+
+       /*
+        * We can walk it lock-free, because entries only get added
+        * to the hash:
+        */
+       hlist_for_each_entry_rcu(chain, hash_head, entry) {
+               if (chain->chain_key == chain_key) {
+                       debug_atomic_inc(chain_lookup_hits);
Quoted 8 lines

kernel/locking/lockdep.c cache_hit: · line 2200

Quoted 5 lines
kernel/locking/lockdep.c +5 -0
+                       return chain;
+               }
+       }
+       return NULL;
+}

Byungchul, do you think we should increment chain_lookup_misses before returning NULL from the above function?

Hello,

No, I don't think so.
It will be done in add_chain_cache().

Thank you,
Byungchul

Quoted 3 lines

--
Nilay

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#9 lore raw

Re: [PATCH v3 03/15] lockdep: Refactor lookup_chain_cache()

Quoted 30 lines · Byungchul Park
Quoted 20 lines · Nilay Vaish
Quoted 19 lines · Byungchul Park
kernel/locking/lockdep.c +15 -0
@@ -2215,6 +2178,75 @@ cache_hit:
        return 1;
 }
 
+/*
+ * Look up a dependency chain.
+ */
+static inline struct lock_chain *lookup_chain_cache(u64 chain_key)
+{
+       struct hlist_head *hash_head = chainhashentry(chain_key);
+       struct lock_chain *chain;
+
+       /*
+        * We can walk it lock-free, because entries only get added
+        * to the hash:
+        */
+       hlist_for_each_entry_rcu(chain, hash_head, entry) {
+               if (chain->chain_key == chain_key) {
+                       debug_atomic_inc(chain_lookup_hits);
Quoted 8 lines

kernel/locking/lockdep.c cache_hit: · line 2200

Quoted 5 lines
kernel/locking/lockdep.c +5 -0
+                       return chain;
+               }
+       }
+       return NULL;
+}

Byungchul, do you think we should increment chain_lookup_misses before returning NULL from the above function?

Quoted 5 lines

Hello,

No, I don't think so.
It will be done in add_chain_cache().

I think you are assuming that a call to lookup will always be followed by add. I thought the point of breaking the original function into two was that each of the functions can be used individually, without the other being called. This means we would not increment the number of misses when only lookup() gets called, but not add(). Or we would increment the number of misses when only add() is called and not lookup().

It really seems odd to me that hits get incremented in lookup and misses don't.

--
Nilay

#10 lore raw

Re: [PATCH v3 03/15] lockdep: Refactor lookup_chain_cache()

Quoted 33 lines · Nilay Vaish
Quoted 32 lines · Byungchul Park
Quoted 20 lines · Nilay Vaish
Quoted 19 lines · Byungchul Park
kernel/locking/lockdep.c +15 -0
@@ -2215,6 +2178,75 @@ cache_hit:
        return 1;
 }
 
+/*
+ * Look up a dependency chain.
+ */
+static inline struct lock_chain *lookup_chain_cache(u64 chain_key)
+{
+       struct hlist_head *hash_head = chainhashentry(chain_key);
+       struct lock_chain *chain;
+
+       /*
+        * We can walk it lock-free, because entries only get added
+        * to the hash:
+        */
+       hlist_for_each_entry_rcu(chain, hash_head, entry) {
+               if (chain->chain_key == chain_key) {
+                       debug_atomic_inc(chain_lookup_hits);
Quoted 8 lines

kernel/locking/lockdep.c cache_hit: · line 2200

Quoted 5 lines
kernel/locking/lockdep.c +5 -0
+                       return chain;
+               }
+       }
+       return NULL;
+}

Byungchul, do you think we should increment chain_lookup_misses before returning NULL from the above function?

Hello,

Quoted 8 lines
Quoted 3 lines

No, I don't think so.
It will be done in add_chain_cache().

I think you are assuming that a call to lookup will always be followed by add. I thought the point of breaking the original function into two was that each of the functions can be used individually, without the other being called. This means we would not increment the number

Right.

But, we have to remind that counting for cache miss can happen twice if it's handled in lookup_chain_cache(), because chain_lookup_misses() is called twice every lookup. One is 'lockless access' for fast path, the other is 'lock-protected access' for guarranting real miss.

So only when the miss is indentified under lock-protected, chain_lookup_misses has to be counted. Current chain_lookup_misses means that "cache miss happened and was _added_ into cache", semantically. Thus I think it's not bad to handle it in add().

Quoted 1 line

of misses when only lookup() gets called, but not add(). Or we would

lookup() might be called locklessly for fast path. It would be useful, but it guarrantees nothing but cache bit. So we cannot count miss in lookup(). Furthermore, we have to assume add() is called when cache miss.

Quoted 2 lines

increment the number of misses when only add() is called and not lookup().

Actually add() will not be called without calling lookup(). Anyway, I can see what you're concerning.. Is there any alterative which is better?

Quoted 5 lines

It really seems odd to me that hits get incremented in lookup and misses don't.

--
Nilay

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#11 lore raw

PATCH v3 4/15 lockdep: Add a function building a chain between two classes

In reply to Byungchul Park

add_chain_cache() should be used in the context where the hlock is owned since it might be racy in another context. However crossrelease feature needs to build a chain between two locks regardless of context. So introduce a new function making it possible.

---
 kernel/locking/lockdep.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)
kernel/locking/lockdep.c +56 -0
index 5df56aa..111839f 100644
@@ -2105,6 +2105,62 @@ static int check_no_collision(struct task_struct *curr,
 	return 1;
 }
 
+/*
+ * This is for building a chain between just two different classes,
+ * instead of adding a new hlock upon current, which is done by
+ * add_chain_cache().
+ *
+ * This can be called in any context with two classes, while
+ * add_chain_cache() must be done within the lock owener's context
+ * since it uses hlock which might be racy in another context.
+ */
+static inline int add_chain_cache_classes(unsigned int prev,
+					  unsigned int next,
+					  unsigned int irq_context,
+					  u64 chain_key)
+{
+	struct hlist_head *hash_head = chainhashentry(chain_key);
+	struct lock_chain *chain;
+
+	/*
+	 * Allocate a new chain entry from the static array, and add
+	 * it to the hash:
+	 */
+
+	/*
+	 * We might need to take the graph lock, ensure we've got IRQs
+	 * disabled to make this an IRQ-safe lock.. for recursion reasons
+	 * lockdep won't complain about its own locking errors.
+	 */
+	if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
+		return 0;
+
+	if (unlikely(nr_lock_chains >= MAX_LOCKDEP_CHAINS)) {
+		if (!debug_locks_off_graph_unlock())
+			return 0;
+
+		print_lockdep_off("BUG: MAX_LOCKDEP_CHAINS too low!");
+		dump_stack();
+		return 0;
+	}
+
+	chain = lock_chains + nr_lock_chains++;
+	chain->chain_key = chain_key;
+	chain->irq_context = irq_context;
+	chain->depth = 2;
+	if (likely(nr_chain_hlocks + chain->depth <= MAX_LOCKDEP_CHAIN_HLOCKS)) {
+		chain->base = nr_chain_hlocks;
+		nr_chain_hlocks += chain->depth;
+		chain_hlocks[chain->base] = prev - 1;
+		chain_hlocks[chain->base + 1] = next -1;
+	}
+	hlist_add_head_rcu(&chain->entry, hash_head);
+	debug_atomic_inc(chain_lookup_misses);
+	inc_chains();
+
+	return 1;
+}
+
 static inline int add_chain_cache(struct task_struct *curr,
 				  struct held_lock *hlock,
 				  u64 chain_key)
Signature · 7 lines
1.9.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#12 lore raw

PATCH v3 5/15 lockdep: Make check_prev_add can use a separate stack_trace

In reply to Byungchul Park

check_prev_add() saves a stack trace of the current. But crossrelease feature needs to use a separate stack trace of another context in check_prev_add(). So make it use a separate stack trace instead of one of the current.

---
 kernel/locking/lockdep.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)
kernel/locking/lockdep.c +9 -7
index 111839f..3eaa11c 100644
@@ -1793,7 +1793,8 @@ check_deadlock(struct task_struct *curr, struct held_lock *next,
  */
 static int
 check_prev_add(struct task_struct *curr, struct held_lock *prev,
-	       struct held_lock *next, int distance, int *stack_saved)
+	       struct held_lock *next, int distance, int *stack_saved,
+	       struct stack_trace *own_trace)
 {
 	struct lock_list *entry;
 	int ret;
@@ -1854,7 +1855,7 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
 		}
 	}
 
-	if (!*stack_saved) {
+	if (!own_trace && stack_saved && !*stack_saved) {
 		if (!save_trace(&trace))
 			return 0;
 		*stack_saved = 1;
@@ -1866,14 +1867,14 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
 	 */
 	ret = add_lock_to_list(hlock_class(prev), hlock_class(next),
 			       &hlock_class(prev)->locks_after,
-			       next->acquire_ip, distance, &trace);
+			       next->acquire_ip, distance, own_trace ?: &trace);
 
 	if (!ret)
 		return 0;
 
 	ret = add_lock_to_list(hlock_class(next), hlock_class(prev),
 			       &hlock_class(next)->locks_before,
-			       next->acquire_ip, distance, &trace);
+			       next->acquire_ip, distance, own_trace ?: &trace);
 	if (!ret)
 		return 0;
 
@@ -1882,7 +1883,8 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
 	 */
 	if (verbose(hlock_class(prev)) || verbose(hlock_class(next))) {
 		/* We drop graph lock, so another thread can overwrite trace. */
-		*stack_saved = 0;
+		if (stack_saved)
+			*stack_saved = 0;
 		graph_unlock();
 		printk("\n new dependency: ");
 		print_lock_name(hlock_class(prev));
@@ -1931,8 +1933,8 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)
 		 * added:
 		 */
 		if (hlock->read != 2 && hlock->check) {
-			if (!check_prev_add(curr, hlock, next,
-						distance, &stack_saved))
+			if (!check_prev_add(curr, hlock, next, distance,
+						&stack_saved, NULL))
 				return 0;
 			/*
 			 * Stop after the first non-trylock entry,
Signature · 1 line
1.9.1
#13 lore raw

PATCH v3 6/15 lockdep: Make save_trace can skip stack tracing of the current

In reply to Byungchul Park

Currently, save_trace() always performs save_stack_trace() for the current. However, crossrelease needs to use stack trace data of another context instead of the current. So add a parameter for skipping stack tracing of the current and make it use trace data, which is already saved by crossrelease framework.

---
 kernel/locking/lockdep.c | 33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)
kernel/locking/lockdep.c +20 -13
index 3eaa11c..11580ec 100644
@@ -387,15 +387,22 @@ static void print_lockdep_off(const char *bug_msg)
 #endif
 }
 
-static int save_trace(struct stack_trace *trace)
+static int save_trace(struct stack_trace *trace, int skip_tracing)
 {
-	trace->nr_entries = 0;
-	trace->max_entries = MAX_STACK_TRACE_ENTRIES - nr_stack_trace_entries;
-	trace->entries = stack_trace + nr_stack_trace_entries;
+	unsigned int nr_avail = MAX_STACK_TRACE_ENTRIES - nr_stack_trace_entries;
 
-	trace->skip = 3;
-
-	save_stack_trace(trace);
+	if (skip_tracing) {
+		trace->nr_entries = min(trace->nr_entries, nr_avail);
+		memcpy(stack_trace + nr_stack_trace_entries, trace->entries,
+				trace->nr_entries * sizeof(trace->entries[0]));
+		trace->entries = stack_trace + nr_stack_trace_entries;
+	} else {
+		trace->nr_entries = 0;
+		trace->max_entries = nr_avail;
+		trace->entries = stack_trace + nr_stack_trace_entries;
+		trace->skip = 3;
+		save_stack_trace(trace);
+	}
 
 	/*
 	 * Some daft arches put -1 at the end to indicate its a full trace.
@@ -1172,7 +1179,7 @@ static noinline int print_circular_bug(struct lock_list *this,
 	if (!debug_locks_off_graph_unlock() || debug_locks_silent)
 		return 0;
 
-	if (!save_trace(&this->trace))
+	if (!save_trace(&this->trace, 0))
 		return 0;
 
 	depth = get_lock_depth(target);
@@ -1518,13 +1525,13 @@ print_bad_irq_dependency(struct task_struct *curr,
 
 	printk("\nthe dependencies between %s-irq-safe lock", irqclass);
 	printk(" and the holding lock:\n");
-	if (!save_trace(&prev_root->trace))
+	if (!save_trace(&prev_root->trace, 0))
 		return 0;
 	print_shortest_lock_dependencies(backwards_entry, prev_root);
 
 	printk("\nthe dependencies between the lock to be acquired");
 	printk(" and %s-irq-unsafe lock:\n", irqclass);
-	if (!save_trace(&next_root->trace))
+	if (!save_trace(&next_root->trace, 0))
 		return 0;
 	print_shortest_lock_dependencies(forwards_entry, next_root);
 
@@ -1856,7 +1863,7 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
 	}
 
 	if (!own_trace && stack_saved && !*stack_saved) {
-		if (!save_trace(&trace))
+		if (!save_trace(&trace, 0))
 			return 0;
 		*stack_saved = 1;
 	}
@@ -2547,7 +2554,7 @@ print_irq_inversion_bug(struct task_struct *curr,
 	lockdep_print_held_locks(curr);
 
 	printk("\nthe shortest dependencies between 2nd lock and 1st lock:\n");
-	if (!save_trace(&root->trace))
+	if (!save_trace(&root->trace, 0))
 		return 0;
 	print_shortest_lock_dependencies(other, root);
 
@@ -3134,7 +3141,7 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
 
 	hlock_class(this)->usage_mask |= new_mask;
 
-	if (!save_trace(hlock_class(this)->usage_traces + new_bit))
+	if (!save_trace(hlock_class(this)->usage_traces + new_bit, 0))
 		return 0;
 
 	switch (new_bit) {
Signature · 7 lines
1.9.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#14 lore raw

PATCH v3 7/15 lockdep: Implement crossrelease feature

In reply to Byungchul Park

Crossrelease feature calls a lock 'crosslock' if it is releasable in any context. For crosslock, all locks having been held in the release context of the crosslock, until eventually the crosslock will be released, have dependency with the crosslock.

Using crossrelease feature, we can detect deadlock possibility even for lock_page(), wait_for_complete() and so on.

---
 include/linux/irqflags.h |  12 +-
 include/linux/lockdep.h  | 122 +++++++++++
 include/linux/sched.h    |   5 +
 kernel/exit.c            |   9 +
 kernel/fork.c            |  20 ++
 kernel/locking/lockdep.c | 517 +++++++++++++++++++++++++++++++++++++++++++++--
 lib/Kconfig.debug        |  13 ++
 7 files changed, 682 insertions(+), 16 deletions(-)
include/linux/irqflags.h +10 -2
index 5dd1272..b1854fa 100644
@@ -23,9 +23,17 @@
 # define trace_softirq_context(p)	((p)->softirq_context)
 # define trace_hardirqs_enabled(p)	((p)->hardirqs_enabled)
 # define trace_softirqs_enabled(p)	((p)->softirqs_enabled)
-# define trace_hardirq_enter()	do { current->hardirq_context++; } while (0)
+# define trace_hardirq_enter()		\
+do {					\
+	current->hardirq_context++;	\
+	crossrelease_hardirq_start();	\
+} while (0)
 # define trace_hardirq_exit()	do { current->hardirq_context--; } while (0)
-# define lockdep_softirq_enter()	do { current->softirq_context++; } while (0)
+# define lockdep_softirq_enter()	\
+do {					\
+	current->softirq_context++;	\
+	crossrelease_softirq_start();	\
+} while (0)
 # define lockdep_softirq_exit()	do { current->softirq_context--; } while (0)
 # define INIT_TRACE_IRQFLAGS	.softirqs_enabled = 1,
 #else
include/linux/lockdep.h +122 -0

159 lines not on this page · raw message

include/linux/sched.h +5 -0
index 253538f..592ee368 100644
@@ -1719,6 +1719,11 @@ struct task_struct {
 	struct held_lock held_locks[MAX_LOCK_DEPTH];
 	gfp_t lockdep_reclaim_gfp;
 #endif
+#ifdef CONFIG_LOCKDEP_CROSSRELEASE
+#define MAX_PLOCKS_NR 1024UL
+	int plock_index;
+	struct pend_lock *plocks;
+#endif
 #ifdef CONFIG_UBSAN
 	unsigned int in_ubsan;
 #endif
kernel/exit.c +9 -0
index 9e6e135..9c69995 100644
@@ -54,6 +54,7 @@
 #include <linux/writeback.h>
 #include <linux/shm.h>
 #include <linux/kcov.h>
+#include <linux/vmalloc.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -822,6 +823,14 @@ void do_exit(long code)
 	smp_mb();
 	raw_spin_unlock_wait(&tsk->pi_lock);
 
+#ifdef CONFIG_LOCKDEP_CROSSRELEASE
+	if (tsk->plocks) {
+		void *tmp = tsk->plocks;
+		/* Disable crossrelease operation for current */
+		tsk->plocks = NULL;
+		vfree(tmp);
+	}
+#endif
 	/* causes final put_task_struct in finish_task_switch(). */
 	tsk->state = TASK_DEAD;
 	tsk->flags |= PF_NOFREEZE;	/* tell freezer to ignore us */
kernel/fork.c +20 -0
index 4a7ec0c..91ab81b 100644
@@ -323,6 +323,14 @@ void __init fork_init(void)
 	init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
 	init_task.signal->rlim[RLIMIT_SIGPENDING] =
 		init_task.signal->rlim[RLIMIT_NPROC];
+#ifdef CONFIG_LOCKDEP_CROSSRELEASE
+	/*
+	 * TODO: We need to make init_task also use crossrelease feature.
+	 * For simplicity, now just disable the feature for init_task.
+	 */
+	init_task.plock_index = 0;
+	init_task.plocks = NULL;
+#endif
 }
 
 int __weak arch_dup_task_struct(struct task_struct *dst,
@@ -1443,6 +1451,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	p->lockdep_depth = 0; /* no locks held yet */
 	p->curr_chain_key = 0;
 	p->lockdep_recursion = 0;
+#ifdef CONFIG_LOCKDEP_CROSSRELEASE
+	p->plock_index = 0;
+	p->plocks = vzalloc(sizeof(struct pend_lock) * MAX_PLOCKS_NR);
+#endif
 #endif
 
 #ifdef CONFIG_DEBUG_MUTEXES
@@ -1686,6 +1698,14 @@ bad_fork_cleanup_audit:
 bad_fork_cleanup_perf:
 	perf_event_free_task(p);
 bad_fork_cleanup_policy:
+#ifdef CONFIG_LOCKDEP_CROSSRELEASE
+	if (p->plocks) {
+		void *tmp = p->plocks;
+		/* Diable crossrelease operation for current */
+		p->plocks = NULL;
+		vfree(tmp);
+	}
+#endif
 #ifdef CONFIG_NUMA
 	mpol_put(p->mempolicy);
 bad_fork_cleanup_threadgroup_lock:
kernel/locking/lockdep.c +503 -14

579 lines not on this page · raw message

lib/Kconfig.debug +13 -0
index b9cfdbf..ef9ca8d 100644
@@ -1027,6 +1027,19 @@ config DEBUG_LOCK_ALLOC
 	 spin_lock_init()/mutex_init()/etc., or whether there is any lock
 	 held during task exit.
 
+config LOCKDEP_CROSSRELEASE
+	bool "Lock debugging: allow other context to unlock a lock"
+	depends on TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
+	select LOCKDEP
+	select TRACE_IRQFLAGS
+	default n
+	help
+	 This allows any context to unlock a lock held by another context.
+	 Normally a lock must be unlocked by the context holding the lock.
+	 However, relexing this constraint helps locks like (un)lock_page()
+	 or wait_for_complete() can use lock correctness detector using
+	 lockdep.
+
 config PROVE_LOCKING
 	bool "Lock debugging: prove locking correctness"
 	depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
Signature · 7 lines
1.9.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
maintainer
#15 lore raw
Quoted 8 lines · Byungchul Park

Crossrelease feature calls a lock 'crosslock' if it is releasable in any context. For crosslock, all locks having been held in the release context of the crosslock, until eventually the crosslock will be released, have dependency with the crosslock.

Using crossrelease feature, we can detect deadlock possibility even for lock_page(), wait_for_complete() and so on.

Completely inadequate.

Please explain how cross-release does what it does. Talk about lock graphs and such.

I do not have time to reverse engineer this stuff.

maintainer
#16 lore raw
Quoted 10 lines · Peter Zijlstra
Quoted 8 lines · Byungchul Park

Crossrelease feature calls a lock 'crosslock' if it is releasable in any context. For crosslock, all locks having been held in the release context of the crosslock, until eventually the crosslock will be released, have dependency with the crosslock.

Using crossrelease feature, we can detect deadlock possibility even for lock_page(), wait_for_complete() and so on.

Quoted 6 lines

Completely inadequate.

Please explain how cross-release does what it does. Talk about lock graphs and such.

I do not have time to reverse engineer this stuff.

Blergh, I'll do it anyway.. hold on for an email asking specific questions.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#17 lore raw
In reply to Peter Zijlstra
Quoted 6 lines · Peter Zijlstra
Quoted 5 lines · Byungchul Park

Crossrelease feature calls a lock 'crosslock' if it is releasable in any context. For crosslock, all locks having been held in the release context of the crosslock, until eventually the crosslock will be released, have dependency with the crosslock.

Quoted 8 lines
Quoted 3 lines

Using crossrelease feature, we can detect deadlock possibility even for lock_page(), wait_for_complete() and so on.

Completely inadequate.

Please explain how cross-release does what it does. Talk about lock graphs and such.

Hello,

Could you tell me about what you intend, in detail? I'm now asking you since I really don't know it.

The reason I reworked on documentation was to answer your requests like "explain mathematically", "tell how it works with graph" and so on. Should I do anything else? I really don't know it.

If I missed something, please let me know. Then I can do whatever you want if it's necessary.

Quoted 1 line

I do not have time to reverse engineer this stuff.

Why don't you read the document in the last patch first? The document is my answer for your requests you asked in version 1 thread. Insufficient?

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#18 lore raw
In reply to Byungchul Park

So the idea is to add support for non-owner serialization primitives, like completions/semaphores, and so far I've not looked at the code yet. I did spend 2+ hours trying to decipher your documentation thing, but am still confused, that thing is exceedingly hard to parse/read.

So the typical scenario would be something like:

L a L a
U a
W b C b

where L := lock, U := unlock, W := wait_for_completion and C := complete.

On the left, the blocking thread we can easily observe the 'b depends on a' relation, since we block while holding a.

On the right however that same relation is hard to see, since by the time we would run complete, a has already been released.

I _think_ you propose to keep track of all prior held locks and then use the union of the held list on the block-chain with the prior held list from the complete context.

The document describes you have a prior held list, and that its a circular thing, but it then completely fails to specify what gets added and how its used.

Also, by it being a circular list (of indeterminate, but finite size), there is the possibility of missing dependencies if they got spooled out by recent activity.

The document has an example in the section 'How cross release works' (the 3rd) that simply cannot be. It lists lock action _after_ acquire, but you place the acquire in wait_for_completion. We _block_ there.

Is this the general idea?

If so, I cannot see how something like:

W a W b
C b C a

would work, somewhere in that document it states that this would be handled by the existing dependencies, but I cannot see how. The blocking thread (either one) has no held context, therefore the previously mentioned union of held and prev-held is empty.

The alternative is not doing the union, but then you end up with endless pointless dependencies afaict.

On the whole 'release context' thing you want to cast lockdep in, please consider something like:

L a L b
L b L a
U a U a
U b U b

Note that the release order of locks is immaterial and can generate 'wrong' dependencies. Note how on both sides a is released under b, failing to observe the stil obvious AB-BA deadlock.

Note that lockdep doesn't model release or anything, it models blocked-on relations, like PI does.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#19 lore raw
Quoted 13 lines · Peter Zijlstra

So the idea is to add support for non-owner serialization primitives, like completions/semaphores, and so far I've not looked at the code yet. I did spend 2+ hours trying to decipher your documentation thing, but am still confused, that thing is exceedingly hard to parse/read.

So the typical scenario would be something like:

L a L a
U a
W b C b

Quoted 5 lines

where L := lock, U := unlock, W := wait_for_completion and C := complete.

On the left, the blocking thread we can easily observe the 'b depends on a' relation, since we block while holding a.

I think 'a depends on b' relation.

Why does b depend on a? b depends on a's what?

Quoted 1 line

On the right however that same relation is hard to see, since by the

Yes, there's no dependency on the right side of your example.

Quoted 1 line

time we would run complete, a has already been released.

I will change your example a little bit.

W b
~~~~~~~ <- serialized
L a
U a
C b

(Remind crossrelease considers dependencies in only case that lock sequence serialized is observable.)

There's a dependency in this case, like 'b depends on a' relation. 'C b' may not be hit, depending on the result of 'L a', that is, acquired or not.

Quoted 3 lines

I _think_ you propose to keep track of all prior held locks and then use the union of the held list on the block-chain with the prior held list from the complete context.

Almost right. Only thing we need to do to consider the union is to connect two chains of two contexts by adding one dependency 'b -> a'.

Quoted 3 lines

The document describes you have a prior held list, and that its a circular thing, but it then completely fails to specify what gets added and how its used.

Why does it fail? It keeps them in the form of hlock. This data is enough to generate dependencies.

Quoted 3 lines

Also, by it being a circular list (of indeterminate, but finite size), there is the possibility of missing dependencies if they got spooled out by recent activity.

Yes, right. They might be missed. It means just missing some chances to check a deadlock. It's all. Better than do nothing.

Furthermore, It just only needs 10~50 entries on qemu-i386 4core since it's optimized as far as possible so that it only considers essential ones instead of all the prior held list. The number of entries might need to be changed on a large system. It's future work.

Quoted 2 lines

The document has an example in the section 'How cross release works' (the 3rd) that simply cannot be. It lists lock action _after_ acquire,

Could you tell me more? Why cannot it be?

Quoted 8 lines

but you place the acquire in wait_for_completion. We _block_ there.

Is this the general idea?

If so, I cannot see how something like:

W a W b
C b C a

I didn't tell it works in this case. But it can be a future work. I'm not sure but I don't think making it work is impossible at all. But anyway current implementation cannot deal with this case.

Quoted 2 lines

would work, somewhere in that document it states that this would be handled by the existing dependencies, but I cannot see how. The blocking

Nowhere I mentioned it can be handled.

However it will work if we can identify and add 'a -> b' and 'b -> a' dependencies. It's fairly possible.

Quoted 2 lines

thread (either one) has no held context, therefore the previously mentioned union of held and prev-held is empty.

Right, in current implementation.

Quoted 2 lines

The alternative is not doing the union, but then you end up with endless pointless dependencies afaict.

That's a matter of whether or not we can identify additional dependencies. I proposed the way to find certain and additional dependencies which original lockdep missed. Of course there might be other dependencies which cannot be identified with current implementation. It must be a future work.

Quoted 10 lines

On the whole 'release context' thing you want to cast lockdep in, please consider something like:

L a     L b
L b     L a
U a     U a
U b     U b

Note that the release order of locks is immaterial and can generate 'wrong' dependencies. Note how on both sides a is released under b,

Who said the release order is important? Wrong for what?

Using the way crossrelease works, AB-BA deadlock of course can be detected, even though typical lock like 'a' and 'b' does not need to use crossrelease feature at all.

On left side,
L a : queue a
L b : queue b
U a : add 'a -> b' (consider only locks having been tried since L a was held.) U b : nop

On right side,
L b : queue b
L a : queue a
U a : nop
U b : add 'b -> a' (consider only locks having been tried since L b was held.)

AB-BA deadlock can be detected with dependencies 'a -> b' and 'b -> a'. Fairly true dependencies can be generated with this concept, and never fail to observe this kind of deadlock.

Quoted 4 lines

failing to observe the stil obvious AB-BA deadlock.

Note that lockdep doesn't model release or anything, it models blocked-on relations, like PI does.

As you said, current lockdep _implementation_ doesn't model it. There are 2 parts roughly in lockdep.

1. detect(identify) dependency
2. check dependencies in graph to detect deadlock

Precisely, The first part doesn't model it. I think it's good for optimized behavior. But it misses some dependencies.
So that's what I proposed to provide the chance to users between more perfect detector and optimized behavior.

I think the second part works perfectly at the moment.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#20 lore raw
Quoted 17 lines · Byungchul Park
Quoted 16 lines · Peter Zijlstra

So the idea is to add support for non-owner serialization primitives, like completions/semaphores, and so far I've not looked at the code yet. I did spend 2+ hours trying to decipher your documentation thing, but am still confused, that thing is exceedingly hard to parse/read.

So the typical scenario would be something like:

L a L a
U a
W b C b

where L := lock, U := unlock, W := wait_for_completion and C := complete.

Quoted 6 lines
Quoted 2 lines

On the left, the blocking thread we can easily observe the 'b depends on a' relation, since we block while holding a.

I think 'a depends on b' relation.

Why does b depend on a? b depends on a's what?

b blocks while holding a. In any case, for the graph it doesn't matter, its not a directed graph as such, all we care about is acyclic.

Quoted 3 lines
Quoted 1 line

On the right however that same relation is hard to see, since by the

Yes, there's no dependency on the right side of your example.

Well, there is, its just not trivially observable. We must be able to acquire a in order to complete b, therefore there is a dependency.

Quoted 4 lines
Quoted 1 line

time we would run complete, a has already been released.

I will change your example a little bit.

Quoted 8 lines

W b
~~~~~~~ <- serialized
L a
U a
C b

(Remind crossrelease considers dependencies in only case that lock sequence serialized is observable.)

What does that mean? Any why? This is a random point in time without actual meaning.

Quoted 3 lines

There's a dependency in this case, like 'b depends on a' relation. 'C b' may not be hit, depending on the result of 'L a', that is, acquired or not.

With or without a random reference point, the dependency is there.

Quoted 6 lines
Quoted 3 lines

I _think_ you propose to keep track of all prior held locks and then use the union of the held list on the block-chain with the prior held list from the complete context.

Almost right. Only thing we need to do to consider the union is to connect two chains of two contexts by adding one dependency 'b -> a'.

Sure, but how do you arrive at which connection to make. The document is entirely silent on this crucial point.

The union between the held-locks of the blocked and prev-held-locks of the release should give a fair indication I think, but then, I've not thought too hard on this yet.

Quoted 6 lines
Quoted 3 lines

The document describes you have a prior held list, and that its a circular thing, but it then completely fails to specify what gets added and how its used.

Why does it fail? It keeps them in the form of hlock. This data is enough to generate dependencies.

It fails to explain. It just barely mentions you keep them, it doesn't mention how they're used or why.

Quoted 6 lines
Quoted 3 lines

Also, by it being a circular list (of indeterminate, but finite size), there is the possibility of missing dependencies if they got spooled out by recent activity.

Yes, right. They might be missed. It means just missing some chances to check a deadlock. It's all. Better than do nothing.

Sure, but you didn't specify. Again, the document is very ambiguous and ill specified.

Quoted 4 lines
Quoted 2 lines

The document has an example in the section 'How cross release works' (the 3rd) that simply cannot be. It lists lock action _after_ acquire,

Could you tell me more? Why cannot it be?

Once you block you cannot take more locks, that simply doesnt make sense.

Quoted 4 lines
Quoted 4 lines

but you place the acquire in wait_for_completion. We _block_ there.

Is this the general idea?

Quoted 8 lines
Quoted 4 lines

If so, I cannot see how something like:

W a W b
C b C a

I didn't tell it works in this case. But it can be a future work. I'm not sure but I don't think making it work is impossible at all. But anyway current implementation cannot deal with this case.

+4. 'crosslock a -> crosslock b' dependency
+
+ Creating this kind of dependency directly is unnecessary since it can
+ be covered by other kinds of dependencies.

Says something different, doesn't it?

Quoted 8 lines
Quoted 8 lines

On the whole 'release context' thing you want to cast lockdep in, please consider something like:

L a     L b
L b     L a
U a     U a
U b     U b
Quoted 4 lines
Quoted 2 lines

Note that the release order of locks is immaterial and can generate 'wrong' dependencies. Note how on both sides a is released under b,

Who said the release order is important? Wrong for what?

Well, again, you mention 'release context' without actually specifying what you mean with that.

L a
L b
U b

and

L a
L b
U a

Here the unlocks obviously have different context. Without further specification its simply impossible to tell what you mean.

maintainer
#21 lore raw
Quoted 7 lines · Peter Zijlstra
Quoted 6 lines
Quoted 3 lines

I _think_ you propose to keep track of all prior held locks and then use the union of the held list on the block-chain with the prior held list from the complete context.

Almost right. Only thing we need to do to consider the union is to connect two chains of two contexts by adding one dependency 'b -> a'.

Quoted 6 lines

Sure, but how do you arrive at which connection to make. The document is entirely silent on this crucial point.

The union between the held-locks of the blocked and prev-held-locks of the release should give a fair indication I think, but then, I've not thought too hard on this yet.

s/union/intersection/

those that are in both sets.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#22 lore raw
Quoted 12 lines · Peter Zijlstra
Quoted 10 lines · Peter Zijlstra
Quoted 6 lines
Quoted 3 lines

I _think_ you propose to keep track of all prior held locks and then use the union of the held list on the block-chain with the prior held list from the complete context.

Almost right. Only thing we need to do to consider the union is to connect two chains of two contexts by adding one dependency 'b -> a'.

Sure, but how do you arrive at which connection to make. The document is entirely silent on this crucial point.

Quoted 7 lines
Quoted 3 lines

The union between the held-locks of the blocked and prev-held-locks of the release should give a fair indication I think, but then, I've not thought too hard on this yet.

s/union/intersection/

those that are in both sets.

Precisely speaking, I introduces separate chains.

For example,

1. Held-locks of the blocked,
A -> B -> C (which original lockdep builds)

2. Prev-held-locks of the release
G -> H -> I (which original lockdep builds, too)

3. Cross chain (which I introduced newly)
C -> G

Then the 'A -> B -> C -> G -> H -> I' can be traversed when bfs is performed.

Signature · 8 lines
Thanks,
Byungchul

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#23 lore raw
In reply to Peter Zijlstra
Quoted 21 lines · Peter Zijlstra
Quoted 20 lines · Byungchul Park
Quoted 18 lines · Peter Zijlstra

So the idea is to add support for non-owner serialization primitives, like completions/semaphores, and so far I've not looked at the code yet. I did spend 2+ hours trying to decipher your documentation thing, but am still confused, that thing is exceedingly hard to parse/read.

So the typical scenario would be something like:

L a L a
U a
W b C b

where L := lock, U := unlock, W := wait_for_completion and C := complete.

On the left, the blocking thread we can easily observe the 'b depends on a' relation, since we block while holding a.

Quoted 6 lines
Quoted 3 lines

I think 'a depends on b' relation.

Why does b depend on a? b depends on a's what?

b blocks while holding a. In any case, for the graph it doesn't matter, its not a directed graph as such, all we care about is acyclic.

It's a directed graph.The meaning of backward traverse is different from the meaning of forward traverse, isn't it?

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

On the right however that same relation is hard to see, since by the

Yes, there's no dependency on the right side of your example.

Well, there is, its just not trivially observable. We must be able to acquire a in order to complete b, therefore there is a dependency.

No. We cannot say there is a dependency unconditionally. There can be a dependency or not.

L a L a
U a
~~~~~~~~~ what if serialized by something?
W b C b

If something we don't recognize serializes locks, which ensures 'W b' happens after 'L a , U a' in the other context, then there's no dependency here.

We should say 'b depends on a' in only case that the sequence 'W b and then L a and then C b, where last two ops are in same context' _actually_ happened at least once. Otherwise, it might add a false dependency.

It's same as how original lockdep works with typical locks. It adds a dependency only when a lock is actually hit.

Quoted 10 lines
Quoted 10 lines
Quoted 1 line

time we would run complete, a has already been released.

I will change your example a little bit.

W b
~~~~~~~ <- serialized
L a
U a
C b

Quoted 5 lines
Quoted 2 lines

(Remind crossrelease considers dependencies in only case that lock sequence serialized is observable.)

What does that mean? Any why? This is a random point in time without actual meaning.

It's not random point. We have to consider meaningful sequences among those which are globally observable. That's why we need to serialize those locks. For example,

W b
L a
U a
C b

Once this sequence is observable globally, we can say 'It's possible to run in this sequence. Is this sequence problematic or not?'.

L a
U a
W b
C b

If only this sequence can be observable, we should not assume this sequence can be changed. However once the former sequence happens, it has a possibility to hit the same sequence again later. So we can check deadlock possibility with the sequence,

_not randomly_.

Quoted 5 lines
Quoted 3 lines

There's a dependency in this case, like 'b depends on a' relation. 'C b' may not be hit, depending on the result of 'L a', that is, acquired or not.

With or without a random reference point, the dependency is there.

The dependency might not be there.

Quoted 9 lines
Quoted 6 lines
Quoted 3 lines

I _think_ you propose to keep track of all prior held locks and then use the union of the held list on the block-chain with the prior held list from the complete context.

Almost right. Only thing we need to do to consider the union is to connect two chains of two contexts by adding one dependency 'b -> a'.

Sure, but how do you arrive at which connection to make. The document is entirely silent on this crucial point.

We need to connect between the crosslock and the first lock among locks having been acquired since the crosslock was held. Others will be connected each other by original lockdep.

By the way, does my document miss this description? If so, sorry. I will check and update it.

Quoted 3 lines

The union between the held-locks of the blocked and prev-held-locks of the release should give a fair indication I think, but then, I've not thought too hard on this yet.

I make the union only If actually the lock sequence happened once so that it's globally visible.

Quoted 9 lines
Quoted 6 lines
Quoted 3 lines

The document describes you have a prior held list, and that its a circular thing, but it then completely fails to specify what gets added and how its used.

Why does it fail? It keeps them in the form of hlock. This data is enough to generate dependencies.

It fails to explain. It just barely mentions you keep them, it doesn't mention how they're used or why.

Okay. I need to explain more about that.

Quoted 9 lines
Quoted 6 lines
Quoted 3 lines

Also, by it being a circular list (of indeterminate, but finite size), there is the possibility of missing dependencies if they got spooled out by recent activity.

Yes, right. They might be missed. It means just missing some chances to check a deadlock. It's all. Better than do nothing.

Sure, but you didn't specify. Again, the document is very ambiguous and ill specified.

Yes, I need to supplement the latter half as you said. I will do it.

Quoted 8 lines
Quoted 5 lines
Quoted 3 lines

The document has an example in the section 'How cross release works' (the 3rd) that simply cannot be. It lists lock action _after_ acquire,

Could you tell me more? Why cannot it be?

Once you block you cannot take more locks, that simply doesnt make sense.

No. Peter.. lockdep check possibilities. All lockdep operations are performed assuming this same sequence can happen again later but in a little bit different order between more than two contexts so that actual deadlock can happen then.

No doubt, it cannot take more locks while blocked at the time. But it's not important for lockdep to work.

Quoted 18 lines
Quoted 4 lines
Quoted 4 lines

but you place the acquire in wait_for_completion. We _block_ there.

Is this the general idea?

Quoted 8 lines
Quoted 4 lines

If so, I cannot see how something like:

W a W b
C b C a

I didn't tell it works in this case. But it can be a future work. I'm not sure but I don't think making it work is impossible at all. But anyway current implementation cannot deal with this case.

+4. 'crosslock a -> crosslock b' dependency

(quoted diff) +3 -0
+
+   Creating this kind of dependency directly is unnecessary since it can
+   be covered by other kinds of dependencies.
Quoted 1 line

Says something different, doesn't it?

Really sorry. I made you much confused. I will update it.

Quoted 20 lines
Quoted 8 lines
Quoted 8 lines

On the whole 'release context' thing you want to cast lockdep in, please consider something like:

L a     L b
L b     L a
U a     U a
U b     U b
Quoted 4 lines
Quoted 2 lines

Note that the release order of locks is immaterial and can generate 'wrong' dependencies. Note how on both sides a is released under b,

Who said the release order is important? Wrong for what?

Well, again, you mention 'release context' without actually specifying what you mean with that.

L a
L b
U b

Quoted 8 lines

and

L a
L b
U a

Here the unlocks obviously have different context. Without further specification its simply impossible to tell what you mean.

I mentioned what the release context means in the document. Or I don't understand what you are asking now.

Signature · 8 lines
Thanks,
Byungchul

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#24 lore raw
Quoted 161 lines · Byungchul Park
Quoted 21 lines · Peter Zijlstra
Quoted 20 lines · Byungchul Park
Quoted 18 lines · Peter Zijlstra

So the idea is to add support for non-owner serialization primitives, like completions/semaphores, and so far I've not looked at the code yet. I did spend 2+ hours trying to decipher your documentation thing, but am still confused, that thing is exceedingly hard to parse/read.

So the typical scenario would be something like:

L a L a
U a
W b C b

where L := lock, U := unlock, W := wait_for_completion and C := complete.

On the left, the blocking thread we can easily observe the 'b depends on a' relation, since we block while holding a.

Quoted 6 lines
Quoted 3 lines

I think 'a depends on b' relation.

Why does b depend on a? b depends on a's what?

b blocks while holding a. In any case, for the graph it doesn't matter, its not a directed graph as such, all we care about is acyclic.

It's a directed graph.The meaning of backward traverse is different from the meaning of forward traverse, isn't it?

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

On the right however that same relation is hard to see, since by the

Yes, there's no dependency on the right side of your example.

Well, there is, its just not trivially observable. We must be able to acquire a in order to complete b, therefore there is a dependency.

No. We cannot say there is a dependency unconditionally. There can be a dependency or not.

L a L a
U a
~~~~~~~~~ what if serialized by something?
W b C b

If something we don't recognize serializes locks, which ensures 'W b' happens after 'L a , U a' in the other context, then there's no dependency here.

We should say 'b depends on a' in only case that the sequence 'W b and then L a and then C b, where last two ops are in same context' _actually_ happened at least once. Otherwise, it might add a false dependency.

It's same as how original lockdep works with typical locks. It adds a dependency only when a lock is actually hit.

Quoted 10 lines
Quoted 10 lines
Quoted 1 line

time we would run complete, a has already been released.

I will change your example a little bit.

W b
~~~~~~~ <- serialized
L a
U a
C b

Quoted 5 lines
Quoted 2 lines

(Remind crossrelease considers dependencies in only case that lock sequence serialized is observable.)

What does that mean? Any why? This is a random point in time without actual meaning.

It's not random point. We have to consider meaningful sequences among those which are globally observable. That's why we need to serialize those locks. For example,

W b
L a
U a
C b

Once this sequence is observable globally, we can say 'It's possible to run in this sequence. Is this sequence problematic or not?'.

L a
U a
W b
C b

If only this sequence can be observable, we should not assume this sequence can be changed. However once the former sequence happens, it has a possibility to hit the same sequence again later. So we can check deadlock possibility with the sequence,

_not randomly_.

Quoted 5 lines
Quoted 3 lines

There's a dependency in this case, like 'b depends on a' relation. 'C b' may not be hit, depending on the result of 'L a', that is, acquired or not.

With or without a random reference point, the dependency is there.

The dependency might not be there.

Quoted 9 lines
Quoted 6 lines
Quoted 3 lines

I _think_ you propose to keep track of all prior held locks and then use the union of the held list on the block-chain with the prior held list from the complete context.

Almost right. Only thing we need to do to consider the union is to connect two chains of two contexts by adding one dependency 'b -> a'.

Sure, but how do you arrive at which connection to make. The document is entirely silent on this crucial point.

We need to connect between the crosslock and the first lock among locks having been acquired since the crosslock was held. Others will be connected each other by original lockdep.

By the way, does my document miss this description? If so, sorry. I will check and update it.

Quoted 3 lines

The union between the held-locks of the blocked and prev-held-locks of the release should give a fair indication I think, but then, I've not thought too hard on this yet.

I make the union only If actually the lock sequence happened once so that it's globally visible.

Quoted 9 lines
Quoted 6 lines
Quoted 3 lines

The document describes you have a prior held list, and that its a circular thing, but it then completely fails to specify what gets added and how its used.

Why does it fail? It keeps them in the form of hlock. This data is enough to generate dependencies.

It fails to explain. It just barely mentions you keep them, it doesn't mention how they're used or why.

Okay. I need to explain more about that.

Quoted 9 lines
Quoted 6 lines
Quoted 3 lines

Also, by it being a circular list (of indeterminate, but finite size), there is the possibility of missing dependencies if they got spooled out by recent activity.

Yes, right. They might be missed. It means just missing some chances to check a deadlock. It's all. Better than do nothing.

Sure, but you didn't specify. Again, the document is very ambiguous and ill specified.

Yes, I need to supplement the latter half as you said. I will do it.

Quoted 6 lines
Quoted 5 lines
Quoted 3 lines

The document has an example in the section 'How cross release works' (the 3rd) that simply cannot be. It lists lock action _after_ acquire,

Could you tell me more? Why cannot it be?

Quoted 7 lines
Quoted 2 lines

Once you block you cannot take more locks, that simply doesnt make sense.

No. Peter.. lockdep check possibilities. All lockdep operations are performed assuming this same sequence can happen again later but in a little bit different order between more than two contexts so that actual deadlock can happen then.

I can see what you are talking about. you are only talking about wait_for_completion. wait_for_completion is a case more complicated than lock_page. Could we talk about lock_page first if you don't mind? And then move to wait_for_complete next?

Anyway even in wait_complete, It's possible like,
(even though it's not much meaningful in case of wait_for_completion)

(Triger complete context to start)
acquire A
wait_for_completion A
acquire another (e.g. wait.lock)
release it
...
(actually sleep)

Not much meaningful in wait_for_completion, though it's not wrong. And this is much meaningful to another crosslock like lock_page. The target I'm mainly focusing is page lock.

Quoted 60 lines

No doubt, it cannot take more locks while blocked at the time. But it's not important for lockdep to work.

Quoted 18 lines
Quoted 4 lines
Quoted 4 lines

but you place the acquire in wait_for_completion. We _block_ there.

Is this the general idea?

Quoted 8 lines
Quoted 4 lines

If so, I cannot see how something like:

W a W b
C b C a

I didn't tell it works in this case. But it can be a future work. I'm not sure but I don't think making it work is impossible at all. But anyway current implementation cannot deal with this case.

+4. 'crosslock a -> crosslock b' dependency

(quoted diff) +3 -0
+
+   Creating this kind of dependency directly is unnecessary since it can
+   be covered by other kinds of dependencies.
Quoted 1 line

Says something different, doesn't it?

Really sorry. I made you much confused. I will update it.

Quoted 20 lines
Quoted 8 lines
Quoted 8 lines

On the whole 'release context' thing you want to cast lockdep in, please consider something like:

L a     L b
L b     L a
U a     U a
U b     U b
Quoted 4 lines
Quoted 2 lines

Note that the release order of locks is immaterial and can generate 'wrong' dependencies. Note how on both sides a is released under b,

Who said the release order is important? Wrong for what?

Well, again, you mention 'release context' without actually specifying what you mean with that.

L a
L b
U b

Quoted 8 lines

and

L a
L b
U a

Here the unlocks obviously have different context. Without further specification its simply impossible to tell what you mean.

I mentioned what the release context means in the document. Or I don't understand what you are asking now.

--
Thanks,
Byungchul

Signature · 8 lines
Thanks,
Byungchul

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
maintainer
#25 lore raw
In reply to Byungchul Park
Quoted 9 lines · Byungchul Park
Quoted 2 lines

Well, there is, its just not trivially observable. We must be able to acquire a in order to complete b, therefore there is a dependency.

No. We cannot say there is a dependency unconditionally. There can be a dependency or not.

L a L a
U a
~~~~~~~~~ what if serialized by something?

Well, there's no serialization in the example, so no what if.

Quoted 5 lines

W b C b

If something we don't recognize serializes locks, which ensures 'W b' happens after 'L a , U a' in the other context, then there's no dependency here.

Its not there.

Quoted 7 lines

We should say 'b depends on a' in only case that the sequence 'W b and then L a and then C b, where last two ops are in same context' _actually_ happened at least once. Otherwise, it might add a false dependency.

It's same as how original lockdep works with typical locks. It adds a dependency only when a lock is actually hit.

But since these threads are independently scheduled there is no point in transferring the point in time thread A does W to thread B. There is no relation there.

B could have already executed the complete or it could not yet have started execution at all or anything in between, entirely random.

Quoted 6 lines
Quoted 2 lines

What does that mean? Any why? This is a random point in time without actual meaning.

It's not random point. We have to consider meaningful sequences among those which are globally observable. That's why we need to serialize those locks.

Serialize how? there is no serialization.

Quoted 15 lines

For example,

W b
L a
U a
C b

Once this sequence is observable globally, we can say 'It's possible to run in this sequence. Is this sequence problematic or not?'.

L a
U a
W b
C b

Quoted 6 lines

If only this sequence can be observable, we should not assume this sequence can be changed. However once the former sequence happens, it has a possibility to hit the same sequence again later. So we can check deadlock possibility with the sequence,

_not randomly_.

I still don't get it.

Quoted 2 lines

We need to connect between the crosslock and the first lock among locks having been acquired since the crosslock was held.

Which can be _any_ lock in the history of that thread. It could be rq->lock from getting the thread scheduled.

Quoted 5 lines

Others will be
connected each other by original lockdep.

By the way, does my document miss this description? If so, sorry. I will check and update it.

I couldn't find anything useful, but then I could not understand most of what was written, and I tried hard :-(

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#26 lore raw
Quoted 4 lines · Peter Zijlstra
Quoted 3 lines · Byungchul Park
Quoted 2 lines

Well, there is, its just not trivially observable. We must be able to acquire a in order to complete b, therefore there is a dependency.

Quoted 8 lines
Quoted 6 lines

No. We cannot say there is a dependency unconditionally. There can be a dependency or not.

L a L a
U a
~~~~~~~~~ what if serialized by something?

Well, there's no serialization in the example, so no what if.

It was a korean traditional holliday for a week so I'm late.

I mean we cannot _ensure_ there's no serialization while lockdep works. In _the_ case you suggested, you'are right if only those code exists. But it's meaningless.

Quoted 16 lines
Quoted 5 lines

W b C b

If something we don't recognize serializes locks, which ensures 'W b' happens after 'L a , U a' in the other context, then there's no dependency here.

Its not there.

Quoted 7 lines

We should say 'b depends on a' in only case that the sequence 'W b and then L a and then C b, where last two ops are in same context' _actually_ happened at least once. Otherwise, it might add a false dependency.

It's same as how original lockdep works with typical locks. It adds a dependency only when a lock is actually hit.

Quoted 6 lines

But since these threads are independently scheduled there is no point in transferring the point in time thread A does W to thread B. There is no relation there.

B could have already executed the complete or it could not yet have started execution at all or anything in between, entirely random.

Of course B could have already executed the complete or it could not yet have started execution at all or anything in between. But it's not entirely random.

It might be a random point since they are independently scheduled, but it's not entirely random. And it's a random point among valid points which lockdep needs to consider. For example,

CONTEXT 1 CONTEXT 2(forked one)
========= =====================
(a) acquire F
acquire A acquire G
acquire B wait_for_completion Z
acquire C
(b) acquire H
fork 2 acquire I
acquire D acquire J
complete Z acquire K

I can provide countless examples with which I can say you're wrong. In this case, all acquires between (a) and (b) must be ignored when generating dependencies with complete operation of Z. It's never random.

Ideally, it would be of course the best to consider all points (not random points) after (b) which are valid points which lockdep needs to work with. But I think it's impossible to parse and identify all synchronizations and forks in kernel code, furthermore, new synchronization interface can be introduced in future.

So IMHO it would be the second best to consider random points among valid points, which anyway actually happened so it's guarrented that it has a depenency with Z.

It's similar to how lockdep works for typical lock e.g. spin lock. Current lockdep builds dependecy graph based on call paths which actually happened in each context, which might be different from each run. Even current lockdep doesn't parse all code and identify dependencies but works based on actual call paths in runtime which can be random but will eventually cover it almost (not perfect).

Quoted 8 lines
Quoted 6 lines
Quoted 2 lines

What does that mean? Any why? This is a random point in time without actual meaning.

It's not random point. We have to consider meaningful sequences among those which are globally observable. That's why we need to serialize those locks.

Serialize how? there is no serialization.

I mean I did it in my crossrelease implementation.

Quoted 23 lines
Quoted 16 lines

For example,

W b
L a
U a
C b

Once this sequence is observable globally, we can say 'It's possible to run in this sequence. Is this sequence problematic or not?'.

L a
U a
W b
C b

Quoted 6 lines

If only this sequence can be observable, we should not assume this sequence can be changed. However once the former sequence happens, it has a possibility to hit the same sequence again later. So we can check deadlock possibility with the sequence,

_not randomly_.

Quoted 7 lines

I still don't get it.

Quoted 2 lines

We need to connect between the crosslock and the first lock among locks having been acquired since the crosslock was held.

Which can be _any_ lock in the history of that thread. It could be rq->lock from getting the thread scheduled.

I think I already answered it. Right?

Quoted 9 lines
Quoted 6 lines

Others will be
connected each other by original lockdep.

By the way, does my document miss this description? If so, sorry. I will check and update it.

I couldn't find anything useful, but then I could not understand most of what was written, and I tried hard :-(

Thank you for trying it.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#27 lore raw
Quoted 16 lines · Byungchul Park
Quoted 6 lines

But since these threads are independently scheduled there is no point in transferring the point in time thread A does W to thread B. There is no relation there.

B could have already executed the complete or it could not yet have started execution at all or anything in between, entirely random.

Of course B could have already executed the complete or it could not yet have started execution at all or anything in between. But it's not entirely random.

It might be a random point since they are independently scheduled, but it's not entirely random. And it's a random point among valid points which lockdep needs to consider. For example,

Quoted 11 lines

CONTEXT 1 CONTEXT 2(forked one)
========= =====================
(a) acquire F
acquire A acquire G
acquire B wait_for_completion Z
acquire C
(b) acquire H
fork 2 acquire I
acquire D acquire J
complete Z acquire K

I'm hoping you left out the releases for brevity? Because calling fork() with locks held is _really_ poor form.

Quoted 3 lines

I can provide countless examples with which I can say you're wrong. In this case, all acquires between (a) and (b) must be ignored when generating dependencies with complete operation of Z.

I still don't get the point. Why does this matter?

Sure, A-C are irrelevant in this example, but I don't see how they're differently irrelevant from a whole bunch of other prior state action.

Earlier you said the algorithm for selecting the dependency is the first acquire observed in the completing thread after the wait_for_completion(). Is this correct?

				W z

	A a
	for (i<0;i<many;i++) {
	  A x[i]
	  R x[i]
	}
	R a

	<IRQ>
	  A b
	  R b
	  C z
	</IRQ>

That would be 'a' in this case, but that isn't at all related. Its just as irrelevant as your A-C. And we can pick @many as big as needed to flush the prev held cyclic buffer (although I've no idea how that matters either).

What we want here is to link z to b, no? That is the last, not the first acquire, it also is independent of when W happened.

At the same time, picking the last is no guarantee either, since that can equally miss dependencies. Suppose the IRQ handler did:

	<IRQ>
	  A c
	  R c
	  A b
	  R b
	  C z
	</IRQ>

instead. We'd miss the z depends on c relation, and since they're independent lock sections, lockdep wouldn't make a b-c relation either.

Clearly I'm still missing stuff...

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#28 lore raw
Quoted 30 lines · Peter Zijlstra
Quoted 16 lines · Byungchul Park
Quoted 6 lines

But since these threads are independently scheduled there is no point in transferring the point in time thread A does W to thread B. There is no relation there.

B could have already executed the complete or it could not yet have started execution at all or anything in between, entirely random.

Of course B could have already executed the complete or it could not yet have started execution at all or anything in between. But it's not entirely random.

It might be a random point since they are independently scheduled, but it's not entirely random. And it's a random point among valid points which lockdep needs to consider. For example,

Quoted 11 lines

CONTEXT 1 CONTEXT 2(forked one)
========= =====================
(a) acquire F
acquire A acquire G
acquire B wait_for_completion Z
acquire C
(b) acquire H
fork 2 acquire I
acquire D acquire J
complete Z acquire K

Quoted 2 lines

I'm hoping you left out the releases for brevity? Because calling fork() with locks held is _really_ poor form.

Exactly. Sorry. I shouldn't have omitted releases.

Quoted 7 lines
Quoted 4 lines

I can provide countless examples with which I can say you're wrong. In this case, all acquires between (a) and (b) must be ignored when generating dependencies with complete operation of Z.

I still don't get the point. Why does this matter?

Quoted 7 lines

Sure, A-C are irrelevant in this example, but I don't see how they're differently irrelevant from a whole bunch of other prior state action.

Earlier you said the algorithm for selecting the dependency is the first acquire observed in the completing thread after the wait_for_completion(). Is this correct?

Sorry for insufficient description.

held_locks of left context will be,

time 1: a
time 2: a, x[0]
time 3: a, x[1]
...
time n: b

Between time 1 and time (n-1), 'a' will be the first among held_locks. At time n, 'b' will be the fist among held_locks. So 'a' and 'b' should be connected to 'z' if we ignore IRQ context. (I will explain it soon.)

Acquire x[i] is also valid one but crossrelease doesn't take it into account since original lockdep will cover using 'a -> x[i]'. So only connections we need are 'z -> a' and 'z -> b'.

Quoted 16 lines

				W z

	A a
	for (i<0;i<many;i++) {
	  A x[i]
	  R x[i]
	}
	R a

	<IRQ>
	  A b
	  R b
	  C z
	</IRQ>

My crossrelease implementation distinguishes each IRQ from normal context or other IRQs in different timeline, even though they might share held_locks. So in this example, precisely speaking, there are two different contexts. One is normal context and the other is IRQ context. So only 'A b' is related with 'W z' in this example.

Quoted 5 lines

That would be 'a' in this case, but that isn't at all related. Its just as irrelevant as your A-C. And we can pick @many as big as needed to flush the prev held cyclic buffer (although I've no idea how that matters either).

I designed crossrelease so that x[i] is not added into ring buffer because adding 'z -> a' is sufficient and x[i] doesn't need to be taken into account in this case.

Quoted 2 lines

What we want here is to link z to b, no? That is the last, not the first

Exactly right. Only 'z -> b' must be added under considering IRQ context. That is the first among held_locks in the IRQ context.

Quoted 1 line

acquire, it also is independent of when W happened.

If the IRQ is really random, then it can happen before W z and it can also happen after W z. We cannot determine the time. Then we need to consider all combination and possibility. It's a key point. We have to consider dependencies for all possibility.

However, we don't know what synchronizes the flow. So it must be based on what actually happened, to identify true dependencies.

Quoted 4 lines

At the same time, picking the last is no guarantee either, since that can equally miss dependencies. Suppose the IRQ handler did:

Quoted 8 lines
	<IRQ>
	  A c
	  R c
	  A b
	  R b
	  C z
	</IRQ>

time 1: c (in held_locks)
time 2: b (in held_locks)

So 'c' and 'b' can be the first among held_locks at each moment. So 'z -> b' and 'z -> c' will be added.

Quoted 5 lines

instead. We'd miss the z depends on c relation, and since they're independent lock sections, lockdep wouldn't make a b-c relation either.

Clearly I'm still missing stuff...

Sorry for insufficient description. I tried to describ crossrelease in as much detail as possible, really.

The reason why I consider only the first among valid locks in held_locks is simple. For example,

Context 1
A a -> A b -> A crosslock -> R a -> R b

Context 2
A c -> A d -> R d -> R the crosslock -> R c

If 'A c' after 'A crosslock' is possible, then 'A crosslock' does not only depends on 'A c' but also 'A d'. But all dependencies we need to add is only 'crosslock -> c' because 'crosslock -> d' will be covered by 'crosslock -> c' and 'a -> b'. 'a -> b' is added by original lockdep.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#29 lore raw
Quoted 143 lines · Byungchul Park
Quoted 30 lines · Peter Zijlstra
Quoted 16 lines · Byungchul Park
Quoted 6 lines

But since these threads are independently scheduled there is no point in transferring the point in time thread A does W to thread B. There is no relation there.

B could have already executed the complete or it could not yet have started execution at all or anything in between, entirely random.

Of course B could have already executed the complete or it could not yet have started execution at all or anything in between. But it's not entirely random.

It might be a random point since they are independently scheduled, but it's not entirely random. And it's a random point among valid points which lockdep needs to consider. For example,

Quoted 11 lines

CONTEXT 1 CONTEXT 2(forked one)
========= =====================
(a) acquire F
acquire A acquire G
acquire B wait_for_completion Z
acquire C
(b) acquire H
fork 2 acquire I
acquire D acquire J
complete Z acquire K

Quoted 2 lines

I'm hoping you left out the releases for brevity? Because calling fork() with locks held is _really_ poor form.

Exactly. Sorry. I shouldn't have omitted releases.

Quoted 7 lines
Quoted 4 lines

I can provide countless examples with which I can say you're wrong. In this case, all acquires between (a) and (b) must be ignored when generating dependencies with complete operation of Z.

I still don't get the point. Why does this matter?

Quoted 7 lines

Sure, A-C are irrelevant in this example, but I don't see how they're differently irrelevant from a whole bunch of other prior state action.

Earlier you said the algorithm for selecting the dependency is the first acquire observed in the completing thread after the wait_for_completion(). Is this correct?

Sorry for insufficient description.

held_locks of left context will be,

time 1: a
time 2: a, x[0]
time 3: a, x[1]
...
time n: b

Between time 1 and time (n-1), 'a' will be the first among held_locks. At time n, 'b' will be the fist among held_locks. So 'a' and 'b' should be connected to 'z' if we ignore IRQ context. (I will explain it soon.)

Acquire x[i] is also valid one but crossrelease doesn't take it into account since original lockdep will cover using 'a -> x[i]'. So only connections we need are 'z -> a' and 'z -> b'.

Quoted 16 lines

				W z

	A a
	for (i<0;i<many;i++) {
	  A x[i]
	  R x[i]
	}
	R a

	<IRQ>
	  A b
	  R b
	  C z
	</IRQ>

My crossrelease implementation distinguishes each IRQ from normal context or other IRQs in different timeline, even though they might share held_locks. So in this example, precisely speaking, there are two different contexts. One is normal context and the other is IRQ context. So only 'A b' is related with 'W z' in this example.

Quoted 5 lines

That would be 'a' in this case, but that isn't at all related. Its just as irrelevant as your A-C. And we can pick @many as big as needed to flush the prev held cyclic buffer (although I've no idea how that matters either).

I designed crossrelease so that x[i] is not added into ring buffer because adding 'z -> a' is sufficient and x[i] doesn't need to be taken into account in this case.

Quoted 2 lines

What we want here is to link z to b, no? That is the last, not the first

Exactly right. Only 'z -> b' must be added under considering IRQ context. That is the first among held_locks in the IRQ context.

Quoted 1 line

acquire, it also is independent of when W happened.

If the IRQ is really random, then it can happen before W z and it can also happen after W z. We cannot determine the time. Then we need to consider all combination and possibility. It's a key point. We have to consider dependencies for all possibility.

However, we don't know what synchronizes the flow. So it must be based on what actually happened, to identify true dependencies.

Quoted 4 lines

At the same time, picking the last is no guarantee either, since that can equally miss dependencies. Suppose the IRQ handler did:

Quoted 8 lines
	<IRQ>
	  A c
	  R c
	  A b
	  R b
	  C z
	</IRQ>

time 1: c (in held_locks)
time 2: b (in held_locks)

So 'c' and 'b' can be the first among held_locks at each moment. So 'z -> b' and 'z -> c' will be added.

Quoted 5 lines

instead. We'd miss the z depends on c relation, and since they're independent lock sections, lockdep wouldn't make a b-c relation either.

Clearly I'm still missing stuff...

Quoted 8 lines

Sorry for insufficient description. I tried to describ crossrelease in as much detail as possible, really.

The reason why I consider only the first among valid locks in held_locks is simple. For example,

Context 1
A a -> A b -> A crosslock -> R a -> R b

Here, '->' represents the order executing A(cquire)s and R(elease)s.

_Not_ dependency.

Quoted 8 lines

Context 2
A c -> A d -> R d -> R the crosslock -> R c

If 'A c' after 'A crosslock' is possible, then 'A crosslock' does not only depends on 'A c' but also 'A d'. But all dependencies we need to add is only 'crosslock -> c' because 'crosslock -> d' will be covered by 'crosslock -> c' and 'a -> b'. 'a -> b' is added by original lockdep.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#30 lore raw
In reply to Byungchul Park
Quoted 61 lines · Byungchul Park
Quoted 30 lines · Peter Zijlstra
Quoted 16 lines · Byungchul Park
Quoted 6 lines

But since these threads are independently scheduled there is no point in transferring the point in time thread A does W to thread B. There is no relation there.

B could have already executed the complete or it could not yet have started execution at all or anything in between, entirely random.

Of course B could have already executed the complete or it could not yet have started execution at all or anything in between. But it's not entirely random.

It might be a random point since they are independently scheduled, but it's not entirely random. And it's a random point among valid points which lockdep needs to consider. For example,

Quoted 11 lines

CONTEXT 1 CONTEXT 2(forked one)
========= =====================
(a) acquire F
acquire A acquire G
acquire B wait_for_completion Z
acquire C
(b) acquire H
fork 2 acquire I
acquire D acquire J
complete Z acquire K

Quoted 2 lines

I'm hoping you left out the releases for brevity? Because calling fork() with locks held is _really_ poor form.

Exactly. Sorry. I shouldn't have omitted releases.

Quoted 7 lines
Quoted 4 lines

I can provide countless examples with which I can say you're wrong. In this case, all acquires between (a) and (b) must be ignored when generating dependencies with complete operation of Z.

I still don't get the point. Why does this matter?

Quoted 7 lines

Sure, A-C are irrelevant in this example, but I don't see how they're differently irrelevant from a whole bunch of other prior state action.

Earlier you said the algorithm for selecting the dependency is the first acquire observed in the completing thread after the wait_for_completion(). Is this correct?

Sorry for insufficient description.

held_locks of left context will be,

time 1: a
time 2: a, x[0]
time 3: a, x[1]
...
time n: b

Quoted 6 lines

Between time 1 and time (n-1), 'a' will be the first among held_locks. At time n, 'b' will be the fist among held_locks. So 'a' and 'b' should be connected to 'z' if we ignore IRQ context. (I will explain it soon.)

Acquire x[i] is also valid one but crossrelease doesn't take it into account since original lockdep will cover using 'a -> x[i]'. So only

... since lockdep will cover 'z -> x[i]' using 'z -> a' and 'a -> x[i]' ...

Quoted 41 lines

connections we need are 'z -> a' and 'z -> b'.

Quoted 16 lines

				W z

	A a
	for (i<0;i<many;i++) {
	  A x[i]
	  R x[i]
	}
	R a

	<IRQ>
	  A b
	  R b
	  C z
	</IRQ>

My crossrelease implementation distinguishes each IRQ from normal context or other IRQs in different timeline, even though they might share held_locks. So in this example, precisely speaking, there are two different contexts. One is normal context and the other is IRQ context. So only 'A b' is related with 'W z' in this example.

Quoted 5 lines

That would be 'a' in this case, but that isn't at all related. Its just as irrelevant as your A-C. And we can pick @many as big as needed to flush the prev held cyclic buffer (although I've no idea how that matters either).

I designed crossrelease so that x[i] is not added into ring buffer because adding 'z -> a' is sufficient and x[i] doesn't need to be taken into account in this case.

Quoted 2 lines

What we want here is to link z to b, no? That is the last, not the first

Exactly right. Only 'z -> b' must be added under considering IRQ context. That is the first among held_locks in the IRQ context.

Quoted 6 lines
Quoted 1 line

acquire, it also is independent of when W happened.

If the IRQ is really random, then it can happen before W z and it can also happen after W z. We cannot determine the time. Then we need to consider all combination and possibility. It's a key point. We have to consider dependencies for all possibility.

possibilities.

Quoted 2 lines

However, we don't know what synchronizes the flow. So it must be based on

                   ^^^
                 generally
Quoted 15 lines

what actually happened, to identify true dependencies.

Quoted 4 lines

At the same time, picking the last is no guarantee either, since that can equally miss dependencies. Suppose the IRQ handler did:

Quoted 8 lines
	<IRQ>
	  A c
	  R c
	  A b
	  R b
	  C z
	</IRQ>
Quoted 4 lines

time 1: c (in held_locks)
time 2: b (in held_locks)

So 'c' and 'b' can be the first among held_locks at each moment.

                 ^^^^^^
                   are
Quoted 8 lines

So 'z -> b' and 'z -> c' will be added.

Quoted 5 lines

instead. We'd miss the z depends on c relation, and since they're independent lock sections, lockdep wouldn't make a b-c relation either.

Clearly I'm still missing stuff...

Quoted 8 lines

Sorry for insufficient description. I tried to describ crossrelease in as much detail as possible, really.

The reason why I consider only the first among valid locks in held_locks is simple. For example,

Context 1
A a -> A b -> A crosslock -> R a -> R b

I meant,

Context 1
=========
A a
A b
A crosslock
R a
R b

Quoted 3 lines

Context 2
A c -> A d -> R d -> R the crosslock -> R c

Context 2
=========
A c
A d
R d
R the crosslock
R c

Quoted 5 lines

If 'A c' after 'A crosslock' is possible, then 'A crosslock' does not only depends on 'A c' but also 'A d'. But all dependencies we need to add is only 'crosslock -> c' because 'crosslock -> d' will be covered by 'crosslock -> c' and 'a -> b'. Here, 'a -> b' is added by original lockdep.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#31 lore raw
In reply to Peter Zijlstra
Quoted 1 line · Peter Zijlstra

Clearly I'm still missing stuff...

By the way.. do I have to explain more? Lack of explanation?

It would be the best to consider 'all valid acquires', which can occur deadlock, but it looks impossible without parsing all code in head.

So it would be the safest to rely on 'acquires which actually happened', even though it might be 'random acquires' among all valid acquires.

This conservative appoach is exactly same as how original lockdep is doing. Let me explain more if you doubt it.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#32 lore raw

PATCH v3 8/15 lockdep: Make crossrelease use save_stack_trace_fast()

In reply to Byungchul Park

Currently crossrelease feature uses save_stack_trace() to save backtrace. However, it has much overhead. So this patch makes it use save_stack_trace_norm() instead, which has smaller overhead.

---
 kernel/locking/lockdep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/locking/lockdep.c +1 -1
index 2c8b2c1..fbd07ee 100644
@@ -4768,7 +4768,7 @@ static void add_plock(struct held_lock *hlock, unsigned int prev_gen_id,
 		plock->trace.max_entries = MAX_PLOCK_TRACE_ENTRIES;
 		plock->trace.entries = plock->trace_entries;
 		plock->trace.skip = 3;
-		save_stack_trace(&plock->trace);
+		save_stack_trace_fast(&plock->trace);
 	}
 }
 
Signature · 7 lines
1.9.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#33 lore raw

PATCH v3 9/15 lockdep: Make print_circular_bug() crosslock-aware

In reply to Byungchul Park

Friends of print_circular_bug() reporting circular bug assumes that target hlock is owned by the current. However, in crossrelease feature, target hlock can be owned by any context.

In this case, the circular bug is caused by target hlock which cannot be released since its dependent lock cannot be released. So the report format needs to be changed to be aware of this.

---
 kernel/locking/lockdep.c | 56 +++++++++++++++++++++++++++++++++---------------
 1 file changed, 39 insertions(+), 17 deletions(-)
kernel/locking/lockdep.c +39 -17
index fbd07ee..cb1a600 100644
@@ -1126,22 +1126,41 @@ print_circular_lock_scenario(struct held_lock *src,
 		printk("\n\n");
 	}
 
-	printk(" Possible unsafe locking scenario:\n\n");
-	printk("       CPU0                    CPU1\n");
-	printk("       ----                    ----\n");
-	printk("  lock(");
-	__print_lock_name(target);
-	printk(");\n");
-	printk("                               lock(");
-	__print_lock_name(parent);
-	printk(");\n");
-	printk("                               lock(");
-	__print_lock_name(target);
-	printk(");\n");
-	printk("  lock(");
-	__print_lock_name(source);
-	printk(");\n");
-	printk("\n *** DEADLOCK ***\n\n");
+	if (cross_class(target)) {
+		printk(" Possible unsafe locking scenario by crosslock:\n\n");
+		printk("       CPU0                    CPU1\n");
+		printk("       ----                    ----\n");
+		printk("  lock(");
+		__print_lock_name(parent);
+		printk(");\n");
+		printk("  lock(");
+		__print_lock_name(target);
+		printk(");\n");
+		printk("                               lock(");
+		__print_lock_name(source);
+		printk(");\n");
+		printk("                               unlock(");
+		__print_lock_name(target);
+		printk(");\n");
+		printk("\n *** DEADLOCK ***\n\n");
+	} else {
+		printk(" Possible unsafe locking scenario:\n\n");
+		printk("       CPU0                    CPU1\n");
+		printk("       ----                    ----\n");
+		printk("  lock(");
+		__print_lock_name(target);
+		printk(");\n");
+		printk("                               lock(");
+		__print_lock_name(parent);
+		printk(");\n");
+		printk("                               lock(");
+		__print_lock_name(target);
+		printk(");\n");
+		printk("  lock(");
+		__print_lock_name(source);
+		printk(");\n");
+		printk("\n *** DEADLOCK ***\n\n");
+	}
 }
 
 /*
@@ -1166,7 +1185,10 @@ print_circular_bug_header(struct lock_list *entry, unsigned int depth,
 	printk("%s/%d is trying to acquire lock:\n",
 		curr->comm, task_pid_nr(curr));
 	print_lock(check_src);
-	printk("\nbut task is already holding lock:\n");
+	if (cross_class(hlock_class(check_tgt)))
+		printk("\nbut now in the release context of lock:\n");
+	else
+		printk("\nbut task is already holding lock:\n");
 	print_lock(check_tgt);
 	printk("\nwhich lock already depends on the new lock.\n\n");
 	printk("\nthe existing dependency chain (in reverse order) is:\n");
Signature · 7 lines
1.9.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#34 lore raw

PATCH v3 10/15 lockdep: Apply crossrelease to completion operation

In reply to Byungchul Park

wait_for_completion() and its family can cause deadlock. Nevertheless, it cannot use the lock correntness validator because complete() will be called in different context from the context calling wait_for_completion(), which violates lockdep's assumption without crossrelease feature.

However, thanks to CONFIG_LOCKDEP_CROSSRELEASE, we can apply the lockdep detector to wait_for_completion() and complete(). Applied it.

---
 include/linux/completion.h | 121 +++++++++++++++++++++++++++++++++++++++++----
 kernel/locking/lockdep.c   |  17 +++++++
 kernel/sched/completion.c  |  54 +++++++++++---------
 lib/Kconfig.debug          |   8 +++
 4 files changed, 167 insertions(+), 33 deletions(-)
include/linux/completion.h +112 -9
index 5d5aaae..67a27af 100644
@@ -9,6 +9,9 @@
  */
 
 #include <linux/wait.h>
+#ifdef CONFIG_LOCKDEP_COMPLETE
+#include <linux/lockdep.h>
+#endif
 
 /*
  * struct completion - structure used to maintain state for a "completion"
@@ -25,10 +28,53 @@
 struct completion {
 	unsigned int done;
 	wait_queue_head_t wait;
+#ifdef CONFIG_LOCKDEP_COMPLETE
+	struct lockdep_map map;
+	struct cross_lock xlock;
+#endif
 };
 
+#ifdef CONFIG_LOCKDEP_COMPLETE
+static inline void complete_acquire(struct completion *x)
+{
+	lock_acquire_exclusive(&x->map, 0, 0, NULL, _RET_IP_);
+}
+
+static inline void complete_release(struct completion *x)
+{
+	lock_release(&x->map, 0, _RET_IP_);
+}
+
+static inline void complete_release_commit(struct completion *x)
+{
+	lock_commit_crosslock(&x->map);
+}
+
+#define init_completion(x)				\
+do {							\
+	static struct lock_class_key __key;		\
+	lockdep_init_map_crosslock(&(x)->map,		\
+			&(x)->xlock,			\
+			"(complete)" #x,		\
+			&__key, 0);			\
+	__init_completion(x);				\
+} while (0)
+#else
+#define init_completion(x) __init_completion(x)
+static inline void complete_acquire(struct completion *x, int try) {}
+static inline void complete_release(struct completion *x) {}
+static inline void complete_release_commit(struct completion *x) {}
+#endif
+
+#ifdef CONFIG_LOCKDEP_COMPLETE
+#define COMPLETION_INITIALIZER(work) \
+	{ 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait), \
+	STATIC_CROSS_LOCKDEP_MAP_INIT("(complete)" #work, &(work), \
+	&(work).xlock), STATIC_CROSS_LOCK_INIT()}
+#else
 #define COMPLETION_INITIALIZER(work) \
 	{ 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) }
+#endif
 
 #define COMPLETION_INITIALIZER_ONSTACK(work) \
 	({ init_completion(&work); work; })
@@ -70,7 +116,7 @@ struct completion {
  * This inline function will initialize a dynamically created completion
  * structure.
  */
-static inline void init_completion(struct completion *x)
+static inline void __init_completion(struct completion *x)
 {
 	x->done = 0;
 	init_waitqueue_head(&x->wait);
@@ -88,18 +134,75 @@ static inline void reinit_completion(struct completion *x)
 	x->done = 0;
 }
 
-extern void wait_for_completion(struct completion *);
-extern void wait_for_completion_io(struct completion *);
-extern int wait_for_completion_interruptible(struct completion *x);
-extern int wait_for_completion_killable(struct completion *x);
-extern unsigned long wait_for_completion_timeout(struct completion *x,
+extern void __wait_for_completion(struct completion *);
+extern void __wait_for_completion_io(struct completion *);
+extern int __wait_for_completion_interruptible(struct completion *x);
+extern int __wait_for_completion_killable(struct completion *x);
+extern unsigned long __wait_for_completion_timeout(struct completion *x,
 						   unsigned long timeout);
-extern unsigned long wait_for_completion_io_timeout(struct completion *x,
+extern unsigned long __wait_for_completion_io_timeout(struct completion *x,
 						    unsigned long timeout);
-extern long wait_for_completion_interruptible_timeout(
+extern long __wait_for_completion_interruptible_timeout(
 	struct completion *x, unsigned long timeout);
-extern long wait_for_completion_killable_timeout(
+extern long __wait_for_completion_killable_timeout(
 	struct completion *x, unsigned long timeout);
+
+static inline void wait_for_completion(struct completion *x)
+{
+	complete_acquire(x);
+	__wait_for_completion(x);
+	complete_release(x);
+}
+
+static inline void wait_for_completion_io(struct completion *x)
+{
+	complete_acquire(x);
+	__wait_for_completion_io(x);
+	complete_release(x);
+}
+
+static inline int wait_for_completion_interruptible(struct completion *x)
+{
+	int ret;
+	complete_acquire(x);
+	ret = __wait_for_completion_interruptible(x);
+	complete_release(x);
+	return ret;
+}
+
+static inline int wait_for_completion_killable(struct completion *x)
+{
+	int ret;
+	complete_acquire(x);
+	ret = __wait_for_completion_killable(x);
+	complete_release(x);
+	return ret;
+}
+
+static inline unsigned long wait_for_completion_timeout(struct completion *x,
+		unsigned long timeout)
+{
+	return __wait_for_completion_timeout(x, timeout);
+}
+
+static inline unsigned long wait_for_completion_io_timeout(struct completion *x,
+		unsigned long timeout)
+{
+	return __wait_for_completion_io_timeout(x, timeout);
+}
+
+static inline long wait_for_completion_interruptible_timeout(
+	struct completion *x, unsigned long timeout)
+{
+	return __wait_for_completion_interruptible_timeout(x, timeout);
+}
+
+static inline long wait_for_completion_killable_timeout(
+	struct completion *x, unsigned long timeout)
+{
+	return __wait_for_completion_killable_timeout(x, timeout);
+}
+
 extern bool try_wait_for_completion(struct completion *x);
 extern bool completion_done(struct completion *x);
 
kernel/locking/lockdep.c +17 -0
index cb1a600..fea69ac 100644
@@ -4794,6 +4794,12 @@ static void add_plock(struct held_lock *hlock, unsigned int prev_gen_id,
 	}
 }
 
+#ifdef CONFIG_LOCKDEP_COMPLETE
+static int xlock_might_onstack = 1;
+#else
+static int xlock_might_onstack = 0;
+#endif
+
 /*
  * No contention. Irq disable is only required.
  */
@@ -4839,6 +4845,14 @@ static void check_add_plock(struct held_lock *hlock)
 	if (!current->plocks || !depend_before(hlock))
 		return;
 
+	/*
+	 * If a xlock instance is on stack, it can be overwritten randomly
+	 * after escaping the stack frame, so we cannot refer to rcu list
+	 * without holding lock.
+	 */
+	if (xlock_might_onstack && !graph_lock())
+		return;
+
 	gen_id = (unsigned int)atomic_read(&cross_gen_id);
 	gen_id_e = gen_id_done();
 	start = current->held_locks;
@@ -4862,6 +4876,9 @@ static void check_add_plock(struct held_lock *hlock)
 			break;
 		}
 	}
+
+	if (xlock_might_onstack)
+		graph_unlock();
 }
 
 /*
kernel/sched/completion.c +30 -24

160 lines not on this page · raw message

lib/Kconfig.debug +8 -0
index ef9ca8d..3466e57 100644
@@ -1040,6 +1040,14 @@ config LOCKDEP_CROSSRELEASE
 	 or wait_for_complete() can use lock correctness detector using
 	 lockdep.
 
+config LOCKDEP_COMPLETE
+	bool "Lock debugging: allow completions to use deadlock detector"
+	select LOCKDEP_CROSSRELEASE
+	default n
+	help
+	 A deadlock caused by wait_for_completion() and complete() can be
+	 detected by lockdep using crossrelease feature.
+
 config PROVE_LOCKING
 	bool "Lock debugging: prove locking correctness"
 	depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
Signature · 1 line
1.9.1
#35 lore raw

PATCH v3 11/15 pagemap.h: Remove trailing white space

In reply to Byungchul Park

Trailing white space is not accepted in kernel coding style. Remove them.

---
 include/linux/pagemap.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
include/linux/pagemap.h +2 -2
index 9735410..0cf6980 100644
@@ -485,7 +485,7 @@ static inline void wake_up_page(struct page *page, int bit)
 	__wake_up_bit(page_waitqueue(page), &page->flags, bit);
 }
 
-/* 
+/*
  * Wait for a page to be unlocked.
  *
  * This must be called with the caller "holding" the page,
@@ -498,7 +498,7 @@ static inline void wait_on_page_locked(struct page *page)
 		wait_on_page_bit(compound_head(page), PG_locked);
 }
 
-/* 
+/*
  * Wait for a page to complete writeback
  */
 static inline void wait_on_page_writeback(struct page *page)
Signature · 7 lines
1.9.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#36 lore raw

PATCH v3 12/15 lockdep: Apply crossrelease to PG_locked lock

In reply to Byungchul Park

lock_page() and its family can cause deadlock. Nevertheless, it cannot use the lock correctness validator becasue unlock_page() can be called in different context from the context calling lock_page(), which violates lockdep's assumption without crossrelease feature.

However, thanks to CONFIG_LOCKDEP_CROSSRELEASE, we can apply the lockdep detector to lock_page(). Applied it.

---
 include/linux/mm_types.h |   9 +++++
 include/linux/pagemap.h  | 100 ++++++++++++++++++++++++++++++++++++++++++++---
 lib/Kconfig.debug        |   8 ++++
 mm/filemap.c             |   4 +-
 mm/page_alloc.c          |   3 ++
 5 files changed, 116 insertions(+), 8 deletions(-)
include/linux/mm_types.h +9 -0
index ca3e517..87db0ac 100644
@@ -16,6 +16,10 @@
 #include <asm/page.h>
 #include <asm/mmu.h>
 
+#ifdef CONFIG_LOCKDEP_PAGELOCK
+#include <linux/lockdep.h>
+#endif
+
 #ifndef AT_VECTOR_SIZE_ARCH
 #define AT_VECTOR_SIZE_ARCH 0
 #endif
@@ -220,6 +224,11 @@ struct page {
 #ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
 	int _last_cpupid;
 #endif
+
+#ifdef CONFIG_LOCKDEP_PAGELOCK
+	struct lockdep_map map;
+	struct cross_lock xlock;
+#endif
 }
 /*
  * The struct page can be forced to be double word aligned so that atomic ops
include/linux/pagemap.h +94 -6

142 lines not on this page · raw message

lib/Kconfig.debug +8 -0
index 3466e57..1926435 100644
@@ -1048,6 +1048,14 @@ config LOCKDEP_COMPLETE
 	 A deadlock caused by wait_for_completion() and complete() can be
 	 detected by lockdep using crossrelease feature.
 
+config LOCKDEP_PAGELOCK
+	bool "Lock debugging: allow PG_locked lock to use deadlock detector"
+	select LOCKDEP_CROSSRELEASE
+	default n
+	help
+	 PG_locked lock is a kind of crosslock. Using crossrelease feature,
+	 PG_locked lock can participate in deadlock detector.
+
 config PROVE_LOCKING
 	bool "Lock debugging: prove locking correctness"
 	depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
mm/filemap.c +2 -2
index 20f3b1f..e1f60fd 100644
@@ -827,7 +827,7 @@ EXPORT_SYMBOL_GPL(add_page_wait_queue);
  * The mb is necessary to enforce ordering between the clear_bit and the read
  * of the waitqueue (to avoid SMP races with a parallel wait_on_page_locked()).
  */
-void unlock_page(struct page *page)
+void do_raw_unlock_page(struct page *page)
 {
 	page = compound_head(page);
 	VM_BUG_ON_PAGE(!PageLocked(page), page);
@@ -835,7 +835,7 @@ void unlock_page(struct page *page)
 	smp_mb__after_atomic();
 	wake_up_page(page, PG_locked);
 }
-EXPORT_SYMBOL(unlock_page);
+EXPORT_SYMBOL(do_raw_unlock_page);
 
 /**
  * end_page_writeback - end writeback against a page
mm/page_alloc.c +3 -0
index 8b3e134..0adc46c 100644
@@ -5225,6 +5225,9 @@ not_early:
 		} else {
 			__init_single_pfn(pfn, zone, nid);
 		}
+#ifdef CONFIG_LOCKDEP_PAGELOCK
+		lock_page_init(pfn_to_page(pfn));
+#endif
 	}
 }
 
Signature · 7 lines
1.9.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#37 lore raw

PATCH v3 13/15 lockdep: Apply lock_acquire(release) on __Set(__Clear)PageLocked

In reply to Byungchul Park

Usually PG_locked bit is updated by lock_page() or unlock_page(). However, it can be also updated through __SetPageLocked() or __ClearPageLockded(). They have to be considered, to get paired between acquire and release.

Furthermore, e.g. __SetPageLocked() in add_to_page_cache_lru() is called frequently. We might miss many chances to check deadlock if we ignore it. Consider __Set(__Clear)PageLockded as well.

---
 include/linux/page-flags.h | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)
include/linux/page-flags.h +29 -1
index e5a3244..e28f232 100644
@@ -249,7 +249,6 @@ static inline int TestClearPage##uname(struct page *page) { return 0; }
 #define TESTSCFLAG_FALSE(uname)						\
 	TESTSETFLAG_FALSE(uname) TESTCLEARFLAG_FALSE(uname)
 
-__PAGEFLAG(Locked, locked, PF_NO_TAIL)
 PAGEFLAG(Error, error, PF_NO_COMPOUND) TESTCLEARFLAG(Error, error, PF_NO_COMPOUND)
 PAGEFLAG(Referenced, referenced, PF_HEAD)
 	TESTCLEARFLAG(Referenced, referenced, PF_HEAD)
@@ -351,6 +350,35 @@ TESTCLEARFLAG(Young, young, PF_ANY)
 PAGEFLAG(Idle, idle, PF_ANY)
 #endif
 
+#ifdef CONFIG_LOCKDEP_PAGELOCK
+#include <linux/lockdep.h>
+
+TESTPAGEFLAG(Locked, locked, PF_NO_TAIL)
+
+static __always_inline void __SetPageLocked(struct page *page)
+{
+	__set_bit(PG_locked, &PF_NO_TAIL(page, 1)->flags);
+
+	page = compound_head(page);
+	lock_acquire_exclusive(&page->map, 0, 1, NULL, _RET_IP_);
+}
+
+static __always_inline void __ClearPageLocked(struct page *page)
+{
+	__clear_bit(PG_locked, &PF_NO_TAIL(page, 1)->flags);
+
+	page = compound_head(page);
+	/*
+	 * lock_commit_crosslock() is necessary for crosslock
+	 * when the lock is released, before lock_release().
+	 */
+	lock_commit_crosslock(&page->map);
+	lock_release(&page->map, 0, _RET_IP_);
+}
+#else
+__PAGEFLAG(Locked, locked, PF_NO_TAIL)
+#endif
+
 /*
  * On an anonymous page mapped into a user virtual memory area,
  * page->mapping points to its anon_vma, not to a struct address_space;
Signature · 1 line
1.9.1
#38 lore raw

PATCH v3 14/15 lockdep: Move data used in CONFIG_LOCKDEP_PAGELOCK from page to page_ext

In reply to Byungchul Park

CONFIG_LOCKDEP_PAGELOCK is keeping data, with which lockdep can check and detect deadlock by page lock, e.g. lockdep_map and cross_lock in struct page. But move it to page_ext since it's a debug feature so it's preferred to keep it in struct page_ext than struct page.

---
 include/linux/mm_types.h   |  5 ----
 include/linux/page-flags.h | 19 ++++++++++--
 include/linux/page_ext.h   |  5 ++++
 include/linux/pagemap.h    | 28 +++++++++++++++---
 lib/Kconfig.debug          |  1 +
 mm/filemap.c               | 72 ++++++++++++++++++++++++++++++++++++++++++++++
 mm/page_alloc.c            |  3 --
 mm/page_ext.c              |  4 +++
 8 files changed, 122 insertions(+), 15 deletions(-)
include/linux/mm_types.h +0 -5
index 87db0ac..6558e12 100644
@@ -224,11 +224,6 @@ struct page {
 #ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
 	int _last_cpupid;
 #endif
-
-#ifdef CONFIG_LOCKDEP_PAGELOCK
-	struct lockdep_map map;
-	struct cross_lock xlock;
-#endif
 }
 /*
  * The struct page can be forced to be double word aligned so that atomic ops
include/linux/page-flags.h +16 -3
index e28f232..9f677ff 100644
@@ -352,28 +352,41 @@ PAGEFLAG(Idle, idle, PF_ANY)
 
 #ifdef CONFIG_LOCKDEP_PAGELOCK
 #include <linux/lockdep.h>
+#include <linux/page_ext.h>
 
 TESTPAGEFLAG(Locked, locked, PF_NO_TAIL)
 
 static __always_inline void __SetPageLocked(struct page *page)
 {
+	struct page_ext *e;
+
 	__set_bit(PG_locked, &PF_NO_TAIL(page, 1)->flags);
 
 	page = compound_head(page);
-	lock_acquire_exclusive(&page->map, 0, 1, NULL, _RET_IP_);
+	e = lookup_page_ext(page);
+	if (unlikely(!e))
+		return;
+
+	lock_acquire_exclusive(&e->map, 0, 1, NULL, _RET_IP_);
 }
 
 static __always_inline void __ClearPageLocked(struct page *page)
 {
+	struct page_ext *e;
+
 	__clear_bit(PG_locked, &PF_NO_TAIL(page, 1)->flags);
 
 	page = compound_head(page);
+	e = lookup_page_ext(page);
+	if (unlikely(!e))
+		return;
+
 	/*
 	 * lock_commit_crosslock() is necessary for crosslock
 	 * when the lock is released, before lock_release().
 	 */
-	lock_commit_crosslock(&page->map);
-	lock_release(&page->map, 0, _RET_IP_);
+	lock_commit_crosslock(&e->map);
+	lock_release(&e->map, 0, _RET_IP_);
 }
 #else
 __PAGEFLAG(Locked, locked, PF_NO_TAIL)
include/linux/page_ext.h +5 -0
index e1fe7cf..f84e9be 100644
@@ -48,6 +48,11 @@ struct page_ext {
 	int last_migrate_reason;
 	unsigned long trace_entries[8];
 #endif
+
+#ifdef CONFIG_LOCKDEP_PAGELOCK
+	struct lockdep_map map;
+	struct cross_lock xlock;
+#endif
 };
 
 extern void pgdat_page_ext_init(struct pglist_data *pgdat);
include/linux/pagemap.h +24 -4
index dbe7adf..79174ad 100644
@@ -16,6 +16,7 @@
 #include <linux/hugetlb_inline.h>
 #ifdef CONFIG_LOCKDEP_PAGELOCK
 #include <linux/lockdep.h>
+#include <linux/page_ext.h>
 #endif
 
 /*
@@ -417,28 +418,47 @@ static inline pgoff_t linear_page_index(struct vm_area_struct *vma,
 }
 
 #ifdef CONFIG_LOCKDEP_PAGELOCK
+extern struct page_ext_operations lockdep_pagelock_ops;
+
 #define lock_page_init(p)					\
 do {								\
 	static struct lock_class_key __key;			\
-	lockdep_init_map_crosslock(&(p)->map, &(p)->xlock,	\
+	struct page_ext *e = lookup_page_ext(p);		\
+								\
+	if (unlikely(!e))					\
+		break;						\
+								\
+	lockdep_init_map_crosslock(&(e)->map, &(e)->xlock,	\
 			"(PG_locked)" #p, &__key, 0);		\
 } while (0)
 
 static inline void lock_page_acquire(struct page *page, int try)
 {
+	struct page_ext *e;
+
 	page = compound_head(page);
-	lock_acquire_exclusive(&page->map, 0, try, NULL, _RET_IP_);
+	e = lookup_page_ext(page);
+	if (unlikely(!e))
+		return;
+
+	lock_acquire_exclusive(&e->map, 0, try, NULL, _RET_IP_);
 }
 
 static inline void lock_page_release(struct page *page)
 {
+	struct page_ext *e;
+
 	page = compound_head(page);
+	e = lookup_page_ext(page);
+	if (unlikely(!e))
+		return;
+
 	/*
 	 * lock_commit_crosslock() is necessary for crosslock
 	 * when the lock is released, before lock_release().
 	 */
-	lock_commit_crosslock(&page->map);
-	lock_release(&page->map, 0, _RET_IP_);
+	lock_commit_crosslock(&e->map);
+	lock_release(&e->map, 0, _RET_IP_);
 }
 #else
 static inline void lock_page_init(struct page *page) {}
lib/Kconfig.debug +1 -0
index 1926435..9c6dc15 100644
@@ -1051,6 +1051,7 @@ config LOCKDEP_COMPLETE
 config LOCKDEP_PAGELOCK
 	bool "Lock debugging: allow PG_locked lock to use deadlock detector"
 	select LOCKDEP_CROSSRELEASE
+	select PAGE_EXTENSION
 	default n
 	help
 	 PG_locked lock is a kind of crosslock. Using crossrelease feature,
mm/filemap.c +72 -0

84 lines not on this page · raw message

mm/page_alloc.c +0 -3
index 0adc46c..8b3e134 100644
@@ -5225,9 +5225,6 @@ not_early:
 		} else {
 			__init_single_pfn(pfn, zone, nid);
 		}
-#ifdef CONFIG_LOCKDEP_PAGELOCK
-		lock_page_init(pfn_to_page(pfn));
-#endif
 	}
 }
 
mm/page_ext.c +4 -0
index 44a4c02..54f7027 100644
@@ -7,6 +7,7 @@
 #include <linux/kmemleak.h>
 #include <linux/page_owner.h>
 #include <linux/page_idle.h>
+#include <linux/pagemap.h>
 
 /*
  * struct page extension
@@ -63,6 +64,9 @@ static struct page_ext_operations *page_ext_ops[] = {
 #if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT)
 	&page_idle_ops,
 #endif
+#ifdef CONFIG_LOCKDEP_PAGELOCK
+	&lockdep_pagelock_ops,
+#endif
 };
 
 static unsigned long total_usage;
Signature · 1 line
1.9.1
#39 lore raw

PATCH v3 15/15 lockdep: Crossrelease feature documentation

In reply to Byungchul Park

This document describes the concept of crossrelease feature, which generalizes what causes a deadlock and how can detect a deadlock.

---
 Documentation/locking/crossrelease.txt | 785 +++++++++++++++++++++++++++++++++
 1 file changed, 785 insertions(+)
 create mode 100644 Documentation/locking/crossrelease.txt
Documentation/locking/crossrelease.txt new file +785 -0
new file mode 100644
index 0000000..78558af
@@ -0,0 +1,785 @@
+Crossrelease
+============
+
+Started by Byungchul Park <[email protected]>
+
+Contents:
+
+ (*) Background.
+
+     - What causes deadlock.
+     - What lockdep detects.
+     - How lockdep works.
+
+ (*) Limitation.
+
+     - Limit to typical lock.
+     - Pros from the limitation.
+     - Cons from the limitation.
+
+ (*) Generalization.
+
+     - Relax the limitation.
+
+ (*) Crossrelease.
+
+     - Introduce crossrelease.
+     - Introduce commit.
+
+ (*) Implementation.
+
+     - Data structures.
+     - How crossrelease works.
+
+ (*) Optimizations.
+
+     - Avoid duplication.
+     - Avoid lock contention.
+
+
+==========
+Background
+==========
+
+What causes deadlock
+--------------------
+
+A deadlock occurs when a context is waiting for an event to be issued
+which cannot be issued because the context or another context who can
+issue the event is also waiting for an event to be issued which cannot
+be issued. Single context or more than one context both waiting for an
+event and issuing an event may paricipate in a deadlock.
+
+For example,
+
+A context who can issue event D is waiting for event A to be issued.
+A context who can issue event A is waiting for event B to be issued.
+A context who can issue event B is waiting for event C to be issued.
+A context who can issue event C is waiting for event D to be issued.
+
+A deadlock occurs when these four operations are run at a time because
+event D cannot be issued if event A isn't issued which in turn cannot be
+issued if event B isn't issued which in turn cannot be issued if event C
+isn't issued which in turn cannot be issued if event D isn't issued. No
+event can be issued since any of them never meets its precondition.
+
+We can easily recognize that each wait operation creates a dependency
+between two issuings e.g. between issuing D and issuing A like, 'event D
+cannot be issued if event A isn't issued', in other words, 'issuing
+event D depends on issuing event A'. So the whole example can be
+rewritten in terms of dependency,
+
+Do an operation making 'event D cannot be issued if event A isn't issued'.
+Do an operation making 'event A cannot be issued if event B isn't issued'.
+Do an operation making 'event B cannot be issued if event C isn't issued'.
+Do an operation making 'event C cannot be issued if event D isn't issued'.
+
+or,
+
+Do an operation making 'issuing event D depends on issuing event A'.
+Do an operation making 'issuing event A depends on issuing event B'.
+Do an operation making 'issuing event B depends on issuing event C'.
+Do an operation making 'issuing event C depends on issuing event D'.
+
+What causes a deadlock is a set of dependencies a chain of which forms a
+cycle, which means that issuing event D depending on issuing event A
+depending on issuing event B depending on issuing event C depending on
+issuing event D, finally depends on issuing event D itself, which means
+no event can be issued.
+
+Any set of operations creating dependencies causes a deadlock. The set
+of lock operations e.g. acquire and release is an example. Waiting for a
+lock to be released corresponds to waiting for an event and releasing a
+lock corresponds to issuing an event. So the description of dependency
+above can be altered to one in terms of lock.
+
+In terms of event, issuing event A depends on issuing event B if,
+
+	Event A cannot be issued if event B isn't issued.
+
+In terms of lock, releasing lock A depends on releasing lock B if,
+
+	Lock A cannot be released if lock B isn't released.
+
+CONCLUSION
+
+A set of dependencies a chain of which forms a cycle, causes a deadlock,
+no matter what creates the dependencies.
+
+
+What lockdep detects
+--------------------
+
+A deadlock actually occurs only when all operations creating problematic
+dependencies are run at a time. However, even if it has not happend, the
+deadlock potentially can occur if the problematic dependencies obviously
+exist. Thus it's meaningful to detect not only an actual deadlock but
+also its possibility. Lockdep does the both.
+
+Whether a deadlock actually occurs or not depends on several factors,
+which means a deadlock may not occur even though problematic
+dependencies exist. For example, what order contexts are switched in is
+a factor. A deadlock will occur when contexts are switched so that all
+operations causing a deadlock become run simultaneously.
+
+Lockdep tries to detect a deadlock or its possibility aggressively,
+though it also tries to avoid false positive detections. So lockdep is
+designed to consider all possible combinations of dependencies so that
+it can detect all potential possibilities of deadlock in advance. What
+lockdep tries in order to consider all possibilities are,
+
+1. Use a global dependency graph including all dependencies.
+
+   What lockdep checks is based on dependencies instead of what actually
+   happened. So no matter which context or call path a new dependency is
+   detected in, it's just referred to as a global factor.
+
+2. Use lock classes than lock instances when checking dependencies.
+
+   What actually causes a deadlock is lock instances. However, lockdep
+   uses lock classes than its instances when checking dependencies since
+   any instance of a same lock class can be altered anytime.
+
+So lockdep detects both an actual deadlock and its possibility. But the
+latter is more valuable than the former. When a deadlock actually
+occures, we can identify what happens in the system by some means or
+other even without lockdep. However, there's no way to detect possiblity
+without lockdep unless the whole code is parsed in head. It's terrible.
+
+CONCLUSION
+
+Lockdep does, the fisrt one is more valuable,
+
+1. Detecting and reporting deadlock possibility.
+2. Detecting and reporting a deadlock actually occured.
+
+
+How lockdep works
+-----------------
+
+What lockdep should do, to detect a deadlock or its possibility are,
+
+1. Detect a new dependency created.
+2. Keep the dependency in a global data structure esp. graph.
+3. Check if any of all possible chains of dependencies forms a cycle.
+4. Report a deadlock or its possibility if a cycle is detected.
+
+A graph used by lockdep to keep all dependencies looks like,
+
+A -> B -        -> F -> G
+        \      /
+         -> E -        -> L
+        /      \      /
+C -> D -        -> H -
+                      \
+                       -> I -> K
+                      /
+                   J -
+
+where A, B,..., L are different lock classes.
+
+Lockdep adds a dependency into graph when a new dependency is detected.
+For example, it adds a dependency 'A -> B' when a dependency between
+releasing lock A and releasing lock B, which has not been added yet, is
+detected. It does same thing on other dependencies, too. See 'What
+causes deadlock' section.
+
+NOTE: Precisely speaking, a dependency is one between releasing a lock
+and releasing another lock as described in 'What causes deadlock'
+section. However from now on, we will describe a dependency as if it's
+one between a lock and another lock for simplicity. Then 'A -> B' can be
+described as a dependency between lock A and lock B.
+
+We already checked how a problematic set of dependencies causes a
+deadlock in 'What causes deadlock' section. This time let's check if a
+deadlock or its possibility can be detected using a problematic set of
+dependencies. Assume that 'A -> B', 'B -> E' and 'E -> A' were added in
+the sequence into graph. Then the graph finally will be,
+
+ -> A -> B -> E -
+/                \
+\                /
+ ----------------
+
+where A, B and E are different lock classes.
+
+From adding three dependencies, a cycle was created which means, by
+definition of dependency, the situation 'lock E must be released to
+release lock B which in turn must be released to release lock A which in
+turn must be released to release lock E which in turn must be released
+to release B and so on infinitely' can happen.
+
+Once the situation happens, no lock can be released since any of them
+can never meet each precondition. It's a deadlock. Lockdep can detect a
+deadlock or its possibility with checking if a cycle was created after
+adding each dependency into graph. This is how lockdep detects a
+deadlock or its possibility.
+
+CONCLUSION
+
+Lockdep detects a deadlock or its possibility with checking if a cycle
+was created after adding each dependency into graph.
+
+
+==========
+Limitation
+==========
+
+Limit to typical lock
+---------------------
+
+Limiting what lockdep has to consider to only ones satisfying the
+following condition, the implementation of adding dependencies becomes
+simple while its capacity for detection becomes limited. Typical lock
+e.g. spin lock and mutex is the case. Let's check what pros and cons of
+it are, in next section.
+
+	A lock should be released within the context holding the lock.
+
+CONCLUSION
+
+Limiting what lockdep has to consider to typical lock e.g. spin lock and
+mutex, the implmentation becomes simple while it has a limited capacity.
+
+
+Pros from the limitation
+------------------------
+
+Given the limitation, when acquiring a lock, any lock being in
+held_locks of the acquire context cannot be released if the lock to
+acquire was not released yet. Yes. It's the exact case to add a new
+dependency 'A -> B' into graph, where lock A represents each lock being
+in held_locks and lock B represents the lock to acquire.
+
+For example, only considering typical lock,
+
+	PROCESS X
+	--------------
+	acquire A
+
+	acquire B -> add a dependency 'A -> B'
+
+	acquire C -> add a dependency 'B -> C'
+
+	release C
+
+	release B
+
+	release A
+
+where A, B and C are different lock classes.
+
+When acquiring lock A, there's nothing in held_locks of PROCESS X thus
+no dependency is added. When acquiring lock B, lockdep detects and adds
+a new dependency 'A -> B' between lock A being in held_locks and lock B.
+And when acquiring lock C, lockdep also adds another dependency 'B -> C'
+for same reason. They are added when acquiring each lock, simply.
+
+NOTE: Even though every lock being in held_locks depends on the lock to
+acquire, lockdep does not add all dependencies between them because all
+of them can be covered by other dependencies except one dependency
+between the lock on top of held_locks and the lock to acquire, which
+must be added.
+
+Besides, we can expect several advantages from the limitation.
+
+1. Any lock being in held_locks cannot be released unconditionally if
+   the context is stuck, thus we can easily identify a dependency when
+   acquiring a lock.
+
+2. Considering only locks being in local held_locks of a single context
+   makes some races avoidable, even though it fails of course when
+   modifying its global dependency graph.
+
+3. To build a dependency graph, lockdep only needs to keep locks not
+   released yet. However relaxing the limitation, it might need to keep
+   even locks already released, additionally. See 'Crossrelease' section.
+
+CONCLUSION
+
+Given the limitation, the implementation becomes simple and efficient.
+
+
+Cons from the limitation
+------------------------
+
+Given the limitation, lockdep is applicable only to typical lock. For
+example, page lock for page access or completion for synchronization
+cannot play with lockdep having the limitation. However since page lock
+or completion also causes a deadlock, it would be better to detect a
+deadlock or its possibility even for them.
+
+Can we detect deadlocks below with lockdep having the limitation?
+
+Example 1:
+
+	PROCESS X	PROCESS Y
+	--------------	--------------
+	mutext_lock A
+			lock_page B
+	lock_page B
+			mutext_lock A // DEADLOCK
+	unlock_page B
+			mutext_unlock A
+	mutex_unlock A
+			unlock_page B
+
+where A and B are different lock classes.
+
+No, we cannot.
+
+Example 2:
+
+	PROCESS X	PROCESS Y	PROCESS Z
+	--------------	--------------	--------------
+			mutex_lock A
+	lock_page B
+			lock_page B
+					mutext_lock A // DEADLOCK
+					mutext_unlock A
+
+					unlock_page B held by X
+			unlock_page B
+			mutex_unlock A
+
+where A and B are different lock classes.
+
+No, we cannot.
+
+Example 3:
+
+	PROCESS X	PROCESS Y
+	--------------	--------------
+			mutex_lock A
+	mutex_lock A
+	mutex_unlock A
+			wait_for_complete B // DEADLOCK
+	complete B
+			mutex_unlock A
+
+where A is a lock class and B is a completion variable.
+
+No, we cannot.
+
+CONCLUSION
+
+Given the limitation, lockdep cannot detect a deadlock or its
+possibility caused by page lock or completion.
+
+
+==============
+Generalization
+==============
+
+Relax the limitation
+--------------------
+
+Detecting and adding new dependencies into graph is very important for
+lockdep to work because adding a dependency means adding a chance to
+check if it causes a deadlock. More dependencies lockdep adds, more
+throughly it can work. Therefore Lockdep has to do its best to add as
+many true dependencies as possible.
+
+Relaxing the limitation, lockdep can add additional dependencies since
+it makes lockdep deal with additional ones creating the dependencies e.g.
+page lock or completion, which might be released in any context. Even so,
+it needs to be noted that behaviors adding dependencies created by
+typical lock don't need to be changed at all.
+
+For example, only considering typical lock, lockdep builds a graph like,
+
+A -> B -        -> F -> G
+        \      /
+         -> E -        -> L
+        /      \      /
+C -> D -        -> H -
+                      \
+                       -> I -> K
+                      /
+                   J -
+
+where A, B,..., L are different lock classes, and upper case letters
+represent typical lock.
+
+After the relaxing, the graph will have additional dependencies like,
+
+A -> B -        -> F -> G
+        \      /
+         -> E -        -> L -> c
+        /      \      /
+C -> D -        -> H -
+               /      \
+            a -        -> I -> K
+                      /
+              b -> J -
+
+where a, b, c, A, B,..., L are different lock classes, and upper case
+letters represent typical lock while lower case letters represent
+non-typical lock e.g. page lock and completion.
+
+However, it might suffer performance degradation since relaxing the
+limitation with which design and implementation of lockdep become
+efficient might introduce inefficiency inevitably. Each option, that is,
+strong detection or efficient detection has its pros and cons, thus the
+right of choice between two options should be given to users.
+
+Choosing efficient detection, lockdep only deals with locks satisfying,
+
+	A lock should be released within the context holding the lock.
+
+Choosing strong detection, lockdep deals with any locks satisfying,
+
+	A lock can be released in any context.
+
+In the latter, of course, some contexts are not allowed if they
+themselves cause a deadlock. For example, acquiring a lock in irq-safe
+context before releasing the lock in irq-unsafe context is not allowed,
+which after all ends in a cycle of a dependency chain, meaning a
+deadlock. Otherwise, any contexts are allowed to release it.
+
+CONCLUSION
+
+Relaxing the limitation, lockdep adds additional dependencies and gets
+additional chances to check if they cause a deadlock. It makes lockdep
+additionally deal with what might be released in any context.
+
+
+============
+Crossrelease
+============
+
+Introduce crossrelease
+----------------------
+
+To allow lockdep to add additional dependencies created by what might be
+released in any context, which we call 'crosslock', it's necessary to
+introduce a new feature which makes it possible to identify and add the
+dependencies. We call the feature 'crossrelease'. Crossrelease feature
+has to do,
+
+1. Identify a new dependency created by crosslock.
+2. Add the dependency into graph when identifying it.
+
+That's all. Once a meaningful dependency is added into graph, lockdep
+will work with the graph as it did. So the most important thing to do is
+to identify a dependency created by crosslock. Remind what a dependency
+is. For example, Lock A depends on lock B if 'lock A cannot be released
+if lock B isn't released'. See 'What causes deadlock' section.
+
+By definition, a lock depends on every lock having been added into
+held_locks in the lock's release context since the lock was acquired,
+because the lock cannot be released if the release context is stuck by
+any of dependent locks, not released. So lockdep should technically
+consider release contexts of locks to identify dependencies.
+
+It's no matter of course to typical lock because acquire context is same
+as release context for typical lock, which means lockdep would work with
+considering only acquire contexts for typical lock. However, for
+crosslock, lockdep cannot identify release context and any dependency
+until the crosslock will be actually released.
+
+Regarding crosslock, lockdep has to record all history by queueing all
+locks potentially creating dependencies so that real dependencies can be
+added using the history recorded when identifying release context. We
+call it 'commit', that is, to add dependencies in batches. See
+'Introduce commit' section.
+
+Of course, some actual deadlocks caused by crosslock cannot be detected
+at the time it happened, because the deadlocks cannot be indentified and
+detected until the crosslock will be actually released. But this way
+deadlock possibility can be detected and it's worth just possibility
+detection of deadlock. See 'What lockdep does' section.
+
+CONCLUSION
+
+With crossrelease feature, lockdep can works with what might be released
+in any context, namely, crosslock.
+
+
+Introduce commit
+----------------
+
+Crossrelease feature names it 'commit' to identify and add dependencies
+into graph in batches. Lockdep is already doing what commit does when
+acquiring a lock, for typical lock. However, that way must be changed
+for crosslock so that it identifies the crosslock's release context
+first and then does commit.
+
+The main reason why lockdep performs additional step, namely commit, for
+crosslock is that some dependencies by crosslock cannot be identified
+until the crosslock's release context is eventually identified, though
+some other dependencies by crosslock can. There are four kinds of
+dependencies to consider.
+
+1. 'typical lock A -> typical lock B' dependency
+
+   Just when acquiring lock B, lockdep can identify the dependency
+   between lock A and lock B as it did. Commit is unnecessary.
+
+2. 'typical lock A -> crosslock b' dependency
+
+   Just when acquiring crosslock b, lockdep can identify the dependency
+   between lock A and crosslock B as well. Commit is unnecessary, too.
+
+3. 'crosslock a -> typical lock B' dependency
+
+   When acquiring lock B, lockdep cannot identify the dependency. It can
+   be identified only when crosslock a is released. Commit is necessary.
+
+4. 'crosslock a -> crosslock b' dependency
+
+   Creating this kind of dependency directly is unnecessary since it can
+   be covered by other kinds of dependencies.
+
+Lockdep works without commit during dealing with only typical locks.
+However, it needs to perform commit step, once at least one crosslock is
+acquired, until all crosslocks in progress are released. Introducing
+commit, lockdep performs three steps i.e. acquire, commit and release.
+What lockdep should do in each step is like,
+
+1. Acquire
+
+   1) For typical lock
+
+	Lockdep does what it originally does and queues the lock so
+	that lockdep can check dependencies using it at commit step.
+
+   2) For crosslock
+
+	The crosslock is added to a global linked list so that lockdep
+	can check dependencies using it at commit step.
+
+2. Commit
+
+   1) For typical lock
+
+	N/A.
+
+   2) For crosslock
+
+	Lockdep checks and adds dependencies using data saved at acquire
+	step, as if the dependencies were added without commit step.
+
+3. Release
+
+   1) For typical lock
+
+	No change.
+
+   2) For crosslock
+
+	Lockdep just remove the crosslock from the global linked list,
+	to which it was added at acquire step.
+
+CONCLUSION
+
+Lockdep can detect a deadlock or its possibility caused by what might be
+released in any context, using commit step, where it checks and adds
+dependencies in batches.
+
+
+==============
+Implementation
+==============
+
+Data structures
+---------------
+
+Crossrelease feature introduces two main data structures.
+
+1. pend_lock (or plock)
+
+   This is an array embedded in task_struct, for keeping locks queued so
+   that real dependencies can be added using them at commit step. So
+   this data can be accessed locklessly within the owner context. The
+   array is filled when acquiring a typical lock and consumed when doing
+   commit. And it's managed in circular manner.
+
+2. cross_lock (or xlock)
+
+   This is a global linked list, for keeping all crosslocks in progress.
+   The list grows when acquiring a crosslock and is shrunk when
+   releasing the crosslock. lockdep_init_map_crosslock() should be used
+   to initialize a crosslock instance instead of lockdep_init_map() so
+   that lockdep can recognize it as crosslock.
+
+CONCLUSION
+
+Crossrelease feature uses two main data structures.
+
+1. A pend_lock array for queueing typical locks in circular manner.
+2. A cross_lock linked list for managing crosslocks in progress.
+
+
+How crossrelease works
+----------------------
+
+Let's take look at how crossrelease feature works step by step, starting
+from how lockdep works without crossrelease feaure.
+
+For example, the below is how lockdep works for typical lock.
+
+	RELEASE CONTEXT of A (= ACQUIRE CONTEXT of A)
+	--------------------
+	acquire A
+
+	acquire B -> add a dependency 'A -> B'
+
+	acquire C -> add a dependency 'B -> C'
+
+	release C
+
+	release B
+
+	release A
+
+where A, B and C are different lock classes, and upper case letters
+represent typical lock.
+
+After adding 'A -> B', the dependency graph will be,
+
+A -> B
+
+where A and B are different lock classes, and upper case letters
+represent typical lock.
+
+And after adding 'B -> C', the graph will be,
+
+A -> B -> C
+
+where A, B and C are different lock classes, and upper case letters
+represent typical lock.
+
+What if applying commit on typical locks? It's not necessary for typical
+lock. Just for showing what commit does.
+
+	RELEASE CONTEXT of A (= ACQUIRE CONTEXT of A)
+	--------------------
+	acquire A -> mark A as started (nothing before, no queueing)
+
+	acquire B -> mark B as started and queue B
+
+	acquire C -> mark C as started and queue C
+
+	release C -> commit C (nothing queued since C started)
+
+	release B -> commit B -> add a dependency 'B -> C'
+
+	release A -> commit A -> add dependencies 'A -> B' and 'A -> C'
+
+where A, B and C are different lock classes, and upper case letters
+represent typical lock.
+
+After doing commit A, B and C, the dependency graph becomes like,
+
+A -> B -> C
+
+where A, B and C are different lock classes, and upper case letters
+represent typical lock.
+
+NOTE: A dependency 'A -> C' is optimized out.
+
+Here we can see the final graph is same as the graph built without
+commit. Of course the former way leads to finish building the graph
+earlier than the latter way, which means we can detect a deadlock or its
+possibility sooner. So the former way would be prefered if possible. But
+we cannot avoid using the latter way using commit, for crosslock.
+
+Let's look at how commit works for crosslock.
+
+	RELEASE CONTEXT of a	ACQUIRE CONTEXT of a
+	--------------------	--------------------
+				acquire a -> mark a as started
+
+	(serialized by some means e.g. barrier)
+
+	acquire D -> queue D
+				acquire B -> queue B
+	release D
+				acquire C -> add 'B -> C' and queue C
+	acquire E -> queue E
+				acquire D -> add 'C -> D' and queue D
+	release E
+				release D
+	release a -> commit a -> add 'a -> D' and 'a -> E'
+				release C
+
+				release B
+
+where a, B,..., E are different lock classes, and upper case letters
+represent typical lock while lower case letters represent crosslock.
+
+When acquiring crosslock a, no dependency can be added since there's
+nothing in the held_locks. However, crossrelease feature marks the
+crosslock as started, which means all locks to acquire from now are
+candidates which might create new dependencies later when identifying
+release context.
+
+When acquiring lock B, lockdep does what it originally does for typical
+lock and additionally queues the lock for later commit to refer to
+because it might be a dependent lock of the crosslock. It does same
+thing on lock C, D and E. And then two dependencies 'a -> D' and 'a -> E'
+are added when identifying the release context, at commit step.
+
+The final graph is, with crossrelease feature using commit,
+
+B -> C -
+        \
+         -> D
+        /
+     a -
+        \
+         -> E
+
+where a, B,..., E are different lock classes, and upper case letters
+represent typical lock while lower case letters represent crosslock.
+
+However, without crossrelease feature, the final graph will be,
+
+B -> C -> D
+
+where B and C are different lock classes, and upper case letters
+represent typical lock.
+
+The former graph has two more dependencies 'a -> D' and 'a -> E' giving
+additional chances to check if they cause a deadlock. This way lockdep
+can detect a deadlock or its possibility caused by crosslock. Again,
+behaviors adding dependencies created by only typical locks are not
+changed at all.
+
+CONCLUSION
+
+Crossrelease works using commit for crosslock, leaving behaviors adding
+dependencies between only typical locks unchanged.
+
+
+=============
+Optimizations
+=============
+
+Avoid duplication
+-----------------
+
+Crossrelease feature uses a cache like what lockdep already uses for
+dependency chains, but this time it's for caching one dependency like
+'crosslock -> typical lock' crossing between two different context. Once
+that dependency is cached, same dependency will never be added any more.
+Even queueing unnecessary locks is also prevented based on the cache.
+
+CONCLUSION
+
+Crossrelease does not add any duplicate dependency.
+
+
+Avoid lock contention
+---------------------
+
+To keep all typical locks for later use, crossrelease feature adopts a
+local array embedded in task_struct, which makes accesses to arrays
+lockless by forcing each array to be accessed only within each own
+context. It's like how held_locks is accessed. Lockless implmentation is
+important since typical locks are very frequently accessed.
+
+CONCLUSION
+
+Crossrelease avoids lock contection as far as possible.
Signature · 1 line
1.9.1
#40 lore raw

Re: [PATCH v3 15/15] lockdep: Crossrelease feature documentation

Quoted 8 lines · Byungchul Park

This document describes the concept of crossrelease feature, which generalizes what causes a deadlock and how can detect a deadlock.

---
 Documentation/locking/crossrelease.txt | 785 +++++++++++++++++++++++++++++++++
 1 file changed, 785 insertions(+)
 create mode 100644 Documentation/locking/crossrelease.txt

Byungchul, I mostly skimmed through the document. I suggest that we split this document. The initial 1/4 of the document talks about lockdep's current implementation which I believe should be combined with the file: Documentation/locking/lockdep-design.txt. Tomorrow I would try to understand the document in detail and hopefully provide some useful comments.

--
Nilay

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#41 lore raw

Re: [PATCH v3 15/15] lockdep: Crossrelease feature documentation

Quoted 10 lines · Nilay Vaish
Quoted 8 lines · Byungchul Park

This document describes the concept of crossrelease feature, which generalizes what causes a deadlock and how can detect a deadlock.

---
 Documentation/locking/crossrelease.txt | 785 +++++++++++++++++++++++++++++++++
 1 file changed, 785 insertions(+)
 create mode 100644 Documentation/locking/crossrelease.txt
Quoted 6 lines

Byungchul, I mostly skimmed through the document. I suggest that we split this document. The initial 1/4 of the document talks about lockdep's current implementation which I believe should be combined with the file: Documentation/locking/lockdep-design.txt. Tomorrow I would try to understand the document in detail and hopefully provide some useful comments.

Hello,

It was a korean traditional holliday for a week so I'm late. And I also think 1/4 of it talks about original lockdep.

Thank you,
Byungchul

Quoted 3 lines

--
Nilay

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#42 lore raw

Re: [PATCH v3 15/15] lockdep: Crossrelease feature documentation

In reply to Byungchul Park
Quoted 55 lines · Byungchul Park

This document describes the concept of crossrelease feature, which generalizes what causes a deadlock and how can detect a deadlock.

---
 Documentation/locking/crossrelease.txt | 785 +++++++++++++++++++++++++++++++++
 1 file changed, 785 insertions(+)
 create mode 100644 Documentation/locking/crossrelease.txt
Documentation/locking/crossrelease.txt new file +40 -0
new file mode 100644
index 0000000..78558af
@@ -0,0 +1,785 @@
+Crossrelease
+============
+
+Started by Byungchul Park <[email protected]>
+
+Contents:
+
+ (*) Background.
+
+     - What causes deadlock.
+     - What lockdep detects.
+     - How lockdep works.
+
+ (*) Limitation.
+
+     - Limit to typical lock.
+     - Pros from the limitation.
+     - Cons from the limitation.
+
+ (*) Generalization.
+
+     - Relax the limitation.
+
+ (*) Crossrelease.
+
+     - Introduce crossrelease.
+     - Introduce commit.
+
+ (*) Implementation.
+
+     - Data structures.
+     - How crossrelease works.
+
+ (*) Optimizations.
+
+     - Avoid duplication.
+     - Avoid lock contention.
+
+
+==========

Documentation/locking/crossrelease.txt line 50

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+Background
+==========
+
+What causes deadlock
+--------------------
+
+A deadlock occurs when a context is waiting for an event to be issued
+which cannot be issued because the context or another context who can
+issue the event is also waiting for an event to be issued which cannot
+be issued.

I think 'some event happened' and 'context triggered an event' is better than 'some event issued' or 'context issued an event'. I think 'happen' and 'trigger' are more widely used words when we talk about events. For example, I would prefer the following version of the above:

A deadlock occurs when a context is waiting for an event to happen, which cannot happen because the context which can trigger the event is also waiting for an event to happen which cannot happen either.

Documentation/locking/crossrelease.txt line 52

Quoted 2 lines
Documentation/locking/crossrelease.txt new file +2 -0
+Single context or more than one context both waiting for an
+event and issuing an event may paricipate in a deadlock.

I am not able to make sense of the line above.

Quoted 16 lines
Documentation/locking/crossrelease.txt new file +16 -0
+
+For example,
+
+A context who can issue event D is waiting for event A to be issued.
+A context who can issue event A is waiting for event B to be issued.
+A context who can issue event B is waiting for event C to be issued.
+A context who can issue event C is waiting for event D to be issued.
+
+A deadlock occurs when these four operations are run at a time because
+event D cannot be issued if event A isn't issued which in turn cannot be
+issued if event B isn't issued which in turn cannot be issued if event C
+isn't issued which in turn cannot be issued if event D isn't issued. No
+event can be issued since any of them never meets its precondition.
+
+We can easily recognize that each wait operation creates a dependency
+between two issuings e.g. between issuing D and issuing A like, 'event D

Documentation/locking/crossrelease.txt line 77

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+cannot be issued if event A isn't issued', in other words, 'issuing
+event D depends on issuing event A'. So the whole example can be
+rewritten in terms of dependency,
+
+Do an operation making 'event D cannot be issued if event A isn't issued'.
+Do an operation making 'event A cannot be issued if event B isn't issued'.
+Do an operation making 'event B cannot be issued if event C isn't issued'.
+Do an operation making 'event C cannot be issued if event D isn't issued'.
+
+or,

I think we can remove the text above. The example only needs to be provided once.

Quoted 19 lines
Documentation/locking/crossrelease.txt new file +19 -0
+
+Do an operation making 'issuing event D depends on issuing event A'.
+Do an operation making 'issuing event A depends on issuing event B'.
+Do an operation making 'issuing event B depends on issuing event C'.
+Do an operation making 'issuing event C depends on issuing event D'.
+
+What causes a deadlock is a set of dependencies a chain of which forms a
+cycle, which means that issuing event D depending on issuing event A
+depending on issuing event B depending on issuing event C depending on
+issuing event D, finally depends on issuing event D itself, which means
+no event can be issued.
+
+Any set of operations creating dependencies causes a deadlock. The set
+of lock operations e.g. acquire and release is an example. Waiting for a
+lock to be released corresponds to waiting for an event and releasing a
+lock corresponds to issuing an event. So the description of dependency
+above can be altered to one in terms of lock.
+
+In terms of event, issuing event A depends on issuing event B if,

Documentation/locking/crossrelease.txt line 106

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+
+       Event A cannot be issued if event B isn't issued.
+
+In terms of lock, releasing lock A depends on releasing lock B if,
+
+       Lock A cannot be released if lock B isn't released.
+
+CONCLUSION
+
+A set of dependencies a chain of which forms a cycle, causes a deadlock,

I think 'a chain of' is not required in the sentence above.

Documentation/locking/crossrelease.txt line 113

Quoted 7 lines
Documentation/locking/crossrelease.txt new file +7 -0
+no matter what creates the dependencies.
+
+
+What lockdep detects
+--------------------
+
+A deadlock actually occurs only when all operations creating problematic

Instead of 'problematic', I would use 'cyclic'.

Documentation/locking/crossrelease.txt line 114

Quoted 1 line
Documentation/locking/crossrelease.txt new file +1 -0
+dependencies are run at a time. However, even if it has not happend, the

dependencies happen at run time. However, even if they don't, the

Documentation/locking/crossrelease.txt line 115

Quoted 1 line
Documentation/locking/crossrelease.txt new file +1 -0
+deadlock potentially can occur if the problematic dependencies obviously

remove obviously

Documentation/locking/crossrelease.txt line 120

Quoted 5 lines
Documentation/locking/crossrelease.txt new file +5 -0
+exist. Thus it's meaningful to detect not only an actual deadlock but
+also its possibility. Lockdep does the both.
+
+Whether a deadlock actually occurs or not depends on several factors,
+which means a deadlock may not occur even though problematic

cyclic instead of problematic

Documentation/locking/crossrelease.txt line 123

Quoted 3 lines
Documentation/locking/crossrelease.txt new file +3 -0
+dependencies exist. For example, what order contexts are switched in is
+a factor. A deadlock will occur when contexts are switched so that all
+operations causing a deadlock become run simultaneously.

delete become.

Documentation/locking/crossrelease.txt line 135

Quoted 12 lines
Documentation/locking/crossrelease.txt new file +12 -0
+
+Lockdep tries to detect a deadlock or its possibility aggressively,
+though it also tries to avoid false positive detections. So lockdep is
+designed to consider all possible combinations of dependencies so that
+it can detect all potential possibilities of deadlock in advance. What
+lockdep tries in order to consider all possibilities are,
+
+1. Use a global dependency graph including all dependencies.
+
+   What lockdep checks is based on dependencies instead of what actually
+   happened. So no matter which context or call path a new dependency is
+   detected in, it's just referred to as a global factor.

Can you explain more what 'global factor' means?

Documentation/locking/crossrelease.txt line 141

Quoted 6 lines
Documentation/locking/crossrelease.txt new file +6 -0
+
+2. Use lock classes than lock instances when checking dependencies.
+
+   What actually causes a deadlock is lock instances. However, lockdep
+   uses lock classes than its instances when checking dependencies since
+   any instance of a same lock class can be altered anytime.

I am unable to make sense of the sentence above. Do you want to say the following:

However, lockdep uses lock classes than its instances when checking dependencies since instances from the same lock class behave in the same (or similar) fashion.

Quoted 34 lines
Documentation/locking/crossrelease.txt new file +34 -0
+
+So lockdep detects both an actual deadlock and its possibility. But the
+latter is more valuable than the former. When a deadlock actually
+occures, we can identify what happens in the system by some means or
+other even without lockdep. However, there's no way to detect possiblity
+without lockdep unless the whole code is parsed in head. It's terrible.
+
+CONCLUSION
+
+Lockdep does, the fisrt one is more valuable,
+
+1. Detecting and reporting deadlock possibility.
+2. Detecting and reporting a deadlock actually occured.
+
+
+How lockdep works
+-----------------
+
+What lockdep should do, to detect a deadlock or its possibility are,
+
+1. Detect a new dependency created.
+2. Keep the dependency in a global data structure esp. graph.
+3. Check if any of all possible chains of dependencies forms a cycle.
+4. Report a deadlock or its possibility if a cycle is detected.
+
+A graph used by lockdep to keep all dependencies looks like,
+
+A -> B -        -> F -> G
+        \      /
+         -> E -        -> L
+        /      \      /
+C -> D -        -> H -
+                      \
+                       -> I -> K

Documentation/locking/crossrelease.txt line 185

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+                      /
+                   J -
+
+where A, B,..., L are different lock classes.
+
+Lockdep adds a dependency into graph when a new dependency is detected.
+For example, it adds a dependency 'A -> B' when a dependency between
+releasing lock A and releasing lock B, which has not been added yet, is
+detected. It does same thing on other dependencies, too. See 'What
+causes deadlock' section.

Just from the text above I am not able to understand at what point the dependency A-> B is added. If I was implementing lockdep, I would probably track all the locks that can be acquired between acquisition and release of A. For example,

acquire A

if (/* some condition */)
acquire B
else
acquire C

release A

I would add to the dependency graph that 'release A' depends on 'acquire B' and 'acquire C'.

Quoted 21 lines
Documentation/locking/crossrelease.txt new file +21 -0
+
+NOTE: Precisely speaking, a dependency is one between releasing a lock
+and releasing another lock as described in 'What causes deadlock'
+section. However from now on, we will describe a dependency as if it's
+one between a lock and another lock for simplicity. Then 'A -> B' can be
+described as a dependency between lock A and lock B.
+
+We already checked how a problematic set of dependencies causes a
+deadlock in 'What causes deadlock' section. This time let's check if a
+deadlock or its possibility can be detected using a problematic set of
+dependencies. Assume that 'A -> B', 'B -> E' and 'E -> A' were added in
+the sequence into graph. Then the graph finally will be,
+
+ -> A -> B -> E -
+/                \
+\                /
+ ----------------
+
+where A, B and E are different lock classes.
+
+From adding three dependencies, a cycle was created which means, by

Documentation/locking/crossrelease.txt line 216

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+definition of dependency, the situation 'lock E must be released to
+release lock B which in turn must be released to release lock A which in
+turn must be released to release lock E which in turn must be released
+to release B and so on infinitely' can happen.
+
+Once the situation happens, no lock can be released since any of them
+can never meet each precondition. It's a deadlock. Lockdep can detect a
+deadlock or its possibility with checking if a cycle was created after
+adding each dependency into graph. This is how lockdep detects a
+deadlock or its possibility.

I think the text here is just repeating what was said above in the 'What causes deadlock' section. You probably should remove of the text here.

Quoted 11 lines
Documentation/locking/crossrelease.txt new file +11 -0
+
+CONCLUSION
+
+Lockdep detects a deadlock or its possibility with checking if a cycle
+was created after adding each dependency into graph.
+
+
+==========
+Limitation
+==========
+

Documentation/locking/crossrelease.txt line 237

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+Limit to typical lock
+---------------------
+
+Limiting what lockdep has to consider to only ones satisfying the
+following condition, the implementation of adding dependencies becomes
+simple while its capacity for detection becomes limited. Typical lock
+e.g. spin lock and mutex is the case. Let's check what pros and cons of
+it are, in next section.
+
+       A lock should be released within the context holding the lock.

I would rephrase the above in the following way: Lockdep is limited to checking dependencies on locks that are released within the context that acquired them. This makes adding dependencies simple but limits lockdep's capacity for detection.

Documentation/locking/crossrelease.txt line 242

Quoted 5 lines
Documentation/locking/crossrelease.txt new file +5 -0
+
+CONCLUSION
+
+Limiting what lockdep has to consider to typical lock e.g. spin lock and
+mutex, the implmentation becomes simple while it has a limited capacity.

I would drop the conclusion altogether. The above paragraph is too small to require a conclusion.

Documentation/locking/crossrelease.txt line 249

Quoted 7 lines
Documentation/locking/crossrelease.txt new file +7 -0
+
+
+Pros from the limitation
+------------------------
+
+Given the limitation, when acquiring a lock, any lock being in
+held_locks of the acquire context cannot be released if the lock to

What does held_locks mean here? Is it some structure maintained by the Linux kernel?

Quoted 23 lines
Documentation/locking/crossrelease.txt new file +23 -0
+acquire was not released yet. Yes. It's the exact case to add a new
+dependency 'A -> B' into graph, where lock A represents each lock being
+in held_locks and lock B represents the lock to acquire.
+
+For example, only considering typical lock,
+
+       PROCESS X
+       --------------
+       acquire A
+
+       acquire B -> add a dependency 'A -> B'
+
+       acquire C -> add a dependency 'B -> C'
+
+       release C
+
+       release B
+
+       release A
+
+where A, B and C are different lock classes.
+
+When acquiring lock A, there's nothing in held_locks of PROCESS X thus

Documentation/locking/crossrelease.txt line 282

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+no dependency is added. When acquiring lock B, lockdep detects and adds
+a new dependency 'A -> B' between lock A being in held_locks and lock B.
+And when acquiring lock C, lockdep also adds another dependency 'B -> C'
+for same reason. They are added when acquiring each lock, simply.
+
+NOTE: Even though every lock being in held_locks depends on the lock to
+acquire, lockdep does not add all dependencies between them because all
+of them can be covered by other dependencies except one dependency
+between the lock on top of held_locks and the lock to acquire, which
+must be added.

I am unable to understand the above sentence. Can you break it into two more sentences?

Quoted 35 lines
Documentation/locking/crossrelease.txt new file +35 -0
+
+Besides, we can expect several advantages from the limitation.
+
+1. Any lock being in held_locks cannot be released unconditionally if
+   the context is stuck, thus we can easily identify a dependency when
+   acquiring a lock.
+
+2. Considering only locks being in local held_locks of a single context
+   makes some races avoidable, even though it fails of course when
+   modifying its global dependency graph.
+
+3. To build a dependency graph, lockdep only needs to keep locks not
+   released yet. However relaxing the limitation, it might need to keep
+   even locks already released, additionally. See 'Crossrelease' section.
+
+CONCLUSION
+
+Given the limitation, the implementation becomes simple and efficient.
+
+
+Cons from the limitation
+------------------------
+
+Given the limitation, lockdep is applicable only to typical lock. For
+example, page lock for page access or completion for synchronization
+cannot play with lockdep having the limitation. However since page lock
+or completion also causes a deadlock, it would be better to detect a
+deadlock or its possibility even for them.
+
+Can we detect deadlocks below with lockdep having the limitation?
+
+Example 1:
+
+       PROCESS X       PROCESS Y
+       --------------  --------------

Documentation/locking/crossrelease.txt line 327

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+       mutext_lock A
+                       lock_page B
+       lock_page B
+                       mutext_lock A // DEADLOCK
+       unlock_page B
+                       mutext_unlock A
+       mutex_unlock A
+                       unlock_page B
+
+where A and B are different lock classes.

I think the formatting is slightly off. The events corresponding to process Y should be shifted more towards right. The vertical ordering would still clearly indicate the order in which the events happened.

Documentation/locking/crossrelease.txt line 330

Quoted 2 lines
Documentation/locking/crossrelease.txt new file +2 -0
+
+No, we cannot.

I do not follow this example. The context that acquired the mutex A or lock B also released it. Should not lockdep be able to detect this? I am guessing I have misunderstood which events occurred in
which context. Here is what I think the example is showing:

X acquired mutex A --> Y acquired lock B --> X tries to acquire B --> Y tries to acquire A --> X and Y are in a deadlock since each of them holds a resource that the other needs.

Quoted 273 lines
Documentation/locking/crossrelease.txt new file +273 -0
+
+Example 2:
+
+       PROCESS X       PROCESS Y       PROCESS Z
+       --------------  --------------  --------------
+                       mutex_lock A
+       lock_page B
+                       lock_page B
+                                       mutext_lock A // DEADLOCK
+                                       mutext_unlock A
+
+                                       unlock_page B held by X
+                       unlock_page B
+                       mutex_unlock A
+
+where A and B are different lock classes.
+
+No, we cannot.
+
+Example 3:
+
+       PROCESS X       PROCESS Y
+       --------------  --------------
+                       mutex_lock A
+       mutex_lock A
+       mutex_unlock A
+                       wait_for_complete B // DEADLOCK
+       complete B
+                       mutex_unlock A
+
+where A is a lock class and B is a completion variable.
+
+No, we cannot.
+
+CONCLUSION
+
+Given the limitation, lockdep cannot detect a deadlock or its
+possibility caused by page lock or completion.
+
+
+==============
+Generalization
+==============
+
+Relax the limitation
+--------------------
+
+Detecting and adding new dependencies into graph is very important for
+lockdep to work because adding a dependency means adding a chance to
+check if it causes a deadlock. More dependencies lockdep adds, more
+throughly it can work. Therefore Lockdep has to do its best to add as
+many true dependencies as possible.
+
+Relaxing the limitation, lockdep can add additional dependencies since
+it makes lockdep deal with additional ones creating the dependencies e.g.
+page lock or completion, which might be released in any context. Even so,
+it needs to be noted that behaviors adding dependencies created by
+typical lock don't need to be changed at all.
+
+For example, only considering typical lock, lockdep builds a graph like,
+
+A -> B -        -> F -> G
+        \      /
+         -> E -        -> L
+        /      \      /
+C -> D -        -> H -
+                      \
+                       -> I -> K
+                      /
+                   J -
+
+where A, B,..., L are different lock classes, and upper case letters
+represent typical lock.
+
+After the relaxing, the graph will have additional dependencies like,
+
+A -> B -        -> F -> G
+        \      /
+         -> E -        -> L -> c
+        /      \      /
+C -> D -        -> H -
+               /      \
+            a -        -> I -> K
+                      /
+              b -> J -
+
+where a, b, c, A, B,..., L are different lock classes, and upper case
+letters represent typical lock while lower case letters represent
+non-typical lock e.g. page lock and completion.
+
+However, it might suffer performance degradation since relaxing the
+limitation with which design and implementation of lockdep become
+efficient might introduce inefficiency inevitably. Each option, that is,
+strong detection or efficient detection has its pros and cons, thus the
+right of choice between two options should be given to users.
+
+Choosing efficient detection, lockdep only deals with locks satisfying,
+
+       A lock should be released within the context holding the lock.
+
+Choosing strong detection, lockdep deals with any locks satisfying,
+
+       A lock can be released in any context.
+
+In the latter, of course, some contexts are not allowed if they
+themselves cause a deadlock. For example, acquiring a lock in irq-safe
+context before releasing the lock in irq-unsafe context is not allowed,
+which after all ends in a cycle of a dependency chain, meaning a
+deadlock. Otherwise, any contexts are allowed to release it.
+
+CONCLUSION
+
+Relaxing the limitation, lockdep adds additional dependencies and gets
+additional chances to check if they cause a deadlock. It makes lockdep
+additionally deal with what might be released in any context.
+
+
+============
+Crossrelease
+============
+
+Introduce crossrelease
+----------------------
+
+To allow lockdep to add additional dependencies created by what might be
+released in any context, which we call 'crosslock', it's necessary to
+introduce a new feature which makes it possible to identify and add the
+dependencies. We call the feature 'crossrelease'. Crossrelease feature
+has to do,
+
+1. Identify a new dependency created by crosslock.
+2. Add the dependency into graph when identifying it.
+
+That's all. Once a meaningful dependency is added into graph, lockdep
+will work with the graph as it did. So the most important thing to do is
+to identify a dependency created by crosslock. Remind what a dependency
+is. For example, Lock A depends on lock B if 'lock A cannot be released
+if lock B isn't released'. See 'What causes deadlock' section.
+
+By definition, a lock depends on every lock having been added into
+held_locks in the lock's release context since the lock was acquired,
+because the lock cannot be released if the release context is stuck by
+any of dependent locks, not released. So lockdep should technically
+consider release contexts of locks to identify dependencies.
+
+It's no matter of course to typical lock because acquire context is same
+as release context for typical lock, which means lockdep would work with
+considering only acquire contexts for typical lock. However, for
+crosslock, lockdep cannot identify release context and any dependency
+until the crosslock will be actually released.
+
+Regarding crosslock, lockdep has to record all history by queueing all
+locks potentially creating dependencies so that real dependencies can be
+added using the history recorded when identifying release context. We
+call it 'commit', that is, to add dependencies in batches. See
+'Introduce commit' section.
+
+Of course, some actual deadlocks caused by crosslock cannot be detected
+at the time it happened, because the deadlocks cannot be indentified and
+detected until the crosslock will be actually released. But this way
+deadlock possibility can be detected and it's worth just possibility
+detection of deadlock. See 'What lockdep does' section.
+
+CONCLUSION
+
+With crossrelease feature, lockdep can works with what might be released
+in any context, namely, crosslock.
+
+
+Introduce commit
+----------------
+
+Crossrelease feature names it 'commit' to identify and add dependencies
+into graph in batches. Lockdep is already doing what commit does when
+acquiring a lock, for typical lock. However, that way must be changed
+for crosslock so that it identifies the crosslock's release context
+first and then does commit.
+
+The main reason why lockdep performs additional step, namely commit, for
+crosslock is that some dependencies by crosslock cannot be identified
+until the crosslock's release context is eventually identified, though
+some other dependencies by crosslock can. There are four kinds of
+dependencies to consider.
+
+1. 'typical lock A -> typical lock B' dependency
+
+   Just when acquiring lock B, lockdep can identify the dependency
+   between lock A and lock B as it did. Commit is unnecessary.
+
+2. 'typical lock A -> crosslock b' dependency
+
+   Just when acquiring crosslock b, lockdep can identify the dependency
+   between lock A and crosslock B as well. Commit is unnecessary, too.
+
+3. 'crosslock a -> typical lock B' dependency
+
+   When acquiring lock B, lockdep cannot identify the dependency. It can
+   be identified only when crosslock a is released. Commit is necessary.
+
+4. 'crosslock a -> crosslock b' dependency
+
+   Creating this kind of dependency directly is unnecessary since it can
+   be covered by other kinds of dependencies.
+
+Lockdep works without commit during dealing with only typical locks.
+However, it needs to perform commit step, once at least one crosslock is
+acquired, until all crosslocks in progress are released. Introducing
+commit, lockdep performs three steps i.e. acquire, commit and release.
+What lockdep should do in each step is like,
+
+1. Acquire
+
+   1) For typical lock
+
+       Lockdep does what it originally does and queues the lock so
+       that lockdep can check dependencies using it at commit step.
+
+   2) For crosslock
+
+       The crosslock is added to a global linked list so that lockdep
+       can check dependencies using it at commit step.
+
+2. Commit
+
+   1) For typical lock
+
+       N/A.
+
+   2) For crosslock
+
+       Lockdep checks and adds dependencies using data saved at acquire
+       step, as if the dependencies were added without commit step.
+
+3. Release
+
+   1) For typical lock
+
+       No change.
+
+   2) For crosslock
+
+       Lockdep just remove the crosslock from the global linked list,
+       to which it was added at acquire step.
+
+CONCLUSION
+
+Lockdep can detect a deadlock or its possibility caused by what might be
+released in any context, using commit step, where it checks and adds
+dependencies in batches.
+
+
+==============
+Implementation
+==============
+
+Data structures
+---------------
+
+Crossrelease feature introduces two main data structures.
+
+1. pend_lock (or plock)
+
+   This is an array embedded in task_struct, for keeping locks queued so
+   that real dependencies can be added using them at commit step. So
+   this data can be accessed locklessly within the owner context. The
+   array is filled when acquiring a typical lock and consumed when doing
+   commit. And it's managed in circular manner.
+
+2. cross_lock (or xlock)
+
+   This is a global linked list, for keeping all crosslocks in progress.
+   The list grows when acquiring a crosslock and is shrunk when
+   releasing the crosslock. lockdep_init_map_crosslock() should be used

Documentation/locking/crossrelease.txt line 612

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+   to initialize a crosslock instance instead of lockdep_init_map() so
+   that lockdep can recognize it as crosslock.
+
+CONCLUSION
+
+Crossrelease feature uses two main data structures.
+
+1. A pend_lock array for queueing typical locks in circular manner.
+2. A cross_lock linked list for managing crosslocks in progress.
+

Drop these conclusion, not need at all.

Quoted 111 lines
Documentation/locking/crossrelease.txt new file +111 -0
+
+How crossrelease works
+----------------------
+
+Let's take look at how crossrelease feature works step by step, starting
+from how lockdep works without crossrelease feaure.
+
+For example, the below is how lockdep works for typical lock.
+
+       RELEASE CONTEXT of A (= ACQUIRE CONTEXT of A)
+       --------------------
+       acquire A
+
+       acquire B -> add a dependency 'A -> B'
+
+       acquire C -> add a dependency 'B -> C'
+
+       release C
+
+       release B
+
+       release A
+
+where A, B and C are different lock classes, and upper case letters
+represent typical lock.
+
+After adding 'A -> B', the dependency graph will be,
+
+A -> B
+
+where A and B are different lock classes, and upper case letters
+represent typical lock.
+
+And after adding 'B -> C', the graph will be,
+
+A -> B -> C
+
+where A, B and C are different lock classes, and upper case letters
+represent typical lock.
+
+What if applying commit on typical locks? It's not necessary for typical
+lock. Just for showing what commit does.
+
+       RELEASE CONTEXT of A (= ACQUIRE CONTEXT of A)
+       --------------------
+       acquire A -> mark A as started (nothing before, no queueing)
+
+       acquire B -> mark B as started and queue B
+
+       acquire C -> mark C as started and queue C
+
+       release C -> commit C (nothing queued since C started)
+
+       release B -> commit B -> add a dependency 'B -> C'
+
+       release A -> commit A -> add dependencies 'A -> B' and 'A -> C'
+
+where A, B and C are different lock classes, and upper case letters
+represent typical lock.
+
+After doing commit A, B and C, the dependency graph becomes like,
+
+A -> B -> C
+
+where A, B and C are different lock classes, and upper case letters
+represent typical lock.
+
+NOTE: A dependency 'A -> C' is optimized out.
+
+Here we can see the final graph is same as the graph built without
+commit. Of course the former way leads to finish building the graph
+earlier than the latter way, which means we can detect a deadlock or its
+possibility sooner. So the former way would be prefered if possible. But
+we cannot avoid using the latter way using commit, for crosslock.
+
+Let's look at how commit works for crosslock.
+
+       RELEASE CONTEXT of a    ACQUIRE CONTEXT of a
+       --------------------    --------------------
+                               acquire a -> mark a as started
+
+       (serialized by some means e.g. barrier)
+
+       acquire D -> queue D
+                               acquire B -> queue B
+       release D
+                               acquire C -> add 'B -> C' and queue C
+       acquire E -> queue E
+                               acquire D -> add 'C -> D' and queue D
+       release E
+                               release D
+       release a -> commit a -> add 'a -> D' and 'a -> E'
+                               release C
+
+                               release B
+
+where a, B,..., E are different lock classes, and upper case letters
+represent typical lock while lower case letters represent crosslock.
+
+When acquiring crosslock a, no dependency can be added since there's
+nothing in the held_locks. However, crossrelease feature marks the
+crosslock as started, which means all locks to acquire from now are
+candidates which might create new dependencies later when identifying
+release context.
+
+When acquiring lock B, lockdep does what it originally does for typical
+lock and additionally queues the lock for later commit to refer to
+because it might be a dependent lock of the crosslock. It does same
+thing on lock C, D and E. And then two dependencies 'a -> D' and 'a -> E'
+are added when identifying the release context, at commit step.
+

Documentation/locking/crossrelease.txt line 733

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+The final graph is, with crossrelease feature using commit,
+
+B -> C -
+        \
+         -> D
+        /
+     a -
+        \
+         -> E
+

Would not the graph also contain edges a->B and a->C, which lockdep would add as it usually does?

Quoted 29 lines
Documentation/locking/crossrelease.txt new file +29 -0
+where a, B,..., E are different lock classes, and upper case letters
+represent typical lock while lower case letters represent crosslock.
+
+However, without crossrelease feature, the final graph will be,
+
+B -> C -> D
+
+where B and C are different lock classes, and upper case letters
+represent typical lock.
+
+The former graph has two more dependencies 'a -> D' and 'a -> E' giving
+additional chances to check if they cause a deadlock. This way lockdep
+can detect a deadlock or its possibility caused by crosslock. Again,
+behaviors adding dependencies created by only typical locks are not
+changed at all.
+
+CONCLUSION
+
+Crossrelease works using commit for crosslock, leaving behaviors adding
+dependencies between only typical locks unchanged.
+
+
+=============
+Optimizations
+=============
+
+Avoid duplication
+-----------------
+

Documentation/locking/crossrelease.txt line 772

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+Crossrelease feature uses a cache like what lockdep already uses for
+dependency chains, but this time it's for caching one dependency like
+'crosslock -> typical lock' crossing between two different context. Once
+that dependency is cached, same dependency will never be added any more.
+Even queueing unnecessary locks is also prevented based on the cache.
+
+CONCLUSION
+
+Crossrelease does not add any duplicate dependency.
+

No need for conclusion.

Quoted 14 lines
Documentation/locking/crossrelease.txt new file +13 -1
+
+Avoid lock contention
+---------------------
+
+To keep all typical locks for later use, crossrelease feature adopts a
+local array embedded in task_struct, which makes accesses to arrays
+lockless by forcing each array to be accessed only within each own
+context. It's like how held_locks is accessed. Lockless implmentation is
+important since typical locks are very frequently accessed.
+
+CONCLUSION
+
+Crossrelease avoids lock contection as far as possible.
--
Quoted 2 lines

1.9.1

No need for conclusion.

Overall, I think I have generally understood what you are trying to do and how are doing it. I think now I'll be able to better review the patches with actual.

Thanks!
Nilay

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#43 lore raw

Re: [PATCH v3 15/15] lockdep: Crossrelease feature documentation

Quoted 73 lines · Nilay Vaish
Quoted 55 lines · Byungchul Park

This document describes the concept of crossrelease feature, which generalizes what causes a deadlock and how can detect a deadlock.

---
 Documentation/locking/crossrelease.txt | 785 +++++++++++++++++++++++++++++++++
 1 file changed, 785 insertions(+)
 create mode 100644 Documentation/locking/crossrelease.txt
Documentation/locking/crossrelease.txt new file +40 -0
new file mode 100644
index 0000000..78558af
@@ -0,0 +1,785 @@
+Crossrelease
+============
+
+Started by Byungchul Park <[email protected]>
+
+Contents:
+
+ (*) Background.
+
+     - What causes deadlock.
+     - What lockdep detects.
+     - How lockdep works.
+
+ (*) Limitation.
+
+     - Limit to typical lock.
+     - Pros from the limitation.
+     - Cons from the limitation.
+
+ (*) Generalization.
+
+     - Relax the limitation.
+
+ (*) Crossrelease.
+
+     - Introduce crossrelease.
+     - Introduce commit.
+
+ (*) Implementation.
+
+     - Data structures.
+     - How crossrelease works.
+
+ (*) Optimizations.
+
+     - Avoid duplication.
+     - Avoid lock contention.
+
+
+==========

Documentation/locking/crossrelease.txt line 50

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+Background
+==========
+
+What causes deadlock
+--------------------
+
+A deadlock occurs when a context is waiting for an event to be issued
+which cannot be issued because the context or another context who can
+issue the event is also waiting for an event to be issued which cannot
+be issued.

I think 'some event happened' and 'context triggered an event' is better than 'some event issued' or 'context issued an event'. I think 'happen' and 'trigger' are more widely used words when we talk about events. For example, I would prefer the following version of the above:

Quoted 3 lines

A deadlock occurs when a context is waiting for an event to happen, which cannot happen because the context which can trigger the event is also waiting for an event to happen which cannot happen either.

Thank you very much for your comments.
I will check it and add my opinions later. :)

Thank you,
Byungchul

Quoted 853 lines

Documentation/locking/crossrelease.txt line 52

Quoted 3 lines
Documentation/locking/crossrelease.txt new file +2 -0
+Single context or more than one context both waiting for an
+event and issuing an event may paricipate in a deadlock.

I am not able to make sense of the line above.

Quoted 16 lines
Documentation/locking/crossrelease.txt new file +16 -0
+
+For example,
+
+A context who can issue event D is waiting for event A to be issued.
+A context who can issue event A is waiting for event B to be issued.
+A context who can issue event B is waiting for event C to be issued.
+A context who can issue event C is waiting for event D to be issued.
+
+A deadlock occurs when these four operations are run at a time because
+event D cannot be issued if event A isn't issued which in turn cannot be
+issued if event B isn't issued which in turn cannot be issued if event C
+isn't issued which in turn cannot be issued if event D isn't issued. No
+event can be issued since any of them never meets its precondition.
+
+We can easily recognize that each wait operation creates a dependency
+between two issuings e.g. between issuing D and issuing A like, 'event D

Documentation/locking/crossrelease.txt line 77

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+cannot be issued if event A isn't issued', in other words, 'issuing
+event D depends on issuing event A'. So the whole example can be
+rewritten in terms of dependency,
+
+Do an operation making 'event D cannot be issued if event A isn't issued'.
+Do an operation making 'event A cannot be issued if event B isn't issued'.
+Do an operation making 'event B cannot be issued if event C isn't issued'.
+Do an operation making 'event C cannot be issued if event D isn't issued'.
+
+or,

I think we can remove the text above. The example only needs to be provided once.

Quoted 19 lines
Documentation/locking/crossrelease.txt new file +19 -0
+
+Do an operation making 'issuing event D depends on issuing event A'.
+Do an operation making 'issuing event A depends on issuing event B'.
+Do an operation making 'issuing event B depends on issuing event C'.
+Do an operation making 'issuing event C depends on issuing event D'.
+
+What causes a deadlock is a set of dependencies a chain of which forms a
+cycle, which means that issuing event D depending on issuing event A
+depending on issuing event B depending on issuing event C depending on
+issuing event D, finally depends on issuing event D itself, which means
+no event can be issued.
+
+Any set of operations creating dependencies causes a deadlock. The set
+of lock operations e.g. acquire and release is an example. Waiting for a
+lock to be released corresponds to waiting for an event and releasing a
+lock corresponds to issuing an event. So the description of dependency
+above can be altered to one in terms of lock.
+
+In terms of event, issuing event A depends on issuing event B if,

Documentation/locking/crossrelease.txt line 106

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+
+       Event A cannot be issued if event B isn't issued.
+
+In terms of lock, releasing lock A depends on releasing lock B if,
+
+       Lock A cannot be released if lock B isn't released.
+
+CONCLUSION
+
+A set of dependencies a chain of which forms a cycle, causes a deadlock,

I think 'a chain of' is not required in the sentence above.

Documentation/locking/crossrelease.txt line 113

Quoted 7 lines
Documentation/locking/crossrelease.txt new file +7 -0
+no matter what creates the dependencies.
+
+
+What lockdep detects
+--------------------
+
+A deadlock actually occurs only when all operations creating problematic

Instead of 'problematic', I would use 'cyclic'.

Documentation/locking/crossrelease.txt line 114

Quoted 1 line
Documentation/locking/crossrelease.txt new file +1 -0
+dependencies are run at a time. However, even if it has not happend, the

dependencies happen at run time. However, even if they don't, the

Documentation/locking/crossrelease.txt line 115

Quoted 1 line
Documentation/locking/crossrelease.txt new file +1 -0
+deadlock potentially can occur if the problematic dependencies obviously

remove obviously

Documentation/locking/crossrelease.txt line 120

Quoted 5 lines
Documentation/locking/crossrelease.txt new file +5 -0
+exist. Thus it's meaningful to detect not only an actual deadlock but
+also its possibility. Lockdep does the both.
+
+Whether a deadlock actually occurs or not depends on several factors,
+which means a deadlock may not occur even though problematic

cyclic instead of problematic

Documentation/locking/crossrelease.txt line 123

Quoted 3 lines
Documentation/locking/crossrelease.txt new file +3 -0
+dependencies exist. For example, what order contexts are switched in is
+a factor. A deadlock will occur when contexts are switched so that all
+operations causing a deadlock become run simultaneously.

delete become.

Documentation/locking/crossrelease.txt line 135

Quoted 12 lines
Documentation/locking/crossrelease.txt new file +12 -0
+
+Lockdep tries to detect a deadlock or its possibility aggressively,
+though it also tries to avoid false positive detections. So lockdep is
+designed to consider all possible combinations of dependencies so that
+it can detect all potential possibilities of deadlock in advance. What
+lockdep tries in order to consider all possibilities are,
+
+1. Use a global dependency graph including all dependencies.
+
+   What lockdep checks is based on dependencies instead of what actually
+   happened. So no matter which context or call path a new dependency is
+   detected in, it's just referred to as a global factor.

Can you explain more what 'global factor' means?

Documentation/locking/crossrelease.txt line 141

Quoted 6 lines
Documentation/locking/crossrelease.txt new file +6 -0
+
+2. Use lock classes than lock instances when checking dependencies.
+
+   What actually causes a deadlock is lock instances. However, lockdep
+   uses lock classes than its instances when checking dependencies since
+   any instance of a same lock class can be altered anytime.

I am unable to make sense of the sentence above. Do you want to say the following:

However, lockdep uses lock classes than its instances when checking dependencies since instances from the same lock class behave in the same (or similar) fashion.

Quoted 34 lines
Documentation/locking/crossrelease.txt new file +34 -0
+
+So lockdep detects both an actual deadlock and its possibility. But the
+latter is more valuable than the former. When a deadlock actually
+occures, we can identify what happens in the system by some means or
+other even without lockdep. However, there's no way to detect possiblity
+without lockdep unless the whole code is parsed in head. It's terrible.
+
+CONCLUSION
+
+Lockdep does, the fisrt one is more valuable,
+
+1. Detecting and reporting deadlock possibility.
+2. Detecting and reporting a deadlock actually occured.
+
+
+How lockdep works
+-----------------
+
+What lockdep should do, to detect a deadlock or its possibility are,
+
+1. Detect a new dependency created.
+2. Keep the dependency in a global data structure esp. graph.
+3. Check if any of all possible chains of dependencies forms a cycle.
+4. Report a deadlock or its possibility if a cycle is detected.
+
+A graph used by lockdep to keep all dependencies looks like,
+
+A -> B -        -> F -> G
+        \      /
+         -> E -        -> L
+        /      \      /
+C -> D -        -> H -
+                      \
+                       -> I -> K

Documentation/locking/crossrelease.txt line 185

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+                      /
+                   J -
+
+where A, B,..., L are different lock classes.
+
+Lockdep adds a dependency into graph when a new dependency is detected.
+For example, it adds a dependency 'A -> B' when a dependency between
+releasing lock A and releasing lock B, which has not been added yet, is
+detected. It does same thing on other dependencies, too. See 'What
+causes deadlock' section.

Just from the text above I am not able to understand at what point the dependency A-> B is added. If I was implementing lockdep, I would probably track all the locks that can be acquired between acquisition and release of A. For example,

acquire A

if (/* some condition */)
acquire B
else
acquire C

release A

I would add to the dependency graph that 'release A' depends on 'acquire B' and 'acquire C'.

Quoted 21 lines
Documentation/locking/crossrelease.txt new file +21 -0
+
+NOTE: Precisely speaking, a dependency is one between releasing a lock
+and releasing another lock as described in 'What causes deadlock'
+section. However from now on, we will describe a dependency as if it's
+one between a lock and another lock for simplicity. Then 'A -> B' can be
+described as a dependency between lock A and lock B.
+
+We already checked how a problematic set of dependencies causes a
+deadlock in 'What causes deadlock' section. This time let's check if a
+deadlock or its possibility can be detected using a problematic set of
+dependencies. Assume that 'A -> B', 'B -> E' and 'E -> A' were added in
+the sequence into graph. Then the graph finally will be,
+
+ -> A -> B -> E -
+/                \
+\                /
+ ----------------
+
+where A, B and E are different lock classes.
+
+From adding three dependencies, a cycle was created which means, by

Documentation/locking/crossrelease.txt line 216

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+definition of dependency, the situation 'lock E must be released to
+release lock B which in turn must be released to release lock A which in
+turn must be released to release lock E which in turn must be released
+to release B and so on infinitely' can happen.
+
+Once the situation happens, no lock can be released since any of them
+can never meet each precondition. It's a deadlock. Lockdep can detect a
+deadlock or its possibility with checking if a cycle was created after
+adding each dependency into graph. This is how lockdep detects a
+deadlock or its possibility.

I think the text here is just repeating what was said above in the 'What causes deadlock' section. You probably should remove of the text here.

Quoted 11 lines
Documentation/locking/crossrelease.txt new file +11 -0
+
+CONCLUSION
+
+Lockdep detects a deadlock or its possibility with checking if a cycle
+was created after adding each dependency into graph.
+
+
+==========
+Limitation
+==========
+

Documentation/locking/crossrelease.txt line 237

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+Limit to typical lock
+---------------------
+
+Limiting what lockdep has to consider to only ones satisfying the
+following condition, the implementation of adding dependencies becomes
+simple while its capacity for detection becomes limited. Typical lock
+e.g. spin lock and mutex is the case. Let's check what pros and cons of
+it are, in next section.
+
+       A lock should be released within the context holding the lock.

I would rephrase the above in the following way: Lockdep is limited to checking dependencies on locks that are released within the context that acquired them. This makes adding dependencies simple but limits lockdep's capacity for detection.

Documentation/locking/crossrelease.txt line 242

Quoted 5 lines
Documentation/locking/crossrelease.txt new file +5 -0
+
+CONCLUSION
+
+Limiting what lockdep has to consider to typical lock e.g. spin lock and
+mutex, the implmentation becomes simple while it has a limited capacity.

I would drop the conclusion altogether. The above paragraph is too small to require a conclusion.

Documentation/locking/crossrelease.txt line 249

Quoted 7 lines
Documentation/locking/crossrelease.txt new file +7 -0
+
+
+Pros from the limitation
+------------------------
+
+Given the limitation, when acquiring a lock, any lock being in
+held_locks of the acquire context cannot be released if the lock to

What does held_locks mean here? Is it some structure maintained by the Linux kernel?

Quoted 23 lines
Documentation/locking/crossrelease.txt new file +23 -0
+acquire was not released yet. Yes. It's the exact case to add a new
+dependency 'A -> B' into graph, where lock A represents each lock being
+in held_locks and lock B represents the lock to acquire.
+
+For example, only considering typical lock,
+
+       PROCESS X
+       --------------
+       acquire A
+
+       acquire B -> add a dependency 'A -> B'
+
+       acquire C -> add a dependency 'B -> C'
+
+       release C
+
+       release B
+
+       release A
+
+where A, B and C are different lock classes.
+
+When acquiring lock A, there's nothing in held_locks of PROCESS X thus

Documentation/locking/crossrelease.txt line 282

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+no dependency is added. When acquiring lock B, lockdep detects and adds
+a new dependency 'A -> B' between lock A being in held_locks and lock B.
+And when acquiring lock C, lockdep also adds another dependency 'B -> C'
+for same reason. They are added when acquiring each lock, simply.
+
+NOTE: Even though every lock being in held_locks depends on the lock to
+acquire, lockdep does not add all dependencies between them because all
+of them can be covered by other dependencies except one dependency
+between the lock on top of held_locks and the lock to acquire, which
+must be added.

I am unable to understand the above sentence. Can you break it into two more sentences?

Quoted 35 lines
Documentation/locking/crossrelease.txt new file +35 -0
+
+Besides, we can expect several advantages from the limitation.
+
+1. Any lock being in held_locks cannot be released unconditionally if
+   the context is stuck, thus we can easily identify a dependency when
+   acquiring a lock.
+
+2. Considering only locks being in local held_locks of a single context
+   makes some races avoidable, even though it fails of course when
+   modifying its global dependency graph.
+
+3. To build a dependency graph, lockdep only needs to keep locks not
+   released yet. However relaxing the limitation, it might need to keep
+   even locks already released, additionally. See 'Crossrelease' section.
+
+CONCLUSION
+
+Given the limitation, the implementation becomes simple and efficient.
+
+
+Cons from the limitation
+------------------------
+
+Given the limitation, lockdep is applicable only to typical lock. For
+example, page lock for page access or completion for synchronization
+cannot play with lockdep having the limitation. However since page lock
+or completion also causes a deadlock, it would be better to detect a
+deadlock or its possibility even for them.
+
+Can we detect deadlocks below with lockdep having the limitation?
+
+Example 1:
+
+       PROCESS X       PROCESS Y
+       --------------  --------------

Documentation/locking/crossrelease.txt line 327

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+       mutext_lock A
+                       lock_page B
+       lock_page B
+                       mutext_lock A // DEADLOCK
+       unlock_page B
+                       mutext_unlock A
+       mutex_unlock A
+                       unlock_page B
+
+where A and B are different lock classes.

I think the formatting is slightly off. The events corresponding to process Y should be shifted more towards right. The vertical ordering would still clearly indicate the order in which the events happened.

Documentation/locking/crossrelease.txt line 330

Quoted 2 lines
Documentation/locking/crossrelease.txt new file +2 -0
+
+No, we cannot.

I do not follow this example. The context that acquired the mutex A or lock B also released it. Should not lockdep be able to detect this? I am guessing I have misunderstood which events occurred in
which context. Here is what I think the example is showing:

X acquired mutex A --> Y acquired lock B --> X tries to acquire B --> Y tries to acquire A --> X and Y are in a deadlock since each of them holds a resource that the other needs.

Quoted 273 lines
Documentation/locking/crossrelease.txt new file +273 -0
+
+Example 2:
+
+       PROCESS X       PROCESS Y       PROCESS Z
+       --------------  --------------  --------------
+                       mutex_lock A
+       lock_page B
+                       lock_page B
+                                       mutext_lock A // DEADLOCK
+                                       mutext_unlock A
+
+                                       unlock_page B held by X
+                       unlock_page B
+                       mutex_unlock A
+
+where A and B are different lock classes.
+
+No, we cannot.
+
+Example 3:
+
+       PROCESS X       PROCESS Y
+       --------------  --------------
+                       mutex_lock A
+       mutex_lock A
+       mutex_unlock A
+                       wait_for_complete B // DEADLOCK
+       complete B
+                       mutex_unlock A
+
+where A is a lock class and B is a completion variable.
+
+No, we cannot.
+
+CONCLUSION
+
+Given the limitation, lockdep cannot detect a deadlock or its
+possibility caused by page lock or completion.
+
+
+==============
+Generalization
+==============
+
+Relax the limitation
+--------------------
+
+Detecting and adding new dependencies into graph is very important for
+lockdep to work because adding a dependency means adding a chance to
+check if it causes a deadlock. More dependencies lockdep adds, more
+throughly it can work. Therefore Lockdep has to do its best to add as
+many true dependencies as possible.
+
+Relaxing the limitation, lockdep can add additional dependencies since
+it makes lockdep deal with additional ones creating the dependencies e.g.
+page lock or completion, which might be released in any context. Even so,
+it needs to be noted that behaviors adding dependencies created by
+typical lock don't need to be changed at all.
+
+For example, only considering typical lock, lockdep builds a graph like,
+
+A -> B -        -> F -> G
+        \      /
+         -> E -        -> L
+        /      \      /
+C -> D -        -> H -
+                      \
+                       -> I -> K
+                      /
+                   J -
+
+where A, B,..., L are different lock classes, and upper case letters
+represent typical lock.
+
+After the relaxing, the graph will have additional dependencies like,
+
+A -> B -        -> F -> G
+        \      /
+         -> E -        -> L -> c
+        /      \      /
+C -> D -        -> H -
+               /      \
+            a -        -> I -> K
+                      /
+              b -> J -
+
+where a, b, c, A, B,..., L are different lock classes, and upper case
+letters represent typical lock while lower case letters represent
+non-typical lock e.g. page lock and completion.
+
+However, it might suffer performance degradation since relaxing the
+limitation with which design and implementation of lockdep become
+efficient might introduce inefficiency inevitably. Each option, that is,
+strong detection or efficient detection has its pros and cons, thus the
+right of choice between two options should be given to users.
+
+Choosing efficient detection, lockdep only deals with locks satisfying,
+
+       A lock should be released within the context holding the lock.
+
+Choosing strong detection, lockdep deals with any locks satisfying,
+
+       A lock can be released in any context.
+
+In the latter, of course, some contexts are not allowed if they
+themselves cause a deadlock. For example, acquiring a lock in irq-safe
+context before releasing the lock in irq-unsafe context is not allowed,
+which after all ends in a cycle of a dependency chain, meaning a
+deadlock. Otherwise, any contexts are allowed to release it.
+
+CONCLUSION
+
+Relaxing the limitation, lockdep adds additional dependencies and gets
+additional chances to check if they cause a deadlock. It makes lockdep
+additionally deal with what might be released in any context.
+
+
+============
+Crossrelease
+============
+
+Introduce crossrelease
+----------------------
+
+To allow lockdep to add additional dependencies created by what might be
+released in any context, which we call 'crosslock', it's necessary to
+introduce a new feature which makes it possible to identify and add the
+dependencies. We call the feature 'crossrelease'. Crossrelease feature
+has to do,
+
+1. Identify a new dependency created by crosslock.
+2. Add the dependency into graph when identifying it.
+
+That's all. Once a meaningful dependency is added into graph, lockdep
+will work with the graph as it did. So the most important thing to do is
+to identify a dependency created by crosslock. Remind what a dependency
+is. For example, Lock A depends on lock B if 'lock A cannot be released
+if lock B isn't released'. See 'What causes deadlock' section.
+
+By definition, a lock depends on every lock having been added into
+held_locks in the lock's release context since the lock was acquired,
+because the lock cannot be released if the release context is stuck by
+any of dependent locks, not released. So lockdep should technically
+consider release contexts of locks to identify dependencies.
+
+It's no matter of course to typical lock because acquire context is same
+as release context for typical lock, which means lockdep would work with
+considering only acquire contexts for typical lock. However, for
+crosslock, lockdep cannot identify release context and any dependency
+until the crosslock will be actually released.
+
+Regarding crosslock, lockdep has to record all history by queueing all
+locks potentially creating dependencies so that real dependencies can be
+added using the history recorded when identifying release context. We
+call it 'commit', that is, to add dependencies in batches. See
+'Introduce commit' section.
+
+Of course, some actual deadlocks caused by crosslock cannot be detected
+at the time it happened, because the deadlocks cannot be indentified and
+detected until the crosslock will be actually released. But this way
+deadlock possibility can be detected and it's worth just possibility
+detection of deadlock. See 'What lockdep does' section.
+
+CONCLUSION
+
+With crossrelease feature, lockdep can works with what might be released
+in any context, namely, crosslock.
+
+
+Introduce commit
+----------------
+
+Crossrelease feature names it 'commit' to identify and add dependencies
+into graph in batches. Lockdep is already doing what commit does when
+acquiring a lock, for typical lock. However, that way must be changed
+for crosslock so that it identifies the crosslock's release context
+first and then does commit.
+
+The main reason why lockdep performs additional step, namely commit, for
+crosslock is that some dependencies by crosslock cannot be identified
+until the crosslock's release context is eventually identified, though
+some other dependencies by crosslock can. There are four kinds of
+dependencies to consider.
+
+1. 'typical lock A -> typical lock B' dependency
+
+   Just when acquiring lock B, lockdep can identify the dependency
+   between lock A and lock B as it did. Commit is unnecessary.
+
+2. 'typical lock A -> crosslock b' dependency
+
+   Just when acquiring crosslock b, lockdep can identify the dependency
+   between lock A and crosslock B as well. Commit is unnecessary, too.
+
+3. 'crosslock a -> typical lock B' dependency
+
+   When acquiring lock B, lockdep cannot identify the dependency. It can
+   be identified only when crosslock a is released. Commit is necessary.
+
+4. 'crosslock a -> crosslock b' dependency
+
+   Creating this kind of dependency directly is unnecessary since it can
+   be covered by other kinds of dependencies.
+
+Lockdep works without commit during dealing with only typical locks.
+However, it needs to perform commit step, once at least one crosslock is
+acquired, until all crosslocks in progress are released. Introducing
+commit, lockdep performs three steps i.e. acquire, commit and release.
+What lockdep should do in each step is like,
+
+1. Acquire
+
+   1) For typical lock
+
+       Lockdep does what it originally does and queues the lock so
+       that lockdep can check dependencies using it at commit step.
+
+   2) For crosslock
+
+       The crosslock is added to a global linked list so that lockdep
+       can check dependencies using it at commit step.
+
+2. Commit
+
+   1) For typical lock
+
+       N/A.
+
+   2) For crosslock
+
+       Lockdep checks and adds dependencies using data saved at acquire
+       step, as if the dependencies were added without commit step.
+
+3. Release
+
+   1) For typical lock
+
+       No change.
+
+   2) For crosslock
+
+       Lockdep just remove the crosslock from the global linked list,
+       to which it was added at acquire step.
+
+CONCLUSION
+
+Lockdep can detect a deadlock or its possibility caused by what might be
+released in any context, using commit step, where it checks and adds
+dependencies in batches.
+
+
+==============
+Implementation
+==============
+
+Data structures
+---------------
+
+Crossrelease feature introduces two main data structures.
+
+1. pend_lock (or plock)
+
+   This is an array embedded in task_struct, for keeping locks queued so
+   that real dependencies can be added using them at commit step. So
+   this data can be accessed locklessly within the owner context. The
+   array is filled when acquiring a typical lock and consumed when doing
+   commit. And it's managed in circular manner.
+
+2. cross_lock (or xlock)
+
+   This is a global linked list, for keeping all crosslocks in progress.
+   The list grows when acquiring a crosslock and is shrunk when
+   releasing the crosslock. lockdep_init_map_crosslock() should be used

Documentation/locking/crossrelease.txt line 612

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+   to initialize a crosslock instance instead of lockdep_init_map() so
+   that lockdep can recognize it as crosslock.
+
+CONCLUSION
+
+Crossrelease feature uses two main data structures.
+
+1. A pend_lock array for queueing typical locks in circular manner.
+2. A cross_lock linked list for managing crosslocks in progress.
+

Drop these conclusion, not need at all.

Quoted 111 lines
Documentation/locking/crossrelease.txt new file +111 -0
+
+How crossrelease works
+----------------------
+
+Let's take look at how crossrelease feature works step by step, starting
+from how lockdep works without crossrelease feaure.
+
+For example, the below is how lockdep works for typical lock.
+
+       RELEASE CONTEXT of A (= ACQUIRE CONTEXT of A)
+       --------------------
+       acquire A
+
+       acquire B -> add a dependency 'A -> B'
+
+       acquire C -> add a dependency 'B -> C'
+
+       release C
+
+       release B
+
+       release A
+
+where A, B and C are different lock classes, and upper case letters
+represent typical lock.
+
+After adding 'A -> B', the dependency graph will be,
+
+A -> B
+
+where A and B are different lock classes, and upper case letters
+represent typical lock.
+
+And after adding 'B -> C', the graph will be,
+
+A -> B -> C
+
+where A, B and C are different lock classes, and upper case letters
+represent typical lock.
+
+What if applying commit on typical locks? It's not necessary for typical
+lock. Just for showing what commit does.
+
+       RELEASE CONTEXT of A (= ACQUIRE CONTEXT of A)
+       --------------------
+       acquire A -> mark A as started (nothing before, no queueing)
+
+       acquire B -> mark B as started and queue B
+
+       acquire C -> mark C as started and queue C
+
+       release C -> commit C (nothing queued since C started)
+
+       release B -> commit B -> add a dependency 'B -> C'
+
+       release A -> commit A -> add dependencies 'A -> B' and 'A -> C'
+
+where A, B and C are different lock classes, and upper case letters
+represent typical lock.
+
+After doing commit A, B and C, the dependency graph becomes like,
+
+A -> B -> C
+
+where A, B and C are different lock classes, and upper case letters
+represent typical lock.
+
+NOTE: A dependency 'A -> C' is optimized out.
+
+Here we can see the final graph is same as the graph built without
+commit. Of course the former way leads to finish building the graph
+earlier than the latter way, which means we can detect a deadlock or its
+possibility sooner. So the former way would be prefered if possible. But
+we cannot avoid using the latter way using commit, for crosslock.
+
+Let's look at how commit works for crosslock.
+
+       RELEASE CONTEXT of a    ACQUIRE CONTEXT of a
+       --------------------    --------------------
+                               acquire a -> mark a as started
+
+       (serialized by some means e.g. barrier)
+
+       acquire D -> queue D
+                               acquire B -> queue B
+       release D
+                               acquire C -> add 'B -> C' and queue C
+       acquire E -> queue E
+                               acquire D -> add 'C -> D' and queue D
+       release E
+                               release D
+       release a -> commit a -> add 'a -> D' and 'a -> E'
+                               release C
+
+                               release B
+
+where a, B,..., E are different lock classes, and upper case letters
+represent typical lock while lower case letters represent crosslock.
+
+When acquiring crosslock a, no dependency can be added since there's
+nothing in the held_locks. However, crossrelease feature marks the
+crosslock as started, which means all locks to acquire from now are
+candidates which might create new dependencies later when identifying
+release context.
+
+When acquiring lock B, lockdep does what it originally does for typical
+lock and additionally queues the lock for later commit to refer to
+because it might be a dependent lock of the crosslock. It does same
+thing on lock C, D and E. And then two dependencies 'a -> D' and 'a -> E'
+are added when identifying the release context, at commit step.
+

Documentation/locking/crossrelease.txt line 733

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+The final graph is, with crossrelease feature using commit,
+
+B -> C -
+        \
+         -> D
+        /
+     a -
+        \
+         -> E
+

Would not the graph also contain edges a->B and a->C, which lockdep would add as it usually does?

Quoted 29 lines
Documentation/locking/crossrelease.txt new file +29 -0
+where a, B,..., E are different lock classes, and upper case letters
+represent typical lock while lower case letters represent crosslock.
+
+However, without crossrelease feature, the final graph will be,
+
+B -> C -> D
+
+where B and C are different lock classes, and upper case letters
+represent typical lock.
+
+The former graph has two more dependencies 'a -> D' and 'a -> E' giving
+additional chances to check if they cause a deadlock. This way lockdep
+can detect a deadlock or its possibility caused by crosslock. Again,
+behaviors adding dependencies created by only typical locks are not
+changed at all.
+
+CONCLUSION
+
+Crossrelease works using commit for crosslock, leaving behaviors adding
+dependencies between only typical locks unchanged.
+
+
+=============
+Optimizations
+=============
+
+Avoid duplication
+-----------------
+

Documentation/locking/crossrelease.txt line 772

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+Crossrelease feature uses a cache like what lockdep already uses for
+dependency chains, but this time it's for caching one dependency like
+'crosslock -> typical lock' crossing between two different context. Once
+that dependency is cached, same dependency will never be added any more.
+Even queueing unnecessary locks is also prevented based on the cache.
+
+CONCLUSION
+
+Crossrelease does not add any duplicate dependency.
+

No need for conclusion.

Quoted 14 lines
Documentation/locking/crossrelease.txt new file +13 -1
+
+Avoid lock contention
+---------------------
+
+To keep all typical locks for later use, crossrelease feature adopts a
+local array embedded in task_struct, which makes accesses to arrays
+lockless by forcing each array to be accessed only within each own
+context. It's like how held_locks is accessed. Lockless implmentation is
+important since typical locks are very frequently accessed.
+
+CONCLUSION
+
+Crossrelease avoids lock contection as far as possible.
--
Quoted 2 lines

1.9.1

No need for conclusion.

Quoted 6 lines

Overall, I think I have generally understood what you are trying to do and how are doing it. I think now I'll be able to better review the patches with actual.

Thanks!
Nilay

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#44 lore raw

Re: [PATCH v3 15/15] lockdep: Crossrelease feature documentation

In reply to Nilay Vaish
Quoted 18 lines · Nilay Vaish

Documentation/locking/crossrelease.txt

Quoted 11 lines

+==========

Documentation/locking/crossrelease.txt new file +10 -0
+Background
+==========
+
+What causes deadlock
+--------------------
+
+A deadlock occurs when a context is waiting for an event to be issued
+which cannot be issued because the context or another context who can
+issue the event is also waiting for an event to be issued which cannot
+be issued.

I think 'some event happened' and 'context triggered an event' is better than 'some event issued' or 'context issued an event'. I think 'happen' and 'trigger' are more widely used words when we talk about events. For example, I would prefer the following version of the above:

Quoted 3 lines

A deadlock occurs when a context is waiting for an event to happen, which cannot happen because the context which can trigger the event is also waiting for an event to happen which cannot happen either.

Looks good.

Quoted 5 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+Single context or more than one context both waiting for an
+event and issuing an event may paricipate in a deadlock.

I am not able to make sense of the line above.

I meant that only one context can be in deadlock by itself, like

A
=
lock a <= waiting
lock b
lock a
unlock a <= triggering
unlock b
unlock a

and more than one context also can be in deadlock, like

A B
= =
lock b lock a
lock a lock b
unlock a unlock b
unlock b unlock a

Is there any alterative to describ it?

Quoted 22 lines
Quoted 22 lines
Documentation/locking/crossrelease.txt new file +21 -0
+
+For example,
+
+A context who can issue event D is waiting for event A to be issued.
+A context who can issue event A is waiting for event B to be issued.
+A context who can issue event B is waiting for event C to be issued.
+A context who can issue event C is waiting for event D to be issued.
+
+A deadlock occurs when these four operations are run at a time because
+event D cannot be issued if event A isn't issued which in turn cannot be
+issued if event B isn't issued which in turn cannot be issued if event C
+isn't issued which in turn cannot be issued if event D isn't issued. No
+event can be issued since any of them never meets its precondition.
+
+We can easily recognize that each wait operation creates a dependency
+between two issuings e.g. between issuing D and issuing A like, 'event D
+cannot be issued if event A isn't issued', in other words, 'issuing
+event D depends on issuing event A'. So the whole example can be
+rewritten in terms of dependency,
+
+Do an operation making 'event D cannot be issued if event A isn't issued'.
Quoted 8 lines

Documentation/locking/crossrelease.txt line 77

Quoted 5 lines
Documentation/locking/crossrelease.txt new file +5 -0
+Do an operation making 'event A cannot be issued if event B isn't issued'.
+Do an operation making 'event B cannot be issued if event C isn't issued'.
+Do an operation making 'event C cannot be issued if event D isn't issued'.
+
+or,

I think we can remove the text above. The example only needs to be provided once.

I tried not to miss any subtle desciption AFAP. I thought and decided that I need to explain what a dependecy is, without any hole in logic.

Quoted 24 lines
Quoted 24 lines
Documentation/locking/crossrelease.txt new file +23 -0
+
+Do an operation making 'issuing event D depends on issuing event A'.
+Do an operation making 'issuing event A depends on issuing event B'.
+Do an operation making 'issuing event B depends on issuing event C'.
+Do an operation making 'issuing event C depends on issuing event D'.
+
+What causes a deadlock is a set of dependencies a chain of which forms a
+cycle, which means that issuing event D depending on issuing event A
+depending on issuing event B depending on issuing event C depending on
+issuing event D, finally depends on issuing event D itself, which means
+no event can be issued.
+
+Any set of operations creating dependencies causes a deadlock. The set
+of lock operations e.g. acquire and release is an example. Waiting for a
+lock to be released corresponds to waiting for an event and releasing a
+lock corresponds to issuing an event. So the description of dependency
+above can be altered to one in terms of lock.
+
+In terms of event, issuing event A depends on issuing event B if,
+
+       Event A cannot be issued if event B isn't issued.
+
+In terms of lock, releasing lock A depends on releasing lock B if,
Quoted 8 lines

Documentation/locking/crossrelease.txt line 106

Quoted 6 lines
Documentation/locking/crossrelease.txt new file +6 -0
+
+       Lock A cannot be released if lock B isn't released.
+
+CONCLUSION
+
+A set of dependencies a chain of which forms a cycle, causes a deadlock,

I think 'a chain of' is not required in the sentence above.

Do you think so? Actually a chain forms a cycle. I thought dependencies are not stuffs making a cycle.

Quoted 10 lines

Documentation/locking/crossrelease.txt line 113

Quoted 8 lines
Documentation/locking/crossrelease.txt new file +7 -0
+no matter what creates the dependencies.
+
+
+What lockdep detects
+--------------------
+
+A deadlock actually occurs only when all operations creating problematic

Instead of 'problematic', I would use 'cyclic'.

I'd like to highlight _problematic_. Is it better to use a specific word, like 'cycle'?

Quoted 4 lines
Quoted 2 lines

+dependencies are run at a time. However, even if it has not happend, the

dependencies happen at run time. However, even if they don't, the

It ends in "operations happen". Is it a right expression?

Quoted 4 lines
Quoted 2 lines

+deadlock potentially can occur if the problematic dependencies obviously

remove obviously

Ok.

Quoted 9 lines

Documentation/locking/crossrelease.txt line 120

Quoted 6 lines
Documentation/locking/crossrelease.txt new file +5 -0
+exist. Thus it's meaningful to detect not only an actual deadlock but
+also its possibility. Lockdep does the both.
+
+Whether a deadlock actually occurs or not depends on several factors,
+which means a deadlock may not occur even though problematic

cyclic instead of problematic

Quoted 5 lines

Documentation/locking/crossrelease.txt line 123

Quoted 3 lines
Documentation/locking/crossrelease.txt new file +3 -0
+dependencies exist. For example, what order contexts are switched in is
+a factor. A deadlock will occur when contexts are switched so that all
+operations causing a deadlock become run simultaneously.

delete become.

Ok.

Quoted 15 lines

Documentation/locking/crossrelease.txt line 135

Quoted 13 lines
Documentation/locking/crossrelease.txt new file +12 -0
+
+Lockdep tries to detect a deadlock or its possibility aggressively,
+though it also tries to avoid false positive detections. So lockdep is
+designed to consider all possible combinations of dependencies so that
+it can detect all potential possibilities of deadlock in advance. What
+lockdep tries in order to consider all possibilities are,
+
+1. Use a global dependency graph including all dependencies.
+
+   What lockdep checks is based on dependencies instead of what actually
+   happened. So no matter which context or call path a new dependency is
+   detected in, it's just referred to as a global factor.

Can you explain more what 'global factor' means?

I'm sorry. My words might be wrong. :(
I wanted to say "there's only one global data managing dependencies".

Quoted 12 lines

Documentation/locking/crossrelease.txt line 141

Quoted 8 lines
Documentation/locking/crossrelease.txt new file +6 -0
+
+2. Use lock classes than lock instances when checking dependencies.
+
+   What actually causes a deadlock is lock instances. However, lockdep
+   uses lock classes than its instances when checking dependencies since
+   any instance of a same lock class can be altered anytime.

I am unable to make sense of the sentence above. Do you want to say the following:

Quoted 3 lines

However, lockdep uses lock classes than its instances when checking dependencies since instances from the same lock class behave in the same (or similar) fashion.

I wanted to say,

For example,

do_handle_something(struct data *d)
{
lock d->a of class A
handle data protected by d->a
unlcok d->a
}

where d can be different between calls but it's always one of class A.

I expressed it as 'altered'.

Quoted 58 lines
Quoted 35 lines
Documentation/locking/crossrelease.txt new file +34 -0
+
+So lockdep detects both an actual deadlock and its possibility. But the
+latter is more valuable than the former. When a deadlock actually
+occures, we can identify what happens in the system by some means or
+other even without lockdep. However, there's no way to detect possiblity
+without lockdep unless the whole code is parsed in head. It's terrible.
+
+CONCLUSION
+
+Lockdep does, the fisrt one is more valuable,
+
+1. Detecting and reporting deadlock possibility.
+2. Detecting and reporting a deadlock actually occured.
+
+
+How lockdep works
+-----------------
+
+What lockdep should do, to detect a deadlock or its possibility are,
+
+1. Detect a new dependency created.
+2. Keep the dependency in a global data structure esp. graph.
+3. Check if any of all possible chains of dependencies forms a cycle.
+4. Report a deadlock or its possibility if a cycle is detected.
+
+A graph used by lockdep to keep all dependencies looks like,
+
+A -> B -        -> F -> G
+        \      /
+         -> E -        -> L
+        /      \      /
+C -> D -        -> H -
+                      \
+                       -> I -> K

Documentation/locking/crossrelease.txt line 185

Quoted 10 lines
Documentation/locking/crossrelease.txt new file +10 -0
+                      /
+                   J -
+
+where A, B,..., L are different lock classes.
+
+Lockdep adds a dependency into graph when a new dependency is detected.
+For example, it adds a dependency 'A -> B' when a dependency between
+releasing lock A and releasing lock B, which has not been added yet, is
+detected. It does same thing on other dependencies, too. See 'What
+causes deadlock' section.

Just from the text above I am not able to understand at what point the dependency A-> B is added. If I was implementing lockdep, I would probably track all the locks that can be acquired between acquisition and release of A. For example,

acquire A

if (/* some condition */)
acquire B
else
acquire C

Quoted 5 lines

release A

I would add to the dependency graph that 'release A' depends on 'acquire B' and 'acquire C'.

It's not wrong. But each acquire B(or C) in turn depends on each release B(or C) when it fails to acquire them right away.

Thus, 'release A depends on release B and release C'.

That's what I wanted to say.

Quoted 28 lines
Quoted 28 lines
Documentation/locking/crossrelease.txt new file +27 -0
+
+NOTE: Precisely speaking, a dependency is one between releasing a lock
+and releasing another lock as described in 'What causes deadlock'
+section. However from now on, we will describe a dependency as if it's
+one between a lock and another lock for simplicity. Then 'A -> B' can be
+described as a dependency between lock A and lock B.
+
+We already checked how a problematic set of dependencies causes a
+deadlock in 'What causes deadlock' section. This time let's check if a
+deadlock or its possibility can be detected using a problematic set of
+dependencies. Assume that 'A -> B', 'B -> E' and 'E -> A' were added in
+the sequence into graph. Then the graph finally will be,
+
+ -> A -> B -> E -
+/                \
+\                /
+ ----------------
+
+where A, B and E are different lock classes.
+
+From adding three dependencies, a cycle was created which means, by
+definition of dependency, the situation 'lock E must be released to
+release lock B which in turn must be released to release lock A which in
+turn must be released to release lock E which in turn must be released
+to release B and so on infinitely' can happen.
+
+Once the situation happens, no lock can be released since any of them
Quoted 8 lines

Documentation/locking/crossrelease.txt line 216

Quoted 4 lines
Documentation/locking/crossrelease.txt new file +4 -0
+can never meet each precondition. It's a deadlock. Lockdep can detect a
+deadlock or its possibility with checking if a cycle was created after
+adding each dependency into graph. This is how lockdep detects a
+deadlock or its possibility.

I think the text here is just repeating what was said above in the 'What causes deadlock' section. You probably should remove of the text here.

Yes. I will check it.

Quoted 19 lines
Quoted 19 lines
Documentation/locking/crossrelease.txt new file +18 -0
+
+CONCLUSION
+
+Lockdep detects a deadlock or its possibility with checking if a cycle
+was created after adding each dependency into graph.
+
+
+==========
+Limitation
+==========
+
+Limit to typical lock
+---------------------
+
+Limiting what lockdep has to consider to only ones satisfying the
+following condition, the implementation of adding dependencies becomes
+simple while its capacity for detection becomes limited. Typical lock
+e.g. spin lock and mutex is the case. Let's check what pros and cons of
Quoted 8 lines

Documentation/locking/crossrelease.txt line 237

Quoted 3 lines
Documentation/locking/crossrelease.txt new file +3 -0
+it are, in next section.
+
+       A lock should be released within the context holding the lock.

I would rephrase the above in the following way: Lockdep is limited to checking dependencies on locks that are released within the context that acquired them. This makes adding dependencies simple but limits lockdep's capacity for detection.

It looks better to me. I'll try to rephrase it.

Quoted 10 lines

Documentation/locking/crossrelease.txt line 242

Quoted 7 lines
Documentation/locking/crossrelease.txt new file +5 -0
+
+CONCLUSION
+
+Limiting what lockdep has to consider to typical lock e.g. spin lock and
+mutex, the implmentation becomes simple while it has a limited capacity.

I would drop the conclusion altogether. The above paragraph is too small to require a conclusion.

I'm not sure. I want to let one read only conclusions, who want to get only conclusions.

Quoted 11 lines

Documentation/locking/crossrelease.txt line 249

Quoted 8 lines
Documentation/locking/crossrelease.txt new file +7 -0
+
+
+Pros from the limitation
+------------------------
+
+Given the limitation, when acquiring a lock, any lock being in
+held_locks of the acquire context cannot be released if the lock to

What does held_locks mean here? Is it some structure maintained by the Linux kernel?

Exactly. It's embedded in struct task as an array.

Quoted 29 lines
Quoted 29 lines
Documentation/locking/crossrelease.txt new file +28 -0
+acquire was not released yet. Yes. It's the exact case to add a new
+dependency 'A -> B' into graph, where lock A represents each lock being
+in held_locks and lock B represents the lock to acquire.
+
+For example, only considering typical lock,
+
+       PROCESS X
+       --------------
+       acquire A
+
+       acquire B -> add a dependency 'A -> B'
+
+       acquire C -> add a dependency 'B -> C'
+
+       release C
+
+       release B
+
+       release A
+
+where A, B and C are different lock classes.
+
+When acquiring lock A, there's nothing in held_locks of PROCESS X thus
+no dependency is added. When acquiring lock B, lockdep detects and adds
+a new dependency 'A -> B' between lock A being in held_locks and lock B.
+And when acquiring lock C, lockdep also adds another dependency 'B -> C'
+for same reason. They are added when acquiring each lock, simply.
+
Quoted 8 lines

Documentation/locking/crossrelease.txt line 282

Quoted 5 lines
Documentation/locking/crossrelease.txt new file +5 -0
+NOTE: Even though every lock being in held_locks depends on the lock to
+acquire, lockdep does not add all dependencies between them because all
+of them can be covered by other dependencies except one dependency
+between the lock on top of held_locks and the lock to acquire, which
+must be added.

I am unable to understand the above sentence. Can you break it into two more sentences?

Sorry. I will try to explain it in more detail.

Quoted 42 lines
Quoted 42 lines
Documentation/locking/crossrelease.txt new file +41 -0
+
+Besides, we can expect several advantages from the limitation.
+
+1. Any lock being in held_locks cannot be released unconditionally if
+   the context is stuck, thus we can easily identify a dependency when
+   acquiring a lock.
+
+2. Considering only locks being in local held_locks of a single context
+   makes some races avoidable, even though it fails of course when
+   modifying its global dependency graph.
+
+3. To build a dependency graph, lockdep only needs to keep locks not
+   released yet. However relaxing the limitation, it might need to keep
+   even locks already released, additionally. See 'Crossrelease' section.
+
+CONCLUSION
+
+Given the limitation, the implementation becomes simple and efficient.
+
+
+Cons from the limitation
+------------------------
+
+Given the limitation, lockdep is applicable only to typical lock. For
+example, page lock for page access or completion for synchronization
+cannot play with lockdep having the limitation. However since page lock
+or completion also causes a deadlock, it would be better to detect a
+deadlock or its possibility even for them.
+
+Can we detect deadlocks below with lockdep having the limitation?
+
+Example 1:
+
+       PROCESS X       PROCESS Y
+       --------------  --------------
+       mutext_lock A
+                       lock_page B
+       lock_page B
+                       mutext_lock A // DEADLOCK
+       unlock_page B
+                       mutext_unlock A
Quoted 8 lines

Documentation/locking/crossrelease.txt line 327

Quoted 4 lines
Documentation/locking/crossrelease.txt new file +4 -0
+       mutex_unlock A
+                       unlock_page B
+
+where A and B are different lock classes.

I think the formatting is slightly off. The events corresponding to process Y should be shifted more towards right. The vertical ordering would still clearly indicate the order in which the events happened.

Do you think it's better to shift it?

Quoted 10 lines

Review

Quoted 4 lines
(quoted diff) +2 -0
+
+No, we cannot.

I do not follow this example. The context that acquired the mutex A or lock B also released it. Should not lockdep be able to detect this? I am guessing I have misunderstood which events occurred in
which context. Here is what I think the example is showing:

Quoted 3 lines

X acquired mutex A --> Y acquired lock B --> X tries to acquire B --> Y tries to acquire A --> X and Y are in a deadlock since each of them holds a resource that the other needs.

Current lockdep is not able to deal with (un)lock_page thingy at all.

Quoted 41 lines
Quoted 41 lines
Documentation/locking/crossrelease.txt new file +41 -0
+Let's look at how commit works for crosslock.
+
+       RELEASE CONTEXT of a    ACQUIRE CONTEXT of a
+       --------------------    --------------------
+                               acquire a -> mark a as started
+
+       (serialized by some means e.g. barrier)
+
+       acquire D -> queue D
+                               acquire B -> queue B
+       release D
+                               acquire C -> add 'B -> C' and queue C
+       acquire E -> queue E
+                               acquire D -> add 'C -> D' and queue D
+       release E
+                               release D
+       release a -> commit a -> add 'a -> D' and 'a -> E'
+                               release C
+
+                               release B
+
+where a, B,..., E are different lock classes, and upper case letters
+represent typical lock while lower case letters represent crosslock.
+
+When acquiring crosslock a, no dependency can be added since there's
+nothing in the held_locks. However, crossrelease feature marks the
+crosslock as started, which means all locks to acquire from now are
+candidates which might create new dependencies later when identifying
+release context.
+
+When acquiring lock B, lockdep does what it originally does for typical
+lock and additionally queues the lock for later commit to refer to
+because it might be a dependent lock of the crosslock. It does same
+thing on lock C, D and E. And then two dependencies 'a -> D' and 'a -> E'
+are added when identifying the release context, at commit step.
+
+The final graph is, with crossrelease feature using commit,
+
+B -> C -
+        \
+         -> D
Quoted 8 lines

Documentation/locking/crossrelease.txt line 733

Quoted 5 lines
Documentation/locking/crossrelease.txt new file +5 -0
+        /
+     a -
+        \
+         -> E
+

Would not the graph also contain edges a->B and a->C, which lockdep would add as it usually does?

No. 'a' is a crosslock. We should not add 'a->B(or C)' dependency. In other words, 'a' can be released without releasing B(or C), by another context.

Quoted 3 lines

Overall, I think I have generally understood what you are trying to do and how are doing it. I think now I'll be able to better review the patches with actual.

Thanks a lot. Your comment would be helpful.

Thank you,
Byungchul

Quoted 3 lines

Thanks!
Nilay

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#45 lore raw

[FYI] Output of 'cat /proc/lockdep' after applying crossrelease

In reply to Byungchul Park

all lock classes:
c1c8b858 FD: 38 BD: 1 +.+...: cgroup_mutex
-> [c1c8b7b0] cgroup_idr_lock
-> [c1c934b8] pcpu_alloc_mutex
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1c8b770] cgroup_file_kn_lock
-> [c1c8b7f0] css_set_lock
-> [c1c8bbb8] freezer_mutex

c1cd86c8 FD: 1 BD: 104 -.-...: input_pool.lock

c1cd85c8 FD: 1 BD: 103 ..-...: nonblocking_pool.lock

c1c80634 FD: 2 BD: 16 ++++..: resource_lock
-> [c1c805f0] bootmem_resource_lock

c1c7f3f0 FD: 1 BD: 21 +.+...: pgd_lock

c1c7e1d8 FD: 12 BD: 1 +.+...: acpi_ioapic_lock
-> [c1c7e6d0] ioapic_lock
-> [c1c7e698] ioapic_mutex

c1c7e6d0 FD: 2 BD: 71 -.-...: ioapic_lock
-> [c1c7bdb0] i8259A_lock

c1cf63d0 FD: 1 BD: 1 ......: map_entries_lock

c1c7d7b0 FD: 1 BD: 1 ......: x86_mce_decoder_chain.lock

c1c89db8 FD: 44 BD: 2 +.+...: clocksource_mutex
-> [c1c89d10] watchdog_lock

c1c89d10 FD: 9 BD: 4 +.-...: watchdog_lock
-> [c259f24c] &(&base->lock)->rlock
-> [c1e0a1a4] &(&pool->lock)->rlock

c1c7ff18 FD: 172 BD: 2 +.+.+.: cpu_add_remove_lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25bc6b4] &swhash->hlist_mutex
-> [c1c7fec0] cpu_hotplug.lock
-> [c1e0a1a4] &(&pool->lock)->rlock
-> [c1e08e10] (complete)&work.complete
-> [c1e08e08] &x->wait#6
-> [c1e0a8bc] &rq->lock
-> [c25db814] &x->wait#3
-> [c1cddc78] gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1cde990] req_lock
-> [c1e098e4] &p->pi_lock
-> [c25db718] (complete)&req.done
-> [c25db710] &x->wait#5
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c1e06400] subsys mutex#18
-> [c1e0640c] subsys mutex#19
-> [c1c934b8] pcpu_alloc_mutex
-> [c1e0a16c] &wq->mutex
-> [c1c82a10] kthread_create_lock
-> [c1e0a360] (complete)&done
-> [c1e0a358] &x->wait
-> [c1c827b8] wq_pool_mutex
-> [c259f24c] &(&base->lock)->rlock
-> [c25c4058] &(&n->list_lock)->rlock
-> [c2607b50] &(&k->k_lock)->rlock

c1c90058 FD: 42 BD: 8 +.+...: jump_label_mutex

c25bc904 FD: 1 BD: 164 ..-...: &(&zone->lock)->rlock

c1c934b8 FD: 2 BD: 77 +.+.+.: pcpu_alloc_mutex
-> [c1c934f0] pcpu_lock

c1c934f0 FD: 1 BD: 80 ..-...: pcpu_lock

c25c4058 FD: 1 BD: 8 -.-...: &(&n->list_lock)->rlock

c1c7fec0 FD: 41 BD: 3 ++++++: cpu_hotplug.lock
-> [c1c7fea8] cpu_hotplug.lock#2

c1c7fea8 FD: 40 BD: 26 +.+.+.: cpu_hotplug.lock#2
-> [c1c7fe54] cpu_hotplug.wq.lock
-> [c1e098e4] &p->pi_lock
-> [c1c830d8] smpboot_threads_lock
-> [c25bc6b4] &swhash->hlist_mutex
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c82a10] kthread_create_lock
-> [c1e0a360] (complete)&done
-> [c1e0a358] &x->wait
-> [c1e0a8bc] &rq->lock
-> [c1e0a184] &pool->attach_mutex
-> [c1e0a1a4] &(&pool->lock)->rlock
-> [c25bc904] &(&zone->lock)->rlock
-> [c259f1d0] rcu_node_0
-> [c1c934b8] pcpu_alloc_mutex
-> [c1c8cf98] relay_channels_mutex
-> [c1c7c378] smp_alt
-> [c1c878d8] sparse_irq_lock
-> [c1e09d9d] (complete)&st->done
-> [c1e09d95] &x->wait#2

c1c93558 FD: 47 BD: 14 +.+.+.: slab_mutex
-> [c1c934b8] pcpu_alloc_mutex
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c25b4244] &(kretprobe_table_locks[i].lock)

c1e0aa3c FD: 1 BD: 2 +.+...: &dl_b->dl_runtime_lock

c1e0a8bc FD: 4 BD: 361 -.-.-.: &rq->lock
-> [c1e0a9e8] &rt_b->rt_runtime_lock
-> [c1e0aa54] &cp->lock

c1c6d034 FD: 5 BD: 1 ......: init_task.pi_lock
-> [c1e0a8bc] &rq->lock

c259f13f FD: 1 BD: 1 ......: rcu_read_lock

c259f1d0 FD: 1 BD: 82 ..-...: rcu_node_0

c1c8d458 FD: 24 BD: 1 +.+.+.: trace_types_lock
-> [c1c99ff0] pin_fs_lock
-> [c1cc3234] &sb->s_type->i_mutex_key#6

c1c7f970 FD: 1 BD: 1 ......: panic_notifier_list.lock

c1c82a50 FD: 1 BD: 1 ......: die_chain.lock

c1c8d6d8 FD: 25 BD: 2 +.+.+.: trace_event_sem
-> [c1c99ff0] pin_fs_lock
-> [c1cc3234] &sb->s_type->i_mutex_key#6
-> [c25c4058] &(&n->list_lock)->rlock
-> [c25bc904] &(&zone->lock)->rlock

c1c8e238 FD: 1 BD: 1 ......: trigger_cmd_mutex

c1c7bdb0 FD: 1 BD: 72 -.-...: i8259A_lock

c259f0c4 FD: 4 BD: 70 -.-...: &irq_desc_lock_class
-> [c1c7bdb0] i8259A_lock
-> [c1c7e5b0] vector_lock
-> [c1c7e6d0] ioapic_lock

c1c87bf8 FD: 10 BD: 3 +.+.+.: irq_domain_mutex
-> [c1e0a8bc] &rq->lock
-> [c1c7e5b0] vector_lock
-> [c259f0c4] &irq_desc_lock_class
-> [c1c7bdb0] i8259A_lock
-> [c1c87b98] revmap_trees_mutex

c1c7c830 FD: 1 BD: 29 ......: rtc_lock

c1c898b0 FD: 2 BD: 64 -.-...: timekeeper_lock
-> [c259ffc4] tk_core

c259ffc4 FD: 1 BD: 65 ----..: tk_core

c1c87830 FD: 1 BD: 1 ......: read_lock

c1c8fd98 FD: 55 BD: 1 +.+.+.: pmus_lock
-> [c1c934b8] pcpu_alloc_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c25db814] &x->wait#3
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c2607b50] &(&k->k_lock)->rlock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1c8f9ec] subsys mutex#23
-> [c25bc904] &(&zone->lock)->rlock
-> [c1e0a8bc] &rq->lock

c25bc6b4 FD: 1 BD: 27 +.+...: &swhash->hlist_mutex

c1cd0eb0 FD: 1 BD: 4 ......: tty_ldiscs_lock

c1c87750 FD: 6 BD: 11 ......: (console_sem).lock
-> [c1e098e4] &p->pi_lock

c1c8772c FD: 67 BD: 11 +.+.+.: console_lock
-> [c1c80634] resource_lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c259f24c] &(&base->lock)->rlock
-> [c1cd1750] kbd_event_lock
-> [c1cccd30] vga_lock
-> [c1c87710] logbuf_lock
-> [c25d74d4] &port_lock_key
-> [c25db814] &x->wait#3
-> [c1cddc78] gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c25d5768] subsys mutex#12
-> [c1b956b4] drivers/tty/vt/vt.c:231
-> [c1cd1250] vt_event_lock
-> [c1e0a8bc] &rq->lock
-> [c1b95555] drivers/tty/vt/keyboard.c:252

c259f24c FD: 1 BD: 170 -.-.-.: &(&base->lock)->rlock

c1cd1750 FD: 10 BD: 23 -.-...: kbd_event_lock
-> [c1cd1710] led_lock
-> [c1e0a1a5] &pool->lock/1

c1cd1710 FD: 1 BD: 24 ..-...: led_lock

c1cccd30 FD: 1 BD: 12 ......: vga_lock

c1c87710 FD: 1 BD: 13 ......: logbuf_lock

c25d74d4 FD: 7 BD: 17 -.-...: &port_lock_key
-> [c25d60c4] &tty->write_wait

c1c972d0 FD: 1 BD: 14 +.+...: vmap_area_lock

c1c97344 FD: 1 BD: 7 +.+...: init_mm.page_table_lock

c1c8a350 FD: 2 BD: 1 ......: clockevents_lock
-> [c1c8a3d0] tick_broadcast_lock

c1c8a3d0 FD: 1 BD: 2 -.....: tick_broadcast_lock

c1c632e8 FD: 2 BD: 64 -.-...: jiffies_lock
-> [c1c632c4] jiffies_lock#2

c1c632c4 FD: 1 BD: 65 ---...: jiffies_lock#2

c7eaf850 FD: 1 BD: 78 -.-...: hrtimer_bases.lock

c1c828f8 FD: 1 BD: 9 +.+...: text_mutex

c25d57d4 FD: 1 BD: 8 ......: semaphore->lock

c25d5ee4 FD: 1 BD: 5 ......: &(*(&acpi_gbl_reference_count_lock))->rlock

c1ccd33c FD: 3 BD: 2 +.+.+.: acpi_ioremap_lock
-> [c1c972d0] vmap_area_lock
-> [c1c97344] init_mm.page_table_lock

c1ccb9d0 FD: 1 BD: 13 ......: percpu_counters_lock

c25d2d9c FD: 1 BD: 81 ......: &(&idp->lock)->rlock

c1ccb5f0 FD: 6 BD: 80 ......: simple_ida_lock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1cc9300] (blk_queue_ida).idr.lock
-> [c1ce3420] (host_index_ida).idr.lock
-> [c1cf0de0] (input_ida).idr.lock
-> [c1cf1980] (rtc_ida).idr.lock

c1c9de78 FD: 31 BD: 69 +.+.+.: kernfs_mutex
-> [c1ccb5f0] simple_ida_lock
-> [c1e0a8bc] &rq->lock
-> [c1c63550] inode_hash_lock
-> [c1c9e04c] &sb->s_type->i_lock_key#17
-> [c25cf500] &isec->lock
-> [c25bc904] &(&zone->lock)->rlock

c1c99db4 FD: 1 BD: 1 ++++..: file_systems_lock

c1c99f80 FD: 1 BD: 53 ......: (mnt_id_ida).idr.lock

c1c99ef0 FD: 2 BD: 52 +.+...: mnt_id_lock
-> [c1c99f80] (mnt_id_ida).idr.lock

c1c99970 FD: 3 BD: 34 +.+...: sb_lock
-> [c1c99940] (unnamed_dev_ida).idr.lock
-> [c1c998f0] unnamed_dev_lock

c1c6caa5 FD: 29 BD: 1 +.+...: &type->s_umount_key/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c25bc904] &(&zone->lock)->rlock
-> [c1c6cacc] &sb->s_type->i_lock_key
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1c99940 FD: 1 BD: 36 ......: (unnamed_dev_ida).idr.lock

c1c998f0 FD: 2 BD: 35 +.+...: unnamed_dev_lock
-> [c1c99940] (unnamed_dev_ida).idr.lock

c1c90a18 FD: 1 BD: 27 +.+...: shrinker_rwsem

c1c6cacc FD: 17 BD: 8 +.+...: &sb->s_type->i_lock_key
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c25c41a4 FD: 1 BD: 120 +.+...: &(&s->s_inode_list_lock)->rlock

c25cf500 FD: 2 BD: 119 +.+...: &isec->lock
-> [c25cf4f0] &(&sbsec->isec_lock)->rlock

c25cf4f0 FD: 1 BD: 120 +.+...: &(&sbsec->isec_lock)->rlock

c25c4628 FD: 16 BD: 172 +.+...: &(&dentry->d_lockref.lock)->rlock
-> [c25c4600] &wq
-> [c25c45f8] &wq#2
-> [c25bcc48] &(&lru->node[i].lock)->rlock -> [c25c4629] &(&dentry->d_lockref.lock)->rlock/1 -> [c25c6f7c] &wq#3
-> [c1c9dc50] sysctl_lock
-> [c25c462a] &(&dentry->d_lockref.lock)->rlock/2

c25cf4f8 FD: 1 BD: 28 +.+...: &sbsec->lock

c1cc7894 FD: 1 BD: 1 .+.+..: policy_rwlock

c1cc46d0 FD: 1 BD: 12 ......: notif_lock

c25ca4c0 FD: 1 BD: 12 ......: &(&avc_cache.slots_lock[i])->rlock

c1c635a8 FD: 19 BD: 53 +.+...: mount_lock
-> [c1c63584] mount_lock#2

c1c63584 FD: 18 BD: 54 +.+...: mount_lock#2
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25c575c] &new_ns->poll

c1c9dbe0 FD: 1 BD: 26 ......: (proc_inum_ida).idr.lock

c1c9db90 FD: 2 BD: 25 ......: proc_inum_lock
-> [c1c9dbe0] (proc_inum_ida).idr.lock

c1c9c0d4 FD: 18 BD: 73 +.+...: init_fs.lock
-> [c1c9c0ec] init_fs.seq
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1c9c0ec FD: 1 BD: 74 +.+...: init_fs.seq

c1c9c2e5 FD: 27 BD: 1 +.+...: &type->s_umount_key#2/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c25bc904] &(&zone->lock)->rlock
-> [c1c9c30c] &sb->s_type->i_lock_key#2
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1c9c30c FD: 17 BD: 103 +.+...: &sb->s_type->i_lock_key#2
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1c9dc14 FD: 1 BD: 13 ++++..: proc_subdir_lock

c1cff098 FD: 215 BD: 1 +.+.+.: net_mutex
-> [c1c9dbe0] (proc_inum_ida).idr.lock
-> [c1c9db90] proc_inum_lock
-> [c1cff938] rtnl_mutex
-> [c1c9dc50] sysctl_lock
-> [c1c934b8] pcpu_alloc_mutex
-> [c1cfdbac] &sb->s_type->i_lock_key#7
-> [c25e1900] slock-AF_NETLINK
-> [c25e1a60] sk_lock-AF_NETLINK
-> [c1d01e14] nl_table_lock
-> [c1d01e50] nl_table_wait.lock
-> [c1ccb6d8] uevent_sock_mutex
-> [c25e29b0] &(&net->rules_mod_lock)->rlock
-> [c25bc904] &(&zone->lock)->rlock
-> [c1c7ff18] cpu_add_remove_lock
-> [c259f24c] &(&base->lock)->rlock
-> [c1ccb9d0] percpu_counters_lock
-> [c1cd8790] random_write_wait.lock
-> [c1cd85c8] nonblocking_pool.lock
-> [c1d038d4] raw_v4_hashinfo.lock
-> [c1cfdda0] (net_generic_ids).idr.lock
-> [c1d0bbf0] cache_list_lock
-> [c1e0a1a4] &(&pool->lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c25e3ad0] &xt[i].mutex
-> [c1d020d8] nf_hook_mutex
-> [c1d07ab4] raw_v6_hashinfo.lock
-> [c25efc40] &(&ip6addrlbl_table.lock)->rlock
-> [c1c90058] jump_label_mutex

c1c9dc50 FD: 1 BD: 174 +.+...: sysctl_lock

c1c9c185 FD: 26 BD: 1 +.+...: &type->s_umount_key#3/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c1c9c1ac] &sb->s_type->i_lock_key#3
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1c9c1ac FD: 17 BD: 2 +.+...: &sb->s_type->i_lock_key#3
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1c8b7b0 FD: 1 BD: 2 +.....: cgroup_idr_lock

c1c8b770 FD: 1 BD: 2 ......: cgroup_file_kn_lock

c1c8b7f0 FD: 1 BD: 2 ......: css_set_lock

c1c8c678 FD: 2 BD: 1 +.+...: cpuset_mutex
-> [c1c8c610] callback_lock

c1c8c610 FD: 1 BD: 2 ......: callback_lock

c1c8bbb8 FD: 1 BD: 2 +.+...: freezer_mutex

c1c63490 FD: 1 BD: 1 +.+...: kmap_lock

c1c971f0 FD: 2 BD: 1 +.+...: purge_lock
-> [c1c972d0] vmap_area_lock

c1c7f570 FD: 2 BD: 1 +.+...: cpa_lock
-> [c1c7f3f0] pgd_lock

c1c90630 FD: 1 BD: 1 +.+...: managed_page_count_lock

c25b38d4 FD: 130 BD: 4 .+.+.+: &cgroup_threadgroup_rwsem
-> [c1c972d0] vmap_area_lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c1e098e4] &p->pi_lock
-> [c1c99cd0] init_files.file_lock
-> [c1c9c0d4] init_fs.lock
-> [c1c6d010] init_task.alloc_lock
-> [c1c99f80] (mnt_id_ida).idr.lock
-> [c1c99ef0] mnt_id_lock
-> [c1c934b8] pcpu_alloc_mutex
-> [c1c99970] sb_lock
-> [c1c9db25] &type->s_umount_key#4/1
-> [c1c635a8] mount_lock
-> [c1c63250] pidmap_lock
-> [c1c631d4] tasklist_lock
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c25c5748] &(&newf->file_lock)->rlock
-> [c1c97344] init_mm.page_table_lock
-> [c25b4244] &(kretprobe_table_locks[i].lock)
-> [c1c7f3f0] pgd_lock
-> [c1dfe42c] &mm->context.lock
-> [c1e09914] &mm->mmap_sem
-> [c25c57bc] &(&fs->lock)->rlock

c1e098e4 FD: 5 BD: 337 -.-.-.: &p->pi_lock
-> [c1e0a8bc] &rq->lock

c1c99cd0 FD: 1 BD: 5 +.+...: init_files.file_lock

c1c6d010 FD: 1 BD: 5 +.+...: init_task.alloc_lock

c1c9db25 FD: 55 BD: 5 +.+...: &type->s_umount_key#4/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c25bc904] &(&zone->lock)->rlock
-> [c1c9db4c] &sb->s_type->i_lock_key#4
-> [c25cf500] &isec->lock
-> [c1c9db54] &sb->s_type->i_mutex_key
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1c9db4c FD: 17 BD: 10 +.+...: &sb->s_type->i_lock_key#4
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1c9db54 FD: 49 BD: 7 ++++.+: &sb->s_type->i_mutex_key
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1c9db4c] &sb->s_type->i_lock_key#4
-> [c25cf500] &isec->lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c1c9dc50] sysctl_lock

c1c63250 FD: 1 BD: 79 ......: pidmap_lock

c1c631d4 FD: 23 BD: 5 .+.+..: tasklist_lock
-> [c1c6edd4] init_sighand.siglock
-> [c1e098a4] &(&sighand->siglock)->rlock

c1c6edd4 FD: 1 BD: 6 ......: init_sighand.siglock

c1da38a0 FD: 1 BD: 1 +.+...: (complete)kthreadd_done

c1da38b4 FD: 6 BD: 1 ......: (kthreadd_done).wait.lock
-> [c1e098e4] &p->pi_lock

c1e098f4 FD: 40 BD: 72 +.+...: &(&p->alloc_lock)->rlock
-> [c1e098ec] &p->mems_allowed_seq
-> [c1c9c0d4] init_fs.lock
-> [c25c57bc] &(&fs->lock)->rlock
-> [c1e0a358] &x->wait
-> [c1e098a4] &(&sighand->siglock)->rlock
-> [c1e098ac] &x->wait#16

c1e098ec FD: 1 BD: 73 ......: &p->mems_allowed_seq

c1c7e698 FD: 11 BD: 2 +.+.+.: ioapic_mutex
-> [c1e0a8bc] &rq->lock
-> [c1c87bf8] irq_domain_mutex

c1e098a4 FD: 21 BD: 76 -.....: &(&sighand->siglock)->rlock
-> [c1e098d4] &sig->wait_chldexit
-> [c1cd86c8] input_pool.lock
-> [c1cd85c8] nonblocking_pool.lock
-> [c1e098c4] &(&(&sig->stats_lock)->lock)->rlock -> [c25d60a4] &(&tty->ctrl_lock)->rlock -> [c1e098e4] &p->pi_lock
-> [c1e098dc] &prev->lock
-> [c1e0989c] &sighand->signalfd_wqh
-> [c25bc904] &(&zone->lock)->rlock
-> [c7eaf850] hrtimer_bases.lock
-> [c7eeb850] hrtimer_bases.lock#4
-> [c7ec3850] hrtimer_bases.lock#2
-> [c7ed7850] hrtimer_bases.lock#3

c1c7e5b0 FD: 1 BD: 71 ......: vector_lock

c1c87b98 FD: 1 BD: 4 +.+.+.: revmap_trees_mutex

c1c7b770 FD: 1 BD: 1 ......: &nmi_desc[0].lock

c1c830d8 FD: 10 BD: 28 +.+.+.: smpboot_threads_lock
-> [c1c82a10] kthread_create_lock
-> [c1e098e4] &p->pi_lock
-> [c1e0a360] (complete)&done
-> [c1e0a8bc] &rq->lock
-> [c1e0a358] &x->wait
-> [c1e0a348] (complete)&self.parked

c1c82a10 FD: 1 BD: 35 +.+...: kthread_create_lock

c1e0a360 FD: 7 BD: 34 +.+...: (complete)&done
-> [c1e0a358] &x->wait
-> [c1e0a8bc] &rq->lock

c1e0a358 FD: 6 BD: 99 ......: &x->wait
-> [c1e098e4] &p->pi_lock

c1e0a348 FD: 7 BD: 29 +.+...: (complete)&self.parked
-> [c1e0a358] &x->wait
-> [c1e0a8bc] &rq->lock

c1c827b8 FD: 26 BD: 28 +.+.+.: wq_pool_mutex
-> [c1e0a16c] &wq->mutex
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1e0a8bc] &rq->lock
-> [c1c82a10] kthread_create_lock
-> [c1e098e4] &p->pi_lock
-> [c1e0a360] (complete)&done
-> [c1e0a358] &x->wait
-> [c1e0a184] &pool->attach_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c25bc904] &(&zone->lock)->rlock

c1e0a184 FD: 12 BD: 31 +.+...: &pool->attach_mutex
-> [c1e098e4] &p->pi_lock
-> [c1e0a1a4] &(&pool->lock)->rlock
-> [c25b3b90] &(&stopper->lock)->rlock
-> [c25b3ba0] (complete)&done->completion
-> [c1e0a8bc] &rq->lock
-> [c25b3b98] &x->wait#7

c1e0a1a4 FD: 8 BD: 141 -.-...: &(&pool->lock)->rlock
-> [c1e098e4] &p->pi_lock
-> [c1c82750] wq_mayday_lock
-> [c259f24c] &(&base->lock)->rlock

c1e0a16c FD: 11 BD: 29 +.+...: &wq->mutex
-> [c1e0a1a4] &(&pool->lock)->rlock
-> [c1e0a1a5] &pool->lock/1
-> [c1e0a1cc] &x->wait#13

c1e0a1a5 FD: 8 BD: 81 -.-...: &pool->lock/1
-> [c1e098e4] &p->pi_lock
-> [c1c82750] wq_mayday_lock
-> [c259f24c] &(&base->lock)->rlock

c259f190 FD: 6 BD: 62 ..-...: &rsp->gp_wq
-> [c1e098e4] &p->pi_lock

c25b3b90 FD: 6 BD: 37 ..-...: &(&stopper->lock)->rlock
-> [c1e098e4] &p->pi_lock

c1cd8648 FD: 1 BD: 1 ......: blocking_pool.lock

c25c5748 FD: 17 BD: 7 +.+...: &(&newf->file_lock)->rlock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1c82750 FD: 6 BD: 151 ..-...: wq_mayday_lock
-> [c1e098e4] &p->pi_lock

c1c7fe54 FD: 1 BD: 27 ......: cpu_hotplug.wq.lock

c1c8cf98 FD: 1 BD: 27 +.+...: relay_channels_mutex

c1c7c378 FD: 1 BD: 27 +.+...: smp_alt

c1c878d8 FD: 6 BD: 27 +.+...: sparse_irq_lock
-> [c1c7c830] rtc_lock
-> [c1e0a8bc] &rq->lock

c1e09d9d FD: 30 BD: 27 +.+...: (complete)&st->done
-> [c1e09d95] &x->wait#2
-> [c1e0a8bc] &rq->lock
-> [c1c827b8] wq_pool_mutex
-> [c1e0a184] &pool->attach_mutex
-> [c1c830d8] smpboot_threads_lock

c7ec3850 FD: 1 BD: 77 -.-...: hrtimer_bases.lock#2

c1e09d95 FD: 6 BD: 28 ......: &x->wait#2
-> [c1e098e4] &p->pi_lock

c1e0a9e8 FD: 2 BD: 362 ......: &rt_b->rt_runtime_lock
-> [c1e0a9d8] &rt_rq->rt_runtime_lock

c1e0a9d8 FD: 1 BD: 363 ......: &rt_rq->rt_runtime_lock

c7ed7850 FD: 1 BD: 79 -.-...: hrtimer_bases.lock#3

c7eeb850 FD: 1 BD: 77 -.-...: hrtimer_bases.lock#4

c1c85298 FD: 10 BD: 1 +.+.+.: sched_domains_mutex
-> [c1c934b8] pcpu_alloc_mutex
-> [c1e0aa3c] &dl_b->dl_runtime_lock
-> [c1e0a8bc] &rq->lock
-> [c1c934f0] pcpu_lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c1c9dc50] sysctl_lock

c1e0aa54 FD: 1 BD: 362 ......: &cp->lock

c1c92e65 FD: 31 BD: 1 +.+.+.: &type->s_umount_key#5/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c1c934b8] pcpu_alloc_mutex
-> [c1ccb9d0] percpu_counters_lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c1c92e8c] &sb->s_type->i_lock_key#5
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock
-> [c25bca94] &(&sbinfo->stat_lock)->rlock

c259f254 FD: 6 BD: 17 +.-.-.: ((&timer))
-> [c1e098e4] &p->pi_lock

c259f127 FD: 1 BD: 1 ......: rcu_callback

c1c92e8c FD: 17 BD: 12 +.+...: &sb->s_type->i_lock_key#5
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1cde880 FD: 70 BD: 1 +.+...: (complete)setup_done
-> [c1cde894] (setup_done).wait.lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25c57bc] &(&fs->lock)->rlock
-> [c1cde94c] &sb->s_type->i_lock_key#6
-> [c1c6cacc] &sb->s_type->i_lock_key
-> [c1c6cad4] &sb->s_type->i_mutex_key#2
-> [c1c635a8] mount_lock
-> [c1cde925] &type->s_umount_key#6/1
-> [c1c934b8] pcpu_alloc_mutex
-> [c25bc904] &(&zone->lock)->rlock
-> [c1c99970] sb_lock
-> [c1c99ef0] mnt_id_lock
-> [c1c99f80] (mnt_id_ida).idr.lock
-> [c25ca4c0] &(&avc_cache.slots_lock[i])->rlock
-> [c1cc46d0] notif_lock
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c1c99eb8] namespace_sem
-> [c1c9db90] proc_inum_lock
-> [c1c9dbe0] (proc_inum_ida).idr.lock

c1cde894 FD: 6 BD: 2 ......: (setup_done).wait.lock
-> [c1e098e4] &p->pi_lock

c1c99eb8 FD: 27 BD: 47 +++++.: namespace_sem
-> [c25bc904] &(&zone->lock)->rlock
-> [c1c99f80] (mnt_id_ida).idr.lock
-> [c1c99ef0] mnt_id_lock
-> [c1c934b8] pcpu_alloc_mutex
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1c635a8] mount_lock
-> [c1c63528] rename_lock

c25c57b4 FD: 1 BD: 74 +.+...: &fs->seq

c1cde925 FD: 31 BD: 2 +.+.+.: &type->s_umount_key#6/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c25bc904] &(&zone->lock)->rlock
-> [c1c934b8] pcpu_alloc_mutex
-> [c1ccb9d0] percpu_counters_lock
-> [c25bca94] &(&sbinfo->stat_lock)->rlock
-> [c1cde94c] &sb->s_type->i_lock_key#6
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c25bca94 FD: 1 BD: 46 +.+...: &(&sbinfo->stat_lock)->rlock

c1cde94c FD: 17 BD: 46 +.+...: &sb->s_type->i_lock_key#6
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1c6cad4 FD: 29 BD: 5 ++++++: &sb->s_type->i_mutex_key#2
-> [c1c99eb8] namespace_sem
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25bc904] &(&zone->lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c1c6cacc] &sb->s_type->i_lock_key

c1c63528 FD: 18 BD: 53 +.+...: rename_lock
-> [c1c63504] rename_lock#2

c1c63504 FD: 17 BD: 54 +.+...: rename_lock#2
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock -> [c25c462a] &(&dentry->d_lockref.lock)->rlock/2 -> [c25c462b] &(&dentry->d_lockref.lock)->rlock/3

c25c575c FD: 1 BD: 55 ......: &new_ns->poll

c25c4620 FD: 2 BD: 175 +.+...: &dentry->d_seq
-> [c25c4621] &dentry->d_seq/1

c25c57bc FD: 18 BD: 73 +.+...: &(&fs->lock)->rlock
-> [c25c57b4] &fs->seq
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1cde990 FD: 1 BD: 34 +.+...: req_lock

c25db814 FD: 1 BD: 43 ......: &x->wait#3

c25d2da8 FD: 1 BD: 54 +.+...: &(&k->list_lock)->rlock

c25db698 FD: 3 BD: 47 ......: &(&dev->power.lock)->rlock
-> [c25db699] &(&dev->power.lock)->rlock/1
-> [c25db754] &dev->power.wait_queue

c1cdee58 FD: 1 BD: 45 +.+...: dpm_list_mtx

c1ccb6d8 FD: 12 BD: 64 +.+.+.: uevent_sock_mutex
-> [c25e1d68] &(&net->nsid_lock)->rlock
-> [c25e16dc] &(&list->lock)->rlock
-> [c1d01e50] nl_table_wait.lock
-> [c1e0a8bc] &rq->lock
-> [c25bc904] &(&zone->lock)->rlock

c1c820b0 FD: 1 BD: 59 ......: running_helpers_waitq.lock

c1c87c58 FD: 4 BD: 12 +.+.+.: register_lock
-> [c1c9dbe0] (proc_inum_ida).idr.lock
-> [c1c9db90] proc_inum_lock
-> [c25bc904] &(&zone->lock)->rlock

c1c82218 FD: 2 BD: 1 +.+...: umhelper_sem
-> [c1c82070] usermodehelper_disabled_waitq.lock

c1c82070 FD: 1 BD: 2 ......: usermodehelper_disabled_waitq.lock

c1cff938 FD: 107 BD: 7 +.+.+.: rtnl_mutex
-> [c1c934b8] pcpu_alloc_mutex
-> [c25db814] &x->wait#3
-> [c1cddc78] gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock -> [c25db698] &(&dev->power.lock)->rlock -> [c1cdee58] dpm_list_mtx
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock -> [c25e2924] subsys mutex#11
-> [c25bc904] &(&zone->lock)->rlock
-> [c1cdedf8] dev_hotplug_mutex
-> [c1cff694] dev_base_lock
-> [c1cd86c8] input_pool.lock
-> [c1cd85c8] nonblocking_pool.lock
-> [c1d01e50] nl_table_wait.lock
-> [c2607354] &(&reg_requests_lock)->rlock -> [c259f24c] &(&base->lock)->rlock
-> [c260734c] &(&reg_pending_beacons_lock)->rlock -> [c25e24e4] &tbl->lock
-> [c1c9dc50] sysctl_lock
-> [c2607344] &(&reg_indoor_lock)->rlock -> [c1e0a8bc] &rq->lock
-> [c1e0a1a4] &(&pool->lock)->rlock
-> [c1d020d8] nf_hook_mutex
-> [c1c90058] jump_label_mutex
-> [c2607b50] &(&k->k_lock)->rlock
-> [c1cff9b0] lweventlist_lock
-> [c1c9dbe0] (proc_inum_ida).idr.lock
-> [c1c9db90] proc_inum_lock
-> [c25efb40] &ndev->lock
-> [c25efcf2] &(&idev->mc_lock)->rlock
-> [c25efd02] &(&mc->mca_lock)->rlock
-> [c1d047d8] (inetaddr_chain).rwsem
-> [c25e2148] _xmit_LOOPBACK
-> [c25ee798] &(&in_dev->mc_tomb_lock)->rlock -> [c1d04a90] fib_info_lock
-> [c25efb58] &(&ifa->lock)->rlock

c1cf5718 FD: 1 BD: 1 +.+...: cpufreq_fast_switch_lock

c1cddf58 FD: 1 BD: 1 +.+...: syscore_ops_lock

c1e0a18c FD: 26 BD: 1 +.+.+.: &pool->manager_arb
-> [c259f24c] &(&base->lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c82a10] kthread_create_lock
-> [c1e098e4] &p->pi_lock
-> [c1e0a360] (complete)&done
-> [c1e0a8bc] &rq->lock
-> [c1e0a358] &x->wait
-> [c1e0a184] &pool->attach_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1e0a194] ((&pool->mayday_timer))
-> [c25bc904] &(&zone->lock)->rlock
-> [c1e0a1a4] &(&pool->lock)->rlock
-> [c25b4244] &(kretprobe_table_locks[i].lock)

c1c90578 FD: 2 BD: 1 +.+...: zonelists_mutex
-> [c25bc904] &(&zone->lock)->rlock

c1c99a94 FD: 1 BD: 1 ++++..: binfmt_lock

c1e0a194 FD: 10 BD: 5 +.-...: ((&pool->mayday_timer))
-> [c1e0a1a5] &pool->lock/1
-> [c259f24c] &(&base->lock)->rlock
-> [c1e0a1a4] &(&pool->lock)->rlock

c1e0a144 FD: 1 BD: 1 .+.+.+: "events_unbound"

c1e0a0f8 FD: 133 BD: 3 +.+.+.: (&sub_info->work)
-> [c25bc904] &(&zone->lock)->rlock
-> [c25b38d4] &cgroup_threadgroup_rwsem
-> [c1e098e4] &p->pi_lock
-> [c1e0a8bc] &rq->lock
-> [c25c4058] &(&n->list_lock)->rlock
-> [c25b4244] &(kretprobe_table_locks[i].lock)
-> [c1e098a4] &(&sighand->siglock)->rlock
-> [c1e098d4] &sig->wait_chldexit
-> [c1e098dc] &prev->lock
-> [c1e0a0e8] &x->wait#12

c1cfdb85 FD: 27 BD: 1 +.+.+.: &type->s_umount_key#7/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c25bc904] &(&zone->lock)->rlock
-> [c1cfdbac] &sb->s_type->i_lock_key#7
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1cfdbac FD: 17 BD: 3 +.+...: &sb->s_type->i_lock_key#7
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1c82250 FD: 1 BD: 1 +.+...: umh_sysctl_lock

c1e098bc FD: 141 BD: 2 +.+.+.: &sig->cred_guard_mutex
-> [c25c57bc] &(&fs->lock)->rlock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1c6cad4] &sb->s_type->i_mutex_key#2
-> [c1e0a8bc] &rq->lock
-> [c1c9c0d4] init_fs.lock
-> [c1c9e3fc] &type->i_mutex_dir_key
-> [c1c9e3ec] &sb->s_type->i_lock_key#16
-> [c1e098e4] &p->pi_lock
-> [c25b3b90] &(&stopper->lock)->rlock
-> [c25b3ba0] (complete)&done->completion
-> [c25b3b98] &x->wait#7
-> [c1c7f3f0] pgd_lock
-> [c1e09914] &mm->mmap_sem
-> [c25c874c] &ei->xattr_sem
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25c8744] &ei->i_data_sem
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c1e0990c] &(&mm->page_table_lock)->rlock
-> [c25c3ce8] &anon_vma->rwsem
-> [c1e0980c] &(ptlock_ptr(page))->rlock
-> [c25bc8fc] &(&zone->lru_lock)->rlock
-> [c25bc924] zone->wait_table + i
-> [c1e098a4] &(&sighand->siglock)->rlock
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c25c5748] &(&newf->file_lock)->rlock
-> [c25c873c] &ei->i_mmap_sem
-> [c1dfe42c] &mm->context.lock
-> [c25ba114] &(&tsk->delays->lock)->rlock
-> [c25c567c] &mapping->i_mmap_rwsem
-> [c25c3cdc] key#3
-> [c1c9e3f4] &sb->s_type->i_mutex_key#8
-> [c25b4244] &(kretprobe_table_locks[i].lock)

c1cfdcb8 FD: 1 BD: 1 +.+...: proto_list_mutex

c25c4600 FD: 6 BD: 173 ......: &wq
-> [c1e098e4] &p->pi_lock

c1cd8790 FD: 1 BD: 16 ..-...: random_write_wait.lock

c25bc6c4 FD: 1 BD: 1 +.+...: &child->perf_event_mutex

c1d01e14 FD: 1 BD: 4 .+.+..: nl_table_lock

c1e098d4 FD: 6 BD: 77 ......: &sig->wait_chldexit
-> [c1e098e4] &p->pi_lock

c1d01e50 FD: 1 BD: 69 ......: nl_table_wait.lock

c1cfdbf0 FD: 1 BD: 1 +.+...: net_family_lock

c1e098c4 FD: 3 BD: 77 ......: &(&(&sig->stats_lock)->lock)->rlock
-> [c1e098cc] &(&sig->stats_lock)->seqcount

c1e098cc FD: 2 BD: 78 ......: &(&sig->stats_lock)->seqcount
-> [c1c63250] pidmap_lock

c25e1900 FD: 1 BD: 3 +.....: slock-AF_NETLINK

c25e1a60 FD: 12 BD: 2 +.+...: sk_lock-AF_NETLINK
-> [c25e1900] slock-AF_NETLINK

c1c80150 FD: 1 BD: 1 +.+...: low_water_lock

c25d2dfd FD: 10 BD: 5 +.....: &(&tbl->locks[i])->rlock
-> [c25d2dfe] &(&tbl->locks[i])->rlock/1
-> [c1e0a1a4] &(&pool->lock)->rlock

c1c99ff0 FD: 1 BD: 11 +.+...: pin_fs_lock

c1cc3085 FD: 27 BD: 1 +.+.+.: &type->s_umount_key#8/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c25bc904] &(&zone->lock)->rlock
-> [c1cc30ac] &sb->s_type->i_lock_key#8
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1cc30ac FD: 17 BD: 10 +.+...: &sb->s_type->i_lock_key#8
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1cc30b4 FD: 22 BD: 8 +.+.+.: &sb->s_type->i_mutex_key#3
-> [c1cc30ac] &sb->s_type->i_lock_key#8
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25bc904] &(&zone->lock)->rlock

c1cddc78 FD: 34 BD: 43 +.+.+.: gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccb630] kobj_ns_type_lock
-> [c1e0a8bc] &rq->lock
-> [c1e098e4] &p->pi_lock

c1c9dfd0 FD: 1 BD: 61 +.+...: sysfs_symlink_target_lock

c25d70dc FD: 8 BD: 1 +.+...: subsys mutex
-> [c2607b50] &(&k->k_lock)->rlock

c2607b50 FD: 7 BD: 78 +.+...: &(&k->k_lock)->rlock
-> [c1d19ed0] klist_remove_lock

c1cdf9d8 FD: 1 BD: 1 +.+...: regmap_debugfs_early_lock

c1cf1c38 FD: 1 BD: 1 +.+...: __i2c_board_lock

c1cf1eb8 FD: 8 BD: 1 +.+...: core_lock
-> [c2607b50] &(&k->k_lock)->rlock

c1cf5c58 FD: 14 BD: 1 +.+...: cpuidle_lock
-> [c1e0a8bc] &rq->lock
-> [c259f118] (complete)&rs_array[i].completion
-> [c259f110] &x->wait#4

c259f118 FD: 11 BD: 4 +.+...: (complete)&rs_array[i].completion
-> [c1e0a8bc] &rq->lock
-> [c259f24c] &(&base->lock)->rlock
-> [c7ed7850] hrtimer_bases.lock#3
-> [c1c898b0] timekeeper_lock
-> [c1c632e8] jiffies_lock

c259f110 FD: 6 BD: 4 ..-...: &x->wait#4
-> [c1e098e4] &p->pi_lock

c1ccd680 FD: 1 BD: 45 ++++..: bus_type_sem

c25df800 FD: 8 BD: 1 +.+...: subsys mutex#2
-> [c2607b50] &(&k->k_lock)->rlock

c1c805f0 FD: 1 BD: 17 +.+...: bootmem_resource_lock

c1cfd730 FD: 1 BD: 15 ......: pci_config_lock

c1e0baa0 FD: 1 BD: 1 ......: &dev->mutex

c1cde52c FD: 52 BD: 2 +.+.+.: subsys mutex#3
-> [c2607b50] &(&k->k_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccff18] performance_mutex
-> [c1cf5814] cpufreq_driver_lock
-> [c25df56c] &policy->rwsem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c1cf5558] s_active#7
-> [c1cf5654] s_active#8
-> [c1cf561c] s_active#9
-> [c1cf5638] s_active#10
-> [c1cf5670] s_active#11
-> [c1cf568c] s_active#12
-> [c1cf5574] s_active#13
-> [c1cf55ac] s_active#14
-> [c1cf5590] s_active#15
-> [c1cf55c8] s_active#16
-> [c1cf553c] s_active#17
-> [c25df544] &x->wait#14
-> [c25df554] (complete)&policy->kobj_unregister

c1c81bf0 FD: 1 BD: 1 ......: uidhash_lock

c1e0a324 FD: 5 BD: 1 +.+...: s_active
-> [c1e0a8bc] &rq->lock

c1cd1050 FD: 1 BD: 1 +.+...: sysrq_key_table_lock

c1c888b0 FD: 1 BD: 1 ....-.: freezer_lock

c1c90350 FD: 1 BD: 1 ......: oom_reaper_wait.lock

c1c8234c FD: 1 BD: 1 +.+...: subsys mutex#4

c25bc90c FD: 1 BD: 1 ......: &pgdat->kcompactd_wait

c1cc91d8 FD: 71 BD: 7 +.+.+.: bio_slab_lock

c1ccaf18 FD: 1 BD: 11 +.+.+.: block_class_lock

c1c99a58 FD: 1 BD: 23 +.+...: chrdevs_lock

c25d5eec FD: 1 BD: 1 ......: &(*(&acpi_gbl_hardware_lock))->rlock

c25d5ef4 FD: 1 BD: 2 ......: &(*(&acpi_gbl_gpe_lock))->rlock

c1c87358 FD: 1 BD: 1 +.+...: pm_mutex

c1ccd868 FD: 81 BD: 1 +.+.+.: acpi_scan_lock
-> [c25d57d4] semaphore->lock
-> [c25db814] &x->wait#3
-> [c1ccd814] acpi_device_lock
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c2607b50] &(&k->k_lock)->rlock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1ccd618] subsys mutex#5
-> [c1e0a8bc] &rq->lock
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c25d5ee4] &(*(&acpi_gbl_reference_count_lock))->rlock -> [c25bc904] &(&zone->lock)->rlock
-> [c1cfd730] pci_config_lock
-> [c25d5b88] &(*(&acpi_gbl_global_lock_pending_lock))->rlock -> [c1ccd33c] acpi_ioremap_lock
-> [c1ccdbe4] osc_lock
-> [c1ccc1f8] pci_bus_sem
-> [c1cfd658] pci_mmcfg_lock
-> [c1c80634] resource_lock
-> [c25d5adc] &device->physical_node_lock
-> [c1cddc78] gdp_mutex
-> [c25d2e48] subsys mutex#6
-> [c1ccbdd0] pci_lock
-> [c1ccc6f8] pci_slot_mutex
-> [c1ccbf10] resource_alignment_lock
-> [c1ccd5b8] acpi_pm_notifier_lock
-> [c1ccc0ac] subsys mutex#7
-> [c1ccbe38] pci_rescan_remove_lock
-> [c1cddfec] subsys mutex#8
-> [c1ccdcd8] acpi_link_lock
-> [c1cde6cc] subsys mutex#9
-> [c1cdefb0] events_lock
-> [c25d5ef4] &(*(&acpi_gbl_gpe_lock))->rlock

c1ccd814 FD: 1 BD: 2 +.+.+.: acpi_device_lock

c1ccd618 FD: 1 BD: 2 +.+...: subsys mutex#5

c25d5b88 FD: 1 BD: 2 ......: &(*(&acpi_gbl_global_lock_pending_lock))->rlock

c1ccdbe4 FD: 3 BD: 2 +.+.+.: osc_lock
-> [c25d57d4] semaphore->lock
-> [c25d5ee4] &(*(&acpi_gbl_reference_count_lock))->rlock

c1ccc1f8 FD: 1 BD: 2 ++++..: pci_bus_sem

c1cfd658 FD: 1 BD: 2 +.+...: pci_mmcfg_lock

c25d5adc FD: 33 BD: 8 +.+.+.: &device->physical_node_lock
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex

c25d2e48 FD: 8 BD: 2 +.+...: subsys mutex#6
-> [c2607b50] &(&k->k_lock)->rlock

c1ccbdd0 FD: 2 BD: 13 ......: pci_lock
-> [c1cfd730] pci_config_lock

c1ccc6f8 FD: 1 BD: 2 +.+...: pci_slot_mutex

c1ccbf10 FD: 1 BD: 2 +.+...: resource_alignment_lock

c25db699 FD: 1 BD: 48 ......: &(&dev->power.lock)->rlock/1

c1ccd5b8 FD: 4 BD: 2 +.+.+.: acpi_pm_notifier_lock
-> [c1cdefb0] events_lock
-> [c25d57d4] semaphore->lock
-> [c25d5ee4] &(*(&acpi_gbl_reference_count_lock))->rlock

c1cdefb0 FD: 1 BD: 3 ......: events_lock

c1ccc0ac FD: 1 BD: 2 +.+...: subsys mutex#7

c1ccbe38 FD: 11 BD: 2 +.+...: pci_rescan_remove_lock

c1cddfec FD: 1 BD: 2 +.+...: subsys mutex#8

c1ccdcd8 FD: 4 BD: 2 +.+.+.: acpi_link_lock
-> [c25d57d4] semaphore->lock
-> [c25d5ee4] &(*(&acpi_gbl_reference_count_lock))->rlock -> [c1cfd730] pci_config_lock

c1cde6cc FD: 1 BD: 2 +.+...: subsys mutex#9

c1cd9458 FD: 145 BD: 1 +.+.+.: misc_mtx
-> [c25db814] &x->wait#3
-> [c1cddc78] gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1cde990] req_lock
-> [c1e098e4] &p->pi_lock
-> [c25db718] (complete)&req.done
-> [c25db710] &x->wait#5
-> [c1e0a8bc] &rq->lock
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c25dae24] subsys mutex#10
-> [c25bc904] &(&zone->lock)->rlock

c25db718 FD: 114 BD: 33 +.+...: (complete)&req.done
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1cde990] req_lock
-> [c1e0a8bc] &rq->lock
-> [c1cde94c] &sb->s_type->i_lock_key#6
-> [c1cde954] &sb->s_type->i_mutex_key#5
-> [c25b4244] &(kretprobe_table_locks[i].lock)

c25db710 FD: 6 BD: 33 ......: &x->wait#5
-> [c1e098e4] &p->pi_lock

c1cde934 FD: 148 BD: 2 .+.+.+: sb_writers
-> [c1cde955] &sb->s_type->i_mutex_key#4/1
-> [c1cde954] &sb->s_type->i_mutex_key#5
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1cde94c] &sb->s_type->i_lock_key#6
-> [c25bc904] &(&zone->lock)->rlock
-> [c25c5780] &p->lock
-> [c1e0a8bc] &rq->lock
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25bca94] &(&sbinfo->stat_lock)->rlock
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25cf4f0] &(&sbsec->isec_lock)->rlock
-> [c1c999f0] cdev_lock
-> [c25bc8fc] &(&zone->lru_lock)->rlock
-> [c25bca84] &(&info->lock)->rlock
-> [c25bcb38] &(&wb->list_lock)->rlock

c1cde955 FD: 121 BD: 3 +.+.+.: &sb->s_type->i_mutex_key#4/1
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25bca94] &(&sbinfo->stat_lock)->rlock
-> [c1cde94c] &sb->s_type->i_lock_key#6
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c1cde954] &sb->s_type->i_mutex_key#5
-> [c1e0a8bc] &rq->lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25b4244] &(kretprobe_table_locks[i].lock)
-> [c1cde958] &sb->s_type->i_mutex_key#5/4
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25cf4f0] &(&sbsec->isec_lock)->rlock
-> [c25efa68] &u->readlock

c1cde954 FD: 111 BD: 37 ++++++: &sb->s_type->i_mutex_key#5
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25bca94] &(&sbinfo->stat_lock)->rlock
-> [c1cde94c] &sb->s_type->i_lock_key#6
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25bca7c] &(&xattrs->lock)->rlock
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25bca84] &(&info->lock)->rlock
-> [c25c566c] &inode->i_size_seqcount
-> [c25bc8c0] (PG_locked)page
-> [c1e0a8bc] &rq->lock
-> [c1cde958] &sb->s_type->i_mutex_key#5/4
-> [c25bc904] &(&zone->lock)->rlock
-> [c1c99eb8] namespace_sem

c25dae24 FD: 8 BD: 2 +.+...: subsys mutex#10
-> [c2607b50] &(&k->k_lock)->rlock

c1cddb70 FD: 3 BD: 1 ......: vga_lock#2
-> [c1ccbdd0] pci_lock

c1cde578 FD: 55 BD: 3 +.+.+.: attribute_container_mutex
-> [c25db814] &x->wait#3
-> [c2607b50] &(&k->k_lock)->rlock
-> [c1cddc78] gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c25db6fc] subsys mutex#29
-> [c1e0a8bc] &rq->lock

c1cdf0d8 FD: 32 BD: 1 +.+.+.: drivers_dir_mutex
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1e0a8bc] &rq->lock

c1cfa3b8 FD: 3 BD: 1 +.+.+.: info_mutex
-> [c1c9dbe0] (proc_inum_ida).idr.lock
-> [c1c9db90] proc_inum_lock

c1ccb630 FD: 1 BD: 44 +.+...: kobj_ns_type_lock

c25e2924 FD: 8 BD: 8 +.+...: subsys mutex#11
-> [c2607b50] &(&k->k_lock)->rlock

c1cdedf8 FD: 4 BD: 15 +.+...: dev_hotplug_mutex
-> [c25db698] &(&dev->power.lock)->rlock

c1cff694 FD: 1 BD: 8 +.....: dev_base_lock

c25dd080 FD: 1 BD: 1 ......: &syncp->seq

c1d01b94 FD: 1 BD: 1 +.+...: qdisc_mod_lock

c1d01fd8 FD: 8 BD: 1 +.+.+.: cb_lock
-> [c1d02038] genl_mutex

c1d02038 FD: 7 BD: 2 +.+.+.: genl_mutex
-> [c1e0a8bc] &rq->lock
-> [c1d01e14] nl_table_lock
-> [c1d01e50] nl_table_wait.lock

c1d02138 FD: 1 BD: 1 +.+...: afinfo_mutex

c1d01dd0 FD: 1 BD: 1 ......: netlink_chain.lock

c2607354 FD: 1 BD: 8 +.+...: &(&reg_requests_lock)->rlock

c1e0a15c FD: 1 BD: 1 .+.+.+: "events"

c1d0c400 FD: 108 BD: 1 +.+.+.: reg_work
-> [c1cff938] rtnl_mutex

c260734c FD: 1 BD: 8 +.....: &(&reg_pending_beacons_lock)->rlock

c1d141b8 FD: 1 BD: 1 +.+.+.: rate_ctrl_mutex

c1d19970 FD: 1 BD: 1 +.+...: netlbl_domhsh_lock

c1d19a90 FD: 1 BD: 1 +.+...: netlbl_unlhsh_lock

c1cf0d98 FD: 155 BD: 5 +.+.+.: input_mutex
-> [c1cf0d30] input_devices_poll_wait.lock
-> [c25deac8] &dev->mutex#2
-> [c1cf0de0] (input_ida).idr.lock
-> [c1ccb5f0] simple_ida_lock
-> [c1e0a8bc] &rq->lock
-> [c25db814] &x->wait#3
-> [c1c99a58] chrdevs_lock
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c25b4244] &(kretprobe_table_locks[i].lock)
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1cde990] req_lock
-> [c1e098e4] &p->pi_lock
-> [c25db718] (complete)&req.done
-> [c25db710] &x->wait#5
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c2607b50] &(&k->k_lock)->rlock
-> [c25deab0] subsys mutex#24
-> [c25df718] subsys mutex#37
-> [c1cf5f38] leds_list_lock
-> [c1cf6018] triggers_list_lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25deb11] &mousedev->mutex/1

c1cf0d30 FD: 1 BD: 6 ......: input_devices_poll_wait.lock

c1e08e10 FD: 25 BD: 3 +.+...: (complete)&work.complete
-> [c1e08e20] (&(&work.work)->work)
-> [c1e0a1a4] &(&pool->lock)->rlock
-> [c259f24c] &(&base->lock)->rlock
-> [c1e0a194] ((&pool->mayday_timer))
-> [c1e0a184] &pool->attach_mutex
-> [c1e098e4] &p->pi_lock
-> [c1e0a358] &x->wait
-> [c1e0a8bc] &rq->lock
-> [c1c82a10] kthread_create_lock
-> [c1ccb5f0] simple_ida_lock
-> [c25d2d9c] &(&idp->lock)->rlock

c1e08e08 FD: 6 BD: 5 ......: &x->wait#6
-> [c1e098e4] &p->pi_lock

c1e08e20 FD: 7 BD: 4 +.+...: (&(&work.work)->work)
-> [c1e08e08] &x->wait#6

c1c8c858 FD: 10 BD: 3 +.+...: stop_cpus_mutex
-> [c1c8c88c] stop_cpus_lock
-> [c25b3ba0] (complete)&done->completion
-> [c1e0a8bc] &rq->lock
-> [c25b3b98] &x->wait#7

c1c8c88c FD: 7 BD: 4 +.+...: stop_cpus_lock
-> [c25b3b90] &(&stopper->lock)->rlock

c25b3ba0 FD: 8 BD: 35 +.+...: (complete)&done->completion
-> [c25b3b98] &x->wait#7
-> [c25b3b90] &(&stopper->lock)->rlock
-> [c1e098e4] &p->pi_lock
-> [c1e0a8bc] &rq->lock

c25b3b98 FD: 6 BD: 36 ......: &x->wait#7
-> [c1e098e4] &p->pi_lock

c1cc3205 FD: 26 BD: 1 +.+.+.: &type->s_umount_key#9/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c1cc322c] &sb->s_type->i_lock_key#9
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1cc322c FD: 17 BD: 6 +.+...: &sb->s_type->i_lock_key#9
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1cc3234 FD: 22 BD: 4 +.+.+.: &sb->s_type->i_mutex_key#6
-> [c1cc322c] &sb->s_type->i_lock_key#9
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25bc904] &(&zone->lock)->rlock

c1c8da78 FD: 26 BD: 1 +.+.+.: event_mutex
-> [c1c99ff0] pin_fs_lock
-> [c1cc3234] &sb->s_type->i_mutex_key#6
-> [c1c8d6d8] trace_event_sem

c1c99b05 FD: 26 BD: 1 +.+.+.: &type->s_umount_key#10/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c1c99b2c] &sb->s_type->i_lock_key#10
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1c99b2c FD: 17 BD: 2 +.+...: &sb->s_type->i_lock_key#10
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1c635d0 FD: 1 BD: 7 +.+...: bdev_lock

c1c9c585 FD: 26 BD: 1 +.+.+.: &type->s_umount_key#11/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c1c9c5ac] &sb->s_type->i_lock_key#11
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1c9c5ac FD: 17 BD: 2 +.+...: &sb->s_type->i_lock_key#11
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1c9dd74 FD: 1 BD: 1 +.+...: kclist_lock

c1ca7585 FD: 27 BD: 1 +.+.+.: &type->s_umount_key#12/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c25bc904] &(&zone->lock)->rlock
-> [c1ca75ac] &sb->s_type->i_lock_key#12
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1ca75ac FD: 17 BD: 2 +.+...: &sb->s_type->i_lock_key#12
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c25d5768 FD: 8 BD: 12 +.+...: subsys mutex#12
-> [c2607b50] &(&k->k_lock)->rlock

c1cd0318 FD: 1 BD: 1 +.+.+.: pnp_lock

c1cd03ec FD: 1 BD: 1 +.+...: subsys mutex#13

c25daa40 FD: 8 BD: 1 +.+...: subsys mutex#14
-> [c2607b50] &(&k->k_lock)->rlock

c25d6084 FD: 8 BD: 12 +.+...: subsys mutex#15
-> [c2607b50] &(&k->k_lock)->rlock

c25d63b0 FD: 8 BD: 1 +.+...: subsys mutex#16
-> [c2607b50] &(&k->k_lock)->rlock

c1cd0d58 FD: 194 BD: 1 +.+.+.: tty_mutex
-> [c1c87750] (console_sem).lock
-> [c1c8772c] console_lock
-> [c1c87710] logbuf_lock
-> [c1cd0eb0] tty_ldiscs_lock
-> [c2607b50] &(&k->k_lock)->rlock
-> [c25d60ec] &tty->legacy_mutex
-> [c25d6218] (&buf->work)
-> [c1e0a1a4] &(&pool->lock)->rlock
-> [c1e0a8bc] &rq->lock

c1cf6018 FD: 25 BD: 6 ++++.+: triggers_list_lock
-> [c25df728] &led_cdev->trigger_lock

c1cf5f38 FD: 1 BD: 6 ++++..: leds_list_lock

c25df734 FD: 1 BD: 8 .+.?..: &trig->leddev_list_lock

c25ddce0 FD: 8 BD: 1 +.+...: subsys mutex#17
-> [c2607b50] &(&k->k_lock)->rlock

c1cf3958 FD: 2 BD: 1 +.+...: thermal_governor_lock
-> [c1cf39b8] thermal_list_lock

c1cf39b8 FD: 1 BD: 2 +.+...: thermal_list_lock

c1cf5778 FD: 1 BD: 1 +.+...: cpufreq_governor_mutex

c1cfd5d0 FD: 1 BD: 1 ......: pcibios_fwaddrmap_lock

c1cff6d0 FD: 1 BD: 1 +.+...: offload_lock

c1d049f0 FD: 1 BD: 1 +.....: inetsw_lock

c1cff710 FD: 1 BD: 1 +.+...: ptype_lock

c25e24e4 FD: 2 BD: 9 +.....: &tbl->lock
-> [c259f24c] &(&base->lock)->rlock

c1e0a134 FD: 1 BD: 1 .+.+.+: "events_power_efficient"

c1d04720 FD: 2 BD: 1 +.+...: (check_lifetime_work).work
-> [c259f24c] &(&base->lock)->rlock

c25e29b0 FD: 1 BD: 2 +.+...: &(&net->rules_mod_lock)->rlock

c1d06790 FD: 1 BD: 1 +.....: xfrm_state_afinfo_lock

c1d06650 FD: 1 BD: 1 +.+...: xfrm_policy_afinfo_lock

c1d067d0 FD: 1 BD: 1 +.....: xfrm_input_afinfo_lock

c1d038d4 FD: 1 BD: 2 +.....: raw_v4_hashinfo.lock

c1d035f0 FD: 1 BD: 1 +.+...: tcp_cong_list_lock

c1cfdda0 FD: 1 BD: 2 ......: (net_generic_ids).idr.lock

c1d0bbf0 FD: 1 BD: 3 +.+...: cache_list_lock

c26067c8 FD: 3 BD: 1 +.+...: (&(&cache_cleaner)->work)
-> [c1d0bbf0] cache_list_lock
-> [c259f24c] &(&base->lock)->rlock

c1d0bc58 FD: 1 BD: 1 +.+...: (rpc_pipefs_notifier_list).rwsem

c1d0bd30 FD: 1 BD: 1 +.+...: svc_xprt_class_lock

c1d092f0 FD: 1 BD: 1 +.+...: xprt_list_lock

c1c6cab4 FD: 34 BD: 1 .+.+.+: sb_writers#2
-> [c1c6cad5] &sb->s_type->i_mutex_key#2/1
-> [c1c6cad4] &sb->s_type->i_mutex_key#2

c1c6cad5 FD: 21 BD: 2 +.+.+.: &sb->s_type->i_mutex_key#2/1
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1c6cacc] &sb->s_type->i_lock_key
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock

c1c7c400 FD: 45 BD: 1 +.+...: (tsc_irqwork).work
-> [c259f24c] &(&base->lock)->rlock
-> [c1c89db8] clocksource_mutex

c26067c0 FD: 9 BD: 1 ..-...: (&(&cache_cleaner)->timer)
-> [c1e0a1a4] &(&pool->lock)->rlock

c1e06400 FD: 8 BD: 3 +.+...: subsys mutex#18
-> [c2607b50] &(&k->k_lock)->rlock

c1e0640c FD: 8 BD: 3 +.+...: subsys mutex#19
-> [c2607b50] &(&k->k_lock)->rlock

c1c0039a FD: 9 BD: 1 ..-...: net/wireless/reg.c:533
-> [c1e0a1a4] &(&pool->lock)->rlock

c1d0c380 FD: 108 BD: 1 +.+.+.: (crda_timeout).work
-> [c1cff938] rtnl_mutex

c2607344 FD: 1 BD: 8 +.+...: &(&reg_indoor_lock)->rlock

c1c7ee00 FD: 2 BD: 1 +.+...: (bios_check_work).work
-> [c259f24c] &(&base->lock)->rlock

c1cc79f8 FD: 11 BD: 1 +.+.+.: crypto_alg_sem
-> [c25d1140] &x->wait#8
-> [c1cc7998] (crypto_chain).rwsem

c1cc7998 FD: 9 BD: 2 .+.+.+: (crypto_chain).rwsem
-> [c1c82a10] kthread_create_lock
-> [c1e098e4] &p->pi_lock
-> [c1e0a360] (complete)&done
-> [c1e0a358] &x->wait
-> [c1e0a8bc] &rq->lock

c25d1148 FD: 1 BD: 1 +.+...: (complete)&larval->completion

c25d1140 FD: 6 BD: 2 ......: &x->wait#8
-> [c1e098e4] &p->pi_lock

c1c89c8c FD: 1 BD: 1 +.+...: subsys mutex#20

c25debe4 FD: 9 BD: 1 +.+...: subsys mutex#21
-> [c2607b50] &(&k->k_lock)->rlock
-> [c1c89f30] rtcdev_lock

c1cddef8 FD: 1 BD: 6 +.+...: deferred_probe_mutex

c1cdde50 FD: 6 BD: 5 ......: probe_waitqueue.lock
-> [c1e098e4] &p->pi_lock

c1c8a2cc FD: 1 BD: 1 +.+...: subsys mutex#22

c1c8ca10 FD: 1 BD: 1 ......: audit_freelist_lock

c1c87670 FD: 1 BD: 1 ......: printk_ratelimit_state.lock

c25b4244 FD: 1 BD: 57 ......: &(kretprobe_table_locks[i].lock)

c1c8f9ec FD: 1 BD: 2 +.+...: subsys mutex#23

c25bc91c FD: 1 BD: 1 ....-.: &pgdat->kswapd_wait

c1b4e159 FD: 9 BD: 1 ..-...: arch/x86/kernel/tsc.c:1128
-> [c1e0a1a4] &(&pool->lock)->rlock

c25a0120 FD: 10 BD: 1 +.-...: (&watchdog_timer)
-> [c1c89d10] watchdog_lock

c1b6ba22 FD: 9 BD: 1 ..-...: mm/vmstat.c:1493
-> [c1e0a1a4] &(&pool->lock)->rlock

c1c92f40 FD: 41 BD: 1 +.+...: (shepherd).work
-> [c259f24c] &(&base->lock)->rlock
-> [c1e0a8bc] &rq->lock

c1c89d40 FD: 9 BD: 1 +.+.+.: watchdog_work
-> [c1c82a10] kthread_create_lock
-> [c1e098e4] &p->pi_lock
-> [c1e0a360] (complete)&done
-> [c1e0a358] &x->wait
-> [c1e0a8bc] &rq->lock

c25bcaf8 FD: 1 BD: 1 .+.+..: "vmstat"

c25bcb08 FD: 2 BD: 1 +.+...: (&(({ do { const void *__vpp_verify = (typeof((&vmstat_work) + 0))((void *)0); (void)__vpp_verify; } while (0); ({ unsigned long __ptr; __asm__ ("" : "=r"(__ptr) : "0"((typeof(*((&vmstat_work))) *)((&vmstat_work)))); (typeof((typeof(*((&vmstat_work))) *)((&vmstat_work)))) (__ptr + (((__per_cpu_offset[(cpu)])))); }); }))->work)
-> [c259f24c] &(&base->lock)->rlock

c1c9c645 FD: 26 BD: 1 +.+.+.: &type->s_umount_key#13/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c1c9c66c] &sb->s_type->i_lock_key#13
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1c9c66c FD: 17 BD: 2 +.+...: &sb->s_type->i_lock_key#13
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1c63690 FD: 1 BD: 1 +.+...: dq_list_lock

c1ca7910 FD: 1 BD: 1 +.+...: nfs_version_lock

c1cc3b30 FD: 1 BD: 2 +.+...: key_user_lock

c1cc3b70 FD: 1 BD: 2 +.+...: key_serial_lock

c1cc3a78 FD: 2 BD: 2 +.+...: key_construction_mutex
-> [c1cc3c74] keyring_name_lock

c1cc3c74 FD: 1 BD: 3 ++++..: keyring_name_lock

c1cc3ad8 FD: 1 BD: 1 +.+...: key_types_sem

c1cc2eb0 FD: 1 BD: 1 +.+...: nls_lock

c1cc3705 FD: 27 BD: 1 +.+.+.: &type->s_umount_key#14/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c25bc904] &(&zone->lock)->rlock
-> [c1cc372c] &sb->s_type->i_lock_key#14
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1cc372c FD: 17 BD: 2 +.+...: &sb->s_type->i_lock_key#14
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1d020d8 FD: 1 BD: 8 +.+...: nf_hook_mutex

c1cc7305 FD: 27 BD: 1 +.+.+.: &type->s_umount_key#15/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c1cc732c] &sb->s_type->i_lock_key#15
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1cc732c FD: 17 BD: 2 +.+...: &sb->s_type->i_lock_key#15
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1cc9230 FD: 1 BD: 8 +.+...: elv_list_lock

c25d36fc FD: 1 BD: 1 +.+...: &(&drv->dynids.lock)->rlock

c25deab0 FD: 8 BD: 6 +.+...: subsys mutex#24
-> [c2607b50] &(&k->k_lock)->rlock

c25deac8 FD: 1 BD: 6 +.+...: &dev->mutex#2

c1ccfa9c FD: 45 BD: 1 +.+.+.: register_count_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c2607b50] &(&k->k_lock)->rlock
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock

c1cf3a38 FD: 1 BD: 1 +.+.+.: thermal_idr_lock

c25dee90 FD: 8 BD: 1 +.+...: subsys mutex#25
-> [c2607b50] &(&k->k_lock)->rlock

c1c83070 FD: 1 BD: 3 ......: async_lock

c25bcb00 FD: 9 BD: 1 ..-...: (&(({ do { const void *__vpp_verify = (typeof((&vmstat_work) + 0))((void *)0); (void)__vpp_verify; } while (0); ({ unsigned long __ptr; __asm__ ("" : "=r"(__ptr) : "0"((typeof(*((&vmstat_work))) *)((&vmstat_work)))); (typeof((typeof(*((&vmstat_work))) *)((&vmstat_work)))) (__ptr + (((__per_cpu_offset[(cpu)])))); }); }))->timer)
-> [c1e0a1a4] &(&pool->lock)->rlock

c1e0a3a4 FD: 231 BD: 1 +.+.+.: (&entry->work)
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1e0a8bc] &rq->lock
-> [c1c9de78] kernfs_mutex
-> [c2607b50] &(&k->k_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c1c83070] async_lock
-> [c1c83030] async_done.lock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c7ed7850] hrtimer_bases.lock#3
-> [c25db814] &x->wait#3
-> [c25dbbe0] &(shost->host_lock)->rlock
-> [c1cde578] attribute_container_mutex
-> [c25db698] &(&dev->power.lock)->rlock
-> [c25dbbd0] &shost->scan_mutex
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25d2788] (complete)&wait
-> [c25d2780] &x->wait#10
-> [c25bc904] &(&zone->lock)->rlock
-> [c25ba114] &(&tsk->delays->lock)->rlock
-> [c1cddc78] gdp_mutex
-> [c25b4244] &(kretprobe_table_locks[i].lock)
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c1e098e4] &p->pi_lock
-> [c1cdee58] dpm_list_mtx
-> [c25bcb50] subsys mutex#26
-> [c1c99ff0] pin_fs_lock
-> [c1cc30b4] &sb->s_type->i_mutex_key#3
-> [c1c930d0] bdi_lock
-> [c1ccaf18] block_class_lock
-> [c1cde990] req_lock
-> [c25db718] (complete)&req.done
-> [c25db710] &x->wait#5
-> [c25d280c] subsys mutex#27
-> [c1cdedf8] dev_hotplug_mutex
-> [c1c63550] inode_hash_lock
-> [c1c635d0] bdev_lock
-> [c1c9c30c] &sb->s_type->i_lock_key#2
-> [c25d2824] &ev->block_mutex
-> [c25c57e4] &bdev->bd_mutex
-> [c25d282c] &(&ev->lock)->rlock
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c1ccac58] disk_events_mutex

c1c83030 FD: 6 BD: 2 ......: async_done.lock
-> [c1e098e4] &p->pi_lock

c1cd4cd8 FD: 163 BD: 1 +.+.+.: serial_mutex
-> [c1cd4ab8] port_mutex

c1cd4ab8 FD: 162 BD: 2 +.+.+.: port_mutex
-> [c25d6238] &port->mutex

c25d6238 FD: 161 BD: 11 +.+.+.: &port->mutex
-> [c1c805f0] bootmem_resource_lock
-> [c1c80634] resource_lock
-> [c25d74d4] &port_lock_key
-> [c1c99a58] chrdevs_lock
-> [c25db814] &x->wait#3
-> [c1cddc78] gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1cde990] req_lock
-> [c1e098e4] &p->pi_lock
-> [c25db718] (complete)&req.done
-> [c25db710] &x->wait#5
-> [c1e0a8bc] &rq->lock
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c2607b50] &(&k->k_lock)->rlock
-> [c25d6084] subsys mutex#15
-> [c25bc904] &(&zone->lock)->rlock
-> [c25d6228] &(&port->lock)->rlock
-> [c1cd4dd8] hash_mutex
-> [c25d7500] &(&i->lock)->rlock
-> [c259f0c4] &irq_desc_lock_class
-> [c1c87c58] register_lock
-> [c1c9dbe0] (proc_inum_ida).idr.lock
-> [c1c9db90] proc_inum_lock
-> [c25d6240] &port->delta_msr_wait
-> [c25d7508] (&up->timer)
-> [c259f24c] &(&base->lock)->rlock
-> [c25d6248] &port->open_wait
-> [c25d60c4] &tty->write_wait

c25db6a0 FD: 1 BD: 6 ......: &(&dev->devres_lock)->rlock

c1cddde8 FD: 1 BD: 1 +.+...: s_active#2

c1cdde04 FD: 1 BD: 1 +.+...: s_active#3

c1ccc19c FD: 1 BD: 1 +.+...: s_active#4

c1ccc180 FD: 1 BD: 1 +.+...: s_active#5

c1cddd94 FD: 1 BD: 1 +.+...: s_active#6

c1d19ed0 FD: 6 BD: 79 +.+...: klist_remove_lock
-> [c1e098e4] &p->pi_lock

c25db6b4 FD: 1 BD: 3 .+.+..: &(&priv->bus_notifier)->rwsem

c25db660 FD: 1 BD: 1 +.....: &(&dev->queue_lock)->rlock

c1cdfdf8 FD: 180 BD: 4 +.+.+.: loop_index_mutex
-> [c1e0a8bc] &rq->lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c1cc9300] (blk_queue_ida).idr.lock
-> [c1ccb5f0] simple_ida_lock
-> [c1cc91d8] bio_slab_lock
-> [c1c934b8] pcpu_alloc_mutex
-> [c1e0a16c] &wq->mutex
-> [c1c82a10] kthread_create_lock
-> [c1e098e4] &p->pi_lock
-> [c1e0a360] (complete)&done
-> [c1e0a358] &x->wait
-> [c1c827b8] wq_pool_mutex
-> [c1ccb9d0] percpu_counters_lock
-> [c1ccabd0] blk_mq_cpu_notify_lock
-> [c1cca998] all_q_mutex
-> [c25db814] &x->wait#3
-> [c1cddc78] gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c25bcb50] subsys mutex#26
-> [c1c99ff0] pin_fs_lock
-> [c1cc30b4] &sb->s_type->i_mutex_key#3
-> [c1c930d0] bdi_lock
-> [c1ccaf18] block_class_lock
-> [c1cde990] req_lock
-> [c25db718] (complete)&req.done
-> [c25db710] &x->wait#5
-> [c25d280c] subsys mutex#27
-> [c1cdedf8] dev_hotplug_mutex
-> [c25d2718] &(&q->__queue_lock)->rlock

c1cc9300 FD: 1 BD: 81 ......: (blk_queue_ida).idr.lock

c1ccabd0 FD: 1 BD: 5 +.+...: blk_mq_cpu_notify_lock

c1cca998 FD: 48 BD: 5 +.+.+.: all_q_mutex
-> [c25d2794] &set->tag_list_lock
-> [c25d2720] &q->sysfs_lock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c25bc904] &(&zone->lock)->rlock

c25d2794 FD: 1 BD: 6 +.+...: &set->tag_list_lock

c25d2720 FD: 21 BD: 7 +.+.+.: &q->sysfs_lock
-> [c1cc9230] elv_list_lock
-> [c25d2718] &(&q->__queue_lock)->rlock

c25bcb50 FD: 8 BD: 8 +.+...: subsys mutex#26
-> [c2607b50] &(&k->k_lock)->rlock

c1c930d0 FD: 1 BD: 8 +.....: bdi_lock

c25d280c FD: 8 BD: 8 +.+...: subsys mutex#27
-> [c2607b50] &(&k->k_lock)->rlock

c25d2718 FD: 19 BD: 80 -.-...: &(&q->__queue_lock)->rlock
-> [c25dbc3c] &(&sdev->list_lock)->rlock
-> [c259f24c] &(&base->lock)->rlock
-> [c25d2780] &x->wait#10
-> [c25bc904] &(&zone->lock)->rlock
-> [c25d2774] &(&ioc->lock)->rlock
-> [c25dbbe0] &(shost->host_lock)->rlock
-> [c1e0a1a4] &(&pool->lock)->rlock
-> [c25d26bc] &x->wait#15
-> [c1cd85c8] nonblocking_pool.lock
-> [c25bc924] zone->wait_table + i
-> [c1cd86c8] input_pool.lock
-> [c1cd87d0] random_read_wait.lock

c25dbd88 FD: 147 BD: 3 +.+.+.: subsys mutex#28
-> [c2607b50] &(&k->k_lock)->rlock
-> [c1c934b8] pcpu_alloc_mutex
-> [c25db814] &x->wait#3
-> [c1ce48d4] sg_index_lock
-> [c1c99a58] chrdevs_lock
-> [c1e0a8bc] &rq->lock
-> [c1cddc78] gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1e098e4] &p->pi_lock
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25b4244] &(kretprobe_table_locks[i].lock)
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1cde990] req_lock
-> [c25db718] (complete)&req.done
-> [c25db710] &x->wait#5
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c25dbf04] subsys mutex#34

c25dbfa8 FD: 23 BD: 74 -.-...: &(&host->lock)->rlock
-> [c25dbbe0] &(shost->host_lock)->rlock
-> [c25dbfc0] &ap->eh_wait_q
-> [c1e0a1a4] &(&pool->lock)->rlock
-> [c25dbfe8] &x->wait#9
-> [c1ce6650] ata_scsi_rbuf_lock
-> [c1e098e4] &p->pi_lock
-> [c25d2718] &(&q->__queue_lock)->rlock

c1ce4970 FD: 1 BD: 1 +.+...: lock

c25db6fc FD: 8 BD: 4 +.+...: subsys mutex#29
-> [c2607b50] &(&k->k_lock)->rlock

c1ce3420 FD: 1 BD: 81 ......: (host_index_ida).idr.lock

c1ce0578 FD: 71 BD: 1 +.+.+.: host_cmd_pool_mutex

c1ce3a8c FD: 1 BD: 3 +.+...: subsys mutex#30

c25dbbc0 FD: 8 BD: 1 +.+...: subsys mutex#31
-> [c2607b50] &(&k->k_lock)->rlock

c25db754 FD: 1 BD: 48 ......: &dev->power.wait_queue

c25dbbe0 FD: 6 BD: 82 -.-...: &(shost->host_lock)->rlock
-> [c1e098e4] &p->pi_lock

c25dbfc0 FD: 6 BD: 75 ......: &ap->eh_wait_q
-> [c1e098e4] &p->pi_lock

c25dd034 FD: 24 BD: 10 +.+...: (&(&ap->sff_pio_task)->work)
-> [c25dbfa8] &(&host->lock)->rlock

c25dbfa0 FD: 29 BD: 9 +.+...: &host->eh_mutex
-> [c25dbfb0] (&ap->fastdrain_timer)
-> [c259f24c] &(&base->lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c1ce7850] piix_lock
-> [c1ccbdd0] pci_lock
-> [c25dd034] (&(&ap->sff_pio_task)->work)
-> [c1e0a1a4] &(&pool->lock)->rlock

c25dbfb0 FD: 1 BD: 10 ......: (&ap->fastdrain_timer)

c1ce7850 FD: 3 BD: 10 ......: piix_lock
-> [c1ccbdd0] pci_lock

c1cff650 FD: 1 BD: 1 +.+...: napi_hash_lock

c1ce9ab8 FD: 5 BD: 1 +.+...: e1000_eeprom_lock
-> [c1e0a8bc] &rq->lock

c25dd024 FD: 1 BD: 1 .+.+..: "ata_sff"

c25dbfe8 FD: 6 BD: 75 -.-...: &x->wait#9
-> [c1e098e4] &p->pi_lock

c25dbbd8 FD: 6 BD: 5 ......: &shost->host_wait
-> [c1e098e4] &p->pi_lock

c25dbbd0 FD: 208 BD: 2 +.+.+.: &shost->scan_mutex
-> [c25db698] &(&dev->power.lock)->rlock
-> [c25dbbe0] &(shost->host_lock)->rlock
-> [c25bc904] &(&zone->lock)->rlock
-> [c1cc9300] (blk_queue_ida).idr.lock
-> [c1ccb5f0] simple_ida_lock
-> [c1cc91d8] bio_slab_lock
-> [c1c934b8] pcpu_alloc_mutex
-> [c1e0a16c] &wq->mutex
-> [c1e0a8bc] &rq->lock
-> [c1c82a10] kthread_create_lock
-> [c1e098e4] &p->pi_lock
-> [c1e0a360] (complete)&done
-> [c1e0a358] &x->wait
-> [c1c827b8] wq_pool_mutex
-> [c1ccb9d0] percpu_counters_lock
-> [c25d2720] &q->sysfs_lock
-> [c25db814] &x->wait#3
-> [c1cde578] attribute_container_mutex
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c25d2788] (complete)&wait
-> [c25d2780] &x->wait#10
-> [c25dbc34] &sdev->inquiry_mutex
-> [c259f118] (complete)&rs_array[i].completion
-> [c259f110] &x->wait#4
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c2607b50] &(&k->k_lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c1ce3a8c] subsys mutex#30
-> [c1cddc78] gdp_mutex
-> [c25dbd88] subsys mutex#28
-> [c1ccb178] bsg_mutex
-> [c25ba114] &(&tsk->delays->lock)->rlock
-> [c25b4244] &(kretprobe_table_locks[i].lock)

c25dbc3c FD: 1 BD: 81 ..-...: &(&sdev->list_lock)->rlock

c1ce6650 FD: 1 BD: 75 -.-...: ata_scsi_rbuf_lock

c25d2780 FD: 6 BD: 81 ..-...: &x->wait#10
-> [c1e098e4] &p->pi_lock

c25d2788 FD: 37 BD: 8 +.+...: (complete)&wait
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25bc904] &(&zone->lock)->rlock
-> [c259f24c] &(&base->lock)->rlock
-> [c259f1d0] rcu_node_0
-> [c259f0c4] &irq_desc_lock_class
-> [c25dbfa8] &(&host->lock)->rlock
-> [c25dbbe0] &(shost->host_lock)->rlock
-> [c25dbfa0] &host->eh_mutex
-> [c25dbfe8] &x->wait#9
-> [c259f254] ((&timer))
-> [c1e0a8bc] &rq->lock
-> [c1e0a1a4] &(&pool->lock)->rlock
-> [c25dd034] (&(&ap->sff_pio_task)->work)
-> [c1cd87d0] random_read_wait.lock
-> [c1cd86c8] input_pool.lock
-> [c7eaf850] hrtimer_bases.lock

c1ce9a50 FD: 1 BD: 1 ......: e1000_phy_lock

c25dbc34 FD: 1 BD: 3 +.+...: &sdev->inquiry_mutex

c1cff9b0 FD: 9 BD: 8 ......: lweventlist_lock
-> [c1e0a1a4] &(&pool->lock)->rlock

c1cff9e0 FD: 108 BD: 1 +.+...: (linkwatch_work).work
-> [c1cff938] rtnl_mutex

c1ce45c0 FD: 1 BD: 4 ......: (sd_index_ida).idr.lock

c1ce45f0 FD: 2 BD: 3 +.+...: sd_index_lock
-> [c1ce45c0] (sd_index_ida).idr.lock

c25dbebc FD: 8 BD: 3 +.+...: subsys mutex#32
-> [c2607b50] &(&k->k_lock)->rlock

c25ba114 FD: 1 BD: 69 ......: &(&tsk->delays->lock)->rlock

c25de438 FD: 8 BD: 1 +.+...: subsys mutex#33
-> [c2607b50] &(&k->k_lock)->rlock

c1cebbf8 FD: 1 BD: 1 +.+...: usb_bus_idr_lock

c1ce48d4 FD: 1 BD: 4 ......: sg_index_lock

c25dbf04 FD: 8 BD: 4 +.+...: subsys mutex#34
-> [c2607b50] &(&k->k_lock)->rlock

c1ccb178 FD: 145 BD: 3 +.+.+.: bsg_mutex
-> [c25db814] &x->wait#3
-> [c1cddc78] gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c1ccb5f0] simple_ida_lock
-> [c25b4244] &(kretprobe_table_locks[i].lock)
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1cde990] req_lock
-> [c1e098e4] &p->pi_lock
-> [c25db718] (complete)&req.done
-> [c25db710] &x->wait#5
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c2607b50] &(&k->k_lock)->rlock
-> [c25d2cd8] subsys mutex#35

c1c63550 FD: 21 BD: 81 +.+...: inode_hash_lock
-> [c1c9c30c] &sb->s_type->i_lock_key#2
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c1c9e3ec] &sb->s_type->i_lock_key#16
-> [c1c9e04c] &sb->s_type->i_lock_key#17

c1cf0730 FD: 2 BD: 7 -.-...: i8042_lock
-> [c25de860] &x->wait#11

c25d2824 FD: 80 BD: 5 +.+...: &ev->block_mutex
-> [c25d282c] &(&ev->lock)->rlock
-> [c25d281c] (&(&ev->dwork)->work)
-> [c1e0a1a4] &(&pool->lock)->rlock

c25d282c FD: 9 BD: 8 ......: &(&ev->lock)->rlock
-> [c1e0a1a4] &(&pool->lock)->rlock

c25c57e4 FD: 206 BD: 3 +.+.+.: &bdev->bd_mutex
-> [c1ce4578] sd_ref_mutex
-> [c1c9c314] &sb->s_type->i_mutex_key#7
-> [c1c63550] inode_hash_lock
-> [c1c99970] sb_lock
-> [c1e0a8bc] &rq->lock
-> [c25b4244] &(kretprobe_table_locks[i].lock)
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c25d2788] (complete)&wait
-> [c25d2780] &x->wait#10
-> [c1c972d0] vmap_area_lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25c5674] &(&mapping->private_lock)->rlock
-> [c25bc924] zone->wait_table + i
-> [c25d282c] &(&ev->lock)->rlock
-> [c25bc8fc] &(&zone->lru_lock)->rlock
-> [c1c9c30c] &sb->s_type->i_lock_key#2
-> [c1cf4930] all_mddevs_lock
-> [c25def74] &mddev->open_mutex
-> [c1c635d0] bdev_lock
-> [c1ce47f8] sr_mutex
-> [c1cdfdf8] loop_index_mutex
-> [c25dbab8] &lo->lo_ctl_mutex

c1ce4578 FD: 1 BD: 7 +.+...: sd_ref_mutex

c1c9c314 FD: 2 BD: 4 +.+...: &sb->s_type->i_mutex_key#7
-> [c25c566c] &inode->i_size_seqcount

c25c566c FD: 1 BD: 63 +.+...: &inode->i_size_seqcount

c25d2cd8 FD: 8 BD: 4 +.+...: subsys mutex#35
-> [c2607b50] &(&k->k_lock)->rlock

c25de860 FD: 1 BD: 8 -.....: &x->wait#11

c25c6f84 FD: 1 BD: 13 +.+...: &(&ent->pde_unload_lock)->rlock

c1cf05b0 FD: 9 BD: 3 ......: serio_event_lock
-> [c1e0a1a4] &(&pool->lock)->rlock

c1e0a14c FD: 1 BD: 1 .+.+.+: "events_long"

c1cf0560 FD: 174 BD: 1 +.+.+.: serio_event_work
-> [c1cf0618] serio_mutex
-> [c1e0a8bc] &rq->lock

c1cf0618 FD: 173 BD: 2 +.+.+.: serio_mutex
-> [c1cf05b0] serio_event_lock
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c2607b50] &(&k->k_lock)->rlock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c25db6b4] &(&priv->bus_notifier)->rwsem
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c1cf03ac] subsys mutex#36
-> [c1e098e4] &p->pi_lock
-> [c25b4244] &(kretprobe_table_locks[i].lock)
-> [c25bc904] &(&zone->lock)->rlock

c1cf0de0 FD: 1 BD: 81 ......: (input_ida).idr.lock

c25bc8c0 FD: 93 BD: 61 +.+...: (PG_locked)page
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25c5674] &(&mapping->private_lock)->rlock
-> [c25bc904] &(&zone->lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c25bc8fc] &(&zone->lru_lock)->rlock
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c259f24c] &(&base->lock)->rlock
-> [c259f0c4] &irq_desc_lock_class
-> [c25dbfa8] &(&host->lock)->rlock
-> [c25bc924] zone->wait_table + i
-> [c1e0980c] &(ptlock_ptr(page))->rlock
-> [c7eeb850] hrtimer_bases.lock#4
-> [c7eaf850] hrtimer_bases.lock
-> [c1c898b0] timekeeper_lock
-> [c1c632e8] jiffies_lock
-> [c7ed7850] hrtimer_bases.lock#3
-> [c7ec3850] hrtimer_bases.lock#2
-> [c25c566c] &inode->i_size_seqcount
-> [c25bca84] &(&info->lock)->rlock
-> [c259f1d0] rcu_node_0
-> [c259f190] &rsp->gp_wq
-> [c25d2d68] (&cfqd->idle_slice_timer)
-> [c1cd87d0] random_read_wait.lock
-> [c25c88c0] &(&sbi->s_bal_lock)->rlock
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c25bcb38] &(&wb->list_lock)->rlock
-> [c1c9e3ec] &sb->s_type->i_lock_key#16
-> [c25c8744] &ei->i_data_sem
-> [c25c89a0] &(&journal->j_list_lock)->rlock
-> [c25c879c] &(&ei->i_raw_lock)->rlock

c25c5684 FD: 5 BD: 69 ..-...: &(&mapping->tree_lock)->rlock
-> [c259f24c] &(&base->lock)->rlock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25d2d74] &pl->lock

c25c5674 FD: 1 BD: 65 +.+...: &(&mapping->private_lock)->rlock

c259f12f FD: 1 BD: 1 ......: rcu_read_lock_sched

c25deb11 FD: 1 BD: 6 +.+...: &mousedev->mutex/1

c25bc924 FD: 6 BD: 90 ..-...: zone->wait_table + i
-> [c1e098e4] &p->pi_lock

c25bc8fc FD: 1 BD: 71 ......: &(&zone->lru_lock)->rlock

c1cf03ac FD: 1 BD: 3 +.+...: subsys mutex#36

c1ccac58 FD: 1 BD: 3 +.+...: disk_events_mutex

c1e0a12c FD: 1 BD: 1 .+.+.+: "events_freezable_power_efficient"

c25d281c FD: 79 BD: 6 +.+.+.: (&(&ev->dwork)->work)
-> [c1ce4578] sd_ref_mutex
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c25d2788] (complete)&wait
-> [c25d2780] &x->wait#10
-> [c1e0a8bc] &rq->lock
-> [c25ba114] &(&tsk->delays->lock)->rlock
-> [c25d282c] &(&ev->lock)->rlock
-> [c25bc904] &(&zone->lock)->rlock
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock

c25d2774 FD: 9 BD: 81 ......: &(&ioc->lock)->rlock
-> [c1e0a1a4] &(&pool->lock)->rlock

c1ce46d0 FD: 1 BD: 3 +.+...: sr_index_lock

c25de840 FD: 167 BD: 3 +.+.+.: &serio->drv_mutex
-> [c25db814] &x->wait#3
-> [c25de848] &serio->lock
-> [c25deaa7] &ps2dev->cmd_mutex
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1e0a8bc] &rq->lock
-> [c1c9de78] kernfs_mutex
-> [c1cddc78] gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c2607b50] &(&k->k_lock)->rlock
-> [c25deab0] subsys mutex#24
-> [c1cf0d98] input_mutex
-> [c1cf0730] i8042_lock
-> [c25db6a0] &(&dev->devres_lock)->rlock
-> [c1cf12f8] psmouse_mutex

c25dbbb0 FD: 9 BD: 1 ..-...: (&(&cmd->abort_work)->timer)
-> [c1e0a1a5] &pool->lock/1

c25de848 FD: 16 BD: 7 -.-...: &serio->lock
-> [c25dea9f] &ps2dev->wait
-> [c25deac0] &(&dev->event_lock)->rlock

c25deaa7 FD: 22 BD: 5 +.+...: &ps2dev->cmd_mutex
-> [c1e0a8bc] &rq->lock
-> [c1cf06f8] i8042_mutex

c25dbbc8 FD: 1 BD: 1 .+.+..: "scsi_tmf_%d"shost->host_no

c25dbbb8 FD: 7 BD: 1 +.+...: (&(&cmd->abort_work)->work)
-> [c25dbbe0] &(shost->host_lock)->rlock

c1cf06f8 FD: 21 BD: 6 +.+...: i8042_mutex
-> [c25de848] &serio->lock
-> [c1cf0730] i8042_lock
-> [c1e0a8bc] &rq->lock
-> [c25dea9f] &ps2dev->wait
-> [c259f24c] &(&base->lock)->rlock
-> [c259f254] ((&timer))
-> [c25b4244] &(kretprobe_table_locks[i].lock)

c25dea9f FD: 6 BD: 8 -.-...: &ps2dev->wait
-> [c1e098e4] &p->pi_lock

c1ceb158 FD: 1 BD: 3 +.+...: cdrom_mutex

c1cf1980 FD: 1 BD: 81 ......: (rtc_ida).idr.lock

c25d2738 FD: 9 BD: 1 +.-...: ((&q->timeout))
-> [c1e0a1a4] &(&pool->lock)->rlock

c25dec0c FD: 2 BD: 1 +.+...: &rtc->ops_lock
-> [c1c7c830] rtc_lock

c25d2700 FD: 1 BD: 1 .+.+..: "kblockd"

c25d2708 FD: 20 BD: 1 +.+...: (&q->timeout_work)
-> [c25d2718] &(&q->__queue_lock)->rlock

c1c89f30 FD: 1 BD: 2 ......: rtcdev_lock

c1cf4ef8 FD: 1 BD: 1 +.+...: _lock

c25df718 FD: 8 BD: 6 +.+...: subsys mutex#37
-> [c2607b50] &(&k->k_lock)->rlock

c25df728 FD: 24 BD: 7 +.+.+.: &led_cdev->trigger_lock
-> [c1e0a8bc] &rq->lock
-> [c25df734] &trig->leddev_list_lock
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock

c25deac0 FD: 14 BD: 11 -.-...: &(&dev->event_lock)->rlock
-> [c1cd86c8] input_pool.lock
-> [c1cd87d0] random_read_wait.lock

c1cf53f0 FD: 1 BD: 1 +.+...: _lock#2

c1cf12f8 FD: 165 BD: 4 +.+.+.: psmouse_mutex
-> [c1e0a8bc] &rq->lock
-> [c25db814] &x->wait#3
-> [c25de848] &serio->lock
-> [c25deaa7] &ps2dev->cmd_mutex
-> [c1cddc78] gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c2607b50] &(&k->k_lock)->rlock
-> [c25deab0] subsys mutex#24
-> [c1cf0d98] input_mutex

c1cfa318 FD: 1 BD: 1 +.+...: snd_ioctl_rwsem

c1cfa418 FD: 1 BD: 1 +.+.+.: strings

c1cfa5b8 FD: 1 BD: 1 +.+...: register_mutex

c1cfa198 FD: 144 BD: 2 +.+.+.: sound_mutex
-> [c1cddc78] gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1cde990] req_lock
-> [c1e098e4] &p->pi_lock
-> [c25db718] (complete)&req.done
-> [c1e0a8bc] &rq->lock
-> [c25db710] &x->wait#5
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c25dfbc4] subsys mutex#38

c25dfbc4 FD: 8 BD: 5 +.+...: subsys mutex#38
-> [c2607b50] &(&k->k_lock)->rlock

c1cfa6b8 FD: 1 BD: 1 +.+...: register_mutex#2

c1cfaed8 FD: 146 BD: 1 +.+.+.: register_mutex#3
-> [c1cfa198] sound_mutex
-> [c1cfaf10] clients_lock
-> [c25bc904] &(&zone->lock)->rlock

c1cfaf10 FD: 1 BD: 4 ......: clients_lock

c25e09c0 FD: 2 BD: 1 +.+...: &client->ports_mutex
-> [c25e09c8] &client->ports_lock

c25e09c8 FD: 1 BD: 2 .+.+..: &client->ports_lock

c1cfb078 FD: 147 BD: 1 +.+.+.: register_mutex#4
-> [c1cfa478] sound_oss_mutex

c1cfa478 FD: 146 BD: 2 +.+.+.: sound_oss_mutex
-> [c1cfa130] sound_loader_lock
-> [c25db814] &x->wait#3
-> [c1cddc78] gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1cde990] req_lock
-> [c1e098e4] &p->pi_lock
-> [c25db718] (complete)&req.done
-> [c25db710] &x->wait#5
-> [c1e0a8bc] &rq->lock
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c25dfbc4] subsys mutex#38

c1cfa130 FD: 1 BD: 3 +.+...: sound_loader_lock

c25e1160 FD: 4 BD: 1 ++++.+: &grp->list_mutex
-> [c25e1168] &grp->list_lock
-> [c1cfaf10] clients_lock
-> [c1cfb1f0] register_lock#2

c25e1168 FD: 1 BD: 2 ......: &grp->list_lock

c1cfb100 FD: 147 BD: 1 +.+.+.: async_lookup_work
-> [c1cfaf10] clients_lock
-> [c1cfa258] snd_card_mutex
-> [c1e0a8bc] &rq->lock
-> [c1e0a1a5] &pool->lock/1
-> [c1e0a0f0] (complete)&done#2
-> [c1e0a0e8] &x->wait#12
-> [c1c820b0] running_helpers_waitq.lock
-> [c1e0a1a4] &(&pool->lock)->rlock
-> [c1cfafa0] autoload_work
-> [c1e0a1bc] (complete)&barr->done
-> [c1e0a1cc] &x->wait#13

c1cfa258 FD: 1 BD: 2 +.+...: snd_card_mutex

c1e0a0f0 FD: 135 BD: 2 +.+...: (complete)&done#2
-> [c1e0a0f8] (&sub_info->work)
-> [c1e0a1a5] &pool->lock/1
-> [c1e0a8bc] &rq->lock

c1e0a0e8 FD: 6 BD: 4 ......: &x->wait#12
-> [c1e098e4] &p->pi_lock

c1cfb1f0 FD: 1 BD: 2 ......: register_lock#2

c1e098dc FD: 1 BD: 77 ......: &prev->lock

c25e3620 FD: 1 BD: 1 +.+...: &table[i].mutex

c1d021b8 FD: 1 BD: 1 +.+...: nf_log_mutex

c1cfafa0 FD: 8 BD: 7 +.+...: autoload_work
-> [c2607b50] &(&k->k_lock)->rlock

c1e0a1bc FD: 15 BD: 6 +.+...: (complete)&barr->done
-> [c1e0a1c4] (&barr->work)
-> [c1e0a1a4] &(&pool->lock)->rlock
-> [c1cfafa0] autoload_work
-> [c1e0a8bc] &rq->lock
-> [c1e0a1a5] &pool->lock/1

c1e0a1cc FD: 6 BD: 37 ......: &x->wait#13
-> [c1e098e4] &p->pi_lock

c1e0a1c4 FD: 7 BD: 7 +.+...: (&barr->work)
-> [c1e0a1cc] &x->wait#13

c1d02bb8 FD: 1 BD: 1 +.+...: nf_ct_ext_type_mutex

c1d02538 FD: 1 BD: 1 +.+...: nf_ct_helper_mutex

c25e3ad0 FD: 1 BD: 2 +.+.+.: &xt[i].mutex

c1d02238 FD: 1 BD: 1 +.+...: nf_sockopt_mutex

c1d02598 FD: 1 BD: 1 +.+.+.: nf_ct_proto_mutex

c1d06690 FD: 1 BD: 1 +.....: xfrm_km_lock

c1d06f50 FD: 1 BD: 1 +.....: inetsw6_lock

c1d07ab4 FD: 1 BD: 2 +.....: raw_v6_hashinfo.lock

c25efc40 FD: 1 BD: 2 +.+...: &(&ip6addrlbl_table.lock)->rlock

c25efb40 FD: 4 BD: 8 ++....: &ndev->lock
-> [c1cd8790] random_write_wait.lock
-> [c1cd85c8] nonblocking_pool.lock
-> [c259f24c] &(&base->lock)->rlock

c25efcf2 FD: 1 BD: 8 +.....: &(&idev->mc_lock)->rlock

c25efd02 FD: 2 BD: 8 +.....: &(&mc->mca_lock)->rlock
-> [c25e2048] _xmit_ETHER

c259f137 FD: 1 BD: 1 ......: rcu_read_lock_bh

c25e2048 FD: 1 BD: 9 +.....: _xmit_ETHER

c25efb20 FD: 1 BD: 1 .+.+..: "%s"("ipv6_addrconf")

c1d07000 FD: 108 BD: 1 +.+...: (addr_chk_work).work
-> [c1cff938] rtnl_mutex

c1d06710 FD: 1 BD: 1 +.....: xfrm_type_lock

c1d08c78 FD: 1 BD: 1 +.+...: xfrm6_protocol_mutex

c1d066d0 FD: 1 BD: 1 +.....: xfrm_mode_lock

c26043d0 FD: 1 BD: 1 ......: &syncp->seq#2

c25efb28 FD: 1 BD: 1 ......: &syncp->seq#3

c1d05b98 FD: 1 BD: 1 +.+...: tunnel4_mutex

c1d0b450 FD: 1 BD: 1 +.+...: rpc_authflavor_lock

c1d0b6b0 FD: 1 BD: 1 +.+...: authtab_lock

c1c7e0b8 FD: 53 BD: 1 +.+.+.: microcode_mutex
-> [c1cde52c] subsys mutex#3

c1cc3d78 FD: 10 BD: 1 +.+.+.: key_user_keyring_mutex
-> [c1cc3b30] key_user_lock
-> [c1cc3d08] root_key_user.lock
-> [c1cd8790] random_write_wait.lock
-> [c1cd85c8] nonblocking_pool.lock
-> [c1cc3b70] key_serial_lock
-> [c1cc3a78] key_construction_mutex
-> [c1cc3c40] &type->lock_class

c1cc3d08 FD: 1 BD: 4 +.+...: root_key_user.lock

c1cc3c40 FD: 3 BD: 2 +.+.+.: &type->lock_class
-> [c1cc3bd8] keyring_serialise_link_sem

c1cc3bd8 FD: 2 BD: 3 +.+.+.: keyring_serialise_link_sem
-> [c1cc3d08] root_key_user.lock

c1ccb850 FD: 3 BD: 1 ......: lock#2
-> [c1cd8790] random_write_wait.lock
-> [c1cd85c8] nonblocking_pool.lock

c25db6c4 FD: 1 BD: 1 ++++..: "%s""deferwq"

c1cdde80 FD: 2 BD: 1 +.+...: deferred_probe_work
-> [c1cddef8] deferred_probe_mutex

c1c9def0 FD: 9 BD: 2 ......: kernfs_notify_lock
-> [c1e0a1a4] &(&pool->lock)->rlock

c1c9dea0 FD: 37 BD: 1 +.+...: kernfs_notify_work
-> [c1c9def0] kernfs_notify_lock
-> [c1c9df90] kernfs_open_node_lock
-> [c1c9de78] kernfs_mutex

c1c9df90 FD: 1 BD: 18 ......: kernfs_open_node_lock

c1ccff18 FD: 2 BD: 3 +.+.+.: performance_mutex
-> [c25d57d4] semaphore->lock

c1cf5814 FD: 1 BD: 3 ......: cpufreq_driver_lock

c25df56c FD: 1 BD: 3 +.+...: &policy->rwsem

c1cf5558 FD: 1 BD: 3 +.+...: s_active#7

c1cf5654 FD: 1 BD: 3 +.+...: s_active#8

c1cf561c FD: 1 BD: 3 +.+...: s_active#9

c1cf5638 FD: 1 BD: 3 +.+...: s_active#10

c1cf5670 FD: 1 BD: 3 +.+...: s_active#11

c1cf568c FD: 1 BD: 3 +.+...: s_active#12

c1cf5574 FD: 1 BD: 3 +.+...: s_active#13

c1cf55ac FD: 1 BD: 3 +.+...: s_active#14

c1cf5590 FD: 1 BD: 3 +.+...: s_active#15

c1cf55c8 FD: 1 BD: 3 +.+...: s_active#16

c1cf553c FD: 1 BD: 3 +.+...: s_active#17

c25df544 FD: 1 BD: 3 ......: &x->wait#14

c25df554 FD: 1 BD: 3 +.+...: (complete)&policy->kobj_unregister

c1c87359 FD: 1 BD: 1 +.+...: pm_mutex/1

c1c999f0 FD: 1 BD: 3 +.+...: cdev_lock

c25d60ec FD: 193 BD: 2 +.+.+.: &tty->legacy_mutex
-> [c1c972d0] vmap_area_lock
-> [c25d60c4] &tty->write_wait
-> [c25d60bc] &tty->read_wait
-> [c25d60dc] &tty->termios_rwsem
-> [c25d6094] &(&tty->files_lock)->rlock
-> [c25d6228] &(&port->lock)->rlock
-> [c25d6238] &port->mutex
-> [c25d74d4] &port_lock_key
-> [c1c87750] (console_sem).lock
-> [c1c8772c] console_lock
-> [c1c87710] logbuf_lock
-> [c25c40d4] &(&f->f_lock)->rlock
-> [c259f24c] &(&base->lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c259f254] ((&timer))
-> [c25bc904] &(&zone->lock)->rlock
-> [c25d60cc] &tty->ldisc_sem
-> [c25d60a4] &(&tty->ctrl_lock)->rlock
-> [c25d6248] &port->open_wait

c25d60c4 FD: 6 BD: 18 -.-...: &tty->write_wait
-> [c1e098e4] &p->pi_lock

c25d60bc FD: 6 BD: 9 ......: &tty->read_wait
-> [c1e098e4] &p->pi_lock

c25d60dc FD: 178 BD: 8 ++++..: &tty->termios_rwsem
-> [c25d6238] &port->mutex
-> [c25d60c4] &tty->write_wait
-> [c25d60bc] &tty->read_wait
-> [c25d6180] &ldata->output_lock
-> [c25d74d4] &port_lock_key
-> [c1c87750] (console_sem).lock
-> [c1c8772c] console_lock
-> [c1c87710] logbuf_lock
-> [c1e0a8bc] &rq->lock
-> [c1c7f3f0] pgd_lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25d609c] &(&tty->flow_lock)->rlock
-> [c25d60e4] &tty->throttle_mutex
-> [c255ba50] &sem->wait_lock
-> [c25d60a4] &(&tty->ctrl_lock)->rlock

c25d6094 FD: 3 BD: 4 +.+...: &(&tty->files_lock)->rlock
-> [c25c40d4] &(&f->f_lock)->rlock

c25d6228 FD: 1 BD: 12 ......: &(&port->lock)->rlock

c1cd4dd8 FD: 17 BD: 12 +.+.+.: hash_mutex
-> [c259f0c4] &irq_desc_lock_class
-> [c1c9dc14] proc_subdir_lock
-> [c25c6f84] &(&ent->pde_unload_lock)->rlock
-> [c1c9db90] proc_inum_lock
-> [c25d7500] &(&i->lock)->rlock

c25d7500 FD: 8 BD: 13 -.-...: &(&i->lock)->rlock
-> [c25d74d4] &port_lock_key

c1cf4930 FD: 1 BD: 4 +.+...: all_mddevs_lock

c25def0c FD: 1 BD: 1 +.+...: "md_misc"

c1cf4398 FD: 176 BD: 1 +.+.+.: disks_mutex
-> [c1cc9300] (blk_queue_ida).idr.lock
-> [c1ccb5f0] simple_ida_lock
-> [c1cc91d8] bio_slab_lock
-> [c1c934b8] pcpu_alloc_mutex
-> [c1e0a16c] &wq->mutex
-> [c1e0a8bc] &rq->lock
-> [c1c82a10] kthread_create_lock
-> [c1e098e4] &p->pi_lock
-> [c1e0a360] (complete)&done
-> [c1e0a358] &x->wait
-> [c1c827b8] wq_pool_mutex
-> [c1ccb9d0] percpu_counters_lock
-> [c25db814] &x->wait#3
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25def74] &mddev->open_mutex

c25def74 FD: 152 BD: 5 +.+.+.: &mddev->open_mutex
-> [c25db814] &x->wait#3
-> [c1cddc78] gdp_mutex
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c1ccd680] bus_type_sem
-> [c1c9dfd0] sysfs_symlink_target_lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25db698] &(&dev->power.lock)->rlock
-> [c1cdee58] dpm_list_mtx
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a1a5] &pool->lock/1
-> [c1c820b0] running_helpers_waitq.lock
-> [c1e0a8bc] &rq->lock
-> [c25bcb50] subsys mutex#26
-> [c1c99ff0] pin_fs_lock
-> [c1cc30b4] &sb->s_type->i_mutex_key#3
-> [c1c930d0] bdi_lock
-> [c1ccaf18] block_class_lock
-> [c1cde990] req_lock
-> [c1e098e4] &p->pi_lock
-> [c25db718] (complete)&req.done
-> [c25db710] &x->wait#5
-> [c25d280c] subsys mutex#27
-> [c1cdedf8] dev_hotplug_mutex
-> [c25d2718] &(&q->__queue_lock)->rlock

c25c57dc FD: 164 BD: 1 +.+.+.: &bdev->bd_fsfreeze_mutex
-> [c1c99970] sb_lock
-> [c1c934b8] pcpu_alloc_mutex
-> [c1c9e4c5] &type->s_umount_key#16/1
-> [c1c9e545] &type->s_umount_key#17/1
-> [c1c9e3c5] &type->s_umount_key#18/1

c1c9e4c5 FD: 64 BD: 2 +.+.+.: &type->s_umount_key#16/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25c5674] &(&mapping->private_lock)->rlock
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c1e0a8bc] &rq->lock

c25d2d60 FD: 24 BD: 1 +.+...: (&cfqd->unplug_work)
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock

c1c9e545 FD: 32 BD: 2 +.+.+.: &type->s_umount_key#17/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25c5674] &(&mapping->private_lock)->rlock
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c1e0a8bc] &rq->lock

c1c9e3c5 FD: 161 BD: 2 +.+.+.: &type->s_umount_key#18/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c25c5684] &(&mapping->tree_lock)->rlock -> [c25c5674] &(&mapping->private_lock)->rlock -> [c25d2718] &(&q->__queue_lock)->rlock -> [c25dbfa8] &(&host->lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c25bc924] zone->wait_table + i
-> [c1cd8790] random_write_wait.lock
-> [c1cd85c8] nonblocking_pool.lock
-> [c1c934b8] pcpu_alloc_mutex
-> [c1ccb9d0] percpu_counters_lock
-> [c1c63550] inode_hash_lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c1c9e3ec] &sb->s_type->i_lock_key#16 -> [c1c9dbe0] (proc_inum_ida).idr.lock
-> [c1c9db90] proc_inum_lock
-> [c25c8744] &ei->i_data_sem
-> [c25c8998] &journal->j_state_lock
-> [c1ca6398] jbd2_slab_create_mutex
-> [c25bc8fc] &(&zone->lru_lock)->rlock -> [c25c8954] &(&journal->j_revoke_lock)->rlock -> [c1c9c30c] &sb->s_type->i_lock_key#2 -> [c25bcb38] &(&wb->list_lock)->rlock
-> [c25bcb30] &(&wb->work_lock)->rlock
-> [c25bc8c0] (PG_locked)page
-> [c25d26c4] (complete)&ret.event
-> [c25d26bc] &x->wait#15
-> [c25ba114] &(&tsk->delays->lock)->rlock -> [c25c89b0] &journal->j_checkpoint_mutex -> [c1c82a10] kthread_create_lock
-> [c1e098e4] &p->pi_lock
-> [c1e0a360] (complete)&done
-> [c1e0a358] &x->wait
-> [c25c89d8] &journal->j_wait_done_commit -> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c1c827b8] wq_pool_mutex
-> [c25cf500] &isec->lock
-> [c1ca5df8] ext4_grpinfo_slab_create_mutex -> [c25c41a4] &(&s->s_inode_list_lock)->rlock -> [c25c875c] &ext4_li_mtx
-> [c25d2da8] &(&k->list_lock)->rlock
-> [c25d2d9c] &(&idp->lock)->rlock
-> [c1ccb5f0] simple_ida_lock
-> [c1c9de78] kernfs_mutex
-> [c25c89b8] &journal->j_barrier
-> [c25c89e0] &journal->j_wait_transaction_locked -> [c259f24c] &(&base->lock)->rlock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock -> [c25cf4f8] &sbsec->lock

c25c876c FD: 3 BD: 1 +.+...: &(&bgl->locks[i].lock)->rlock
-> [c25c88c0] &(&sbi->s_bal_lock)->rlock
-> [c25c88c8] &(&sbi->s_md_lock)->rlock

c1c9e3ec FD: 17 BD: 105 +.+...: &sb->s_type->i_lock_key#16
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25bcc48] &(&lru->node[i].lock)->rlock

c1b7b789 FD: 9 BD: 1 ..-...: fs/file_table.c:262
-> [c1e0a1a4] &(&pool->lock)->rlock

c1c99840 FD: 207 BD: 1 +.+...: (delayed_fput_work).work
-> [c1e0a8bc] &rq->lock
-> [c25c57e4] &bdev->bd_mutex

c25d2d68 FD: 20 BD: 62 +.-...: (&cfqd->idle_slice_timer)
-> [c25d2718] &(&q->__queue_lock)->rlock

c25c41bc FD: 3 BD: 1 +.+...: (&s->destroy_work)
-> [c259f150] &rsp->gp_wait
-> [c1c934f0] pcpu_lock

c259f150 FD: 1 BD: 2 ......: &rsp->gp_wait

c25c878c FD: 5 BD: 63 ++++..: &ei->i_es_lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25c8920] &(&sbi->s_es_lock)->rlock
-> [c25c8910] key#5
-> [c25c8918] key#6

c25c8744 FD: 76 BD: 62 ++++..: &ei->i_data_sem
-> [c25c878c] &ei->i_es_lock
-> [c1e0a8bc] &rq->lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25c5674] &(&mapping->private_lock)->rlock -> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c25bc924] zone->wait_table + i
-> [c25ba114] &(&tsk->delays->lock)->rlock
-> [c25c8794] &(&ei->i_prealloc_lock)->rlock -> [c25c879c] &(&ei->i_raw_lock)->rlock
-> [c25c89a0] &(&journal->j_list_lock)->rlock -> [c25c8954] &(&journal->j_revoke_lock)->rlock -> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c1c9e3ec] &sb->s_type->i_lock_key#16
-> [c25c8784] &(&(ei->i_block_reservation_lock))->rlock

c25c8920 FD: 1 BD: 64 +.+...: &(&sbi->s_es_lock)->rlock

c25c8998 FD: 31 BD: 16 ++++..: &journal->j_state_lock
-> [c25c89d8] &journal->j_wait_done_commit -> [c25c89d0] &journal->j_wait_commit
-> [c259f24c] &(&base->lock)->rlock
-> [c25c8940] &(&transaction->t_handle_lock)->rlock -> [c25c89a0] &(&journal->j_list_lock)->rlock -> [c25c89e0] &journal->j_wait_transaction_locked

c1ca6398 FD: 71 BD: 3 +.+.+.: jbd2_slab_create_mutex

c25c8954 FD: 1 BD: 63 +.+...: &(&journal->j_revoke_lock)->rlock

c25bcb38 FD: 19 BD: 69 +.+...: &(&wb->list_lock)->rlock
-> [c1c9c30c] &sb->s_type->i_lock_key#2
-> [c1c9e3ec] &sb->s_type->i_lock_key#16

c25bcb30 FD: 2 BD: 67 +.....: &(&wb->work_lock)->rlock
-> [c259f24c] &(&base->lock)->rlock

c25d26c4 FD: 1 BD: 3 +.+...: (complete)&ret.event

c25d26bc FD: 6 BD: 81 ..-...: &x->wait#15
-> [c1e098e4] &p->pi_lock

c25d2730 FD: 20 BD: 1 +.+...: (&(&q->delay_work)->work)
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbbe0] &(shost->host_lock)->rlock

c25c89b0 FD: 49 BD: 4 +.+...: &journal->j_checkpoint_mutex
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c25bc924] zone->wait_table + i
-> [c1e0a8bc] &rq->lock
-> [c25ba114] &(&tsk->delays->lock)->rlock
-> [c25c8998] &journal->j_state_lock

c25c89d8 FD: 6 BD: 17 ......: &journal->j_wait_done_commit
-> [c1e098e4] &p->pi_lock

c25c89d0 FD: 6 BD: 17 ......: &journal->j_wait_commit
-> [c1e098e4] &p->pi_lock

c1ca5df8 FD: 71 BD: 3 +.+.+.: ext4_grpinfo_slab_create_mutex

c25c875c FD: 1 BD: 4 +.+...: &ext4_li_mtx

c25c89b8 FD: 52 BD: 3 +.+...: &journal->j_barrier
-> [c25c8998] &journal->j_state_lock
-> [c25c89a0] &(&journal->j_list_lock)->rlock
-> [c25c89b0] &journal->j_checkpoint_mutex
-> [c25c87c4] key
-> [c25c87bc] key#2
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c25bc924] zone->wait_table + i
-> [c1e0a8bc] &rq->lock
-> [c25ba114] &(&tsk->delays->lock)->rlock

c25c89a0 FD: 26 BD: 66 +.+...: &(&journal->j_list_lock)->rlock
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c1c9c30c] &sb->s_type->i_lock_key#2
-> [c25bcb38] &(&wb->list_lock)->rlock
-> [c25bcb30] &(&wb->work_lock)->rlock

c25c87c4 FD: 1 BD: 5 ......: key

c25c87bc FD: 1 BD: 5 ......: key#2

c25c89e0 FD: 1 BD: 17 ......: &journal->j_wait_transaction_locked

c25c8764 FD: 1 BD: 1 ......: &rs->lock

c1c9e3fc FD: 121 BD: 4 ++++++: &type->i_mutex_dir_key
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25c8744] &ei->i_data_sem
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25c5674] &(&mapping->private_lock)->rlock
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c25bc924] zone->wait_table + i
-> [c1c63550] inode_hash_lock
-> [c1e0a8bc] &rq->lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25ba114] &(&tsk->delays->lock)->rlock
-> [c1c9e3ec] &sb->s_type->i_lock_key#16
-> [c25cf500] &isec->lock
-> [c1c99eb8] namespace_sem
-> [c25bc8fc] &(&zone->lru_lock)->rlock
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c1c7f3f0] pgd_lock
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25c8948] jbd2_handle

c1cde924 FD: 22 BD: 1 +.+...: &type->s_umount_key#19
-> [c1c99970] sb_lock
-> [c25bcc48] &(&lru->node[i].lock)->rlock
-> [c25bca94] &(&sbinfo->stat_lock)->rlock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c25bcc48 FD: 1 BD: 174 +.+...: &(&lru->node[i].lock)->rlock

c25c45f8 FD: 6 BD: 173 ......: &wq#2
-> [c1e098e4] &p->pi_lock

c1e09914 FD: 103 BD: 7 ++++++: &mm->mmap_sem
-> [c25c3ce8] &anon_vma->rwsem
-> [c1e0980c] &(ptlock_ptr(page))->rlock
-> [c25c567c] &mapping->i_mmap_rwsem
-> [c25bc904] &(&zone->lock)->rlock
-> [c1e0990c] &(&mm->page_table_lock)->rlock
-> [c25c873c] &ei->i_mmap_sem
-> [c25bc8fc] &(&zone->lru_lock)->rlock
-> [c25bc8c0] (PG_locked)page
-> [c25c3cdc] key#3
-> [c1e09915] &mm->mmap_sem/1
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c25b4244] &(kretprobe_table_locks[i].lock)
-> [c25bc924] zone->wait_table + i
-> [c25ba114] &(&tsk->delays->lock)->rlock

c25c874c FD: 1 BD: 12 .+.+..: &ei->xattr_sem

c1cd8710 FD: 1 BD: 1 ..-...: random_ready_list_lock

c1cd8750 FD: 1 BD: 1 ..-...: urandom_init_wait.lock

c1e0990c FD: 1 BD: 14 +.+...: &(&mm->page_table_lock)->rlock

c25c3ce8 FD: 4 BD: 13 +.+...: &anon_vma->rwsem
-> [c1e0990c] &(&mm->page_table_lock)->rlock
-> [c25c3cdc] key#3
-> [c25bc904] &(&zone->lock)->rlock

c1e0980c FD: 10 BD: 70 +.+...: &(ptlock_ptr(page))->rlock
-> [c1e0980d] &(ptlock_ptr(page))->rlock/1
-> [c25bc904] &(&zone->lock)->rlock
-> [c25bc8fc] &(&zone->lru_lock)->rlock
-> [c25bc924] zone->wait_table + i

c1c9d554 FD: 1 BD: 1 .+.+..: entries_lock

c25c3cdc FD: 1 BD: 14 ......: key#3

c25c567c FD: 11 BD: 9 +.+...: &mapping->i_mmap_rwsem
-> [c25c3ce8] &anon_vma->rwsem
-> [c1e0a8bc] &rq->lock
-> [c255ba50] &sem->wait_lock

c25c873c FD: 95 BD: 8 .+.+.+: &ei->i_mmap_sem
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25c8744] &ei->i_data_sem
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c25bc8c0] (PG_locked)page
-> [c25bc904] &(&zone->lock)->rlock
-> [c25bc8fc] &(&zone->lru_lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c25bc924] zone->wait_table + i
-> [c25ba114] &(&tsk->delays->lock)->rlock
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c25c5674] &(&mapping->private_lock)->rlock
-> [c1c7f3f0] pgd_lock

c1c82fb8 FD: 1 BD: 1 +.+...: reboot_mutex

c1cd17f0 FD: 1 BD: 1 ......: vt_spawn_con.lock

c25c40d4 FD: 2 BD: 7 +.+...: &(&f->f_lock)->rlock
-> [c1c99b70] fasync_lock

c1c99b70 FD: 1 BD: 8 +.+...: fasync_lock

c25d60cc FD: 188 BD: 3 ++++++: &tty->ldisc_sem
-> [c1c972d0] vmap_area_lock
-> [c1cd0eb0] tty_ldiscs_lock
-> [c25d6220] &buf->lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25d60dc] &tty->termios_rwsem
-> [c25d60c4] &tty->write_wait
-> [c25d60bc] &tty->read_wait
-> [c25d74d4] &port_lock_key
-> [c25d609c] &(&tty->flow_lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c25d6188] &ldata->atomic_read_lock
-> [c25d6218] (&buf->work)
-> [c1e0a1a5] &pool->lock/1
-> [c1e0a1bc] (complete)&barr->done
-> [c1e0a1cc] &x->wait#13

c25d608c FD: 1 BD: 1 +.+...: (&tty->SAK_work)

c25d60b4 FD: 1 BD: 1 +.+...: (&tty->hangup_work)

c25d6218 FD: 180 BD: 5 +.+...: (&buf->work)

c25d60f4 FD: 4 BD: 1 +.+...: (&tty->hangup_work)#2
-> [c25d6094] &(&tty->files_lock)->rlock

c25d6220 FD: 179 BD: 6 +.+...: &buf->lock
-> [c25d60dc] &tty->termios_rwsem

c25d6240 FD: 1 BD: 12 ......: &port->delta_msr_wait

c25d7508 FD: 1 BD: 12 ......: (&up->timer)

c25d6248 FD: 1 BD: 12 ......: &port->open_wait

c1c9e3d4 FD: 124 BD: 1 .+.+.+: sb_writers#3
-> [c1e0a8bc] &rq->lock
-> [c25c8948] jbd2_handle
-> [c1c9e3ec] &sb->s_type->i_lock_key#16
-> [c25bcb38] &(&wb->list_lock)->rlock
-> [c1c9e3fd] &type->i_mutex_dir_key/1
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25bc8fc] &(&zone->lru_lock)->rlock
-> [c1c63550] inode_hash_lock
-> [c25cf4f0] &(&sbsec->isec_lock)->rlock
-> [c1c9e3fc] &type->i_mutex_dir_key
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1c9e3f4] &sb->s_type->i_mutex_key#8

c1cd0cf0 FD: 1 BD: 1 +.+...: redirect_lock

c25d60ac FD: 179 BD: 1 +.+.+.: &tty->atomic_write_lock
-> [c25d60dc] &tty->termios_rwsem
-> [c255ba50] &sem->wait_lock

c25d6180 FD: 69 BD: 9 +.+...: &ldata->output_lock
-> [c25d74d4] &port_lock_key
-> [c1c87750] (console_sem).lock
-> [c1c8772c] console_lock
-> [c1c87710] logbuf_lock
-> [c1e0a8bc] &rq->lock

c1dfe42c FD: 1 BD: 7 +.+...: &mm->context.lock

c1e09915 FD: 17 BD: 8 +.+.+.: &mm->mmap_sem/1
-> [c25c567c] &mapping->i_mmap_rwsem
-> [c25c3ce8] &anon_vma->rwsem
-> [c25bc904] &(&zone->lock)->rlock
-> [c1e0990c] &(&mm->page_table_lock)->rlock
-> [c1e0980c] &(ptlock_ptr(page))->rlock
-> [c25c3cdc] key#3
-> [c1e0a8bc] &rq->lock
-> [c1c7f3f0] pgd_lock

c1e0980d FD: 1 BD: 71 +.+...: &(ptlock_ptr(page))->rlock/1

c25c45e9 FD: 13 BD: 1 +.+.+.: &pipe->mutex/1
-> [c25c45f0] &pipe->wait
-> [c25bc904] &(&zone->lock)->rlock
-> [c1e0a8bc] &rq->lock

c25c45f0 FD: 7 BD: 4 ......: &pipe->wait
-> [c1e098e4] &p->pi_lock
-> [c25c5980] &(&ep->lock)->rlock

c25d60a4 FD: 1 BD: 77 ......: &(&tty->ctrl_lock)->rlock

c1c81f98 FD: 2 BD: 1 ++++..: uts_sem
-> [c1c8d154] hostname_poll.wait.lock

c1c9e3f4 FD: 110 BD: 5 +.+.+.: &sb->s_type->i_mutex_key#8
-> [c25c5674] &(&mapping->private_lock)->rlock
-> [c25bc904] &(&zone->lock)->rlock
-> [c25c8948] jbd2_handle
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25c874c] &ei->xattr_sem
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25bc8c0] (PG_locked)page
-> [c1c9e3ec] &sb->s_type->i_lock_key#16
-> [c25bcb38] &(&wb->list_lock)->rlock
-> [c25bcb30] &(&wb->work_lock)->rlock

c1c9e3fd FD: 111 BD: 2 +.+...: &type->i_mutex_dir_key/1
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1c9e3f4] &sb->s_type->i_mutex_key#8
-> [c1c9e3ec] &sb->s_type->i_lock_key#16

c1c9db24 FD: 21 BD: 1 +.+...: &type->s_umount_key#20
-> [c1c99970] sb_lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c25d2775 FD: 2 BD: 2 ......: &(&ioc->lock)->rlock/1

c25d276c FD: 3 BD: 1 +.+...: (&ioc->release_work)
-> [c25d2775] &(&ioc->lock)->rlock/1

c25c5780 FD: 85 BD: 3 +.+.+.: &p->lock
-> [c1c99eb8] namespace_sem
-> [c1c99a58] chrdevs_lock
-> [c1ccaf18] block_class_lock
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c1e098a4] &(&sighand->siglock)->rlock
-> [c25ba114] &(&tsk->delays->lock)->rlock
-> [c25c8090] &of->mutex
-> [c1c635d0] bdev_lock
-> [c1c98e70] swap_lock
-> [c1e0a8bc] &rq->lock

c1cd87d0 FD: 1 BD: 87 -.-...: random_read_wait.lock

c1c9db34 FD: 50 BD: 1 .+.+.+: sb_writers#4
-> [c1c9db4c] &sb->s_type->i_lock_key#4
-> [c1c9db54] &sb->s_type->i_mutex_key
-> [c1c9dc50] sysctl_lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1e098f4] &(&p->alloc_lock)->rlock

c1c9e025 FD: 37 BD: 1 +.+.+.: &type->s_umount_key#21/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c1c9de78] kernfs_mutex
-> [c25cf500] &isec->lock
-> [c1c9e04c] &sb->s_type->i_lock_key#17
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1c9e04c FD: 17 BD: 82 +.+...: &sb->s_type->i_lock_key#17
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1c9e05c FD: 43 BD: 1 ++++++: &type->i_mutex_dir_key#2
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1c9de78] kernfs_mutex
-> [c1c99eb8] namespace_sem
-> [c25bc904] &(&zone->lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c1e098e4] &p->pi_lock

c1cc3084 FD: 21 BD: 1 +.+...: &type->s_umount_key#22
-> [c1c99970] sb_lock
-> [c25bcc48] &(&lru->node[i].lock)->rlock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c25c4629 FD: 2 BD: 173 +.+...: &(&dentry->d_lockref.lock)->rlock/1
-> [c25bcc48] &(&lru->node[i].lock)->rlock

c1c92e74 FD: 115 BD: 2 .+.+.+: sb_writers#5
-> [c1c92e95] &sb->s_type->i_mutex_key#9/1
-> [c1c92e94] &sb->s_type->i_mutex_key#10
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1c92e8c] &sb->s_type->i_lock_key#5
-> [c1e0a8bc] &rq->lock
-> [c255ba50] &sem->wait_lock

c1c92e95 FD: 114 BD: 3 +.+.+.: &sb->s_type->i_mutex_key#9/1
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25bca94] &(&sbinfo->stat_lock)->rlock
-> [c1c92e8c] &sb->s_type->i_lock_key#5
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25efa68] &u->readlock
-> [c1c92e98] &sb->s_type->i_mutex_key#10/4
-> [c25bc904] &(&zone->lock)->rlock
-> [c1c92e94] &sb->s_type->i_mutex_key#10
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25bc8fc] &(&zone->lru_lock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c25bca84] &(&info->lock)->rlock
-> [c25cf4f0] &(&sbsec->isec_lock)->rlock
-> [c255ba50] &sem->wait_lock

c1c92e94 FD: 105 BD: 4 ++++++: &sb->s_type->i_mutex_key#10
-> [c25bc904] &(&zone->lock)->rlock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25bca94] &(&sbinfo->stat_lock)->rlock
-> [c1c92e8c] &sb->s_type->i_lock_key#5
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25bca7c] &(&xattrs->lock)->rlock
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25bca84] &(&info->lock)->rlock
-> [c25c566c] &inode->i_size_seqcount
-> [c25bc8c0] (PG_locked)page
-> [c1c92e98] &sb->s_type->i_mutex_key#10/4
-> [c1e0a8bc] &rq->lock
-> [c255ba50] &sem->wait_lock
-> [c25b4244] &(kretprobe_table_locks[i].lock)
-> [c25bc8fc] &(&zone->lru_lock)->rlock

c25bca7c FD: 1 BD: 41 +.+...: &(&xattrs->lock)->rlock

c25bca84 FD: 1 BD: 62 +.+...: &(&info->lock)->rlock

c1c99b14 FD: 1 BD: 1 .+.+..: sb_writers#6

c25c40cc FD: 154 BD: 1 +.+.+.: &f->f_pos_lock
-> [c1cde934] sb_writers
-> [c1c92e74] sb_writers#5
-> [c1e0a8bc] &rq->lock
-> [c25c5780] &p->lock

c25bca40 FD: 4 BD: 1 +.-...: (&dom->period_timer)
-> [c25d2d94] key#4
-> [c25d2d8c] &p->sequence
-> [c259f24c] &(&base->lock)->rlock

c25d2d94 FD: 1 BD: 2 ..-...: key#4

c25d2d8c FD: 1 BD: 2 ..-...: &p->sequence

c25c6f7c FD: 1 BD: 173 ......: &wq#3

c1d06dd0 FD: 1 BD: 7 +.+...: unix_table_lock

c25efa68 FD: 31 BD: 6 +.+.+.: &u->readlock
-> [c25bca94] &(&sbinfo->stat_lock)->rlock
-> [c1c92e8c] &sb->s_type->i_lock_key#5
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1d06dd0] unix_table_lock
-> [c25efa78] &af_unix_sk_receive_queue_lock_key
-> [c25bc904] &(&zone->lock)->rlock
-> [c1cde94c] &sb->s_type->i_lock_key#6
-> [c25efa60] &u->peer_wait

c25efa70 FD: 21 BD: 1 +.+...: &(&u->lock)->rlock
-> [c25e1728] clock-AF_UNIX
-> [c25efa71] &(&u->lock)->rlock/1
-> [c25efa78] &af_unix_sk_receive_queue_lock_key
-> [c25efa60] &u->peer_wait

c1c82c70 FD: 7 BD: 1 .+.+.+: s_active#18
-> [c1c9df58] kernfs_open_file_mutex

c1c9df58 FD: 6 BD: 16 +.+...: kernfs_open_file_mutex
-> [c1c9df90] kernfs_open_node_lock
-> [c1e0a8bc] &rq->lock

c25c8090 FD: 40 BD: 5 +.+.+.: &of->mutex

c1c92e98 FD: 19 BD: 5 +.+...: &sb->s_type->i_mutex_key#10/4
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1c63528] rename_lock

c25c462a FD: 4 BD: 173 +.+...: &(&dentry->d_lockref.lock)->rlock/2
-> [c25c462b] &(&dentry->d_lockref.lock)->rlock/3

c25c462b FD: 3 BD: 174 +.+...: &(&dentry->d_lockref.lock)->rlock/3
-> [c25c4620] &dentry->d_seq

c25c4621 FD: 1 BD: 176 +.+...: &dentry->d_seq/1

c25e1728 FD: 1 BD: 2 +.....: clock-AF_UNIX

c25efa60 FD: 6 BD: 8 +.+...: &u->peer_wait
-> [c1e098e4] &p->pi_lock

c25efa78 FD: 1 BD: 8 +.+...: &af_unix_sk_receive_queue_lock_key

c25efa71 FD: 17 BD: 2 +.+...: &(&u->lock)->rlock/1
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c25e1680 FD: 7 BD: 71 ......: &wq->wait
-> [c1e098e4] &p->pi_lock
-> [c25c5980] &(&ep->lock)->rlock

c25c8910 FD: 1 BD: 64 ......: key#5

c25c8918 FD: 1 BD: 64 ......: key#6

c25c5978 FD: 32 BD: 2 +.+.+.: &ep->mtx
-> [c25e1680] &wq->wait
-> [c25c40d4] &(&f->f_lock)->rlock
-> [c25c5980] &(&ep->lock)->rlock
-> [c25c5834] &group->notification_waitq
-> [c25c583c] &group->notification_mutex
-> [c1e0989c] &sighand->signalfd_wqh
-> [c1e098a4] &(&sighand->siglock)->rlock
-> [c1e0a8bc] &rq->lock
-> [c25c45f0] &pipe->wait

c25c5980 FD: 6 BD: 106 ......: &(&ep->lock)->rlock
-> [c1e098e4] &p->pi_lock

c25c5834 FD: 1 BD: 3 ......: &group->notification_waitq

c25c583c FD: 1 BD: 3 +.+...: &group->notification_mutex

c1e0989c FD: 7 BD: 77 ......: &sighand->signalfd_wqh
-> [c25c5980] &(&ep->lock)->rlock

c1c98e70 FD: 1 BD: 4 +.+...: swap_lock

c25e1888 FD: 1 BD: 2 +.....: slock-AF_UNIX

c25e19e8 FD: 2 BD: 1 +.+...: sk_lock-AF_UNIX
-> [c25e1888] slock-AF_UNIX

c1c9e034 FD: 42 BD: 1 .+.+.+: sb_writers#7
-> [c1c9e04c] &sb->s_type->i_lock_key#17
-> [c25bcb38] &(&wb->list_lock)->rlock
-> [c25c8090] &of->mutex
-> [c1e0a8bc] &rq->lock

c25e1d68 FD: 1 BD: 65 ......: &(&net->nsid_lock)->rlock

c25e16dc FD: 1 BD: 65 ..-...: &(&list->lock)->rlock

c25e2a20 FD: 1 BD: 1 ......: &nlk->wait

c1cddce4 FD: 42 BD: 1 .+.+.+: s_active#19
-> [c1c9df58] kernfs_open_file_mutex
-> [c1ccb6d8] uevent_sock_mutex
-> [c1e0a8bc] &rq->lock
-> [c1e098e4] &p->pi_lock
-> [c25d5adc] &device->physical_node_lock
-> [c25bc904] &(&zone->lock)->rlock

c25bcb20 FD: 9 BD: 1 ..-...: (&(&wb->dwork)->timer)
-> [c1e0a1a5] &pool->lock/1

c25bcb48 FD: 1 BD: 1 .+.+.+: "writeback"

c25bcb28 FD: 111 BD: 1 +.+.+.: (&(&wb->dwork)->work)
-> [c25bcb30] &(&wb->work_lock)->rlock
-> [c25bcb38] &(&wb->list_lock)->rlock
-> [c25d2d74] &pl->lock
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock

c25d2d74 FD: 2 BD: 70 ..-...: &pl->lock
-> [c25d2d7c] key#7

c25d2d7c FD: 1 BD: 71 ..-...: key#7

c1cf0bb4 FD: 7 BD: 1 .+.+.+: s_active#20
-> [c1c9df58] kernfs_open_file_mutex

c1cf0b60 FD: 7 BD: 1 .+.+.+: s_active#21
-> [c1c9df58] kernfs_open_file_mutex

c1cf0b7c FD: 7 BD: 1 .+.+.+: s_active#22
-> [c1c9df58] kernfs_open_file_mutex

c1cf0b98 FD: 8 BD: 1 .+.+.+: s_active#23
-> [c1c9df58] kernfs_open_file_mutex
-> [c1e098e4] &p->pi_lock
-> [c1e0a8bc] &rq->lock

c1cf0d04 FD: 7 BD: 1 .+.+.+: s_active#24
-> [c1c9df58] kernfs_open_file_mutex

c1cf630c FD: 8 BD: 1 .+.+.+: s_active#25
-> [c1c9df58] kernfs_open_file_mutex
-> [c1e098e4] &p->pi_lock

c255ba50 FD: 6 BD: 22 ......: &sem->wait_lock
-> [c1e098e4] &p->pi_lock

c25c40c0 FD: 1 BD: 1 ......: key#8

c25c582c FD: 22 BD: 1 +.+.+.: &group->mark_mutex
-> [c1c92e8c] &sb->s_type->i_lock_key#5
-> [c1e0a8bc] &rq->lock
-> [c25c5944] &(&group->inotify_data.idr_lock)->rlock -> [c25c5938] &(&mark->lock)->rlock
-> [c1cde94c] &sb->s_type->i_lock_key#6
-> [c1c9e3ec] &sb->s_type->i_lock_key#16

c25c5944 FD: 1 BD: 2 +.+...: &(&group->inotify_data.idr_lock)->rlock

c25c5938 FD: 20 BD: 3 +.+...: &(&mark->lock)->rlock
-> [c1c92e8c] &sb->s_type->i_lock_key#5
-> [c1cde94c] &sb->s_type->i_lock_key#6
-> [c1c9e3ec] &sb->s_type->i_lock_key#16

c1ce39ec FD: 7 BD: 1 .+.+.+: s_active#26
-> [c1e0a8bc] &rq->lock
-> [c1c9df58] kernfs_open_file_mutex

c1ccc62c FD: 7 BD: 1 .+.+.+: s_active#27
-> [c1c9df58] kernfs_open_file_mutex

c1ce3a24 FD: 7 BD: 1 .+.+.+: s_active#28
-> [c1c9df58] kernfs_open_file_mutex

c1ccc610 FD: 7 BD: 1 .+.+.+: s_active#29
-> [c1c9df58] kernfs_open_file_mutex

c1c9c538 FD: 33 BD: 1 +.+...: epmutex
-> [c1e0a8bc] &rq->lock
-> [c25c5978] &ep->mtx

c1ce47f8 FD: 86 BD: 4 +.+.+.: sr_mutex
-> [c1ce4698] sr_ref_mutex
-> [c1e0a8bc] &rq->lock
-> [c25d2824] &ev->block_mutex
-> [c25d282c] &(&ev->lock)->rlock
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c25d2788] (complete)&wait
-> [c25d2780] &x->wait#10
-> [c25ba114] &(&tsk->delays->lock)->rlock
-> [c1c99970] sb_lock
-> [c25dbbd8] &shost->host_wait
-> [c25bc904] &(&zone->lock)->rlock
-> [c25dbbe0] &(shost->host_lock)->rlock
-> [c1e098f4] &(&p->alloc_lock)->rlock

c1ce4698 FD: 1 BD: 5 +.+...: sr_ref_mutex

c1cf1a28 FD: 7 BD: 1 .+.+.+: s_active#30
-> [c1c9df58] kernfs_open_file_mutex

c25d2728 FD: 9 BD: 1 ..-...: (&(&q->delay_work)->timer)
-> [c1e0a1a4] &(&pool->lock)->rlock

c25c582d FD: 21 BD: 1 +.+...: &group->mark_mutex/1
-> [c25c5938] &(&mark->lock)->rlock

c1c9c3d0 FD: 1 BD: 1 +.+...: destroy_lock

c259f178 FD: 1 BD: 1 ......: &(&sp->queue_lock)->rlock

c1c9e3c4 FD: 117 BD: 1 ++++.+: &type->s_umount_key#23
-> [c25bcc48] &(&lru->node[i].lock)->rlock
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1c9e3ec] &sb->s_type->i_lock_key#16
-> [c25c8998] &journal->j_state_lock
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c25c87c4] key
-> [c25c87bc] key#2
-> [c1e0a8bc] &rq->lock
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25dbfa8] &(&host->lock)->rlock
-> [c25bc924] zone->wait_table + i
-> [c25ba114] &(&tsk->delays->lock)->rlock
-> [c25c875c] &ext4_li_mtx
-> [c1c635a8] mount_lock
-> [c25c87a4] &sbi->s_journal_flag_rwsem
-> [c25bcb38] &(&wb->list_lock)->rlock

c25c8948 FD: 109 BD: 11 +.+...: jbd2_handle
-> [c25c89a0] &(&journal->j_list_lock)->rlock
-> [c25c8954] &(&journal->j_revoke_lock)->rlock
-> [c25c5674] &(&mapping->private_lock)->rlock
-> [c25c89c8] &journal->j_wait_updates
-> [c25bc904] &(&zone->lock)->rlock
-> [c25c879c] &(&ei->i_raw_lock)->rlock
-> [c25c8998] &journal->j_state_lock
-> [c25c87d4] &sbi->s_orphan_lock
-> [c25c8744] &ei->i_data_sem
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c25c8794] &(&ei->i_prealloc_lock)->rlock
-> [c25c878c] &ei->i_es_lock
-> [c25c88d0] &meta_group_info[i]->alloc_sem
-> [c1c63550] inode_hash_lock
-> [c25c87e4] &(&sbi->s_next_gen_lock)->rlock
-> [c25c874c] &ei->xattr_sem
-> [c1c9e3ec] &sb->s_type->i_lock_key#16
-> [c25cf500] &isec->lock
-> [c25bc8c0] (PG_locked)page
-> [c25bcb38] &(&wb->list_lock)->rlock
-> [c25c566c] &inode->i_size_seqcount
-> [c25bc8fc] &(&zone->lru_lock)->rlock

c25c89c8 FD: 1 BD: 12 ......: &journal->j_wait_updates

c1cde958 FD: 19 BD: 38 +.+...: &sb->s_type->i_mutex_key#5/4
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1c63528] rename_lock

c1ce3a08 FD: 8 BD: 1 .+.+.+: s_active#31
-> [c1c9df58] kernfs_open_file_mutex
-> [c1e098e4] &p->pi_lock

c1ccadfc FD: 7 BD: 1 .+.+.+: s_active#32
-> [c1c9df58] kernfs_open_file_mutex
-> [c1e0a8bc] &rq->lock

c25e17a0 FD: 1 BD: 1 +.....: clock-AF_NETLINK

c25d2de5 FD: 15 BD: 1 +.+.+.: (&ht->run_work)
-> [c25d2df5] &ht->mutex

c25d2df5 FD: 14 BD: 2 +.+.+.: &ht->mutex
-> [c1e0a8bc] &rq->lock
-> [c1cd8790] random_write_wait.lock
-> [c1cd85c8] nonblocking_pool.lock
-> [c25d2dfd] &(&tbl->locks[i])->rlock
-> [c25d2ded] &(&ht->lock)->rlock

c25d2dfe FD: 1 BD: 6 +.....: &(&tbl->locks[i])->rlock/1

c25d2ded FD: 1 BD: 3 +.+...: &(&ht->lock)->rlock

c25dbab8 FD: 7 BD: 4 +.+...: &lo->lo_ctl_mutex
-> [c1e0a8bc] &rq->lock
-> [c25d2710] &q->mq_freeze_wq

c25d2710 FD: 6 BD: 5 ..-...: &q->mq_freeze_wq
-> [c1e098e4] &p->pi_lock

c1ccb8f0 FD: 1 BD: 1 ..-...: percpu_ref_switch_waitq.lock

c25e24d4 FD: 9 BD: 1 ..-...: (&(&tbl->gc_work)->timer)
-> [c1e0a1a4] &(&pool->lock)->rlock

c25e24dc FD: 3 BD: 1 +.+...: (&(&tbl->gc_work)->work)
-> [c25e24e4] &tbl->lock

c25c879c FD: 1 BD: 63 +.+...: &(&ei->i_raw_lock)->rlock

c25c8988 FD: 6 BD: 1 +.-...: ((&journal->j_commit_timer))
-> [c1e098e4] &p->pi_lock

c25c8940 FD: 1 BD: 17 +.+...: &(&transaction->t_handle_lock)->rlock

c25c88c8 FD: 1 BD: 64 +.+...: &(&sbi->s_md_lock)->rlock

c25c8990 FD: 1 BD: 1 +.+...: &(&journal->j_history_lock)->rlock

c25c87d4 FD: 1 BD: 12 +.+...: &sbi->s_orphan_lock

c1c9e3e4 FD: 110 BD: 1 .+.+..: sb_internal
-> [c25c8948] jbd2_handle

c25c8794 FD: 1 BD: 63 +.+...: &(&ei->i_prealloc_lock)->rlock

c25c88c0 FD: 1 BD: 64 +.+...: &(&sbi->s_bal_lock)->rlock

c25c88d0 FD: 1 BD: 12 .+.+..: &meta_group_info[i]->alloc_sem

c25c87e4 FD: 1 BD: 12 +.+...: &(&sbi->s_next_gen_lock)->rlock

c25c8784 FD: 1 BD: 63 +.+...: &(&(ei->i_block_reservation_lock))->rlock

c1c9e0a5 FD: 27 BD: 1 +.+.+.: &type->s_umount_key#24/1
-> [c1c99970] sb_lock
-> [c1c90a18] shrinker_rwsem
-> [c1c9e0cc] &sb->s_type->i_lock_key#18
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock
-> [c1c9e0d4] &sb->s_type->i_mutex_key#11
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c25cf4f8] &sbsec->lock

c1c9e0cc FD: 17 BD: 3 +.+...: &sb->s_type->i_lock_key#18
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock

c1c9e0d4 FD: 21 BD: 2 +.+.+.: &sb->s_type->i_mutex_key#11
-> [c25c4628] &(&dentry->d_lockref.lock)->rlock
-> [c1c9e0cc] &sb->s_type->i_lock_key#18
-> [c25c41a4] &(&s->s_inode_list_lock)->rlock
-> [c25cf500] &isec->lock

c255e580 FD: 2 BD: 1 +.+...: &user->lock
-> [c1c87710] logbuf_lock

c1c9c2e4 FD: 94 BD: 1 .+.+..: &type->s_umount_key#25
-> [c1c9c30c] &sb->s_type->i_lock_key#2
-> [c25bc8c0] (PG_locked)page
-> [c25c5684] &(&mapping->tree_lock)->rlock
-> [c1e098f4] &(&p->alloc_lock)->rlock
-> [c25d2718] &(&q->__queue_lock)->rlock
-> [c25bc8fc] &(&zone->lru_lock)->rlock
-> [c25bcb38] &(&wb->list_lock)->rlock
-> [c25bc904] &(&zone->lock)->rlock

c1c8d154 FD: 1 BD: 2 ......: hostname_poll.wait.lock

c25dec04 FD: 1 BD: 1 ......: &(&rtc->irq_lock)->rlock

c25debfc FD: 1 BD: 1 ......: &(&rtc->irq_task_lock)->rlock

c25c5ac0 FD: 2 BD: 1 +.+...: &(&ctx->flc_lock)->rlock
-> [c1c9c724] file_lock_lglock

c1c9c724 FD: 1 BD: 2 .+.+..: file_lock_lglock

c1e098b4 FD: 142 BD: 1 +.+...: (complete)&vfork
-> [c1e098bc] &sig->cred_guard_mutex
-> [c1e0980c] &(ptlock_ptr(page))->rlock
-> [c1e0a8bc] &rq->lock
-> [c25bc904] &(&zone->lock)->rlock
-> [c1c7f3f0] pgd_lock

c1e098ac FD: 6 BD: 73 ......: &x->wait#16
-> [c1e098e4] &p->pi_lock

c1d047d8 FD: 5 BD: 8 .+.+.+: (inetaddr_chain).rwsem
-> [c1d04a90] fib_info_lock
-> [c1c934b8] pcpu_alloc_mutex
-> [c1d01e50] nl_table_wait.lock

c1d04a90 FD: 1 BD: 9 +.....: fib_info_lock

c25e2148 FD: 1 BD: 8 +.....: _xmit_LOOPBACK

c1d005e4 FD: 1 BD: 1 ......: netpoll_srcu

c25ee798 FD: 1 BD: 8 +.....: &(&in_dev->mc_tomb_lock)->rlock

c1d07090 FD: 2 BD: 8 +.....: addrconf_hash_lock
-> [c1c934f0] pcpu_lock

c25efb58 FD: 1 BD: 8 +.....: &(&ifa->lock)->rlock

c25efca0 FD: 3 BD: 8 +.....: &tb->tb6_lock
-> [c1d01e50] nl_table_wait.lock
-> [c25efcb0] &net->ipv6.fib6_walker_lock

c25efcb0 FD: 1 BD: 9 +.....: &net->ipv6.fib6_walker_lock

c25e1890 FD: 1 BD: 1 +.....: slock-AF_INET

c25e1730 FD: 1 BD: 1 +.....: clock-AF_INET

c1c876d0 FD: 6 BD: 1 -.....: log_wait.lock
-> [c1e098e4] &p->pi_lock

c25d609c FD: 1 BD: 9 ......: &(&tty->flow_lock)->rlock

c25d6188 FD: 185 BD: 4 +.+...: &ldata->atomic_read_lock
-> [c25d60dc] &tty->termios_rwsem
-> [c25d6218] (&buf->work)
-> [c1e0a8bc] &rq->lock
-> [c1c7f3f0] pgd_lock
-> [c25d60bc] &tty->read_wait
-> [c1e0a1a5] &pool->lock/1
-> [c1e0a1bc] (complete)&barr->done
-> [c1e0a1cc] &x->wait#13

c1b8863b FD: 5 BD: 1 +.-...: lib/random32.c:217
-> [c1cd8790] random_write_wait.lock
-> [c1cd85c8] nonblocking_pool.lock
-> [c259f24c] &(&base->lock)->rlock
-> [c1cd86c8] input_pool.lock

c1b50661 FD: 9 BD: 1 ..-...: arch/x86/kernel/check.c:145
-> [c1e0a1a4] &(&pool->lock)->rlock

c25c87a4 FD: 110 BD: 3 .+.+.+: &sbi->s_journal_flag_rwsem
-> [c25bc904] &(&zone->lock)->rlock
-> [c25c8948] jbd2_handle
-> [c25d2718] &(&q->__queue_lock)->rlock

c1cd25a0 FD: 69 BD: 1 +.+...: console_work
-> [c1c87750] (console_sem).lock
-> [c1c8772c] console_lock
-> [c1c87710] logbuf_lock
-> [c1e0a8bc] &rq->lock

c25d60e4 FD: 1 BD: 9 +.+...: &tty->throttle_mutex

c25d60d4 FD: 1 BD: 1 +.+...: &tty->winsize_mutex

c1c003d1 FD: 9 BD: 1 ..-...: net/wireless/reg.c:212
-> [c1e0a1a4] &(&pool->lock)->rlock

c1d0c440 FD: 108 BD: 1 +.+...: (reg_check_chans).work
-> [c1cff938] rtnl_mutex

c1bfe51f FD: 9 BD: 1 ..-...: net/ipv6/addrconf.c:150
-> [c1e0a1a4] &(&pool->lock)->rlock

c1bfc462 FD: 9 BD: 1 ..-...: net/ipv4/devinet.c:438
-> [c1e0a1a4] &(&pool->lock)->rlock

c1e0a19c FD: 10 BD: 1 +.-...: (&pool->idle_timer)
-> [c1e0a1a5] &pool->lock/1
-> [c1e0a1a4] &(&pool->lock)->rlock

c25c87dc FD: 2 BD: 1 +.-...: ((&sbi->s_err_report))
-> [c259f24c] &(&base->lock)->rlock

c25e28ec FD: 2 BD: 1 +.-...: ((&fc->rnd_timer))
-> [c259f24c] &(&base->lock)->rlock

c1b956b4 FD: 9 BD: 12 +.-...: drivers/tty/vt/vt.c:231
-> [c1e0a1a4] &(&pool->lock)->rlock

c1cd1250 FD: 1 BD: 12 ......: vt_event_lock

c1b95555 FD: 1 BD: 12 +.-...: drivers/tty/vt/keyboard.c:252

#46 lore raw

PATCH v3 1/1 Crossrelease Lockdep

In reply to Byungchul Park

Crossrelease
============

Started by Byungchul Park <[email protected]>

Contents:

(*) Background.

- What causes deadlock.
- What lockdep detects.
- How lockdep works.

(*) Limitation.

- Limit to typical locks.
- Pros from the limitation.
- Cons from the limitation.

(*) Generalization.

- Relax the limitation.

(*) Crossrelease.

- Introduce crossrelease.
- Pick true dependencies.
- Introduce commit.

(*) Implementation.

- Data structures.
- How crossrelease works.

(*) Optimizations.

- Avoid duplication.
- Lockless for hot paths.

==========
Background
==========

What causes deadlock
--------------------

A deadlock occurs when a context is waiting for an event to happen, which is impossible because another (or the) context who can trigger the event is also waiting for another (or the) event to happen, which is also impossible due to the same reason. Single or more contexts paricipate in such a deadlock.

For example,

A context going to trigger event D is waiting for event A to happen. A context going to trigger event A is waiting for event B to happen. A context going to trigger event B is waiting for event C to happen. A context going to trigger event C is waiting for event D to happen.

A deadlock occurs when these four wait operations run at the same time, because event D cannot be triggered if event A does not happen, which in turn cannot be triggered if event B does not happen, which in turn cannot be triggered if event C does not happen, which in turn cannot be triggered if event D does not happen. After all, no event can be triggered since any of them never meets its precondition to wake up.

In terms of dependency, a wait for an event creates a dependency if the context is going to wake up another waiter by triggering an proper event. In other words, a dependency exists if,

COND 1. There are two waiters waiting for each event at the same time. COND 2. Only way to wake up each waiter is to trigger its events. COND 3. Whether one can be woken up depends on whether the other can.

Each wait in the example creates its dependency like,

Event D depends on event A.
Event A depends on event B.
Event B depends on event C.
Event C depends on event D.

NOTE: Precisely speaking, a dependency is one between whether a waiter for an event can be woken up and whether another waiter for another event can be woken up. However from now on, we will describe a dependency as if it's one between an event and another event for simplicity, so e.g. 'event D depends on event A'.

And they form circular dependencies like,

    -> D -> A -> B -> C -
   /                     \
   \                     /
    ---------------------

where A, B,..., D are different events, and '->' represents 'depends on'.

Such circular dependencies lead to a deadlock since no waiter can meet its precondition to wake up if they run simultaneously, as described.

CONCLUSION

Circular dependencies cause a deadlock.

What lockdep detects
--------------------

Lockdep tries to detect a deadlock by checking dependencies created by lock operations e.i. acquire and release. Waiting for a lock to be released corresponds to waiting for an event to happen, and releasing a lock corresponds to triggering an event. See 'What causes deadlock' section.

A deadlock actually occurs when all wait operations creating circular dependencies run at the same time. Even though they don't, a potential deadlock exists if the problematic dependencies exist. Thus it's meaningful to detect not only an actual deadlock but also its potential possibility. Lockdep does the both.

Whether or not a deadlock actually occurs depends on several factors. For example, what order contexts are switched in is a factor. Assuming circular dependencies exist, a deadlock would occur when contexts are switched so that all wait operations creating the problematic dependencies run simultaneously.

To detect a potential possibility which means a deadlock has not happened yet but might happen in future, lockdep considers all possible combinations of dependencies so that its potential possibility can be detected in advance. To do this, lockdep is trying to,

1. Use a global dependency graph.

Lockdep combines all dependencies into one global graph and uses them, regardless of which context generates them or what order contexts are switched in. Aggregated dependencies are only considered so they are prone to be circular if a problem exists.

2. Check dependencies between classes instead of instances.

What actually causes a deadlock are instances of lock. However, lockdep checks dependencies between classes instead of instances. This way lockdep can detect a deadlock which has not happened but might happen in future by others but the same classes.

3. Assume all acquisitions lead to waiting.

Although locks might be acquired without waiting which is essential to create dependencies, lockdep assumes all acquisitions lead to waiting and generates dependencies, since it might be true some time or another. Potential possibilities can be checked in this way.

Lockdep detects both an actual deadlock and its possibility. But the latter is more valuable than the former. When a deadlock occurs actually, we can identify what happens in the system by some means or other even without lockdep. However, there's no way to detect possiblity without lockdep unless the whole code is parsed in head. It's terrible.

CONCLUSION

Lockdep detects and reports,

1. A deadlock possibility.
2. A deadlock which actually occured.

How lockdep works
-----------------

Lockdep does,

1. Detect a new dependency created.
2. Keep the dependency in a global data structure, graph.
3. Check if circular dependencies exist.
4. Report a deadlock or its possibility if so.

A graph built by lockdep looks like, e.g.

   A -> B -        -> F -> G
           \      /
            -> E -        -> L
           /      \      /
   C -> D -        -> H -
                         \
                          -> I -> K
                         /
                      J -

where A, B,..., L are different lock classes.

Lockdep will add a dependency into graph when a new dependency is detected. For example, it will add a dependency 'K -> J' when a new dependency between lock K and lock J is detected. Then the graph will be,

   A -> B -        -> F -> G
           \      /
            -> E -        -> L
           /      \      /
   C -> D -        -> H -
                         \
                          -> I -> K -
                         /           \
                   -> J -             \
                  /                   /
                  \                  /
                   ------------------

where A, B,..., L are different lock classes.

Now, circular dependencies are detected like,

           -> I -> K -
          /           \
    -> J -             \
   /                   /
   \                  /
    ------------------

where J, I and K are different lock classes.

As decribed in 'What causes deadlock', this is the condition under which a deadlock might occur. Lockdep detects a deadlock or its possibility by checking if circular dependencies were created after adding each new dependency into the global graph. This is the way how lockdep works.

CONCLUSION

Lockdep detects a deadlock or its possibility by checking if circular dependencies were created after adding each new dependency.

==========
Limitation
==========

Limit to typical locks
----------------------

Limiting lockdep to checking dependencies only on typical locks e.g. spin locks and mutexes, which should be released within the acquire context, the implementation of detecting and adding dependencies becomes simple but its capacity for detection becomes limited. Let's check what its pros and cons are, in next section.

CONCLUSION

Limiting lockdep to working on typical locks e.g. spin locks and mutexes, the implmentation becomes simple but limits its capacity.

Pros from the limitation
------------------------

Given the limitation, when acquiring a lock, locks in the held_locks of the context cannot be released if the context fails to acquire it and has to wait for it. It also makes waiters for the locks in the held_locks stuck. It's the exact case to create a dependency 'A -> B', where lock A is each lock in held_locks and lock B is the lock to acquire. See 'What casues deadlock' section.

For example,

CONTEXT X
---------
acquire A

acquire B /* Add a dependency 'A -> B' */

acquire C /* Add a dependency 'B -> C' */

release C

release B

release A

where A, B and C are different lock classes.

When acquiring lock A, the held_locks of CONTEXT X is empty thus no dependency is added. When acquiring lock B, lockdep detects and adds a new dependency 'A -> B' between lock A in held_locks and lock B. When acquiring lock C, lockdep also adds another dependency 'B -> C' for the same reason. They can be simply added whenever acquiring each lock.

And most data required by lockdep exists in a local structure e.i. 'task_struct -> held_locks'. Forcing to access those data within the context, lockdep can avoid racy problems without explicit locks while handling the local data.

Lastly, lockdep only needs to keep locks currently being held, to build the dependency graph. However relaxing the limitation, it might need to keep even locks already released, because the decision of whether they created dependencies might be long-deferred. See 'Crossrelease' section.

To sum up, we can expect several advantages from the limitation.

1. Lockdep can easily identify a dependency when acquiring a lock.
2. Requiring only local locks makes many races avoidable.
3. Lockdep only needs to keep locks currently being held.

CONCLUSION

Given the limitation, the implementation becomes simple and efficient.

Cons from the limitation
------------------------

Given the limitation, lockdep is applicable only to typical locks. For example, page locks for page access or completions for synchronization cannot play with lockdep under the limitation.

Can we detect deadlocks below, under the limitation?

Example 1:

CONTEXT X CONTEXT Y
--------- ---------
mutext_lock A
lock_page B
lock_page B
mutext_lock A /* DEADLOCK */
unlock_page B
mutext_unlock A
mutex_unlock A
unlock_page B

where A is a lock class and B is a page lock.

No, we cannot.

Example 2:

   CONTEXT X	   CONTEXT Y	   CONTEXT Z
   ---------	   ---------	   ----------

mutex_lock A
lock_page B
lock_page B
mutext_lock A /* DEADLOCK */ mutext_unlock A unlock_page B held by X
unlock_page B
mutex_unlock A

where A is a lock class and B is a page lock.

No, we cannot.

Example 3:

CONTEXT X CONTEXT Y
--------- ---------
mutex_lock A
mutex_lock A
mutex_unlock A
wait_for_complete B /* DEADLOCK */
complete B
mutex_unlock A

where A is a lock class and B is a completion variable.

No, we cannot.

CONCLUSION

Given the limitation, lockdep cannot detect a deadlock or its possibility caused by page locks or completions.

==============
Generalization
==============

Relax the limitation
--------------------

Under the limitation, things to create dependencies are limited to typical locks. However, e.g. page locks and completions which are not typical locks also create dependencies and cause a deadlock. Therefore it would be better for lockdep to detect a deadlock or its possibility even for them.

Detecting and adding dependencies into graph is very important for lockdep to work because adding a dependency means adding a chance to check if it causes a deadlock. The more lockdep adds dependencies, the more it thoroughly works. Therefore Lockdep has to do its best to add as many true dependencies as possible into the graph.

Relaxing the limitation, lockdep can add more dependencies since additional things e.g. page locks or completions create additional dependencies. However even so, it needs to be noted that the relaxation does not affect the behavior of adding dependencies for typical locks.

For example, considering only typical locks, lockdep builds a graph like,

   A -> B -        -> F -> G
           \      /
            -> E -        -> L
           /      \      /
   C -> D -        -> H -
                         \
                          -> I -> K
                         /
                      J -

where A, B,..., L are different lock classes.

On the other hand, under the relaxation, additional dependencies might be created and added. Assuming additional 'MX -> H', 'L -> NX' and 'OX -> J' dependencies are added thanks to the relaxation, the graph will be, giving additional chances to check circular dependencies,

   A -> B -        -> F -> G
           \      /
            -> E -        -> L -> NX
           /      \      /
   C -> D -        -> H -
                  /      \
              MX -        -> I -> K
                         /
                   -> J -
                  /
              OX -

where A, B,..., L, MX, NX and OX are different lock classes, and a suffix 'X' is added on non-typical locks e.g. page locks and completions.

However, it might suffer performance degradation since relaxing the limitation with which design and implementation of lockdep could be efficient might introduce inefficiency inevitably. Each option, strong detection or efficient detection, has its pros and cons, thus the right of choice between two options should be given to users.

Choosing efficient detection, lockdep only deals with locks satisfying,

A lock should be released within the context holding the lock.

Choosing strong detection, lockdep deals with any locks satisfying,

A lock can be released in any context.

The latter, of course, doesn't allow illegal contexts to release a lock. For example, acquiring a lock in irq-safe context before releasing the lock in irq-unsafe context is not allowed, which after all ends in circular dependencies, meaning a deadlock. Otherwise, any contexts are allowed to release it.

CONCLUSION

Relaxing the limitation, lockdep can add additional dependencies and get additional chances to check if they cause deadlocks.

============
Crossrelease
============

Introduce crossrelease
----------------------

To allow lockdep to handle additional dependencies by what might be released in any context, namely 'crosslock', a new feature 'crossrelease' is introduced. Thanks to the feature, now lockdep can identify such dependencies. Crossrelease feature has to do,

1. Identify dependencies by crosslocks.
2. Add the dependencies into graph.

That's all. Once a meaningful dependency is added into graph, then lockdep would work with the graph as it did. So the most important thing crossrelease feature has to do is to correctly identify and add true dependencies into the global graph.

A dependency e.g. 'A -> B' can be identified only in the A's release context because a decision required to identify the dependency can be made only in the release context. That is to decide whether A can be released so that a waiter for A can be woken up. It cannot be made in other contexts than the A's release context. See 'What causes deadlock' section to remind what a dependency is.

It's no matter for typical locks because each acquire context is same as its release context, thus lockdep can decide whether a lock can be released, in the acquire context. However for crosslocks, lockdep cannot make the decision in the acquire context but has to wait until the release context is identified.

Therefore lockdep has to queue all acquisitions which might create dependencies until the decision can be made, so that they can be used when it proves they are the right ones. We call the step 'commit'. See 'Introduce commit' section.

Of course, some actual deadlocks caused by crosslocks cannot be detected just when it happens, because the deadlocks cannot be identified until the crosslocks is actually released. However, deadlock possibilities can be detected in this way. It's worth possibility detection of deadlock. See 'What lockdep does' section.

CONCLUSION

With crossrelease feature, lockdep can work with what might be released in any context, namely crosslock.

Pick true dependencies
----------------------

Remind what a dependency is. A dependency exists if,

COND 1. There are two waiters waiting for each event at the same time. COND 2. Only way to wake up each waiter is to trigger its events. COND 3. Whether one can be woken up depends on whether the other can.

For example,

TASK X
------
acquire A

acquire B /* A dependency 'A -> B' exists */

acquire C /* A dependency 'B -> C' exists */

release C

release B

release A

where A, B and C are different lock classes.

A depedency 'A -> B' exists since,

1. A waiter for A and a waiter for B might exist when acquiring B.
2. Only way to wake up each of them is to release what it waits for.
3. Whether the waiter for A can be woken up depends on whether the other can. IOW, TASK X cannot release A if it cannot acquire B.

Other dependencies 'B -> C' and 'A -> C' also exist for the same reason. But the second is ignored since it's covered by 'A -> B' and 'B -> C'.

For another example,

TASK X TASK Y
------ ------
acquire AX
acquire D
/* A dependency 'AX -> D' exists */
acquire B
release D

				   acquire C
				   /* A dependency 'B -> C' exists */
   acquire E
   /* A dependency 'AX -> E' exists */
				   acquire D
				   /* A dependency 'C -> D' exists */

release E
release D
release AX held by Y
release C

release B

where AX, B, C,..., E are different lock classes, and a suffix 'X' is added on crosslocks.

Even in this case involving crosslocks, the same rules can be applied. A depedency 'AX -> D' exists since,

1. A waiter for AX and a waiter for D might exist when acquiring D.
2. Only way to wake up each of them is to release what it waits for.
3. Whether the waiter for AX can be woken up depends on whether the other can. IOW, TASK X cannot release AX if it cannot acquire D.

The same rules can be applied to other dependencies, too.

Let's take a look at more complicated example.

TASK X TASK Y
------ ------
acquire B

release B

acquire C

release C
(1)
fork Y
acquire AX
acquire D
/* A dependency 'AX -> D' exists */
acquire F
release D

				   acquire G
				   /* A dependency 'F -> G' exists */
   acquire E
   /* A dependency 'AX -> E' exists */
				   acquire H
				   /* A dependency 'G -> H' exists */

release E
release H
release AX held by Y
release G

release F

where AX, B, C,..., H are different lock classes, and a suffix 'X' is added on crosslocks.

Does a dependency 'AX -> B' exist? Nope.

Two waiters, one is for AX and the other is for B, are essential elements to create the dependency 'AX -> B'. However in this example, these two waiters cannot exist at the same time. Thus the dependency 'AX -> B' cannot be created.

In fact, AX depends on all acquisitions after (1) in TASK X e.i. D and E, but excluding all acquisitions before (1) in the context e.i. A and C. Thus only 'AX -> D' and 'AX -> E' are true dependencies by AX.

It would be ideal if the full set of true ones can be added. But parsing the whole code is necessary to do it, which is impossible. Relying on what actually happens at runtime, we can anyway add only true ones even though they might be a subset of the full set. This way we can avoid adding false ones.

It's similar to how lockdep works for typical locks. Ideally there might be more true dependencies than ones being in the gloabl dependency graph, however, lockdep has no choice but to rely on what actually happens since otherwise it's almost impossible.

CONCLUSION

Relying on what actually happens, adding false dependencies can be avoided.

Introduce commit
----------------

Crossrelease feature names it 'commit' to identify and add dependencies into graph in batches. Lockdep is already doing what commit is supposed to do, when acquiring a lock for typical locks. However, that way must be changed for crosslocks so that it identifies a crosslock's release context first, then does commit.

There are four types of dependencies.

1. TT type: 'Typical lock A -> Typical lock B' dependency

Just when acquiring B, lockdep can see it's in the A's release context. So the dependency between A and B can be identified immediately. Commit is unnecessary.

2. TC type: 'Typical lock A -> Crosslock BX' dependency

Just when acquiring BX, lockdep can see it's in the A's release context. So the dependency between A and BX can be identified immediately. Commit is unnecessary, too.

3. CT type: 'Crosslock AX -> Typical lock B' dependency

When acquiring B, lockdep cannot identify the dependency because there's no way to know whether it's in the AX's release context. It has to wait until the decision can be made. Commit is necessary.

4. CC type: 'Crosslock AX -> Crosslock BX' dependency

If there is a typical lock acting as a bridge so that 'AX -> a lock' and 'the lock -> BX' can be added, then this dependency can be detected. But direct ways are not implemented yet. It's a future work.

Lockdep works even without commit for typical locks. However, commit step is necessary once crosslocks are involved, until all crosslocks in progress are released. Introducing commit, lockdep performs three steps i.e. acquire, commit and release. What lockdep does in each step is,

1. Acquire

1) For typical lock

Lockdep does what it originally did and queues the lock so that lockdep can check CT type dependencies using it at commit step.

2) For crosslock

The crosslock is added to a global linked list so that lockdep can check CT type dependencies using it at commit step.

2. Commit

1) For typical lock

      N/A.

2) For crosslock

Lockdep checks and adds CT Type dependencies using data saved at acquire step.

3. Release

1) For typical lock

No change.

2) For crosslock

Lockdep just remove the crosslock from the global linked list, to which it was added at acquire step.

CONCLUSION

Crossrelease feature introduces commit step to handle dependencies by crosslocks in batches, which lockdep cannot handle in its original way.

==============
Implementation
==============

Data structures
---------------

Crossrelease feature introduces two main data structures.

1. pend_lock

This is an array embedded in task_struct, for keeping locks queued so that real dependencies can be added using them at commit step. Since it's local data, it can be accessed locklessly in the owner context. The array is filled at acquire step and consumed at commit step. And it's managed in circular manner.

2. cross_lock

This is a global linked list, for keeping all crosslocks in progress. The list grows at acquire step and is shrunk at release step.

CONCLUSION

Crossrelease feature introduces two main data structures.

1. A pend_lock array for queueing typical locks in circular manner.
2. A cross_lock linked list for managing crosslocks in progress.

How crossrelease works
----------------------

Let's take a look at how crossrelease feature works step by step, starting from how lockdep works without crossrelease feaure.

For example, the below is how lockdep works for typical locks.

A's RELEASE CONTEXT (= A's ACQUIRE CONTEXT)
-------------------------------------------
acquire A

acquire B /* Add 'A -> B' */

acquire C /* Add 'B -> C' */

release C

release B

release A

where A, B and C are different lock classes.

After adding 'A -> B', the dependency graph will be,

A -> B

where A and B are different lock classes.

And after adding 'B -> C', the graph will be,

A -> B -> C

where A, B and C are different lock classes.

What if we use commit step to add dependencies even for typical locks? Commit step is not necessary for them, however it anyway would work well, because this is a more general way.

A's RELEASE CONTEXT (= A's ACQUIRE CONTEXT)
-------------------------------------------
acquire A
/*
* 1. Mark A as started
* 2. Queue A
*
* In pend_lock: A
* In graph: Empty
*/

acquire B
/*
* 1. Mark B as started
* 2. Queue B
*
* In pend_lock: A, B
* In graph: Empty
*/

acquire C
/*
* 1. Mark C as started
* 2. Queue C
*
* In pend_lock: A, B, C
* In graph: Empty
*/

release C
/*
* 1. Commit C (= Add 'C -> ?')
* a. What queued since C was marked: Nothing
* b. Add nothing
*
* In pend_lock: A, B, C
* In graph: Empty
*/

release B
/*
* 1. Commit B (= Add 'B -> ?')
* a. What queued since B was marked: C
* b. Add 'B -> C'
*
* In pend_lock: A, B, C
* In graph: 'B -> C'
*/

release A
/*
* 1. Commit A (= Add 'A -> ?')
* a. What queued since A was marked: B, C
* b. Add 'A -> B'
* c. Add 'A -> C'
*
* In pend_lock: A, B, C
* In graph: 'B -> C', 'A -> B', 'A -> C'
*/

where A, B and C are different lock classes.

After doing commit A, B and C, the dependency graph becomes like,

A -> B -> C

where A, B and C are different lock classes.

NOTE: A dependency 'A -> C' is optimized out.

We can see the former graph built without commit step is same as the latter graph built using commit steps. Of course the former way leads to earlier finish for building the graph, which means we can detect a deadlock or its possibility sooner. So the former way would be prefered if possible. But we cannot avoid using the latter way for crosslocks.

Let's look at how commit works for crosslocks.

AX's RELEASE CONTEXT AX's ACQUIRE CONTEXT
-------------------- --------------------

				   acquire AX
				   /*
				    * 1. Mark AX as started
				    *
				    * (No queuing for crosslocks)
				    *
				    * In pend_lock: Empty
				    * In graph: Empty
				    */

(serialized by some means e.g. barrier)

acquire D
/*
* (No marking for typical locks)
*
* 1. Queue D
*
* In pend_lock: D
* In graph: Empty
*/
acquire B
/*
* (No marking for typical locks) *
* 1. Queue B
*
* In pend_lock: B
* In graph: Empty
*/
release D
/*
* (No commit for typical locks)
*
* In pend_lock: D
* In graph: Empty
*/
acquire C
/*
* (No marking for typical locks) *
* 1. Add 'B -> C' of TT type
* 2. Queue C
*
* In pend_lock: B, C
* In graph: 'B -> C' */
acquire E
/*
* (No marking for typical locks)
*
* 1. Queue E
*
* In pend_lock: D, E
* In graph: 'B -> C'
*/
acquire D
/*
* (No marking for typical locks) *
* 1. Add 'C -> D' of TT type
* 2. Queue D
*
* In pend_lock: B, C, D
* In graph: 'B -> C', 'C -> D' */
release E
/*
* (No commit for typical locks)
*
* In pend_lock: D, E
* In graph: 'B -> C', 'C -> D'
*/
release D
/*
* (No commit for typical locks) *
* In pend_lock: B, C, D
* In graph: 'B -> C', 'C -> D' */
release AX
/*
* 1. Commit AX (= Add 'AX -> ?')
* a. What queued since AX was marked: D, E
* b. Add 'AX -> D' of CT type
* c. Add 'AX -> E' of CT type
*
* In pend_lock: D, E
* In graph: 'B -> C', 'C -> D',
* 'AX -> D', 'AX -> E'
*/
release C
/*
* (No commit for typical locks) *
* In pend_lock: B, C, D
* In graph: 'B -> C', 'C -> D',
* 'AX -> D', 'AX -> E'
*/

release B
/*
* (No commit for typical locks) *
* In pend_lock: B, C, D
* In graph: 'B -> C', 'C -> D',
* 'AX -> D', 'AX -> E'
*/

where AX, B, C,..., E are different lock classes, and a suffix 'X' is added on crosslocks.

When acquiring crosslock AX, crossrelease feature marks AX as started, which means all acquisitions from now are candidates which might create dependencies with AX. True dependencies will be determined when identifying the AX's release context.

When acquiring typical lock B, lockdep queues B so that it can be used at commit step later since any crosslocks in progress might depends on B. The same thing is done on lock C, D and E. And then two dependencies 'AX -> D' and 'AX -> E' are added at commit step, when identifying the AX's release context.

The final graph is, with crossrelease feature using commit,

   B -> C -
           \
            -> D
           /
       AX -
           \
            -> E

where AX, B, C,..., E are different lock classes, and a suffix 'X' is added on crosslocks.

However, without crossrelease feature, the final graph would be,

B -> C -> D

where B and C are different lock classes.

The former graph has two more dependencies 'AX -> D' and 'AX -> E' giving additional chances to check if they cause deadlocks. This way lockdep can detect a deadlock or its possibility caused by crosslocks. Again, crossrelease feature does not affect the behavior of adding dependencies for typical locks.

CONCLUSION

Crossrelease works well for crosslock, thanks to commit step.

=============
Optimizations
=============

Avoid duplication
-----------------

Crossrelease feature uses a cache like what lockdep is already using for dependency chains, but this time it's for caching a dependency of CT type, crossing between two different context. Once that dependency is cached, same dependencies will never be added again. Queueing unnecessary locks is also prevented based on the cache.

CONCLUSION

Crossrelease does not add any duplicate dependencies.

Lockless for hot paths
----------------------

To keep all typical locks for later use, crossrelease feature adopts a local array embedded in task_struct, which makes accesses to arrays lockless by forcing the accesses to happen only within the owner context. It's like how lockdep accesses held_locks. Lockless implmentation is important since typical locks are very frequently acquired and released.

CONCLUSION

Crossrelease is designed to use no lock for hot paths.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#47 lore raw

Re: [REVISED DOC on v3] Crossrelease Lockdep

Hello Peterz,

I tried to explain about what you asked me for.
I wonder if I did it exactly. But I hope so. Please let me know if there's something more I need to add.

Thank you,
Byungchul

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#48 lore raw

Re: [REVISED DOC on v3] Crossrelease Lockdep

Quoted 5 lines · Byungchul Park

Hello Peterz,

I tried to explain about what you asked me for.
I wonder if I did it exactly. But I hope so. Please let me know if there's something more I need to add.

Just to be sure, are you concerning about sync and propagation delay of memory contents including lock variables between cpus?

IMHO, it makes no difference. It's a true dependence once the dependency is viewable by a cpu, which means anyway it actually happened. And please remind all locks related to crosslocks are serialized via proper memory barriers. I think this was already descibed in my document.

Is there something I missed? Please let me know.

Thank you,
Byungchul

Quoted 3 lines

Thank you,
Byungchul

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>