Commit 1fb00c6c authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[PATCH] work around ppc64 bootup bug by making mutex-debugging save/restore irqs

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: default avatarIngo Molnar <mingo@elte.hu>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 20c5426f
...@@ -153,13 +153,13 @@ void show_held_locks(struct task_struct *filter) ...@@ -153,13 +153,13 @@ void show_held_locks(struct task_struct *filter)
continue; continue;
count++; count++;
cursor = curr->next; cursor = curr->next;
debug_spin_lock_restore(&debug_mutex_lock, flags); debug_spin_unlock_restore(&debug_mutex_lock, flags);
printk("\n#%03d: ", count); printk("\n#%03d: ", count);
printk_lock(lock, filter ? 0 : 1); printk_lock(lock, filter ? 0 : 1);
goto next; goto next;
} }
debug_spin_lock_restore(&debug_mutex_lock, flags); debug_spin_unlock_restore(&debug_mutex_lock, flags);
printk("\n"); printk("\n");
} }
...@@ -316,7 +316,7 @@ void mutex_debug_check_no_locks_held(struct task_struct *task) ...@@ -316,7 +316,7 @@ void mutex_debug_check_no_locks_held(struct task_struct *task)
continue; continue;
list_del_init(curr); list_del_init(curr);
DEBUG_OFF(); DEBUG_OFF();
debug_spin_lock_restore(&debug_mutex_lock, flags); debug_spin_unlock_restore(&debug_mutex_lock, flags);
printk("BUG: %s/%d, lock held at task exit time!\n", printk("BUG: %s/%d, lock held at task exit time!\n",
task->comm, task->pid); task->comm, task->pid);
...@@ -325,7 +325,7 @@ void mutex_debug_check_no_locks_held(struct task_struct *task) ...@@ -325,7 +325,7 @@ void mutex_debug_check_no_locks_held(struct task_struct *task)
printk("exiting task is not even the owner??\n"); printk("exiting task is not even the owner??\n");
return; return;
} }
debug_spin_lock_restore(&debug_mutex_lock, flags); debug_spin_unlock_restore(&debug_mutex_lock, flags);
} }
/* /*
...@@ -352,7 +352,7 @@ void mutex_debug_check_no_locks_freed(const void *from, unsigned long len) ...@@ -352,7 +352,7 @@ void mutex_debug_check_no_locks_freed(const void *from, unsigned long len)
continue; continue;
list_del_init(curr); list_del_init(curr);
DEBUG_OFF(); DEBUG_OFF();
debug_spin_lock_restore(&debug_mutex_lock, flags); debug_spin_unlock_restore(&debug_mutex_lock, flags);
printk("BUG: %s/%d, active lock [%p(%p-%p)] freed!\n", printk("BUG: %s/%d, active lock [%p(%p-%p)] freed!\n",
current->comm, current->pid, lock, from, to); current->comm, current->pid, lock, from, to);
...@@ -362,7 +362,7 @@ void mutex_debug_check_no_locks_freed(const void *from, unsigned long len) ...@@ -362,7 +362,7 @@ void mutex_debug_check_no_locks_freed(const void *from, unsigned long len)
printk("freeing task is not even the owner??\n"); printk("freeing task is not even the owner??\n");
return; return;
} }
debug_spin_lock_restore(&debug_mutex_lock, flags); debug_spin_unlock_restore(&debug_mutex_lock, flags);
} }
/* /*
......
...@@ -46,21 +46,6 @@ extern void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter, ...@@ -46,21 +46,6 @@ extern void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter,
extern void debug_mutex_unlock(struct mutex *lock); extern void debug_mutex_unlock(struct mutex *lock);
extern void debug_mutex_init(struct mutex *lock, const char *name); extern void debug_mutex_init(struct mutex *lock, const char *name);
#define debug_spin_lock(lock) \
do { \
local_irq_disable(); \
if (debug_mutex_on) \
spin_lock(lock); \
} while (0)
#define debug_spin_unlock(lock) \
do { \
if (debug_mutex_on) \
spin_unlock(lock); \
local_irq_enable(); \
preempt_check_resched(); \
} while (0)
#define debug_spin_lock_save(lock, flags) \ #define debug_spin_lock_save(lock, flags) \
do { \ do { \
local_irq_save(flags); \ local_irq_save(flags); \
...@@ -68,7 +53,7 @@ extern void debug_mutex_init(struct mutex *lock, const char *name); ...@@ -68,7 +53,7 @@ extern void debug_mutex_init(struct mutex *lock, const char *name);
spin_lock(lock); \ spin_lock(lock); \
} while (0) } while (0)
#define debug_spin_lock_restore(lock, flags) \ #define debug_spin_unlock_restore(lock, flags) \
do { \ do { \
if (debug_mutex_on) \ if (debug_mutex_on) \
spin_unlock(lock); \ spin_unlock(lock); \
...@@ -76,20 +61,20 @@ extern void debug_mutex_init(struct mutex *lock, const char *name); ...@@ -76,20 +61,20 @@ extern void debug_mutex_init(struct mutex *lock, const char *name);
preempt_check_resched(); \ preempt_check_resched(); \
} while (0) } while (0)
#define spin_lock_mutex(lock) \ #define spin_lock_mutex(lock, flags) \
do { \ do { \
struct mutex *l = container_of(lock, struct mutex, wait_lock); \ struct mutex *l = container_of(lock, struct mutex, wait_lock); \
\ \
DEBUG_WARN_ON(in_interrupt()); \ DEBUG_WARN_ON(in_interrupt()); \
debug_spin_lock(&debug_mutex_lock); \ debug_spin_lock_save(&debug_mutex_lock, flags); \
spin_lock(lock); \ spin_lock(lock); \
DEBUG_WARN_ON(l->magic != l); \ DEBUG_WARN_ON(l->magic != l); \
} while (0) } while (0)
#define spin_unlock_mutex(lock) \ #define spin_unlock_mutex(lock, flags) \
do { \ do { \
spin_unlock(lock); \ spin_unlock(lock); \
debug_spin_unlock(&debug_mutex_lock); \ debug_spin_unlock_restore(&debug_mutex_lock, flags); \
} while (0) } while (0)
#define DEBUG_OFF() \ #define DEBUG_OFF() \
......
...@@ -125,10 +125,11 @@ __mutex_lock_common(struct mutex *lock, long state __IP_DECL__) ...@@ -125,10 +125,11 @@ __mutex_lock_common(struct mutex *lock, long state __IP_DECL__)
struct task_struct *task = current; struct task_struct *task = current;
struct mutex_waiter waiter; struct mutex_waiter waiter;
unsigned int old_val; unsigned int old_val;
unsigned long flags;
debug_mutex_init_waiter(&waiter); debug_mutex_init_waiter(&waiter);
spin_lock_mutex(&lock->wait_lock); spin_lock_mutex(&lock->wait_lock, flags);
debug_mutex_add_waiter(lock, &waiter, task->thread_info, ip); debug_mutex_add_waiter(lock, &waiter, task->thread_info, ip);
...@@ -157,7 +158,7 @@ __mutex_lock_common(struct mutex *lock, long state __IP_DECL__) ...@@ -157,7 +158,7 @@ __mutex_lock_common(struct mutex *lock, long state __IP_DECL__)
if (unlikely(state == TASK_INTERRUPTIBLE && if (unlikely(state == TASK_INTERRUPTIBLE &&
signal_pending(task))) { signal_pending(task))) {
mutex_remove_waiter(lock, &waiter, task->thread_info); mutex_remove_waiter(lock, &waiter, task->thread_info);
spin_unlock_mutex(&lock->wait_lock); spin_unlock_mutex(&lock->wait_lock, flags);
debug_mutex_free_waiter(&waiter); debug_mutex_free_waiter(&waiter);
return -EINTR; return -EINTR;
...@@ -165,9 +166,9 @@ __mutex_lock_common(struct mutex *lock, long state __IP_DECL__) ...@@ -165,9 +166,9 @@ __mutex_lock_common(struct mutex *lock, long state __IP_DECL__)
__set_task_state(task, state); __set_task_state(task, state);
/* didnt get the lock, go to sleep: */ /* didnt get the lock, go to sleep: */
spin_unlock_mutex(&lock->wait_lock); spin_unlock_mutex(&lock->wait_lock, flags);
schedule(); schedule();
spin_lock_mutex(&lock->wait_lock); spin_lock_mutex(&lock->wait_lock, flags);
} }
/* got the lock - rejoice! */ /* got the lock - rejoice! */
...@@ -178,7 +179,7 @@ __mutex_lock_common(struct mutex *lock, long state __IP_DECL__) ...@@ -178,7 +179,7 @@ __mutex_lock_common(struct mutex *lock, long state __IP_DECL__)
if (likely(list_empty(&lock->wait_list))) if (likely(list_empty(&lock->wait_list)))
atomic_set(&lock->count, 0); atomic_set(&lock->count, 0);
spin_unlock_mutex(&lock->wait_lock); spin_unlock_mutex(&lock->wait_lock, flags);
debug_mutex_free_waiter(&waiter); debug_mutex_free_waiter(&waiter);
...@@ -203,10 +204,11 @@ static fastcall noinline void ...@@ -203,10 +204,11 @@ static fastcall noinline void
__mutex_unlock_slowpath(atomic_t *lock_count __IP_DECL__) __mutex_unlock_slowpath(atomic_t *lock_count __IP_DECL__)
{ {
struct mutex *lock = container_of(lock_count, struct mutex, count); struct mutex *lock = container_of(lock_count, struct mutex, count);
unsigned long flags;
DEBUG_WARN_ON(lock->owner != current_thread_info()); DEBUG_WARN_ON(lock->owner != current_thread_info());
spin_lock_mutex(&lock->wait_lock); spin_lock_mutex(&lock->wait_lock, flags);
/* /*
* some architectures leave the lock unlocked in the fastpath failure * some architectures leave the lock unlocked in the fastpath failure
...@@ -231,7 +233,7 @@ __mutex_unlock_slowpath(atomic_t *lock_count __IP_DECL__) ...@@ -231,7 +233,7 @@ __mutex_unlock_slowpath(atomic_t *lock_count __IP_DECL__)
debug_mutex_clear_owner(lock); debug_mutex_clear_owner(lock);
spin_unlock_mutex(&lock->wait_lock); spin_unlock_mutex(&lock->wait_lock, flags);
} }
/* /*
...@@ -276,9 +278,10 @@ __mutex_lock_interruptible_slowpath(atomic_t *lock_count __IP_DECL__) ...@@ -276,9 +278,10 @@ __mutex_lock_interruptible_slowpath(atomic_t *lock_count __IP_DECL__)
static inline int __mutex_trylock_slowpath(atomic_t *lock_count) static inline int __mutex_trylock_slowpath(atomic_t *lock_count)
{ {
struct mutex *lock = container_of(lock_count, struct mutex, count); struct mutex *lock = container_of(lock_count, struct mutex, count);
unsigned long flags;
int prev; int prev;
spin_lock_mutex(&lock->wait_lock); spin_lock_mutex(&lock->wait_lock, flags);
prev = atomic_xchg(&lock->count, -1); prev = atomic_xchg(&lock->count, -1);
if (likely(prev == 1)) if (likely(prev == 1))
...@@ -287,7 +290,7 @@ static inline int __mutex_trylock_slowpath(atomic_t *lock_count) ...@@ -287,7 +290,7 @@ static inline int __mutex_trylock_slowpath(atomic_t *lock_count)
if (likely(list_empty(&lock->wait_list))) if (likely(list_empty(&lock->wait_list)))
atomic_set(&lock->count, 0); atomic_set(&lock->count, 0);
spin_unlock_mutex(&lock->wait_lock); spin_unlock_mutex(&lock->wait_lock, flags);
return prev == 1; return prev == 1;
} }
......
...@@ -9,8 +9,10 @@ ...@@ -9,8 +9,10 @@
* !CONFIG_DEBUG_MUTEXES case. Most of them are NOPs: * !CONFIG_DEBUG_MUTEXES case. Most of them are NOPs:
*/ */
#define spin_lock_mutex(lock) spin_lock(lock) #define spin_lock_mutex(lock, flags) \
#define spin_unlock_mutex(lock) spin_unlock(lock) do { spin_lock(lock); (void)(flags); } while (0)
#define spin_unlock_mutex(lock, flags) \
do { spin_unlock(lock); (void)(flags); } while (0)
#define mutex_remove_waiter(lock, waiter, ti) \ #define mutex_remove_waiter(lock, waiter, ti) \
__list_del((waiter)->list.prev, (waiter)->list.next) __list_del((waiter)->list.prev, (waiter)->list.next)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment