[PATCH] lockdep: prove rwsem locking correctness
Use the lock validator framework to prove rwsem locking correctness. Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
committed by
Linus Torvalds
parent
a8f24a3978
commit
4ea2176dfa
@@ -40,6 +40,7 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/lockdep.h>
|
||||
|
||||
struct rwsem_waiter;
|
||||
|
||||
@@ -61,21 +62,34 @@ struct rw_semaphore {
|
||||
#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
|
||||
spinlock_t wait_lock;
|
||||
struct list_head wait_list;
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
struct lockdep_map dep_map;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
|
||||
#else
|
||||
# define __RWSEM_DEP_MAP_INIT(lockname)
|
||||
#endif
|
||||
|
||||
|
||||
#define __RWSEM_INITIALIZER(name) \
|
||||
{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \
|
||||
}
|
||||
__RWSEM_DEP_MAP_INIT(name) }
|
||||
|
||||
#define DECLARE_RWSEM(name) \
|
||||
struct rw_semaphore name = __RWSEM_INITIALIZER(name)
|
||||
|
||||
static inline void init_rwsem(struct rw_semaphore *sem)
|
||||
{
|
||||
sem->count = RWSEM_UNLOCKED_VALUE;
|
||||
spin_lock_init(&sem->wait_lock);
|
||||
INIT_LIST_HEAD(&sem->wait_list);
|
||||
}
|
||||
extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
|
||||
struct lock_class_key *key);
|
||||
|
||||
#define init_rwsem(sem) \
|
||||
do { \
|
||||
static struct lock_class_key __key; \
|
||||
\
|
||||
__init_rwsem((sem), #sem, &__key); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* lock for reading
|
||||
@@ -128,7 +142,7 @@ LOCK_PREFIX " cmpxchgl %2,%0\n\t"
|
||||
/*
|
||||
* lock for writing
|
||||
*/
|
||||
static inline void __down_write(struct rw_semaphore *sem)
|
||||
static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
@@ -152,6 +166,11 @@ LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" /* subtract 0x0000ffff, returns the
|
||||
: "memory", "cc");
|
||||
}
|
||||
|
||||
static inline void __down_write(struct rw_semaphore *sem)
|
||||
{
|
||||
__down_write_nested(sem, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* trylock for writing -- returns 1 if successful, 0 if contention
|
||||
*/
|
||||
|
||||
@@ -61,6 +61,9 @@ struct rw_semaphore {
|
||||
signed long count;
|
||||
spinlock_t wait_lock;
|
||||
struct list_head wait_list;
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
struct lockdep_map dep_map;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef __s390x__
|
||||
@@ -80,8 +83,16 @@ struct rw_semaphore {
|
||||
/*
|
||||
* initialisation
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
|
||||
#else
|
||||
# define __RWSEM_DEP_MAP_INIT(lockname)
|
||||
#endif
|
||||
|
||||
#define __RWSEM_INITIALIZER(name) \
|
||||
{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) }
|
||||
{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \
|
||||
__RWSEM_DEP_MAP_INIT(name) }
|
||||
|
||||
#define DECLARE_RWSEM(name) \
|
||||
struct rw_semaphore name = __RWSEM_INITIALIZER(name)
|
||||
@@ -93,6 +104,17 @@ static inline void init_rwsem(struct rw_semaphore *sem)
|
||||
INIT_LIST_HEAD(&sem->wait_list);
|
||||
}
|
||||
|
||||
extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
|
||||
struct lock_class_key *key);
|
||||
|
||||
#define init_rwsem(sem) \
|
||||
do { \
|
||||
static struct lock_class_key __key; \
|
||||
\
|
||||
__init_rwsem((sem), #sem, &__key); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* lock for reading
|
||||
*/
|
||||
@@ -155,7 +177,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
|
||||
/*
|
||||
* lock for writing
|
||||
*/
|
||||
static inline void __down_write(struct rw_semaphore *sem)
|
||||
static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
|
||||
{
|
||||
signed long old, new, tmp;
|
||||
|
||||
@@ -181,6 +203,11 @@ static inline void __down_write(struct rw_semaphore *sem)
|
||||
rwsem_down_write_failed(sem);
|
||||
}
|
||||
|
||||
static inline void __down_write(struct rw_semaphore *sem)
|
||||
{
|
||||
__down_write_nested(sem, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* trylock for writing -- returns 1 if successful, 0 if contention
|
||||
*/
|
||||
|
||||
@@ -37,7 +37,8 @@ struct semaphore {
|
||||
|
||||
static inline void sema_init (struct semaphore *sem, int val)
|
||||
{
|
||||
*sem = (struct semaphore) __SEMAPHORE_INITIALIZER((*sem),val);
|
||||
atomic_set(&sem->count, val);
|
||||
init_waitqueue_head(&sem->wait);
|
||||
}
|
||||
|
||||
static inline void init_MUTEX (struct semaphore *sem)
|
||||
|
||||
@@ -32,18 +32,37 @@ struct rw_semaphore {
|
||||
__s32 activity;
|
||||
spinlock_t wait_lock;
|
||||
struct list_head wait_list;
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
struct lockdep_map dep_map;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
|
||||
#else
|
||||
# define __RWSEM_DEP_MAP_INIT(lockname)
|
||||
#endif
|
||||
|
||||
#define __RWSEM_INITIALIZER(name) \
|
||||
{ 0, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) }
|
||||
{ 0, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
|
||||
|
||||
#define DECLARE_RWSEM(name) \
|
||||
struct rw_semaphore name = __RWSEM_INITIALIZER(name)
|
||||
|
||||
extern void FASTCALL(init_rwsem(struct rw_semaphore *sem));
|
||||
extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
|
||||
struct lock_class_key *key);
|
||||
|
||||
#define init_rwsem(sem) \
|
||||
do { \
|
||||
static struct lock_class_key __key; \
|
||||
\
|
||||
__init_rwsem((sem), #sem, &__key); \
|
||||
} while (0)
|
||||
|
||||
extern void FASTCALL(__down_read(struct rw_semaphore *sem));
|
||||
extern int FASTCALL(__down_read_trylock(struct rw_semaphore *sem));
|
||||
extern void FASTCALL(__down_write(struct rw_semaphore *sem));
|
||||
extern void FASTCALL(__down_write_nested(struct rw_semaphore *sem, int subclass));
|
||||
extern int FASTCALL(__down_write_trylock(struct rw_semaphore *sem));
|
||||
extern void FASTCALL(__up_read(struct rw_semaphore *sem));
|
||||
extern void FASTCALL(__up_write(struct rw_semaphore *sem));
|
||||
|
||||
+25
-34
@@ -27,64 +27,55 @@ struct rw_semaphore;
|
||||
/*
|
||||
* lock for reading
|
||||
*/
|
||||
static inline void down_read(struct rw_semaphore *sem)
|
||||
{
|
||||
might_sleep();
|
||||
__down_read(sem);
|
||||
}
|
||||
extern void down_read(struct rw_semaphore *sem);
|
||||
|
||||
/*
|
||||
* trylock for reading -- returns 1 if successful, 0 if contention
|
||||
*/
|
||||
static inline int down_read_trylock(struct rw_semaphore *sem)
|
||||
{
|
||||
int ret;
|
||||
ret = __down_read_trylock(sem);
|
||||
return ret;
|
||||
}
|
||||
extern int down_read_trylock(struct rw_semaphore *sem);
|
||||
|
||||
/*
|
||||
* lock for writing
|
||||
*/
|
||||
static inline void down_write(struct rw_semaphore *sem)
|
||||
{
|
||||
might_sleep();
|
||||
__down_write(sem);
|
||||
}
|
||||
extern void down_write(struct rw_semaphore *sem);
|
||||
|
||||
/*
|
||||
* trylock for writing -- returns 1 if successful, 0 if contention
|
||||
*/
|
||||
static inline int down_write_trylock(struct rw_semaphore *sem)
|
||||
{
|
||||
int ret;
|
||||
ret = __down_write_trylock(sem);
|
||||
return ret;
|
||||
}
|
||||
extern int down_write_trylock(struct rw_semaphore *sem);
|
||||
|
||||
/*
|
||||
* release a read lock
|
||||
*/
|
||||
static inline void up_read(struct rw_semaphore *sem)
|
||||
{
|
||||
__up_read(sem);
|
||||
}
|
||||
extern void up_read(struct rw_semaphore *sem);
|
||||
|
||||
/*
|
||||
* release a write lock
|
||||
*/
|
||||
static inline void up_write(struct rw_semaphore *sem)
|
||||
{
|
||||
__up_write(sem);
|
||||
}
|
||||
extern void up_write(struct rw_semaphore *sem);
|
||||
|
||||
/*
|
||||
* downgrade write lock to read lock
|
||||
*/
|
||||
static inline void downgrade_write(struct rw_semaphore *sem)
|
||||
{
|
||||
__downgrade_write(sem);
|
||||
}
|
||||
extern void downgrade_write(struct rw_semaphore *sem);
|
||||
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
/*
|
||||
* nested locking:
|
||||
*/
|
||||
extern void down_read_nested(struct rw_semaphore *sem, int subclass);
|
||||
extern void down_write_nested(struct rw_semaphore *sem, int subclass);
|
||||
/*
|
||||
* Take/release a lock when not the owner will release it:
|
||||
*/
|
||||
extern void down_read_non_owner(struct rw_semaphore *sem);
|
||||
extern void up_read_non_owner(struct rw_semaphore *sem);
|
||||
#else
|
||||
# define down_read_nested(sem, subclass) down_read(sem)
|
||||
# define down_write_nested(sem, subclass) down_write(sem)
|
||||
# define down_read_non_owner(sem) down_read(sem)
|
||||
# define up_read_non_owner(sem) up_read(sem)
|
||||
#endif
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _LINUX_RWSEM_H */
|
||||
|
||||
Reference in New Issue
Block a user