[PATCH] process accounting: take original leader's start_time in non-leader exec
[sfrench/cifs-2.6.git] / fs / exec.c
index 995cba3c62b86fe51f7f21688892e534ce30e087..3234a0c32d5405bdfd8f46f97cd97994e93828ee 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -561,7 +561,7 @@ static int exec_mmap(struct mm_struct *mm)
        arch_pick_mmap_layout(mm);
        if (old_mm) {
                up_read(&old_mm->mmap_sem);
-               if (active_mm != old_mm) BUG();
+               BUG_ON(active_mm != old_mm);
                mmput(old_mm);
                return 0;
        }
@@ -616,6 +616,15 @@ static int de_thread(struct task_struct *tsk)
                kmem_cache_free(sighand_cachep, newsighand);
                return -EAGAIN;
        }
+
+       /*
+        * child_reaper ignores SIGKILL, change it now.
+        * Reparenting needs write_lock on tasklist_lock,
+        * so it is safe to do it under read_lock.
+        */
+       if (unlikely(current->group_leader == child_reaper))
+               child_reaper = current;
+
        zap_other_threads(current);
        read_unlock(&tasklist_lock);
 
@@ -632,7 +641,7 @@ static int de_thread(struct task_struct *tsk)
                 * synchronize with any firing (by calling del_timer_sync)
                 * before we can safely let the old group leader die.
                 */
-               sig->real_timer.data = current;
+               sig->tsk = current;
                spin_unlock_irq(lock);
                if (hrtimer_cancel(&sig->real_timer))
                        hrtimer_restart(&sig->real_timer);
@@ -669,6 +678,18 @@ static int de_thread(struct task_struct *tsk)
                while (leader->exit_state != EXIT_ZOMBIE)
                        yield();
 
+               /*
+                * The only record we have of the real-time age of a
+                * process, regardless of execs it's done, is start_time.
+                * All the past CPU time is accumulated in signal_struct
+                * from sister threads now dead.  But in this non-leader
+                * exec, nothing survives from the original leader thread,
+                * whose birth marks the true age of this process now.
+                * When we take on its identity by switching to its PID, we
+                * also take its birthdate (always earlier than our own).
+                */
+               current->start_time = leader->start_time;
+
                spin_lock(&leader->proc_lock);
                spin_lock(&current->proc_lock);
                proc_dentry1 = proc_pid_unhash(current);
@@ -699,22 +720,35 @@ static int de_thread(struct task_struct *tsk)
                remove_parent(current);
                remove_parent(leader);
 
-               switch_exec_pids(leader, current);
+
+               /* Become a process group leader with the old leader's pid.
+                * Note: The old leader also uses thispid until release_task
+                *       is called.  Odd but simple and correct.
+                */
+               detach_pid(current, PIDTYPE_PID);
+               current->pid = leader->pid;
+               attach_pid(current, PIDTYPE_PID,  current->pid);
+               attach_pid(current, PIDTYPE_PGID, current->signal->pgrp);
+               attach_pid(current, PIDTYPE_SID,  current->signal->session);
+               list_add_tail(&current->tasks, &init_task.tasks);
 
                current->parent = current->real_parent = leader->real_parent;
                leader->parent = leader->real_parent = child_reaper;
                current->group_leader = current;
-               leader->group_leader = leader;
+               leader->group_leader = current;
+
+               /* Reduce leader to a thread */
+               detach_pid(leader, PIDTYPE_PGID);
+               detach_pid(leader, PIDTYPE_SID);
+               list_del_init(&leader->tasks);
 
-               add_parent(current, current->parent);
-               add_parent(leader, leader->parent);
+               add_parent(current);
+               add_parent(leader);
                if (ptrace) {
                        current->ptrace = ptrace;
                        __ptrace_link(current, parent);
                }
 
-               list_del(&current->tasks);
-               list_add_tail(&current->tasks, &init_task.tasks);
                current->exit_signal = SIGCHLD;
 
                BUG_ON(leader->exit_state != EXIT_ZOMBIE);
@@ -751,7 +785,6 @@ no_thread_group:
                /*
                 * Move our state over to newsighand and switch it in.
                 */
-               spin_lock_init(&newsighand->siglock);
                atomic_set(&newsighand->count, 1);
                memcpy(newsighand->action, oldsighand->action,
                       sizeof(newsighand->action));
@@ -768,7 +801,7 @@ no_thread_group:
                write_unlock_irq(&tasklist_lock);
 
                if (atomic_dec_and_test(&oldsighand->count))
-                       sighand_free(oldsighand);
+                       kmem_cache_free(sighand_cachep, oldsighand);
        }
 
        BUG_ON(!thread_group_leader(current));