linux/lib/locking-selftest.c

// SPDX-License-Identifier: GPL-2.0
/*
 * lib/locking-selftest.c
 *
 * Testsuite for various locking APIs: spinlocks, rwlocks,
 * mutexes and rw-semaphores.
 *
 * It is checking both false positives and false negatives.
 *
 * Started by Ingo Molnar:
 *
 *  Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <[email protected]>
 */
#include <linux/rwsem.h>
#include <linux/mutex.h>
#include <linux/ww_mutex.h>
#include <linux/sched.h>
#include <linux/sched/mm.h>
#include <linux/delay.h>
#include <linux/lockdep.h>
#include <linux/spinlock.h>
#include <linux/kallsyms.h>
#include <linux/interrupt.h>
#include <linux/debug_locks.h>
#include <linux/irqflags.h>
#include <linux/rtmutex.h>
#include <linux/local_lock.h>

#ifdef CONFIG_PREEMPT_RT
#define NON_RT
#else
#define NON_RT(...)
#endif

/*
 * Change this to 1 if you want to see the failure printouts:
 */
static unsigned int debug_locks_verbose;
unsigned int force_read_lock_recursive;

static DEFINE_WD_CLASS(ww_lockdep);

static int __init setup_debug_locks_verbose(char *str)
{}

__setup();

#define FAILURE
#define SUCCESS

#define LOCKTYPE_SPIN
#define LOCKTYPE_RWLOCK
#define LOCKTYPE_MUTEX
#define LOCKTYPE_RWSEM
#define LOCKTYPE_WW
#define LOCKTYPE_RTMUTEX
#define LOCKTYPE_LL
#define LOCKTYPE_SPECIAL

static struct ww_acquire_ctx t, t2;
static struct ww_mutex o, o2, o3;

/*
 * Normal standalone locks, for the circular and irq-context
 * dependency tests:
 */
static DEFINE_SPINLOCK(lock_A);
static DEFINE_SPINLOCK(lock_B);
static DEFINE_SPINLOCK(lock_C);
static DEFINE_SPINLOCK(lock_D);

static DEFINE_RAW_SPINLOCK(raw_lock_A);
static DEFINE_RAW_SPINLOCK(raw_lock_B);

static DEFINE_RWLOCK(rwlock_A);
static DEFINE_RWLOCK(rwlock_B);
static DEFINE_RWLOCK(rwlock_C);
static DEFINE_RWLOCK(rwlock_D);

static DEFINE_MUTEX(mutex_A);
static DEFINE_MUTEX(mutex_B);
static DEFINE_MUTEX(mutex_C);
static DEFINE_MUTEX(mutex_D);

static DECLARE_RWSEM(rwsem_A);
static DECLARE_RWSEM(rwsem_B);
static DECLARE_RWSEM(rwsem_C);
static DECLARE_RWSEM(rwsem_D);

#ifdef CONFIG_RT_MUTEXES

static DEFINE_RT_MUTEX(rtmutex_A);
static DEFINE_RT_MUTEX(rtmutex_B);
static DEFINE_RT_MUTEX(rtmutex_C);
static DEFINE_RT_MUTEX(rtmutex_D);

#endif

/*
 * Locks that we initialize dynamically as well so that
 * e.g. X1 and X2 becomes two instances of the same class,
 * but X* and Y* are different classes. We do this so that
 * we do not trigger a real lockup:
 */
static DEFINE_SPINLOCK(lock_X1);
static DEFINE_SPINLOCK(lock_X2);
static DEFINE_SPINLOCK(lock_Y1);
static DEFINE_SPINLOCK(lock_Y2);
static DEFINE_SPINLOCK(lock_Z1);
static DEFINE_SPINLOCK(lock_Z2);

static DEFINE_RWLOCK(rwlock_X1);
static DEFINE_RWLOCK(rwlock_X2);
static DEFINE_RWLOCK(rwlock_Y1);
static DEFINE_RWLOCK(rwlock_Y2);
static DEFINE_RWLOCK(rwlock_Z1);
static DEFINE_RWLOCK(rwlock_Z2);

static DEFINE_MUTEX(mutex_X1);
static DEFINE_MUTEX(mutex_X2);
static DEFINE_MUTEX(mutex_Y1);
static DEFINE_MUTEX(mutex_Y2);
static DEFINE_MUTEX(mutex_Z1);
static DEFINE_MUTEX(mutex_Z2);

static DECLARE_RWSEM(rwsem_X1);
static DECLARE_RWSEM(rwsem_X2);
static DECLARE_RWSEM(rwsem_Y1);
static DECLARE_RWSEM(rwsem_Y2);
static DECLARE_RWSEM(rwsem_Z1);
static DECLARE_RWSEM(rwsem_Z2);

#ifdef CONFIG_RT_MUTEXES

static DEFINE_RT_MUTEX(rtmutex_X1);
static DEFINE_RT_MUTEX(rtmutex_X2);
static DEFINE_RT_MUTEX(rtmutex_Y1);
static DEFINE_RT_MUTEX(rtmutex_Y2);
static DEFINE_RT_MUTEX(rtmutex_Z1);
static DEFINE_RT_MUTEX(rtmutex_Z2);

#endif

static DEFINE_PER_CPU(local_lock_t, local_A);

/*
 * non-inlined runtime initializers, to let separate locks share
 * the same lock-class:
 */
#define INIT_CLASS_FUNC(class)

INIT_CLASS_FUNC(X)
INIT_CLASS_FUNC(Y)
INIT_CLASS_FUNC(Z)

static void init_shared_classes(void)
{}

/*
 * For spinlocks and rwlocks we also do hardirq-safe / softirq-safe tests.
 * The following functions use a lock from a simulated hardirq/softirq
 * context, causing the locks to be marked as hardirq-safe/softirq-safe:
 */

#define HARDIRQ_DISABLE
#define HARDIRQ_ENABLE

#define HARDIRQ_ENTER()

#define HARDIRQ_EXIT()

#define SOFTIRQ_DISABLE
#define SOFTIRQ_ENABLE

#define SOFTIRQ_ENTER()

#define SOFTIRQ_EXIT()

/*
 * Shortcuts for lock/unlock API variants, to keep
 * the testcases compact:
 */
#define L(x)
#define U(x)
#define LU(x)
#define SI(x)

#define WL(x)
#define WU(x)
#define WLU(x)

#define RL(x)
#define RU(x)
#define RLU(x)
#define RWI(x)

#define ML(x)
#define MU(x)
#define MI(x)

#define RTL(x)
#define RTU(x)
#define RTI(x)

#define WSL(x)
#define WSU(x)

#define RSL(x)
#define RSU(x)
#define RWSI(x)

#ifndef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
#define WWAI
#else
#define WWAI(x)
#endif
#define WWAD(x)
#define WWAF(x)

#define WWL(x, c)
#define WWT(x)
#define WWL1(x)
#define WWU(x)


#define LOCK_UNLOCK_2(x,y)

/*
 * Generate different permutations of the same testcase, using
 * the same basic lock-dependency/state events:
 */

#define GENERATE_TESTCASE(name)

#define GENERATE_PERMUTATIONS_2_EVENTS(name)

#define GENERATE_PERMUTATIONS_3_EVENTS(name)

/*
 * AA deadlock:
 */

#define E

/*
 * 6 testcases:
 */
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(AA_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(AA_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(AA_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(AA_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(AA_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(AA_rsem)

#ifdef CONFIG_RT_MUTEXES
#include "locking-selftest-rtmutex.h"
GENERATE_TESTCASE(AA_rtmutex);
#endif

#undef E

/*
 * Special-case for read-locking, they are
 * allowed to recurse on the same lock class:
 */
static void rlock_AA1(void)
{}

static void rlock_AA1B(void)
{}

static void rsem_AA1(void)
{}

static void rsem_AA1B(void)
{}
/*
 * The mixing of read and write locks is not allowed:
 */
static void rlock_AA2(void)
{}

static void rsem_AA2(void)
{}

static void rlock_AA3(void)
{}

static void rsem_AA3(void)
{}

/*
 * read_lock(A)
 * spin_lock(B)
 *		spin_lock(B)
 *		write_lock(A)
 */
static void rlock_ABBA1(void)
{}

static void rwsem_ABBA1(void)
{}

/*
 * read_lock(A)
 * spin_lock(B)
 *		spin_lock(B)
 *		write_lock(A)
 *
 * This test case is aimed at poking whether the chain cache prevents us from
 * detecting a read-lock/lock-write deadlock: if the chain cache doesn't differ
 * read/write locks, the following case may happen
 *
 * 	{ read_lock(A)->lock(B) dependency exists }
 *
 * 	P0:
 * 	lock(B);
 * 	read_lock(A);
 *
 *	{ Not a deadlock, B -> A is added in the chain cache }
 *
 *	P1:
 *	lock(B);
 *	write_lock(A);
 *
 *	{ B->A found in chain cache, not reported as a deadlock }
 *
 */
static void rlock_chaincache_ABBA1(void)
{}

/*
 * read_lock(A)
 * spin_lock(B)
 *		spin_lock(B)
 *		read_lock(A)
 */
static void rlock_ABBA2(void)
{}

static void rwsem_ABBA2(void)
{}


/*
 * write_lock(A)
 * spin_lock(B)
 *		spin_lock(B)
 *		write_lock(A)
 */
static void rlock_ABBA3(void)
{}

static void rwsem_ABBA3(void)
{}

/*
 * ABBA deadlock:
 */

#define E

/*
 * 6 testcases:
 */
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(ABBA_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(ABBA_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(ABBA_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(ABBA_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(ABBA_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(ABBA_rsem)

#ifdef CONFIG_RT_MUTEXES
#include "locking-selftest-rtmutex.h"
GENERATE_TESTCASE(ABBA_rtmutex);
#endif

#undef E

/*
 * AB BC CA deadlock:
 */

#define E

/*
 * 6 testcases:
 */
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(ABBCCA_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(ABBCCA_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(ABBCCA_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(ABBCCA_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(ABBCCA_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(ABBCCA_rsem)

#ifdef CONFIG_RT_MUTEXES
#include "locking-selftest-rtmutex.h"
GENERATE_TESTCASE(ABBCCA_rtmutex);
#endif

#undef E

/*
 * AB CA BC deadlock:
 */

#define E

/*
 * 6 testcases:
 */
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(ABCABC_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(ABCABC_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(ABCABC_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(ABCABC_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(ABCABC_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(ABCABC_rsem)

#ifdef CONFIG_RT_MUTEXES
#include "locking-selftest-rtmutex.h"
GENERATE_TESTCASE(ABCABC_rtmutex);
#endif

#undef E

/*
 * AB BC CD DA deadlock:
 */

#define E

/*
 * 6 testcases:
 */
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(ABBCCDDA_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(ABBCCDDA_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(ABBCCDDA_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(ABBCCDDA_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(ABBCCDDA_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(ABBCCDDA_rsem)

#ifdef CONFIG_RT_MUTEXES
#include "locking-selftest-rtmutex.h"
GENERATE_TESTCASE(ABBCCDDA_rtmutex);
#endif

#undef E

/*
 * AB CD BD DA deadlock:
 */
#define E

/*
 * 6 testcases:
 */
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(ABCDBDDA_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(ABCDBDDA_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(ABCDBDDA_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(ABCDBDDA_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(ABCDBDDA_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(ABCDBDDA_rsem)

#ifdef CONFIG_RT_MUTEXES
#include "locking-selftest-rtmutex.h"
GENERATE_TESTCASE(ABCDBDDA_rtmutex);
#endif

#undef E

/*
 * AB CD BC DA deadlock:
 */
#define E

/*
 * 6 testcases:
 */
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(ABCDBCDA_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(ABCDBCDA_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(ABCDBCDA_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(ABCDBCDA_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(ABCDBCDA_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(ABCDBCDA_rsem)

#ifdef CONFIG_RT_MUTEXES
#include "locking-selftest-rtmutex.h"
GENERATE_TESTCASE(ABCDBCDA_rtmutex);
#endif

#undef E

#ifdef CONFIG_PREEMPT_RT
#define RT_PREPARE_DBL_UNLOCK
#else
#define RT_PREPARE_DBL_UNLOCK()
#endif
/*
 * Double unlock:
 */
#define E

/*
 * 6 testcases:
 */
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(double_unlock_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(double_unlock_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(double_unlock_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(double_unlock_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(double_unlock_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(double_unlock_rsem)

#ifdef CONFIG_RT_MUTEXES
#include "locking-selftest-rtmutex.h"
GENERATE_TESTCASE(double_unlock_rtmutex);
#endif

#undef E

/*
 * initializing a held lock:
 */
#define E

/*
 * 6 testcases:
 */
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(init_held_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(init_held_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(init_held_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(init_held_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(init_held_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(init_held_rsem)

#ifdef CONFIG_RT_MUTEXES
#include "locking-selftest-rtmutex.h"
GENERATE_TESTCASE(init_held_rtmutex);
#endif

#undef E

/*
 * locking an irq-safe lock with irqs enabled:
 */
#define E1()

#define E2()

/*
 * Generate 24 testcases:
 */
#include "locking-selftest-spin-hardirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_hard_spin)

#include "locking-selftest-rlock-hardirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_hard_rlock)

#include "locking-selftest-wlock-hardirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_hard_wlock)

#ifndef CONFIG_PREEMPT_RT
#include "locking-selftest-spin-softirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_soft_spin)

#include "locking-selftest-rlock-softirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_soft_rlock)

#include "locking-selftest-wlock-softirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_soft_wlock)
#endif

#undef E1
#undef E2

#ifndef CONFIG_PREEMPT_RT
/*
 * Enabling hardirqs with a softirq-safe lock held:
 */
#define E1()

#define E2()

/*
 * Generate 12 testcases:
 */
#include "locking-selftest-spin.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2A_spin)

#include "locking-selftest-wlock.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2A_wlock)

#include "locking-selftest-rlock.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2A_rlock)

#undef E1
#undef E2

#endif

/*
 * Enabling irqs with an irq-safe lock held:
 */
#define E1()

#define E2()

/*
 * Generate 24 testcases:
 */
#include "locking-selftest-spin-hardirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_hard_spin)

#include "locking-selftest-rlock-hardirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_hard_rlock)

#include "locking-selftest-wlock-hardirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_hard_wlock)

#ifndef CONFIG_PREEMPT_RT
#include "locking-selftest-spin-softirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_soft_spin)

#include "locking-selftest-rlock-softirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_soft_rlock)

#include "locking-selftest-wlock-softirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_soft_wlock)
#endif

#undef E1
#undef E2

/*
 * Acquiring a irq-unsafe lock while holding an irq-safe-lock:
 */
#define E1()			\

#define E2()

#define E3()

/*
 * Generate 36 testcases:
 */
#include "locking-selftest-spin-hardirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_hard_spin)

#include "locking-selftest-rlock-hardirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_hard_rlock)

#include "locking-selftest-wlock-hardirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_hard_wlock)

#ifndef CONFIG_PREEMPT_RT
#include "locking-selftest-spin-softirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_soft_spin)

#include "locking-selftest-rlock-softirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_soft_rlock)

#include "locking-selftest-wlock-softirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_soft_wlock)
#endif

#undef E1
#undef E2
#undef E3

/*
 * If a lock turns into softirq-safe, but earlier it took
 * a softirq-unsafe lock:
 */

#define E1()

#define E2()

#define E3()

/*
 * Generate 36 testcases:
 */
#include "locking-selftest-spin-hardirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_hard_spin)

#include "locking-selftest-rlock-hardirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_hard_rlock)

#include "locking-selftest-wlock-hardirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_hard_wlock)

#ifndef CONFIG_PREEMPT_RT
#include "locking-selftest-spin-softirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_soft_spin)

#include "locking-selftest-rlock-softirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_soft_rlock)

#include "locking-selftest-wlock-softirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_soft_wlock)
#endif

#undef E1
#undef E2
#undef E3

/*
 * read-lock / write-lock irq inversion.
 *
 * Deadlock scenario:
 *
 * CPU#1 is at #1, i.e. it has write-locked A, but has not
 * taken B yet.
 *
 * CPU#2 is at #2, i.e. it has locked B.
 *
 * Hardirq hits CPU#2 at point #2 and is trying to read-lock A.
 *
 * The deadlock occurs because CPU#1 will spin on B, and CPU#2
 * will spin on A.
 */

#define E1()

#define E2()

#define E3()

/*
 * Generate 36 testcases:
 */
#include "locking-selftest-spin-hardirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_hard_spin)

#include "locking-selftest-rlock-hardirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_hard_rlock)

#include "locking-selftest-wlock-hardirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_hard_wlock)

#ifndef CONFIG_PREEMPT_RT
#include "locking-selftest-spin-softirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_soft_spin)

#include "locking-selftest-rlock-softirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_soft_rlock)

#include "locking-selftest-wlock-softirq.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_soft_wlock)
#endif

#undef E1
#undef E2
#undef E3

/*
 * write-read / write-read / write-read deadlock even if read is recursive
 */

#define E1()

#define E2()

#define E3()

#include "locking-selftest-rlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(W1R2_W2R3_W3R1)

#undef E1
#undef E2
#undef E3

/*
 * write-write / read-read / write-read deadlock even if read is recursive
 */

#define E1()

#define E2()

#define E3()

#include "locking-selftest-rlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(W1W2_R2R3_W3R1)

#undef E1
#undef E2
#undef E3

/*
 * write-write / read-read / read-write is not deadlock when read is recursive
 */

#define E1()

#define E2()

#define E3()

#include "locking-selftest-rlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(W1R2_R2R3_W3W1)

#undef E1
#undef E2
#undef E3

/*
 * write-read / read-read / write-write is not deadlock when read is recursive
 */

#define E1()

#define E2()

#define E3()

#include "locking-selftest-rlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(W1W2_R2R3_R3W1)

#undef E1
#undef E2
#undef E3
/*
 * read-lock / write-lock recursion that is actually safe.
 */

#define E1()

#define E2()				\

#define E3()

/*
 * Generate 24 testcases:
 */
#include "locking-selftest-hardirq.h"
#include "locking-selftest-rlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_hard_rlock)

#include "locking-selftest-wlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_hard_wlock)

#ifndef CONFIG_PREEMPT_RT
#include "locking-selftest-softirq.h"
#include "locking-selftest-rlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft_rlock)

#include "locking-selftest-wlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft_wlock)
#endif

#undef E1
#undef E2
#undef E3

/*
 * read-lock / write-lock recursion that is unsafe.
 */

#define E1()

#define E2()				\

#define E3()

/*
 * Generate 24 testcases:
 */
#include "locking-selftest-hardirq.h"
#include "locking-selftest-rlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_hard_rlock)

#include "locking-selftest-wlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_hard_wlock)

#ifndef CONFIG_PREEMPT_RT
#include "locking-selftest-softirq.h"
#include "locking-selftest-rlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_soft_rlock)

#include "locking-selftest-wlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_soft_wlock)
#endif

#undef E1
#undef E2
#undef E3
/*
 * read-lock / write-lock recursion that is unsafe.
 *
 * A is a ENABLED_*_READ lock
 * B is a USED_IN_*_READ lock
 *
 * read_lock(A);
 *			write_lock(B);
 * <interrupt>
 * read_lock(B);
 * 			write_lock(A); // if this one is read_lock(), no deadlock
 */

#define E1()

#define E2()				\

#define E3()

/*
 * Generate 24 testcases:
 */
#include "locking-selftest-hardirq.h"
#include "locking-selftest-rlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_hard_rlock)

#include "locking-selftest-wlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_hard_wlock)

#ifndef CONFIG_PREEMPT_RT
#include "locking-selftest-softirq.h"
#include "locking-selftest-rlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_soft_rlock)

#include "locking-selftest-wlock.h"
GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_soft_wlock)
#endif

#ifdef CONFIG_DEBUG_LOCK_ALLOC
#define I_SPINLOCK(x)
#define I_RAW_SPINLOCK(x)
#define I_RWLOCK(x)
#define I_MUTEX(x)
#define I_RWSEM(x)
#define I_WW(x)
#define I_LOCAL_LOCK(x)
#ifdef CONFIG_RT_MUTEXES
#define I_RTMUTEX(x)
#endif
#else
#define I_SPINLOCK
#define I_RAW_SPINLOCK
#define I_RWLOCK
#define I_MUTEX
#define I_RWSEM
#define I_WW
#define I_LOCAL_LOCK
#endif

#ifndef I_RTMUTEX
#define I_RTMUTEX
#endif

#ifdef CONFIG_RT_MUTEXES
#define I2_RTMUTEX(x)
#else
#define I2_RTMUTEX
#endif

#define I1(x)

#define I2(x)

static void reset_locks(void)
{}

#undef I

static int testcase_total;
static int testcase_successes;
static int expected_testcase_failures;
static int unexpected_testcase_failures;

static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask)
{}

#ifdef CONFIG_RT_MUTEXES
#define dotest_rt(fn, e, m)
#else
#define dotest_rt
#endif

static inline void print_testname(const char *testname)
{}

#define DO_TESTCASE_1(desc, name, nr)

#define DO_TESTCASE_1B(desc, name, nr)

#define DO_TESTCASE_1RR(desc, name, nr)

#define DO_TESTCASE_1RRB(desc, name, nr)


#define DO_TESTCASE_3(desc, name, nr)

#define DO_TESTCASE_3RW(desc, name, nr)

#define DO_TESTCASE_2RW(desc, name, nr)

#define DO_TESTCASE_2x2RW(desc, name, nr)	\

#define DO_TESTCASE_6x2x2RW(desc, name)

#define DO_TESTCASE_6(desc, name)

#define DO_TESTCASE_6_SUCCESS(desc, name)

/*
 * 'read' variant: rlocks must not trigger.
 */
#define DO_TESTCASE_6R(desc, name)

#define DO_TESTCASE_2I(desc, name, nr)

#define DO_TESTCASE_2IB(desc, name, nr)

#define DO_TESTCASE_6I(desc, name, nr)

#define DO_TESTCASE_6IRW(desc, name, nr)

#define DO_TESTCASE_2x3(desc, name)

#define DO_TESTCASE_2x6(desc, name)

#define DO_TESTCASE_6x2(desc, name)

#define DO_TESTCASE_6x2B(desc, name)

#define DO_TESTCASE_6x1RR(desc, name)

#define DO_TESTCASE_6x1RRB(desc, name)

#define DO_TESTCASE_6x6(desc, name)

#define DO_TESTCASE_6x6RW(desc, name)

static void ww_test_fail_acquire(void)
{}

#ifdef CONFIG_PREEMPT_RT
#define ww_mutex_base_lock
#define ww_mutex_base_trylock
#define ww_mutex_base_lock_nest_lock
#define ww_mutex_base_lock_interruptible
#define ww_mutex_base_lock_killable
#define ww_mutex_base_unlock
#else
#define ww_mutex_base_lock(b)
#define ww_mutex_base_trylock(b)
#define ww_mutex_base_lock_nest_lock(b, b2)
#define ww_mutex_base_lock_interruptible(b)
#define ww_mutex_base_lock_killable(b)
#define ww_mutex_base_unlock(b)
#endif

static void ww_test_normal(void)
{}

static void ww_test_two_contexts(void)
{}

static void ww_test_diff_class(void)
{}

static void ww_test_context_done_twice(void)
{}

static void ww_test_context_unlock_twice(void)
{}

static void ww_test_context_fini_early(void)
{}

static void ww_test_context_lock_after_done(void)
{}

static void ww_test_object_unlock_twice(void)
{}

static void ww_test_object_lock_unbalanced(void)
{}

static void ww_test_object_lock_stale_context(void)
{}

static void ww_test_edeadlk_normal(void)
{}

static void ww_test_edeadlk_normal_slow(void)
{}

static void ww_test_edeadlk_no_unlock(void)
{}

static void ww_test_edeadlk_no_unlock_slow(void)
{}

static void ww_test_edeadlk_acquire_more(void)
{}

static void ww_test_edeadlk_acquire_more_slow(void)
{}

static void ww_test_edeadlk_acquire_more_edeadlk(void)
{}

static void ww_test_edeadlk_acquire_more_edeadlk_slow(void)
{}

static void ww_test_edeadlk_acquire_wrong(void)
{}

static void ww_test_edeadlk_acquire_wrong_slow(void)
{}

static void ww_test_spin_nest_unlocked(void)
{}

/* This is not a deadlock, because we have X1 to serialize Y1 and Y2 */
static void ww_test_spin_nest_lock(void)
{}

static void ww_test_unneeded_slow(void)
{}

static void ww_test_context_block(void)
{}

static void ww_test_context_try(void)
{}

static void ww_test_context_context(void)
{}

static void ww_test_try_block(void)
{}

static void ww_test_try_try(void)
{}

static void ww_test_try_context(void)
{}

static void ww_test_block_block(void)
{}

static void ww_test_block_try(void)
{}

static void ww_test_block_context(void)
{}

static void ww_test_spin_block(void)
{}

static void ww_test_spin_try(void)
{}

static void ww_test_spin_context(void)
{}

static void ww_tests(void)
{}


/*
 * <in hardirq handler>
 * read_lock(&A);
 *			<hardirq disable>
 *			spin_lock(&B);
 * spin_lock(&B);
 *			read_lock(&A);
 *
 * is a deadlock.
 */
static void queued_read_lock_hardirq_RE_Er(void)
{}

/*
 * <in hardirq handler>
 * spin_lock(&B);
 *			<hardirq disable>
 *			read_lock(&A);
 * read_lock(&A);
 *			spin_lock(&B);
 *
 * is not a deadlock.
 */
static void queued_read_lock_hardirq_ER_rE(void)
{}

/*
 * <hardirq disable>
 * spin_lock(&B);
 *			read_lock(&A);
 *			<in hardirq handler>
 *			spin_lock(&B);
 * read_lock(&A);
 *
 * is a deadlock. Because the two read_lock()s are both non-recursive readers.
 */
static void queued_read_lock_hardirq_inversion(void)
{}

static void queued_read_lock_tests(void)
{}

static void fs_reclaim_correct_nesting(void)
{}

static void fs_reclaim_wrong_nesting(void)
{}

static void fs_reclaim_protected_nesting(void)
{}

static void fs_reclaim_tests(void)
{}

/* Defines guard classes to create contexts */
DEFINE_LOCK_GUARD_0(HARDIRQ, HARDIRQ_ENTER(), HARDIRQ_EXIT())
DEFINE_LOCK_GUARD_0(NOTTHREADED_HARDIRQ,
	do {}
DEFINE_LOCK_GUARD_0(SOFTIRQ, SOFTIRQ_ENTER(), SOFTIRQ_EXIT())

/* Define RCU guards, should go away when RCU has its own guard definitions */
DEFINE_LOCK_GUARD_0(RCU, rcu_read_lock(), rcu_read_unlock())
DEFINE_LOCK_GUARD_0(RCU_BH, rcu_read_lock_bh(), rcu_read_unlock_bh())
DEFINE_LOCK_GUARD_0(RCU_SCHED, rcu_read_lock_sched(), rcu_read_unlock_sched())


#define GENERATE_2_CONTEXT_TESTCASE(outer, outer_lock, inner, inner_lock)

/*
 * wait contexts (considering PREEMPT_RT)
 *
 * o: inner is allowed in outer
 * x: inner is disallowed in outer
 *
 *       \  inner |  RCU  | RAW_SPIN | SPIN | MUTEX
 * outer  \       |       |          |      |
 * ---------------+-------+----------+------+-------
 * HARDIRQ        |   o   |    o     |  o   |  x
 * ---------------+-------+----------+------+-------
 * NOTTHREADED_IRQ|   o   |    o     |  x   |  x
 * ---------------+-------+----------+------+-------
 * SOFTIRQ        |   o   |    o     |  o   |  x
 * ---------------+-------+----------+------+-------
 * RCU            |   o   |    o     |  o   |  x
 * ---------------+-------+----------+------+-------
 * RCU_BH         |   o   |    o     |  o   |  x
 * ---------------+-------+----------+------+-------
 * RCU_SCHED      |   o   |    o     |  x   |  x
 * ---------------+-------+----------+------+-------
 * RAW_SPIN       |   o   |    o     |  x   |  x
 * ---------------+-------+----------+------+-------
 * SPIN           |   o   |    o     |  o   |  x
 * ---------------+-------+----------+------+-------
 * MUTEX          |   o   |    o     |  o   |  o
 * ---------------+-------+----------+------+-------
 */

#define GENERATE_2_CONTEXT_TESTCASE_FOR_ALL_OUTER(inner, inner_lock)

GENERATE_2_CONTEXT_TESTCASE_FOR_ALL_OUTER()
GENERATE_2_CONTEXT_TESTCASE_FOR_ALL_OUTER()
GENERATE_2_CONTEXT_TESTCASE_FOR_ALL_OUTER()
GENERATE_2_CONTEXT_TESTCASE_FOR_ALL_OUTER()

/* the outer context allows all kinds of preemption */
#define DO_CONTEXT_TESTCASE_OUTER_PREEMPTIBLE(outer)		\

/*
 * the outer context only allows the preemption introduced by spinlock_t (which
 * is a sleepable lock for PREEMPT_RT)
 */
#define DO_CONTEXT_TESTCASE_OUTER_LIMITED_PREEMPTIBLE(outer)		\

/* the outer doesn't allows any kind of preemption */
#define DO_CONTEXT_TESTCASE_OUTER_NOT_PREEMPTIBLE(outer)		\

static void wait_context_tests(void)
{}

static void local_lock_2(void)
{}

static void local_lock_3A(void)
{}

static void local_lock_3B(void)
{}

static void local_lock_tests(void)
{}

static void hardirq_deadlock_softirq_not_deadlock(void)
{}

void locking_selftest(void)
{}