aboutsummaryrefslogtreecommitdiffstats
path: root/fs/exec.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2002-11-05 04:25:29 -0800
committerIngo Molnar <mingo@elte.hu>2002-11-05 04:25:29 -0800
commitd89f3847def4a55a84cc42809994bde2a148e9e0 (patch)
tree44e264429c0e2f71167e77ee272e22c40d6acef8 /fs/exec.c
parent5a7728c6d3eb83df9d120944cca4cf476dd326a1 (diff)
downloadtip-d89f3847def4.tar.gz
[PATCH] thread-aware coredumps, 2.5.43-C3
Notice: this object is not reachable from any branch.
This is the second iteration of thread-aware coredumps. Changes: - Ulrich Drepper has reviewed the data structures and checked actual coredumps via readelf - everything looks fine and according to the spec. - a serious bug has been fixed in the thread-state dumping code - it was still based on the 2.4 assumption that the task struct points to the kernel stack - it's task->thread_info in 2.5. This bug caused bogus register info to be filled in for threads. - properly wait for all threads that share the same MM to serialize with the coredumping thread. This is CLONE_VM based, not tied to CLONE_THREAD and/or signal semantics, ie. old-style (or different-style) threaded apps will be properly stopped as well. The locking might look a bit complex, but i wanted to keep the __exit_mm() overhead as low as possible. It's not quite trivial to get these bits right, because 'sharing the MM' is detached from signals semantics, so we cannot rely on broadcast-kill catching all threads. So zap_threads() iterates through every thread and zaps those which were left out. (There's a minimal race left in where a newly forked child might escape the attention of zap_threads() - this race is fixed by the OOM fixes in the mmap-speedup patch.) - fill_psinfo() is now called with the thread group leader, for the coredump to get 'process' state. - initialize the elf_thread_status structure with zeroes. the IA64 ELF bits are not included, yet, to reduce complexity of the patch. The patch has been tested on x86 UP and SMP.
Notice: this object is not reachable from any branch.
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c38
1 files changed, 36 insertions, 2 deletions
diff --git a/fs/exec.c b/fs/exec.c
index eef86f55c0cb2f..0bdbf8710d6239 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1209,6 +1209,35 @@ void format_corename(char *corename, const char *pattern, long signr)
*out_ptr = 0;
}
+static void zap_threads (struct mm_struct *mm)
+{
+ struct task_struct *g, *p;
+
+ /* give other threads a chance to run: */
+ yield();
+
+ read_lock(&tasklist_lock);
+ do_each_thread(g,p)
+ if (mm == p->mm && !p->core_waiter)
+ force_sig_specific(SIGKILL, p);
+ while_each_thread(g,p);
+ read_unlock(&tasklist_lock);
+}
+
+static void coredump_wait(struct mm_struct *mm)
+{
+ DECLARE_WAITQUEUE(wait, current);
+
+ atomic_inc(&mm->core_waiters);
+ add_wait_queue(&mm->core_wait, &wait);
+ zap_threads(mm);
+ current->state = TASK_UNINTERRUPTIBLE;
+ if (atomic_read(&mm->core_waiters) != atomic_read(&mm->mm_users))
+ schedule();
+ else
+ current->state = TASK_RUNNING;
+}
+
int do_coredump(long signr, struct pt_regs * regs)
{
struct linux_binfmt * binfmt;
@@ -1224,13 +1253,16 @@ int do_coredump(long signr, struct pt_regs * regs)
if (!current->mm->dumpable)
goto fail;
current->mm->dumpable = 0;
+ if (down_trylock(&current->mm->core_sem))
+ BUG();
+ coredump_wait(current->mm);
if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
- goto fail;
+ goto fail_unlock;
format_corename(corename, core_pattern, signr);
file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW, 0600);
if (IS_ERR(file))
- goto fail;
+ goto fail_unlock;
inode = file->f_dentry->d_inode;
if (inode->i_nlink > 1)
goto close_fail; /* multiple links - don't dump */
@@ -1250,6 +1282,8 @@ int do_coredump(long signr, struct pt_regs * regs)
close_fail:
filp_close(file, NULL);
+fail_unlock:
+ up(&current->mm->core_sem);
fail:
unlock_kernel();
return retval;