diff options
| -rw-r--r-- | include/asm-i386/rwsem.h | 35 | ||||
| -rw-r--r-- | include/asm-s390/rwsem.h | 31 | ||||
| -rw-r--r-- | include/asm-s390/semaphore.h | 3 | ||||
| -rw-r--r-- | include/linux/rwsem-spinlock.h | 23 | ||||
| -rw-r--r-- | include/linux/rwsem.h | 59 | ||||
| -rw-r--r-- | kernel/Makefile | 2 | ||||
| -rw-r--r-- | kernel/rwsem.c | 42 | ||||
| -rw-r--r-- | lib/rwsem-spinlock.c | 20 | ||||
| -rw-r--r-- | lib/rwsem.c | 20 | 
9 files changed, 184 insertions, 51 deletions
diff --git a/include/asm-i386/rwsem.h b/include/asm-i386/rwsem.h index 558804e4a03..2f07601562e 100644 --- a/include/asm-i386/rwsem.h +++ b/include/asm-i386/rwsem.h @@ -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   */ diff --git a/include/asm-s390/rwsem.h b/include/asm-s390/rwsem.h index 0422a085dd5..13ec1696515 100644 --- a/include/asm-s390/rwsem.h +++ b/include/asm-s390/rwsem.h @@ -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   */ diff --git a/include/asm-s390/semaphore.h b/include/asm-s390/semaphore.h index 702cf436698..32cdc69f39f 100644 --- a/include/asm-s390/semaphore.h +++ b/include/asm-s390/semaphore.h @@ -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) diff --git a/include/linux/rwsem-spinlock.h b/include/linux/rwsem-spinlock.h index d68afcc36ac..ae1fcadd598 100644 --- a/include/linux/rwsem-spinlock.h +++ b/include/linux/rwsem-spinlock.h @@ -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)); diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h index 93581534b91..658afb37c3f 100644 --- a/include/linux/rwsem.h +++ b/include/linux/rwsem.h @@ -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 */ diff --git a/kernel/Makefile b/kernel/Makefile index 3dd994eedc5..df6ef326369 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -8,7 +8,7 @@ obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \  	    signal.o sys.o kmod.o workqueue.o pid.o \  	    rcupdate.o extable.o params.o posix-timers.o \  	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ -	    hrtimer.o +	    hrtimer.o rwsem.o  obj-$(CONFIG_STACKTRACE) += stacktrace.o  obj-y += time/ diff --git a/kernel/rwsem.c b/kernel/rwsem.c index 790a99bb25a..291ded556aa 100644 --- a/kernel/rwsem.c +++ b/kernel/rwsem.c @@ -103,3 +103,45 @@ void downgrade_write(struct rw_semaphore *sem)  }  EXPORT_SYMBOL(downgrade_write); + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + +void down_read_nested(struct rw_semaphore *sem, int subclass) +{ +	might_sleep(); +	rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_); + +	__down_read(sem); +} + +EXPORT_SYMBOL(down_read_nested); + +void down_read_non_owner(struct rw_semaphore *sem) +{ +	might_sleep(); + +	__down_read(sem); +} + +EXPORT_SYMBOL(down_read_non_owner); + +void down_write_nested(struct rw_semaphore *sem, int subclass) +{ +	might_sleep(); +	rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_); + +	__down_write_nested(sem, subclass); +} + +EXPORT_SYMBOL(down_write_nested); + +void up_read_non_owner(struct rw_semaphore *sem) +{ +	__up_read(sem); +} + +EXPORT_SYMBOL(up_read_non_owner); + +#endif + + diff --git a/lib/rwsem-spinlock.c b/lib/rwsem-spinlock.c index 03b6097eb04..db4fed74b94 100644 --- a/lib/rwsem-spinlock.c +++ b/lib/rwsem-spinlock.c @@ -20,8 +20,16 @@ struct rwsem_waiter {  /*   * initialise the semaphore   */ -void fastcall init_rwsem(struct rw_semaphore *sem) +void __init_rwsem(struct rw_semaphore *sem, const char *name, +		  struct lock_class_key *key)  { +#ifdef CONFIG_DEBUG_LOCK_ALLOC +	/* +	 * Make sure we are not reinitializing a held semaphore: +	 */ +	debug_check_no_locks_freed((void *)sem, sizeof(*sem)); +	lockdep_init_map(&sem->dep_map, name, key); +#endif  	sem->activity = 0;  	spin_lock_init(&sem->wait_lock);  	INIT_LIST_HEAD(&sem->wait_list); @@ -183,7 +191,7 @@ int fastcall __down_read_trylock(struct rw_semaphore *sem)   * get a write lock on the semaphore   * - we increment the waiting count anyway to indicate an exclusive lock   */ -void fastcall __sched __down_write(struct rw_semaphore *sem) +void fastcall __sched __down_write_nested(struct rw_semaphore *sem, int subclass)  {  	struct rwsem_waiter waiter;  	struct task_struct *tsk; @@ -223,6 +231,11 @@ void fastcall __sched __down_write(struct rw_semaphore *sem)  	;  } +void fastcall __sched __down_write(struct rw_semaphore *sem) +{ +	__down_write_nested(sem, 0); +} +  /*   * trylock for writing -- returns 1 if successful, 0 if contention   */ @@ -292,9 +305,10 @@ void fastcall __downgrade_write(struct rw_semaphore *sem)  	spin_unlock_irqrestore(&sem->wait_lock, flags);  } -EXPORT_SYMBOL(init_rwsem); +EXPORT_SYMBOL(__init_rwsem);  EXPORT_SYMBOL(__down_read);  EXPORT_SYMBOL(__down_read_trylock); +EXPORT_SYMBOL(__down_write_nested);  EXPORT_SYMBOL(__down_write);  EXPORT_SYMBOL(__down_write_trylock);  EXPORT_SYMBOL(__up_read); diff --git a/lib/rwsem.c b/lib/rwsem.c index bae59728488..b322421c296 100644 --- a/lib/rwsem.c +++ b/lib/rwsem.c @@ -8,6 +8,26 @@  #include <linux/init.h>  #include <linux/module.h> +/* + * Initialize an rwsem: + */ +void __init_rwsem(struct rw_semaphore *sem, const char *name, +		  struct lock_class_key *key) +{ +#ifdef CONFIG_DEBUG_LOCK_ALLOC +	/* +	 * Make sure we are not reinitializing a held semaphore: +	 */ +	debug_check_no_locks_freed((void *)sem, sizeof(*sem)); +	lockdep_init_map(&sem->dep_map, name, key); +#endif +	sem->count = RWSEM_UNLOCKED_VALUE; +	spin_lock_init(&sem->wait_lock); +	INIT_LIST_HEAD(&sem->wait_list); +} + +EXPORT_SYMBOL(__init_rwsem); +  struct rwsem_waiter {  	struct list_head list;  	struct task_struct *task;  |