From patchwork Sun Apr 28 17:04:14 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maarten Lankhorst X-Patchwork-Id: 16466 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-vb0-f70.google.com (mail-vb0-f70.google.com [209.85.212.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 7AF8D2395E for ; Sun, 28 Apr 2013 17:06:40 +0000 (UTC) Received: by mail-vb0-f70.google.com with SMTP id e13sf3210090vbg.5 for ; Sun, 28 Apr 2013 10:05:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:x-beenthere:x-received:received-spf:x-received :x-forwarded-to:x-forwarded-for:delivered-to:x-received:received-spf :to:from:date:message-id:in-reply-to:references:user-agent :mime-version:cc:subject:x-beenthere:x-mailman-version:precedence :list-id:list-unsubscribe:list-archive:list-post:list-help :list-subscribe:errors-to:sender:x-gm-message-state :x-original-sender:x-original-authentication-results:mailing-list :x-google-group-id:content-type:content-transfer-encoding; bh=9qhzPI89tv+ULThGvnB6IVdkAc7rEKQVjUjpgZbONxc=; b=YO84kRSTC+CWviTWF9j5o/C2KBk2QxsPK29YuPUpWKk3jSfGk/v3MzNWM7eGwfcuH/ +xi6rSXCiC6FHdkV88YG/xsgsjUuTixgPxmChYXOlHGdHyws/BAp4ii1IXqBMXE/UU5s dnThcwQmvTYw7bRGW45PyVoJcipIIU0czCLInG9Vp1MYoqnk1dLhDTSpmS3OBnhTbVk5 jNv9JXLrNnSG3/PzLKla/eR9wZUSGLDjUVqqSimi5/GrpeFWUb92V0/GmEjBzHOFgI7V 6hKolPxiKl1AGQmYUbTuAYMJVOMTS2bzKU+LqU5hli9NJhKxfWHs2pQRTzuygzpkZ7hC v7Jw== X-Received: by 10.224.217.195 with SMTP id hn3mr37876217qab.5.1367168739835; Sun, 28 Apr 2013 10:05:39 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.4.71 with SMTP id i7ls2609053qei.86.gmail; Sun, 28 Apr 2013 10:05:39 -0700 (PDT) X-Received: by 10.220.67.67 with SMTP id q3mr936949vci.38.1367168739665; Sun, 28 Apr 2013 10:05:39 -0700 (PDT) Received: from mail-vc0-f178.google.com (mail-vc0-f178.google.com [209.85.220.178]) by mx.google.com with ESMTPS id lb19si8635579vcb.71.2013.04.28.10.05.39 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 28 Apr 2013 10:05:39 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.220.178 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.178; Received: by mail-vc0-f178.google.com with SMTP id ha11so1314180vcb.9 for ; Sun, 28 Apr 2013 10:05:39 -0700 (PDT) X-Received: by 10.58.144.231 with SMTP id sp7mr1816798veb.34.1367168739444; Sun, 28 Apr 2013 10:05:39 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.58.127.98 with SMTP id nf2csp27097veb; Sun, 28 Apr 2013 10:05:38 -0700 (PDT) X-Received: by 10.194.63.109 with SMTP id f13mr91787996wjs.11.1367168738306; Sun, 28 Apr 2013 10:05:38 -0700 (PDT) Received: from ip-10-141-164-156.ec2.internal (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTPS id wi4si6298329wjc.112.2013.04.28.10.05.37 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Sun, 28 Apr 2013 10:05:38 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linaro-mm-sig-bounces@lists.linaro.org designates 54.225.227.206 as permitted sender) client-ip=54.225.227.206; Received: from localhost ([127.0.0.1] helo=ip-10-141-164-156.ec2.internal) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1UWV1j-0007a5-EM; Sun, 28 Apr 2013 17:04:39 +0000 Received: from adelie.canonical.com ([91.189.90.139]) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1UWV1i-0007a0-5z for linaro-mm-sig@lists.linaro.org; Sun, 28 Apr 2013 17:04:38 +0000 Received: from lillypilly.canonical.com ([91.189.89.62]) by adelie.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1UWV1N-0006Wa-Ld; Sun, 28 Apr 2013 17:04:19 +0000 Received: by lillypilly.canonical.com (Postfix, from userid 3489) id 0D38826C28DF; Sun, 28 Apr 2013 17:04:15 +0000 (UTC) To: linux-kernel@vger.kernel.org From: Maarten Lankhorst Date: Sun, 28 Apr 2013 19:04:14 +0200 Message-ID: <20130428170414.17075.40337.stgit@patser> In-Reply-To: <20130428165914.17075.57751.stgit@patser> References: <20130428165914.17075.57751.stgit@patser> User-Agent: StGit/0.15 MIME-Version: 1.0 Cc: linux-arch@vger.kernel.org, peterz@infradead.org, x86@kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, robclark@gmail.com, rostedt@goodmis.org, daniel@ffwll.ch, tglx@linutronix.de, mingo@elte.hu, linux-media@vger.kernel.org Subject: [Linaro-mm-sig] [PATCH v3 3/3] mutex: Add ww tests to lib/locking-selftest.c. v3 X-BeenThere: linaro-mm-sig@lists.linaro.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , Errors-To: linaro-mm-sig-bounces@lists.linaro.org Sender: linaro-mm-sig-bounces@lists.linaro.org X-Gm-Message-State: ALoCoQkj5XUze6qOXnB/DRBafL8LFgoAW5YCoDLcXDxy0fCj+0uMRjeJ+Qwnt2Kk+cZJxUPtoq06 X-Original-Sender: maarten.lankhorst@canonical.com X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.220.178 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 This stresses the lockdep code in some ways specifically useful to ww_mutexes. It adds checks for most of the common locking errors. Changes since v1: - Add tests to verify reservation_id is untouched. - Use L() and U() macros where possible. Changes since v2: - Use the ww_mutex api directly. - Use macros for most of the code. Signed-off-by: Maarten Lankhorst --- lib/locking-selftest.c | 439 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 420 insertions(+), 19 deletions(-) diff --git a/lib/locking-selftest.c b/lib/locking-selftest.c index c3eb261..9cef196 100644 --- a/lib/locking-selftest.c +++ b/lib/locking-selftest.c @@ -26,6 +26,8 @@ */ static unsigned int debug_locks_verbose; +static DEFINE_WW_CLASS(ww_lockdep); + static int __init setup_debug_locks_verbose(char *str) { get_option(&str, &debug_locks_verbose); @@ -42,6 +44,10 @@ __setup("debug_locks_verbose=", setup_debug_locks_verbose); #define LOCKTYPE_RWLOCK 0x2 #define LOCKTYPE_MUTEX 0x4 #define LOCKTYPE_RWSEM 0x8 +#define LOCKTYPE_WW 0x10 + +static struct ww_acquire_ctx t, t2; +static struct ww_mutex o, o2; /* * Normal standalone locks, for the circular and irq-context @@ -193,6 +199,17 @@ static void init_shared_classes(void) #define RSU(x) up_read(&rwsem_##x) #define RWSI(x) init_rwsem(&rwsem_##x) +#define WWAI(x) ww_acquire_init(x, &ww_lockdep) +#define WWAD(x) ww_acquire_done(x) +#define WWAF(x) ww_acquire_fini(x) + +#define WWL(x, c) ww_mutex_lock(x, c) +#define WWU(x) ww_mutex_unlock(x) + +#define WWL1(x) ww_mutex_lock_single(x) +#define WWT1(x) ww_mutex_trylock_single(x) +#define WWU1(x) ww_mutex_unlock_single(x) + #define LOCK_UNLOCK_2(x,y) LOCK(x); LOCK(y); UNLOCK(y); UNLOCK(x) /* @@ -894,11 +911,13 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft) # define I_RWLOCK(x) lockdep_reset_lock(&rwlock_##x.dep_map) # define I_MUTEX(x) lockdep_reset_lock(&mutex_##x.dep_map) # define I_RWSEM(x) lockdep_reset_lock(&rwsem_##x.dep_map) +# define I_WW(x) lockdep_reset_lock(&x.dep_map) #else # define I_SPINLOCK(x) # define I_RWLOCK(x) # define I_MUTEX(x) # define I_RWSEM(x) +# define I_WW(x) #endif #define I1(x) \ @@ -920,11 +939,20 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft) static void reset_locks(void) { local_irq_disable(); + lockdep_free_key_range(&ww_lockdep.acquire_key, 1); + lockdep_free_key_range(&ww_lockdep.mutex_key, 1); + I1(A); I1(B); I1(C); I1(D); I1(X1); I1(X2); I1(Y1); I1(Y2); I1(Z1); I1(Z2); + I_WW(t); I_WW(t2); I_WW(o.base); I_WW(o2.base); lockdep_reset(); I2(A); I2(B); I2(C); I2(D); init_shared_classes(); + + ww_mutex_init(&o, &ww_lockdep); ww_mutex_init(&o2, &ww_lockdep); + memset(&t, 0, sizeof(t)); memset(&t2, 0, sizeof(t2)); + memset(&ww_lockdep.acquire_key, 0, sizeof(ww_lockdep.acquire_key)); + memset(&ww_lockdep.mutex_key, 0, sizeof(ww_lockdep.mutex_key)); local_irq_enable(); } @@ -938,7 +966,6 @@ static int unexpected_testcase_failures; static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask) { unsigned long saved_preempt_count = preempt_count(); - int expected_failure = 0; WARN_ON(irqs_disabled()); @@ -946,26 +973,16 @@ static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask) /* * Filter out expected failures: */ + if (debug_locks != expected) { #ifndef CONFIG_PROVE_LOCKING - if ((lockclass_mask & LOCKTYPE_SPIN) && debug_locks != expected) - expected_failure = 1; - if ((lockclass_mask & LOCKTYPE_RWLOCK) && debug_locks != expected) - expected_failure = 1; - if ((lockclass_mask & LOCKTYPE_MUTEX) && debug_locks != expected) - expected_failure = 1; - if ((lockclass_mask & LOCKTYPE_RWSEM) && debug_locks != expected) - expected_failure = 1; + expected_testcase_failures++; + printk("failed|"); +#else + unexpected_testcase_failures++; + printk("FAILED|"); + + dump_stack(); #endif - if (debug_locks != expected) { - if (expected_failure) { - expected_testcase_failures++; - printk("failed|"); - } else { - unexpected_testcase_failures++; - - printk("FAILED|"); - dump_stack(); - } } else { testcase_successes++; printk(" ok |"); @@ -1108,6 +1125,388 @@ static inline void print_testname(const char *testname) DO_TESTCASE_6IRW(desc, name, 312); \ DO_TESTCASE_6IRW(desc, name, 321); +static void ww_test_fail_acquire(void) +{ + int ret; + + WWAI(&t); + t.stamp++; + + ret = WWL(&o, &t); + + if (WARN_ON(!o.ctx) || + WARN_ON(ret)) + return; + + /* No lockdep test, pure API */ + ret = WWL(&o, &t); + WARN_ON(ret != -EALREADY); + + ret = WWT1(&o); + WARN_ON(ret); + + t2 = t; + t2.stamp++; + ret = WWL(&o, &t2); + WARN_ON(ret != -EDEADLK); + WWU(&o); + + if (WWT1(&o)) + WWU1(&o); +#ifdef CONFIG_DEBUG_LOCK_ALLOC + else + DEBUG_LOCKS_WARN_ON(1); +#endif +} + +static void ww_test_normal(void) +{ + int ret; + + WWAI(&t); + + /* + * test if ww_id is kept identical if not + * called with any of the ww_* locking calls + */ + + /* mutex_lock (and indirectly, mutex_lock_nested) */ + o.ctx = (void *)~0UL; + WWL1(&o); + WWU1(&o); + WARN_ON(o.ctx != (void *)~0UL); + + /* mutex_lock_interruptible (and *_nested) */ + o.ctx = (void *)~0UL; + ret = mutex_lock_interruptible(&o.base); + if (!ret) + WWU1(&o); + else + WARN_ON(1); + WARN_ON(o.ctx != (void *)~0UL); + + /* mutex_lock_killable (and *_nested) */ + o.ctx = (void *)~0UL; + ret = mutex_lock_killable(&o.base); + if (!ret) + WWU1(&o); + else + WARN_ON(1); + WARN_ON(o.ctx != (void *)~0UL); + + /* trylock, succeeding */ + o.ctx = (void *)~0UL; + ret = WWT1(&o); + WARN_ON(!ret); + if (ret) + WWU1(&o); + else + WARN_ON(1); + WARN_ON(o.ctx != (void *)~0UL); + + /* trylock, failing */ + o.ctx = (void *)~0UL; + WWL1(&o); + ret = WWT1(&o); + WARN_ON(ret); + WWU1(&o); + WARN_ON(o.ctx != (void *)~0UL); + + /* nest_lock */ + o.ctx = (void *)~0UL; + mutex_lock_nest_lock(&o.base, &t); + WWU1(&o); + WARN_ON(o.ctx != (void *)~0UL); +} + +static void ww_test_two_contexts(void) +{ + WWAI(&t); + WWAI(&t2); +} + +static void ww_test_context_unlock_twice(void) +{ + WWAI(&t); + WWAD(&t); + WWAF(&t); + WWAF(&t); +} + +static void ww_test_object_unlock_twice(void) +{ + WWL1(&o); + WWU1(&o); + WWU1(&o); +} + +static void ww_test_spin_nest_unlocked(void) +{ + raw_spin_lock_nest_lock(&lock_A, &o.base); + U(A); +} + +static void ww_test_mismatch_normal_ww(void) +{ + WWL1(&o); + WWU(&o); +} + +static void ww_test_mismatch_ww_normal(void) +{ + int ret; + + WWAI(&t); + + ret = WWL(&o, &t); + WARN_ON(ret); + WWU1(&o); + + /* + * the second ww_mutex_lock will detect the + * mismatch of the first one + */ + ret = WWL(&o, &t); + WARN_ON(ret); +} + +static void ww_test_mismatch_ww_normal_slow(void) +{ + int ret; + + WWAI(&t); + + ret = WWL(&o, &t); + WARN_ON(ret); + WWU1(&o); + + ww_mutex_lock_slow(&o, &t); +} + +static void ww_test_context_block(void) +{ + int ret; + + WWAI(&t); + + ret = WWL(&o, &t); + WARN_ON(ret); + WWL1(&o2); +} + +static void ww_test_context_try(void) +{ + int ret; + + WWAI(&t); + + ret = WWL(&o, &t); + WARN_ON(ret); + + ret = WWT1(&o2); + WARN_ON(!ret); + WWU1(&o2); + WWU(&o); +} + +static void ww_test_context_context(void) +{ + int ret; + + WWAI(&t); + + ret = WWL(&o, &t); + WARN_ON(ret); + + ret = WWL(&o2, &t); + WARN_ON(ret); + + WWU(&o2); + WWU(&o); +} + +static void ww_test_try_block(void) +{ + bool ret; + + ret = WWT1(&o); + WARN_ON(!ret); + + WWL1(&o2); + WWU1(&o2); + WWU1(&o); +} + +static void ww_test_try_try(void) +{ + bool ret; + + ret = WWT1(&o); + WARN_ON(!ret); + ret = WWT1(&o2); + WARN_ON(!ret); + WWU1(&o2); + WWU1(&o); +} + +static void ww_test_try_context(void) +{ + int ret; + + ret = WWT1(&o); + WARN_ON(!ret); + + WWAI(&t); + + ret = WWL(&o2, &t); + WARN_ON(ret); +} + +static void ww_test_block_block(void) +{ + WWL1(&o); + WWL1(&o2); +} + +static void ww_test_block_try(void) +{ + bool ret; + + WWL1(&o); + ret = WWT1(&o2); + WARN_ON(!ret); +} + +static void ww_test_block_context(void) +{ + int ret; + + WWL1(&o); + WWAI(&t); + + ret = WWL(&o2, &t); + WARN_ON(ret); +} + +static void ww_test_spin_block(void) +{ + L(A); + U(A); + + WWL1(&o); + L(A); + U(A); + WWU1(&o); + + L(A); + WWL1(&o); + WWU1(&o); + U(A); +} + +static void ww_test_spin_try(void) +{ + bool ret; + + L(A); + U(A); + + ret = WWT1(&o); + WARN_ON(!ret); + L(A); + U(A); + WWU1(&o); + + L(A); + ret = WWT1(&o); + WARN_ON(!ret); + WWU1(&o); + U(A); +} + +static void ww_test_spin_context(void) +{ + int ret; + + L(A); + U(A); + + WWAI(&t); + + ret = WWL(&o, &t); + WARN_ON(ret); + L(A); + U(A); + WWU(&o); + + L(A); + ret = WWL(&o, &t); + WARN_ON(ret); + WWU(&o); + U(A); +} + +static void ww_tests(void) +{ + printk(" --------------------------------------------------------------------------\n"); + printk(" | Wound/wait tests |\n"); + printk(" ---------------------\n"); + + print_testname("ww api failures"); + dotest(ww_test_fail_acquire, SUCCESS, LOCKTYPE_WW); + dotest(ww_test_normal, SUCCESS, LOCKTYPE_WW); + printk("\n"); + + print_testname("using two ww contexts"); + dotest(ww_test_two_contexts, FAILURE, LOCKTYPE_WW); + printk("\n"); + + print_testname("finish ww context twice"); + dotest(ww_test_context_unlock_twice, FAILURE, LOCKTYPE_WW); + printk("\n"); + + print_testname("unlock twice"); + dotest(ww_test_object_unlock_twice, FAILURE, LOCKTYPE_WW); + printk("\n"); + + print_testname("spinlock nest unlocked"); + dotest(ww_test_spin_nest_unlocked, FAILURE, LOCKTYPE_WW); + printk("\n"); + + print_testname("ww mutex (un)lock mismatch"); + dotest(ww_test_mismatch_normal_ww, FAILURE, LOCKTYPE_WW); + dotest(ww_test_mismatch_ww_normal, FAILURE, LOCKTYPE_WW); + dotest(ww_test_mismatch_ww_normal_slow, FAILURE, LOCKTYPE_WW); + printk("\n"); + + printk(" -----------------------------------------------------\n"); + printk(" |block | try |context|\n"); + printk(" -----------------------------------------------------\n"); + + print_testname("context"); + dotest(ww_test_context_block, FAILURE, LOCKTYPE_WW); + dotest(ww_test_context_try, SUCCESS, LOCKTYPE_WW); + dotest(ww_test_context_context, SUCCESS, LOCKTYPE_WW); + printk("\n"); + + print_testname("try"); + dotest(ww_test_try_block, FAILURE, LOCKTYPE_WW); + dotest(ww_test_try_try, SUCCESS, LOCKTYPE_WW); + dotest(ww_test_try_context, FAILURE, LOCKTYPE_WW); + printk("\n"); + + print_testname("block"); + dotest(ww_test_block_block, FAILURE, LOCKTYPE_WW); + dotest(ww_test_block_try, SUCCESS, LOCKTYPE_WW); + dotest(ww_test_block_context, FAILURE, LOCKTYPE_WW); + printk("\n"); + + print_testname("spinlock"); + dotest(ww_test_spin_block, FAILURE, LOCKTYPE_WW); + dotest(ww_test_spin_try, SUCCESS, LOCKTYPE_WW); + dotest(ww_test_spin_context, FAILURE, LOCKTYPE_WW); + printk("\n"); +} void locking_selftest(void) { @@ -1188,6 +1587,8 @@ void locking_selftest(void) DO_TESTCASE_6x2("irq read-recursion", irq_read_recursion); // DO_TESTCASE_6x2B("irq read-recursion #2", irq_read_recursion2); + ww_tests(); + if (unexpected_testcase_failures) { printk("-----------------------------------------------------------------\n"); debug_locks = 0;