From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754018AbcBPF7A (ORCPT ); Tue, 16 Feb 2016 00:59:00 -0500 Received: from mail-pa0-f51.google.com ([209.85.220.51]:34828 "EHLO mail-pa0-f51.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753544AbcBPF64 (ORCPT ); Tue, 16 Feb 2016 00:58:56 -0500 From: Boqun Feng To: linux-kernel@vger.kernel.org Cc: Peter Zijlstra , Ingo Molnar , "Paul E. McKenney" , Josh Triplett , Steven Rostedt , Mathieu Desnoyers , Lai Jiangshan , sasha.levin@oracle.com, Boqun Feng Subject: [RFC v2 4/6] lockdep: LOCKED_ACCESS: Introduce locked_access_point() Date: Tue, 16 Feb 2016 13:57:43 +0800 Message-Id: <1455602265-16490-5-git-send-email-boqun.feng@gmail.com> X-Mailer: git-send-email 2.7.1 In-Reply-To: <1455602265-16490-1-git-send-email-boqun.feng@gmail.com> References: <1455602265-16490-1-git-send-email-boqun.feng@gmail.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org locked_access_point() is the entry point of the whole LOCKED_ACCESS framework, every time a locked_access_point() is called, LOCKE_ACCESS will correlate the data access location with the current acqchain. So putting locked_access_point() at the data accesses you care about is the step #2 to use LOCKED_ACCESS. Signed-off-by: Boqun Feng --- include/linux/lockdep.h | 29 ++++++++++++ kernel/locking/lockdep.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 2ffe6c3..cf7b6c8 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -570,4 +570,33 @@ lockdep_rcu_suspicious(const char *file, const int line, const char *s) } #endif +#ifdef CONFIG_LOCKED_ACCESS +struct locked_access_location { + /* Filename of the access */ + const char *filename; + /* Line number of the access */ + long lineno; +}; + +#define LOCKED_ACCESS_TYPE_READ 1 /* read */ + +extern void locked_access(struct locked_access_class *laclass, + struct locked_access_location *access, + int type); + +/* + * Entry point of LOCKED_ACCESS, should be called at every place the data + * accesses of the laclass happen. + * + * @_type must be one of the LOCKED_ACCESS_TYPE_* + */ +#define locked_access_point(_laclass, _type) \ +({ \ + static struct locked_access_location a = { \ + .filename = __FILE__, \ + .lineno = __LINE__, \ + }; \ + locked_access(_laclass, &a, _type); \ +}) +#endif /* CONFIG_LOCKED_ACCESS */ #endif /* __LINUX_LOCKDEP_H */ diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 3ebd00d..4094757 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -4496,4 +4496,125 @@ lookup_or_add_acqchain(struct locked_access_class *laclass, return acqchain; } +/* + * Lookup the data access at @loc in the ->accesses list of @acqchain. + * + * Must be called after @laclass is initialized. + */ +static int lookup_locked_access(struct acqchain *acqchain, + struct locked_access_location *loc) +{ + struct locked_access_struct *s; + + list_for_each_entry_lockless(s, &acqchain->accesses, list) { + if (s->loc == loc) + return 1; + } + return 0; + +} + +/* + * Add the data access at @loc into the ->accesses list of @acqchain. + * + * Return 1 if one access is added, otherwise return 0. + * + * Must be called after @laclass is initialized. + */ +static int add_locked_access(struct locked_access_class *laclass, + struct acqchain *acqchain, + struct locked_access_location *loc, + int type) +{ + unsigned long flags; + struct locked_access_struct *s; + + local_irq_save(flags); + arch_spin_lock(&laclass->lock); + + /* Lookup again while holding the lock */ + if (lookup_locked_access(acqchain, loc)) { + arch_spin_unlock(&laclass->lock); + local_irq_restore(flags); + return 1; + } + + if (unlikely(laclass->nr_access_structs >= MAX_LOCKED_ACCESS_STRUCTS)) { + arch_spin_unlock(&laclass->lock); + local_irq_restore(flags); + return 0; + } + + s = laclass->access_structs + laclass->nr_access_structs; + s->loc = loc; + s->type = type; + laclass->nr_access_structs++; + + /* + * Pair with the list_for_each_entry_lockless() in + * lookup_locked_access() + */ + list_add_tail_rcu(&s->list, &acqchain->accesses); + + arch_spin_unlock(&laclass->lock); + local_irq_restore(flags); + return 1; +} + +/* + * Correlate the data access at @loc with @acqchain for @laclass + * + * Must be called after @laclass is initialized. + */ +static int correlate_locked_access(struct locked_access_class *laclass, + struct acqchain *acqchain, + struct locked_access_location *loc, + int type) +{ + if (lookup_locked_access(acqchain, loc)) + return 1; + + return add_locked_access(laclass, acqchain, loc, type); +} + +/* + * The implementation of entry point locked_access_point(), called when a data + * access belonging to @laclass happens. + */ +void locked_access(struct locked_access_class *laclass, + struct locked_access_location *loc, + int type) +{ + u64 acqchain_key = current->curr_acqchain_key; + struct acqchain *acqchain; + + if (unlikely(!laclass)) + return; + + /* + * Don't track for data access for lockdep itself, because we rely + * on the ->held_locks lockdep maintains, and if ->lockdep_recursion is + * not 0, the lock is not being maintained in ->held_locks. + */ + if (unlikely(current->lockdep_recursion)) + return; + + /* Data access outside a critical section */ + if (current->lockdep_depth <= 0) + return; + + /* + * we only check whether laclass is initialized in locked_access, + * because this is the entry point of LOCKED_ACCESS. + */ + if (unlikely(!smp_load_acquire(&laclass->initialized))) + locked_access_class_init(laclass); + + acqchain = lookup_or_add_acqchain(laclass, current, acqchain_key); + + if (acqchain) + correlate_locked_access(laclass, acqchain, loc, type); +} +EXPORT_SYMBOL(locked_access); + #endif /* CONFIG_LOCKED_ACCESS */ -- 2.7.1