diff options
| author | Ingo Molnar <mingo@elte.hu> | 2002-11-05 04:25:29 -0800 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2002-11-05 04:25:29 -0800 |
| commit | d89f3847def4a55a84cc42809994bde2a148e9e0 (patch) | |
| tree | 44e264429c0e2f71167e77ee272e22c40d6acef8 /fs/exec.c | |
| parent | 5a7728c6d3eb83df9d120944cca4cf476dd326a1 (diff) | |
| download | tip-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.c | 38 |
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(¤t->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(¤t->mm->core_sem); fail: unlock_kernel(); return retval; |
