]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/exec.c
edac: core fix static to dynamic kset
[linux-2.6-omap-h63xx.git] / fs / exec.c
index 50de3aaff4d008921a62fb54ea4cc809babeb2d7..5e559013e303fbcb6f9666828cca450ab57de7f9 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1379,17 +1379,14 @@ EXPORT_SYMBOL(set_binfmt);
  * name into corename, which must have space for at least
  * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator.
  */
-static int format_corename(char *corename, const char *pattern, long signr)
+static int format_corename(char *corename, int nr_threads, long signr)
 {
-       const char *pat_ptr = pattern;
+       const char *pat_ptr = core_pattern;
+       int ispipe = (*pat_ptr == '|');
        char *out_ptr = corename;
        char *const out_end = corename + CORENAME_MAX_SIZE;
        int rc;
        int pid_in_pattern = 0;
-       int ispipe = 0;
-
-       if (*pattern == '|')
-               ispipe = 1;
 
        /* Repeat as long as we have more pattern to process and more output
           space */
@@ -1490,7 +1487,7 @@ static int format_corename(char *corename, const char *pattern, long signr)
         * and core_uses_pid is set, then .%pid will be appended to
         * the filename. Do not do this for piped commands. */
        if (!ispipe && !pid_in_pattern
-            && (core_uses_pid || atomic_read(&current->mm->mm_users) != 1)) {
+           && (core_uses_pid || nr_threads)) {
                rc = snprintf(out_ptr, out_end - out_ptr,
                              ".%d", task_tgid_vnr(current));
                if (rc > out_end - out_ptr)
@@ -1502,9 +1499,10 @@ out:
        return ispipe;
 }
 
-static void zap_process(struct task_struct *start)
+static int zap_process(struct task_struct *start)
 {
        struct task_struct *t;
+       int nr = 0;
 
        start->signal->flags = SIGNAL_GROUP_EXIT;
        start->signal->group_stop_count = 0;
@@ -1512,31 +1510,33 @@ static void zap_process(struct task_struct *start)
        t = start;
        do {
                if (t != current && t->mm) {
-                       t->mm->core_state->nr_threads++;
                        sigaddset(&t->pending.signal, SIGKILL);
                        signal_wake_up(t, 1);
+                       nr++;
                }
        } while_each_thread(start, t);
+
+       return nr;
 }
 
 static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
-                               int exit_code)
+                               struct core_state *core_state, int exit_code)
 {
        struct task_struct *g, *p;
        unsigned long flags;
-       int err = -EAGAIN;
+       int nr = -EAGAIN;
 
        spin_lock_irq(&tsk->sighand->siglock);
        if (!signal_group_exit(tsk->signal)) {
+               mm->core_state = core_state;
                tsk->signal->group_exit_code = exit_code;
-               zap_process(tsk);
-               err = 0;
+               nr = zap_process(tsk);
        }
        spin_unlock_irq(&tsk->sighand->siglock);
-       if (err)
-               return err;
+       if (unlikely(nr < 0))
+               return nr;
 
-       if (atomic_read(&mm->mm_users) == mm->core_state->nr_threads + 1)
+       if (atomic_read(&mm->mm_users) == nr + 1)
                goto done;
        /*
         * We should find and kill all tasks which use this mm, and we should
@@ -1579,7 +1579,7 @@ static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
                        if (p->mm) {
                                if (unlikely(p->mm == mm)) {
                                        lock_task_sighand(p, &flags);
-                                       zap_process(p);
+                                       nr += zap_process(p);
                                        unlock_task_sighand(p, &flags);
                                }
                                break;
@@ -1588,25 +1588,21 @@ static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
        }
        rcu_read_unlock();
 done:
-       return mm->core_state->nr_threads;
+       atomic_set(&core_state->nr_threads, nr);
+       return nr;
 }
 
-static int coredump_wait(int exit_code)
+static int coredump_wait(int exit_code, struct core_state *core_state)
 {
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->mm;
-       struct core_state core_state;
        struct completion *vfork_done;
        int core_waiters;
 
-       init_completion(&mm->core_done);
-       init_completion(&core_state.startup);
-       core_state.nr_threads = 0;
-       mm->core_state = &core_state;
-
-       core_waiters = zap_threads(tsk, mm, exit_code);
-       if (core_waiters < 0)
-               mm->core_state = NULL;
+       init_completion(&core_state->startup);
+       core_state->dumper.task = tsk;
+       core_state->dumper.next = NULL;
+       core_waiters = zap_threads(tsk, mm, core_state, exit_code);
        up_write(&mm->mmap_sem);
 
        if (unlikely(core_waiters < 0))
@@ -1623,12 +1619,32 @@ static int coredump_wait(int exit_code)
        }
 
        if (core_waiters)
-               wait_for_completion(&core_state.startup);
-       mm->core_state = NULL;
+               wait_for_completion(&core_state->startup);
 fail:
        return core_waiters;
 }
 
+static void coredump_finish(struct mm_struct *mm)
+{
+       struct core_thread *curr, *next;
+       struct task_struct *task;
+
+       next = mm->core_state->dumper.next;
+       while ((curr = next) != NULL) {
+               next = curr->next;
+               task = curr->task;
+               /*
+                * see exit_mm(), curr->task must not see
+                * ->task == NULL before we read ->next.
+                */
+               smp_mb();
+               curr->task = NULL;
+               wake_up_process(task);
+       }
+
+       mm->core_state = NULL;
+}
+
 /*
  * set_dumpable converts traditional three-value dumpable to two flags and
  * stores them into mm->flags.  It modifies lower two bits of mm->flags, but
@@ -1680,6 +1696,7 @@ int get_dumpable(struct mm_struct *mm)
 
 int do_coredump(long signr, int exit_code, struct pt_regs * regs)
 {
+       struct core_state core_state;
        char corename[CORENAME_MAX_SIZE + 1];
        struct mm_struct *mm = current->mm;
        struct linux_binfmt * binfmt;
@@ -1718,7 +1735,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
                current->fsuid = 0;     /* Dump root private */
        }
 
-       retval = coredump_wait(exit_code);
+       retval = coredump_wait(exit_code, &core_state);
        if (retval < 0)
                goto fail;
 
@@ -1733,7 +1750,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
         * uses lock_kernel()
         */
        lock_kernel();
-       ispipe = format_corename(corename, core_pattern, signr);
+       ispipe = format_corename(corename, retval, signr);
        unlock_kernel();
        /*
         * Don't bother to check the RLIMIT_CORE value if core_pattern points
@@ -1812,7 +1829,7 @@ fail_unlock:
                argv_free(helper_argv);
 
        current->fsuid = fsuid;
-       complete_all(&mm->core_done);
+       coredump_finish(mm);
 fail:
        return retval;
 }