Messages in this thread Patch in this message | | | From | Boqun Feng <> | Subject | [RFC 4/6] lockdep: LOCKED_ACCESS: Introduce locked_access_point() | Date | Thu, 4 Feb 2016 00:45:10 +0800 |
| |
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 <boqun.feng@gmail.com> --- 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 77732a9..996c2d5 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -4503,4 +4503,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.0
| |