lkml.org 
[lkml]   [2016]   [Feb]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC 4/6] lockdep: LOCKED_ACCESS: Introduce locked_access_point()
    Date
    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
    \
     
     \ /
      Last update: 2016-02-03 18:21    [W:2.342 / U:0.700 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site