Merge git://git.kernel.org/pub/scm/linux/kernel/git/tglx/linux-2.6-hrt
[pandora-kernel.git] / kernel / fork.c
index d2f4a42..ddafdfa 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/taskstats_kern.h>
 #include <linux/random.h>
 #include <linux/tty.h>
+#include <linux/proc_fs.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -116,7 +117,7 @@ EXPORT_SYMBOL(free_task);
 
 void __put_task_struct(struct task_struct *tsk)
 {
-       WARN_ON(!(tsk->exit_state & (EXIT_DEAD | EXIT_ZOMBIE)));
+       WARN_ON(!tsk->exit_state);
        WARN_ON(atomic_read(&tsk->usage));
        WARN_ON(tsk == current);
 
@@ -205,7 +206,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
 }
 
 #ifdef CONFIG_MMU
-static inline int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
+static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
 {
        struct vm_area_struct *mpnt, *tmp, **pprev;
        struct rb_node **rb_link, *rb_parent;
@@ -583,7 +584,7 @@ fail_nomem:
        return retval;
 }
 
-static inline struct fs_struct *__copy_fs_struct(struct fs_struct *old)
+static struct fs_struct *__copy_fs_struct(struct fs_struct *old)
 {
        struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL);
        /* We don't need to lock fs - think why ;-) */
@@ -615,7 +616,7 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old)
 
 EXPORT_SYMBOL_GPL(copy_fs_struct);
 
-static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk)
+static int copy_fs(unsigned long clone_flags, struct task_struct *tsk)
 {
        if (clone_flags & CLONE_FS) {
                atomic_inc(&current->fs->count);
@@ -818,7 +819,7 @@ int unshare_files(void)
 
 EXPORT_SYMBOL(unshare_files);
 
-static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk)
+static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
 {
        struct sighand_struct *sig;
 
@@ -841,7 +842,7 @@ void __cleanup_sighand(struct sighand_struct *sighand)
                kmem_cache_free(sighand_cachep, sighand);
 }
 
-static inline int copy_signal(unsigned long clone_flags, struct task_struct * tsk)
+static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 {
        struct signal_struct *sig;
        int ret;
@@ -923,7 +924,7 @@ void __cleanup_signal(struct signal_struct *sig)
        kmem_cache_free(signal_cachep, sig);
 }
 
-static inline void cleanup_signal(struct task_struct *tsk)
+static void cleanup_signal(struct task_struct *tsk)
 {
        struct signal_struct *sig = tsk->signal;
 
@@ -933,7 +934,7 @@ static inline void cleanup_signal(struct task_struct *tsk)
                __cleanup_signal(sig);
 }
 
-static inline void copy_flags(unsigned long clone_flags, struct task_struct *p)
+static void copy_flags(unsigned long clone_flags, struct task_struct *p)
 {
        unsigned long new_flags = p->flags;
 
@@ -949,10 +950,10 @@ asmlinkage long sys_set_tid_address(int __user *tidptr)
 {
        current->clear_child_tid = tidptr;
 
-       return current->pid;
+       return task_pid_vnr(current);
 }
 
-static inline void rt_mutex_init_task(struct task_struct *p)
+static void rt_mutex_init_task(struct task_struct *p)
 {
        spin_lock_init(&p->pi_lock);
 #ifdef CONFIG_RT_MUTEXES
@@ -973,12 +974,11 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                                        unsigned long stack_start,
                                        struct pt_regs *regs,
                                        unsigned long stack_size,
-                                       int __user *parent_tidptr,
                                        int __user *child_tidptr,
                                        struct pid *pid)
 {
        int retval;
-       struct task_struct *p = NULL;
+       struct task_struct *p;
        int cgroup_callbacks_done = 0;
 
        if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
@@ -1040,21 +1040,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        if (p->binfmt && !try_module_get(p->binfmt->module))
                goto bad_fork_cleanup_put_domain;
 
-       if (pid != &init_struct_pid) {
-               pid = alloc_pid();
-               if (!pid)
-                       goto bad_fork_put_binfmt_module;
-       }
-
        p->did_exec = 0;
        delayacct_tsk_init(p);  /* Must remain after dup_task_struct() */
        copy_flags(clone_flags, p);
-       p->pid = pid_nr(pid);
-       retval = -EFAULT;
-       if (clone_flags & CLONE_PARENT_SETTID)
-               if (put_user(p->pid, parent_tidptr))
-                       goto bad_fork_cleanup_delays_binfmt;
-
        INIT_LIST_HEAD(&p->children);
        INIT_LIST_HEAD(&p->sibling);
        p->vfork_done = NULL;
@@ -1133,10 +1121,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        p->blocked_on = NULL; /* not blocked yet */
 #endif
 
-       p->tgid = p->pid;
-       if (clone_flags & CLONE_THREAD)
-               p->tgid = current->tgid;
-
        if ((retval = security_task_alloc(p)))
                goto bad_fork_cleanup_policy;
        if ((retval = audit_alloc(p)))
@@ -1162,6 +1146,24 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        if (retval)
                goto bad_fork_cleanup_namespaces;
 
+       if (pid != &init_struct_pid) {
+               retval = -ENOMEM;
+               pid = alloc_pid(task_active_pid_ns(p));
+               if (!pid)
+                       goto bad_fork_cleanup_namespaces;
+
+               if (clone_flags & CLONE_NEWPID) {
+                       retval = pid_ns_prepare_proc(task_active_pid_ns(p));
+                       if (retval < 0)
+                               goto bad_fork_free_pid;
+               }
+       }
+
+       p->pid = pid_nr(pid);
+       p->tgid = p->pid;
+       if (clone_flags & CLONE_THREAD)
+               p->tgid = current->tgid;
+
        p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
        /*
         * Clear TID on mm_release()?
@@ -1259,7 +1261,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                spin_unlock(&current->sighand->siglock);
                write_unlock_irq(&tasklist_lock);
                retval = -ERESTARTNOINTR;
-               goto bad_fork_cleanup_namespaces;
+               goto bad_fork_free_pid;
        }
 
        if (clone_flags & CLONE_THREAD) {
@@ -1288,11 +1290,22 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                        __ptrace_link(p, current->parent);
 
                if (thread_group_leader(p)) {
-                       p->signal->tty = current->signal->tty;
-                       p->signal->pgrp = task_pgrp_nr(current);
-                       set_task_session(p, task_session_nr(current));
-                       attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
-                       attach_pid(p, PIDTYPE_SID, task_session(current));
+                       if (clone_flags & CLONE_NEWPID) {
+                               p->nsproxy->pid_ns->child_reaper = p;
+                               p->signal->tty = NULL;
+                               set_task_pgrp(p, p->pid);
+                               set_task_session(p, p->pid);
+                               attach_pid(p, PIDTYPE_PGID, pid);
+                               attach_pid(p, PIDTYPE_SID, pid);
+                       } else {
+                               p->signal->tty = current->signal->tty;
+                               set_task_pgrp(p, task_pgrp_nr(current));
+                               set_task_session(p, task_session_nr(current));
+                               attach_pid(p, PIDTYPE_PGID,
+                                               task_pgrp(current));
+                               attach_pid(p, PIDTYPE_SID,
+                                               task_session(current));
+                       }
 
                        list_add_tail_rcu(&p->tasks, &init_task.tasks);
                        __get_cpu_var(process_counts)++;
@@ -1308,6 +1321,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        cgroup_post_fork(p);
        return p;
 
+bad_fork_free_pid:
+       if (pid != &init_struct_pid)
+               free_pid(pid);
 bad_fork_cleanup_namespaces:
        exit_task_namespaces(p);
 bad_fork_cleanup_keys:
@@ -1335,11 +1351,7 @@ bad_fork_cleanup_policy:
 bad_fork_cleanup_cgroup:
 #endif
        cgroup_exit(p, cgroup_callbacks_done);
-bad_fork_cleanup_delays_binfmt:
        delayacct_tsk_free(p);
-       if (pid != &init_struct_pid)
-               free_pid(pid);
-bad_fork_put_binfmt_module:
        if (p->binfmt)
                module_put(p->binfmt->module);
 bad_fork_cleanup_put_domain:
@@ -1365,7 +1377,7 @@ struct task_struct * __cpuinit fork_idle(int cpu)
        struct task_struct *task;
        struct pt_regs regs;
 
-       task = copy_process(CLONE_VM, 0, idle_regs(&regs), 0, NULL, NULL,
+       task = copy_process(CLONE_VM, 0, idle_regs(&regs), 0, NULL,
                                &init_struct_pid);
        if (!IS_ERR(task))
                init_idle(task, cpu);
@@ -1373,7 +1385,7 @@ struct task_struct * __cpuinit fork_idle(int cpu)
        return task;
 }
 
-static inline int fork_traceflag (unsigned clone_flags)
+static int fork_traceflag(unsigned clone_flags)
 {
        if (clone_flags & CLONE_UNTRACED)
                return 0;
@@ -1413,7 +1425,7 @@ long do_fork(unsigned long clone_flags,
        }
 
        p = copy_process(clone_flags, stack_start, regs, stack_size,
-                       parent_tidptr, child_tidptr, NULL);
+                       child_tidptr, NULL);
        /*
         * Do this prior waking up the new thread - the thread pointer
         * might get invalid after that point, if the thread exits quickly.
@@ -1421,7 +1433,16 @@ long do_fork(unsigned long clone_flags,
        if (!IS_ERR(p)) {
                struct completion vfork;
 
-               nr = pid_nr(task_pid(p));
+               /*
+                * this is enough to call pid_nr_ns here, but this if
+                * improves optimisation of regular fork()
+                */
+               nr = (clone_flags & CLONE_NEWPID) ?
+                       task_pid_nr_ns(p, current->nsproxy->pid_ns) :
+                               task_pid_vnr(p);
+
+               if (clone_flags & CLONE_PARENT_SETTID)
+                       put_user(nr, parent_tidptr);
 
                if (clone_flags & CLONE_VFORK) {
                        p->vfork_done = &vfork;
@@ -1500,7 +1521,7 @@ void __init proc_caches_init(void)
  * Check constraints on flags passed to the unshare system call and
  * force unsharing of additional process context as appropriate.
  */
-static inline void check_unshare_flags(unsigned long *flags_ptr)
+static void check_unshare_flags(unsigned long *flags_ptr)
 {
        /*
         * If unsharing a thread from a thread group, must also