Commit 1327ca85 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] sysv semundo fixes

From: Manfred Spraul <manfred@colorfullife.com>

The CLONE_SYSVSEM implementation is racy: it does an (atomic_read(->refcnt)
==1) instead of atomic_dec_and_test calls in the exit handling.  The patch
fixes that.

Additionally, the patch contains the following changes:

- lock_undo() locks the list of undo structures.  The lock is held
  throughout the semop() syscall, but that's unnecessary - we can drop it
  immediately after the lookup.

- undo structures are only allocated when necessary.  The need for undo
  structures is only noticed in the middle of the semop operation, while
  holding the semaphore array spinlock.  The result is a convoluted
  unlock&revalidate implementation.  I've reordered the code, and now the
  undo allocation can happen before acquiring the semaphore array spinlock.
   As a bonus, less code runs under the semaphore array spinlock.

- sysvsem.sleep_list looks like code to handle oopses: if an oops kills a
  thread that sleeps in sys_timedsemop(), then sem_exit tries to recover.
  I've removed that - too fragile.
parent 0d5ff9d0
...@@ -128,13 +128,11 @@ struct sem_undo { ...@@ -128,13 +128,11 @@ struct sem_undo {
struct sem_undo_list { struct sem_undo_list {
atomic_t refcnt; atomic_t refcnt;
spinlock_t lock; spinlock_t lock;
volatile unsigned long add_count;
struct sem_undo *proc_list; struct sem_undo *proc_list;
}; };
struct sysv_sem { struct sysv_sem {
struct sem_undo_list *undo_list; struct sem_undo_list *undo_list;
struct sem_queue *sleep_list;
}; };
asmlinkage long sys_semget (key_t key, int nsems, int semflg); asmlinkage long sys_semget (key_t key, int nsems, int semflg);
...@@ -143,6 +141,8 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg); ...@@ -143,6 +141,8 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg);
asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops, asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops,
unsigned nsops, const struct timespec __user *timeout); unsigned nsops, const struct timespec __user *timeout);
void exit_sem(struct task_struct *p);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _LINUX_SEM_H */ #endif /* _LINUX_SEM_H */
This diff is collapsed.
...@@ -541,17 +541,11 @@ int copy_semundo(unsigned long clone_flags, struct task_struct *tsk) ...@@ -541,17 +541,11 @@ int copy_semundo(unsigned long clone_flags, struct task_struct *tsk)
return 0; return 0;
} }
void exit_semundo(struct task_struct *tsk) void exit_sem(struct task_struct *tsk)
{ {
return; return;
} }
void sem_exit (void)
{
return;
}
asmlinkage long sys_semget (key_t key, int nsems, int semflg) asmlinkage long sys_semget (key_t key, int nsems, int semflg)
{ {
return -ENOSYS; return -ENOSYS;
......
...@@ -698,7 +698,7 @@ NORET_TYPE void do_exit(long code) ...@@ -698,7 +698,7 @@ NORET_TYPE void do_exit(long code)
acct_process(code); acct_process(code);
__exit_mm(tsk); __exit_mm(tsk);
sem_exit(); exit_sem(tsk);
__exit_files(tsk); __exit_files(tsk);
__exit_fs(tsk); __exit_fs(tsk);
exit_namespace(tsk); exit_namespace(tsk);
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
extern int copy_semundo(unsigned long clone_flags, struct task_struct *tsk); extern int copy_semundo(unsigned long clone_flags, struct task_struct *tsk);
extern void exit_semundo(struct task_struct *tsk); extern void exit_sem(struct task_struct *tsk);
/* The idle threads do not count.. /* The idle threads do not count..
* Protected by write_lock_irq(&tasklist_lock) * Protected by write_lock_irq(&tasklist_lock)
...@@ -1032,7 +1032,7 @@ struct task_struct *copy_process(unsigned long clone_flags, ...@@ -1032,7 +1032,7 @@ struct task_struct *copy_process(unsigned long clone_flags,
bad_fork_cleanup_files: bad_fork_cleanup_files:
exit_files(p); /* blocking */ exit_files(p); /* blocking */
bad_fork_cleanup_semundo: bad_fork_cleanup_semundo:
exit_semundo(p); exit_sem(p);
bad_fork_cleanup_security: bad_fork_cleanup_security:
security_task_free(p); security_task_free(p);
bad_fork_cleanup: bad_fork_cleanup:
......
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