@@ -20,6 +20,33 @@
extern int prove_locking;
extern int lock_stat;
+#ifdef CONFIG_DEPT
+static inline void dept_after_copy_map(struct dept_map *to,
+ struct dept_map *from)
+{
+ int i;
+
+ if (from->keys == &from->keys_local)
+ to->keys = &to->keys_local;
+
+ if (!to->keys)
+ return;
+
+ /*
+ * Since the class cache can be modified concurrently we could observe
+ * half pointers (64bit arch using 32bit copy insns). Therefore clear
+ * the caches and take the performance hit.
+ *
+ * XXX it doesn't work well with lockdep_set_class_and_subclass(), since
+ * that relies on cache abuse.
+ */
+ for (i = 0; i < DEPT_MAX_SUBCLASSES_CACHE; i++)
+ to->keys->classes[i] = NULL;
+}
+#else
+#define dept_after_copy_map(t, f) do { } while (0)
+#endif
+
#ifdef CONFIG_LOCKDEP
#include <linux/linkage.h>
@@ -43,6 +70,8 @@ static inline void lockdep_copy_map(struct lockdep_map *to,
*/
for (i = 0; i < NR_LOCKDEP_CACHING_CLASSES; i++)
to->class_cache[i] = NULL;
+
+ dept_after_copy_map(&to->dmap, &from->dmap);
}
/*
@@ -176,8 +205,19 @@ struct held_lock {
current->lockdep_recursion -= LOCKDEP_OFF; \
} while (0)
-extern void lockdep_register_key(struct lock_class_key *key);
-extern void lockdep_unregister_key(struct lock_class_key *key);
+extern void __lockdep_register_key(struct lock_class_key *key);
+extern void __lockdep_unregister_key(struct lock_class_key *key);
+
+#define lockdep_register_key(k) \
+do { \
+ __lockdep_register_key(k); \
+ dept_key_init(&(k)->dkey); \
+} while (0)
+#define lockdep_unregister_key(k) \
+do { \
+ __lockdep_unregister_key(k); \
+ dept_key_destroy(&(k)->dkey); \
+} while (0)
/*
* These methods are used by specific locking variants (spinlocks,
@@ -185,9 +225,18 @@ struct held_lock {
* to lockdep:
*/
-extern void lockdep_init_map_type(struct lockdep_map *lock, const char *name,
+extern void __lockdep_init_map_type(struct lockdep_map *lock, const char *name,
struct lock_class_key *key, int subclass, u8 inner, u8 outer, u8 lock_type);
+#define lockdep_init_map_type(l, n, k, s, i, o, t) \
+do { \
+ __lockdep_init_map_type(l, n, k, s, i, o, t); \
+ if ((k) == &__lockdep_no_validate__) \
+ dept_map_nocheck(&(l)->dmap); \
+ else \
+ dept_map_init(&(l)->dmap, &(k)->dkey, s, n); \
+} while (0)
+
static inline void
lockdep_init_map_waits(struct lockdep_map *lock, const char *name,
struct lock_class_key *key, int subclass, u8 inner, u8 outer)
@@ -431,13 +480,28 @@ enum xhlock_context_t {
XHLOCK_CTX_NR,
};
+#ifdef CONFIG_DEPT
+/*
+ * TODO: I found the case to use an address of other than a real key as
+ * _key, for instance, in workqueue. So for now, we cannot use the
+ * assignment like '.dmap.keys = &(_key)->dkey' unless it's fixed.
+ */
+#define STATIC_DEPT_MAP_INIT(_name, _key) .dmap = { \
+ .name = (_name), \
+ .keys = NULL, \
+ },
+#else
+#define STATIC_DEPT_MAP_INIT(_name, _key)
+#endif
+
#define lockdep_init_map_crosslock(m, n, k, s) do {} while (0)
/*
* To initialize a lockdep_map statically use this macro.
* Note that _name must not be NULL.
*/
#define STATIC_LOCKDEP_MAP_INIT(_name, _key) \
- { .name = (_name), .key = (void *)(_key), }
+ { .name = (_name), .key = (void *)(_key), \
+ STATIC_DEPT_MAP_INIT(_name, _key) }
static inline void lockdep_invariant_state(bool force) {}
static inline void lockdep_free_task(struct task_struct *task) {}
@@ -11,6 +11,7 @@
#define __LINUX_LOCKDEP_TYPES_H
#include <linux/types.h>
+#include <linux/dept.h>
#define MAX_LOCKDEP_SUBCLASSES 8UL
@@ -76,6 +77,7 @@ struct lock_class_key {
struct hlist_node hash_entry;
struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES];
};
+ struct dept_key dkey;
};
extern struct lock_class_key __lockdep_no_validate__;
@@ -185,6 +187,7 @@ struct lockdep_map {
int cpu;
unsigned long ip;
#endif
+ struct dept_map dmap;
};
struct pin_cookie { unsigned int val; };
@@ -1184,7 +1184,7 @@ static inline struct hlist_head *keyhashentry(const struct lock_class_key *key)
}
/* Register a dynamically allocated key. */
-void lockdep_register_key(struct lock_class_key *key)
+void __lockdep_register_key(struct lock_class_key *key)
{
struct hlist_head *hash_head;
struct lock_class_key *k;
@@ -1207,7 +1207,7 @@ void lockdep_register_key(struct lock_class_key *key)
restore_irqs:
raw_local_irq_restore(flags);
}
-EXPORT_SYMBOL_GPL(lockdep_register_key);
+EXPORT_SYMBOL_GPL(__lockdep_register_key);
/* Check whether a key has been registered as a dynamic key. */
static bool is_dynamic_key(const struct lock_class_key *key)
@@ -4771,7 +4771,7 @@ static inline int check_wait_context(struct task_struct *curr,
/*
* Initialize a lock instance's lock-class mapping info:
*/
-void lockdep_init_map_type(struct lockdep_map *lock, const char *name,
+void __lockdep_init_map_type(struct lockdep_map *lock, const char *name,
struct lock_class_key *key, int subclass,
u8 inner, u8 outer, u8 lock_type)
{
@@ -4831,7 +4831,7 @@ void lockdep_init_map_type(struct lockdep_map *lock, const char *name,
raw_local_irq_restore(flags);
}
}
-EXPORT_SYMBOL_GPL(lockdep_init_map_type);
+EXPORT_SYMBOL_GPL(__lockdep_init_map_type);
struct lock_class_key __lockdep_no_validate__;
EXPORT_SYMBOL_GPL(__lockdep_no_validate__);
@@ -6291,7 +6291,7 @@ void lockdep_reset_lock(struct lockdep_map *lock)
}
/* Unregister a dynamically allocated key. */
-void lockdep_unregister_key(struct lock_class_key *key)
+void __lockdep_unregister_key(struct lock_class_key *key)
{
struct hlist_head *hash_head = keyhashentry(key);
struct lock_class_key *k;
@@ -6326,7 +6326,7 @@ void lockdep_unregister_key(struct lock_class_key *key)
/* Wait until is_dynamic_key() has finished accessing k->hash_entry. */
synchronize_rcu();
}
-EXPORT_SYMBOL_GPL(lockdep_unregister_key);
+EXPORT_SYMBOL_GPL(__lockdep_unregister_key);
void __init lockdep_init(void)
{
Dept should work independently from Lockdep. However, there's no choise but to rely on Lockdep code and its instances for now. Signed-off-by: Byungchul Park <byungchul.park@lge.com> --- include/linux/lockdep.h | 72 ++++++++++++++++++++++++++++++++++++++++--- include/linux/lockdep_types.h | 3 ++ kernel/locking/lockdep.c | 12 ++++---- 3 files changed, 77 insertions(+), 10 deletions(-)