summaryrefslogtreecommitdiff
path: root/fs/exec.c
diff options
context:
space:
mode:
authorAndrew Morton <akpm@digeo.com>2003-05-25 01:10:37 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2003-05-25 01:10:37 -0700
commit055e188d5ce5d5edd5d916a0cd549ebb195388a3 (patch)
treeb1f2d4dd72df0d360f528aa8107a62fe47fe5e6d /fs/exec.c
parent05cdeac3efd3bbffd5f01a1822c4f941e19ba31d (diff)
[PATCH] Fix dcache_lock/tasklist_lock ranking bug
__unhash_process acquires the dcache_lock while holding the tasklist_lock for writing. This can deadlock. Additionally, fs/proc/base.c incorrectly assumed that p->pid would be set to 0 during release_task. The patch fixes that by adding a new spinlock to the task structure and fixing all references to (!p->pid). The alternative to the new spinlock would be to hold dcache_lock around __unhash_process. - fs/proc/base.c assumed that p->pid is reset to 0 during exit. This is not the case anymore. I now look at the count of the pid structure for PIDTYPE_PID. - de_thread now tested - as broken as it was before: open handles to /proc/<pid> are either stale or invalid after an exec of a nptl process, if the exec was call from a secondary thread. - a few lock_kernels removed - that part of /proc doesn't need it. - additional instances of 'if(current->pid)' replaced with pid_alive.
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c37
1 files changed, 8 insertions, 29 deletions
diff --git a/fs/exec.c b/fs/exec.c
index e214e30ca525..9bbd3b4e76dc 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -529,30 +529,6 @@ static int exec_mmap(struct mm_struct *mm)
return 0;
}
-static struct dentry *clean_proc_dentry(struct task_struct *p)
-{
- struct dentry *proc_dentry = p->proc_dentry;
-
- if (proc_dentry) {
- spin_lock(&dcache_lock);
- if (!d_unhashed(proc_dentry)) {
- dget_locked(proc_dentry);
- __d_drop(proc_dentry);
- } else
- proc_dentry = NULL;
- spin_unlock(&dcache_lock);
- }
- return proc_dentry;
-}
-
-static inline void put_proc_dentry(struct dentry *dentry)
-{
- if (dentry) {
- shrink_dcache_parent(dentry);
- dput(dentry);
- }
-}
-
/*
* This function makes sure the current process has its own signal table,
* so that flush_signal_handlers can later reset the handlers without
@@ -660,9 +636,11 @@ static inline int de_thread(struct task_struct *tsk)
while (leader->state != TASK_ZOMBIE)
yield();
+ spin_lock(&leader->proc_lock);
+ spin_lock(&current->proc_lock);
+ proc_dentry1 = proc_pid_unhash(current);
+ proc_dentry2 = proc_pid_unhash(leader);
write_lock_irq(&tasklist_lock);
- proc_dentry1 = clean_proc_dentry(current);
- proc_dentry2 = clean_proc_dentry(leader);
if (leader->tgid != current->tgid)
BUG();
@@ -702,9 +680,10 @@ static inline int de_thread(struct task_struct *tsk)
state = leader->state;
write_unlock_irq(&tasklist_lock);
-
- put_proc_dentry(proc_dentry1);
- put_proc_dentry(proc_dentry2);
+ spin_unlock(&leader->proc_lock);
+ spin_unlock(&current->proc_lock);
+ proc_pid_flush(proc_dentry1);
+ proc_pid_flush(proc_dentry2);
if (state != TASK_ZOMBIE)
BUG();