mirror of
https://github.com/torvalds/linux.git
synced 2024-11-17 09:31:50 +00:00
1fb00c6cbd
It seems ppc64 wants to lock mutexes in early bootup code, with interrupts disabled, and they expect interrupts to stay disabled, else they crash. Work around this bug by making mutex debugging variants save/restore irq flags. Signed-off-by: Ingo Molnar <mingo@elte.hu> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
120 lines
3.1 KiB
C
120 lines
3.1 KiB
C
/*
|
|
* Mutexes: blocking mutual exclusion locks
|
|
*
|
|
* started by Ingo Molnar:
|
|
*
|
|
* Copyright (C) 2004, 2005, 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
|
|
*
|
|
* This file contains mutex debugging related internal declarations,
|
|
* prototypes and inline functions, for the CONFIG_DEBUG_MUTEXES case.
|
|
* More details are in kernel/mutex-debug.c.
|
|
*/
|
|
|
|
extern spinlock_t debug_mutex_lock;
|
|
extern struct list_head debug_mutex_held_locks;
|
|
extern int debug_mutex_on;
|
|
|
|
/*
|
|
* In the debug case we carry the caller's instruction pointer into
|
|
* other functions, but we dont want the function argument overhead
|
|
* in the nondebug case - hence these macros:
|
|
*/
|
|
#define __IP_DECL__ , unsigned long ip
|
|
#define __IP__ , ip
|
|
#define __RET_IP__ , (unsigned long)__builtin_return_address(0)
|
|
|
|
/*
|
|
* This must be called with lock->wait_lock held.
|
|
*/
|
|
extern void debug_mutex_set_owner(struct mutex *lock,
|
|
struct thread_info *new_owner __IP_DECL__);
|
|
|
|
static inline void debug_mutex_clear_owner(struct mutex *lock)
|
|
{
|
|
lock->owner = NULL;
|
|
}
|
|
|
|
extern void debug_mutex_init_waiter(struct mutex_waiter *waiter);
|
|
extern void debug_mutex_wake_waiter(struct mutex *lock,
|
|
struct mutex_waiter *waiter);
|
|
extern void debug_mutex_free_waiter(struct mutex_waiter *waiter);
|
|
extern void debug_mutex_add_waiter(struct mutex *lock,
|
|
struct mutex_waiter *waiter,
|
|
struct thread_info *ti __IP_DECL__);
|
|
extern void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter,
|
|
struct thread_info *ti);
|
|
extern void debug_mutex_unlock(struct mutex *lock);
|
|
extern void debug_mutex_init(struct mutex *lock, const char *name);
|
|
|
|
#define debug_spin_lock_save(lock, flags) \
|
|
do { \
|
|
local_irq_save(flags); \
|
|
if (debug_mutex_on) \
|
|
spin_lock(lock); \
|
|
} while (0)
|
|
|
|
#define debug_spin_unlock_restore(lock, flags) \
|
|
do { \
|
|
if (debug_mutex_on) \
|
|
spin_unlock(lock); \
|
|
local_irq_restore(flags); \
|
|
preempt_check_resched(); \
|
|
} while (0)
|
|
|
|
#define spin_lock_mutex(lock, flags) \
|
|
do { \
|
|
struct mutex *l = container_of(lock, struct mutex, wait_lock); \
|
|
\
|
|
DEBUG_WARN_ON(in_interrupt()); \
|
|
debug_spin_lock_save(&debug_mutex_lock, flags); \
|
|
spin_lock(lock); \
|
|
DEBUG_WARN_ON(l->magic != l); \
|
|
} while (0)
|
|
|
|
#define spin_unlock_mutex(lock, flags) \
|
|
do { \
|
|
spin_unlock(lock); \
|
|
debug_spin_unlock_restore(&debug_mutex_lock, flags); \
|
|
} while (0)
|
|
|
|
#define DEBUG_OFF() \
|
|
do { \
|
|
if (debug_mutex_on) { \
|
|
debug_mutex_on = 0; \
|
|
console_verbose(); \
|
|
if (spin_is_locked(&debug_mutex_lock)) \
|
|
spin_unlock(&debug_mutex_lock); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define DEBUG_BUG() \
|
|
do { \
|
|
if (debug_mutex_on) { \
|
|
DEBUG_OFF(); \
|
|
BUG(); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define DEBUG_WARN_ON(c) \
|
|
do { \
|
|
if (unlikely(c && debug_mutex_on)) { \
|
|
DEBUG_OFF(); \
|
|
WARN_ON(1); \
|
|
} \
|
|
} while (0)
|
|
|
|
# define DEBUG_BUG_ON(c) \
|
|
do { \
|
|
if (unlikely(c)) \
|
|
DEBUG_BUG(); \
|
|
} while (0)
|
|
|
|
#ifdef CONFIG_SMP
|
|
# define SMP_DEBUG_WARN_ON(c) DEBUG_WARN_ON(c)
|
|
# define SMP_DEBUG_BUG_ON(c) DEBUG_BUG_ON(c)
|
|
#else
|
|
# define SMP_DEBUG_WARN_ON(c) do { } while (0)
|
|
# define SMP_DEBUG_BUG_ON(c) do { } while (0)
|
|
#endif
|
|
|