As one more example, let's check out a (demo) kernel module that quite deliberately creates a circular dependency, which will ultimately result in a deadlock. The code is here: ch13/3_lockdep/deadlock_eg_AB-BA. We've based this module on our earlier one (ch13/2_percpu); as you'll recall, we create two kernel threads and ensure (by using a hacked sched_setaffinity()) that each kernel thread runs on a unique CPU core (the first kernel thread on CPU core 0 and the second on core 1).
This way, we have concurrency. Now, within the threads, we have them work with two spinlocks, lockA and lockB. Understanding that we have a process context with two or more locks, we document and follow a lock ordering rule: first take lockA, then lockB. Great; so, one way it should not be done is like this:
kthread 0 on CPU #0 kthread 1 on CPU #1
Take lockA ...