Merge branch 'timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / kernel / fork.c
index 14cf79f..51ad0b0 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/ftrace.h>
 #include <linux/profile.h>
 #include <linux/rmap.h>
+#include <linux/ksm.h>
 #include <linux/acct.h>
 #include <linux/tsacct_kern.h>
 #include <linux/cn_proc.h>
@@ -61,7 +62,7 @@
 #include <linux/blkdev.h>
 #include <linux/fs_struct.h>
 #include <linux/magic.h>
-#include <linux/perf_counter.h>
+#include <linux/perf_event.h>
 #include <linux/posix-timers.h>
 
 #include <asm/pgtable.h>
@@ -137,9 +138,17 @@ struct kmem_cache *vm_area_cachep;
 /* SLAB cache for mm_struct structures (tsk->mm) */
 static struct kmem_cache *mm_cachep;
 
+static void account_kernel_stack(struct thread_info *ti, int account)
+{
+       struct zone *zone = page_zone(virt_to_page(ti));
+
+       mod_zone_page_state(zone, NR_KERNEL_STACK, account);
+}
+
 void free_task(struct task_struct *tsk)
 {
        prop_local_destroy_single(&tsk->dirties);
+       account_kernel_stack(tsk->stack, -1);
        free_thread_info(tsk->stack);
        rt_mutex_debug_task_free(tsk);
        ftrace_graph_exit_task(tsk);
@@ -153,8 +162,7 @@ void __put_task_struct(struct task_struct *tsk)
        WARN_ON(atomic_read(&tsk->usage));
        WARN_ON(tsk == current);
 
-       put_cred(tsk->real_cred);
-       put_cred(tsk->cred);
+       exit_creds(tsk);
        delayacct_tsk_free(tsk);
 
        if (!profile_handoff_task(tsk))
@@ -255,6 +263,9 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
        tsk->btrace_seq = 0;
 #endif
        tsk->splice_pipe = NULL;
+
+       account_kernel_stack(ti, 1);
+
        return tsk;
 
 out:
@@ -290,6 +301,9 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
        rb_link = &mm->mm_rb.rb_node;
        rb_parent = NULL;
        pprev = &mm->mmap;
+       retval = ksm_fork(mm, oldmm);
+       if (retval)
+               goto out;
 
        for (mpnt = oldmm->mmap; mpnt; mpnt = mpnt->vm_next) {
                struct file *file;
@@ -426,8 +440,8 @@ static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p)
        atomic_set(&mm->mm_count, 1);
        init_rwsem(&mm->mmap_sem);
        INIT_LIST_HEAD(&mm->mmlist);
-       mm->flags = (current->mm) ? current->mm->flags : default_dump_filter;
-       mm->oom_adj = (current->mm) ? current->mm->oom_adj : 0;
+       mm->flags = (current->mm) ?
+               (current->mm->flags & MMF_INIT_MASK) : default_dump_filter;
        mm->core_state = NULL;
        mm->nr_ptes = 0;
        set_mm_counter(mm, file_rss, 0);
@@ -488,6 +502,7 @@ void mmput(struct mm_struct *mm)
 
        if (atomic_dec_and_test(&mm->mm_users)) {
                exit_aio(mm);
+               ksm_exit(mm);
                exit_mmap(mm);
                set_mm_exe_file(mm, NULL);
                if (!list_empty(&mm->mmlist)) {
@@ -817,11 +832,8 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 {
        struct signal_struct *sig;
 
-       if (clone_flags & CLONE_THREAD) {
-               atomic_inc(&current->signal->count);
-               atomic_inc(&current->signal->live);
+       if (clone_flags & CLONE_THREAD)
                return 0;
-       }
 
        sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL);
        tsk->signal = sig;
@@ -855,6 +867,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
        sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
        sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0;
+       sig->maxrss = sig->cmaxrss = 0;
        task_io_accounting_init(&sig->ioac);
        sig->sum_sched_runtime = 0;
        taskstats_tgid_init(sig);
@@ -869,6 +882,8 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 
        tty_audit_fork(sig);
 
+       sig->oom_adj = current->signal->oom_adj;
+
        return 0;
 }
 
@@ -879,16 +894,6 @@ void __cleanup_signal(struct signal_struct *sig)
        kmem_cache_free(signal_cachep, sig);
 }
 
-static void cleanup_signal(struct task_struct *tsk)
-{
-       struct signal_struct *sig = tsk->signal;
-
-       atomic_dec(&sig->live);
-
-       if (atomic_dec_and_test(&sig->count))
-               __cleanup_signal(sig);
-}
-
 static void copy_flags(unsigned long clone_flags, struct task_struct *p)
 {
        unsigned long new_flags = p->flags;
@@ -1023,10 +1028,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        copy_flags(clone_flags, p);
        INIT_LIST_HEAD(&p->children);
        INIT_LIST_HEAD(&p->sibling);
-#ifdef CONFIG_PREEMPT_RCU
-       p->rcu_read_lock_nesting = 0;
-       p->rcu_flipctr_idx = 0;
-#endif /* #ifdef CONFIG_PREEMPT_RCU */
+       rcu_copy_process(p);
        p->vfork_done = NULL;
        spin_lock_init(&p->alloc_lock);
 
@@ -1094,10 +1096,12 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 
        p->bts = NULL;
 
+       p->stack_start = stack_start;
+
        /* Perform scheduler related setup. Assign this task to a CPU. */
        sched_fork(p, clone_flags);
 
-       retval = perf_counter_init_task(p);
+       retval = perf_event_init_task(p);
        if (retval)
                goto bad_fork_cleanup_policy;
 
@@ -1241,6 +1245,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        }
 
        if (clone_flags & CLONE_THREAD) {
+               atomic_inc(&current->signal->count);
+               atomic_inc(&current->signal->live);
                p->group_leader = current->group_leader;
                list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group);
        }
@@ -1270,7 +1276,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        write_unlock_irq(&tasklist_lock);
        proc_fork_connector(p);
        cgroup_post_fork(p);
-       perf_counter_fork(p);
+       perf_event_fork(p);
        return p;
 
 bad_fork_free_pid:
@@ -1284,7 +1290,8 @@ bad_fork_cleanup_mm:
        if (p->mm)
                mmput(p->mm);
 bad_fork_cleanup_signal:
-       cleanup_signal(p);
+       if (!(clone_flags & CLONE_THREAD))
+               __cleanup_signal(p->signal);
 bad_fork_cleanup_sighand:
        __cleanup_sighand(p->sighand);
 bad_fork_cleanup_fs:
@@ -1296,7 +1303,7 @@ bad_fork_cleanup_semundo:
 bad_fork_cleanup_audit:
        audit_free(p);
 bad_fork_cleanup_policy:
-       perf_counter_free_task(p);
+       perf_event_free_task(p);
 #ifdef CONFIG_NUMA
        mpol_put(p->mempolicy);
 bad_fork_cleanup_cgroup:
@@ -1309,8 +1316,7 @@ bad_fork_cleanup_put_domain:
        module_put(task_thread_info(p)->exec_domain->module);
 bad_fork_cleanup_count:
        atomic_dec(&p->cred->user->processes);
-       put_cred(p->real_cred);
-       put_cred(p->cred);
+       exit_creds(p);
 bad_fork_free:
        free_task(p);
 fork_out: