Commit 00a5dfdb authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[PATCH] Fix semundo lock leakage

semundo->lock can leak if semundo->refcount goes from 2 to 1 while
another thread has it locked.  This causes major problems for PREEMPT
kernels.

The simplest fix for now is to undo the single-thread optimization.

This bug was found via relentless testing by Dominik Karall.
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ba025082
...@@ -895,7 +895,7 @@ static inline void lock_semundo(void) ...@@ -895,7 +895,7 @@ static inline void lock_semundo(void)
struct sem_undo_list *undo_list; struct sem_undo_list *undo_list;
undo_list = current->sysvsem.undo_list; undo_list = current->sysvsem.undo_list;
if ((undo_list != NULL) && (atomic_read(&undo_list->refcnt) != 1)) if (undo_list)
spin_lock(&undo_list->lock); spin_lock(&undo_list->lock);
} }
...@@ -915,7 +915,7 @@ static inline void unlock_semundo(void) ...@@ -915,7 +915,7 @@ static inline void unlock_semundo(void)
struct sem_undo_list *undo_list; struct sem_undo_list *undo_list;
undo_list = current->sysvsem.undo_list; undo_list = current->sysvsem.undo_list;
if ((undo_list != NULL) && (atomic_read(&undo_list->refcnt) != 1)) if (undo_list)
spin_unlock(&undo_list->lock); spin_unlock(&undo_list->lock);
} }
...@@ -943,9 +943,7 @@ static inline int get_undo_list(struct sem_undo_list **undo_listp) ...@@ -943,9 +943,7 @@ static inline int get_undo_list(struct sem_undo_list **undo_listp)
if (undo_list == NULL) if (undo_list == NULL)
return -ENOMEM; return -ENOMEM;
memset(undo_list, 0, size); memset(undo_list, 0, size);
/* don't initialize unodhd->lock here. It's done spin_lock_init(&undo_list->lock);
* in copy_semundo() instead.
*/
atomic_set(&undo_list->refcnt, 1); atomic_set(&undo_list->refcnt, 1);
current->sysvsem.undo_list = undo_list; current->sysvsem.undo_list = undo_list;
} }
...@@ -1231,8 +1229,6 @@ int copy_semundo(unsigned long clone_flags, struct task_struct *tsk) ...@@ -1231,8 +1229,6 @@ int copy_semundo(unsigned long clone_flags, struct task_struct *tsk)
error = get_undo_list(&undo_list); error = get_undo_list(&undo_list);
if (error) if (error)
return error; return error;
if (atomic_read(&undo_list->refcnt) == 1)
spin_lock_init(&undo_list->lock);
atomic_inc(&undo_list->refcnt); atomic_inc(&undo_list->refcnt);
tsk->sysvsem.undo_list = undo_list; tsk->sysvsem.undo_list = undo_list;
} else } else
......
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