]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - kernel/fork.c
ipv4: Don't recompute net in ipmr_queue_xmit
[karo-tx-linux.git] / kernel / fork.c
index dbd9b8d7b7cc2baa8c425bf35191ce8dfd117ecf..7d5f0f118a6348f81f08f10dd7dbb499f89dd243 100644 (file)
@@ -454,8 +454,9 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
                tmp->vm_mm = mm;
                if (anon_vma_fork(tmp, mpnt))
                        goto fail_nomem_anon_vma_fork;
-               tmp->vm_flags &= ~VM_LOCKED;
+               tmp->vm_flags &= ~(VM_LOCKED|VM_UFFD_MISSING|VM_UFFD_WP);
                tmp->vm_next = tmp->vm_prev = NULL;
+               tmp->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX;
                file = tmp->vm_file;
                if (file) {
                        struct inode *inode = file_inode(file);
@@ -1072,6 +1073,7 @@ static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
        rcu_assign_pointer(tsk->sighand, sig);
        if (!sig)
                return -ENOMEM;
+
        atomic_set(&sig->count, 1);
        memcpy(sig->action, current->sighand->action, sizeof(sig->action));
        return 0;
@@ -1133,6 +1135,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        init_sigpending(&sig->shared_pending);
        INIT_LIST_HEAD(&sig->posix_timers);
        seqlock_init(&sig->stats_lock);
+       prev_cputime_init(&sig->prev_cputime);
 
        hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        sig->real_timer.function = it_real_fn;
@@ -1244,6 +1247,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 {
        int retval;
        struct task_struct *p;
+       void *cgrp_ss_priv[CGROUP_CANFORK_COUNT] = {};
 
        if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
                return ERR_PTR(-EINVAL);
@@ -1278,10 +1282,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 
        /*
         * If the new process will be in a different pid or user namespace
-        * do not allow it to share a thread group or signal handlers or
-        * parent with the forking task.
+        * do not allow it to share a thread group with the forking task.
         */
-       if (clone_flags & CLONE_SIGHAND) {
+       if (clone_flags & CLONE_THREAD) {
                if ((clone_flags & (CLONE_NEWUSER | CLONE_NEWPID)) ||
                    (task_active_pid_ns(current) !=
                                current->nsproxy->pid_ns_for_children))
@@ -1340,9 +1343,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 
        p->utime = p->stime = p->gtime = 0;
        p->utimescaled = p->stimescaled = 0;
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
-       p->prev_cputime.utime = p->prev_cputime.stime = 0;
-#endif
+       prev_cputime_init(&p->prev_cputime);
+
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
        seqlock_init(&p->vtime_seqlock);
        p->vtime_snap = 0;
@@ -1517,6 +1519,16 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        INIT_LIST_HEAD(&p->thread_group);
        p->task_works = NULL;
 
+       /*
+        * Ensure that the cgroup subsystem policies allow the new process to be
+        * forked. It should be noted the the new process's css_set can be changed
+        * between here and cgroup_post_fork() if an organisation operation is in
+        * progress.
+        */
+       retval = cgroup_can_fork(p, cgrp_ss_priv);
+       if (retval)
+               goto bad_fork_free_pid;
+
        /*
         * Make it visible to the rest of the system, but dont wake it up yet.
         * Need tasklist lock for parent etc handling!
@@ -1553,7 +1565,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_free_pid;
+               goto bad_fork_cancel_cgroup;
        }
 
        if (likely(p->pid)) {
@@ -1595,7 +1607,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        write_unlock_irq(&tasklist_lock);
 
        proc_fork_connector(p);
-       cgroup_post_fork(p);
+       cgroup_post_fork(p, cgrp_ss_priv);
        if (clone_flags & CLONE_THREAD)
                threadgroup_change_end(current);
        perf_event_fork(p);
@@ -1605,6 +1617,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 
        return p;
 
+bad_fork_cancel_cgroup:
+       cgroup_cancel_fork(p, cgrp_ss_priv);
 bad_fork_free_pid:
        if (pid != &init_struct_pid)
                free_pid(pid);
@@ -1871,13 +1885,21 @@ static int check_unshare_flags(unsigned long unshare_flags)
                                CLONE_NEWUSER|CLONE_NEWPID))
                return -EINVAL;
        /*
-        * Not implemented, but pretend it works if there is nothing to
-        * unshare. Note that unsharing CLONE_THREAD or CLONE_SIGHAND
-        * needs to unshare vm.
+        * Not implemented, but pretend it works if there is nothing
+        * to unshare.  Note that unsharing the address space or the
+        * signal handlers also need to unshare the signal queues (aka
+        * CLONE_THREAD).
         */
        if (unshare_flags & (CLONE_THREAD | CLONE_SIGHAND | CLONE_VM)) {
-               /* FIXME: get_task_mm() increments ->mm_users */
-               if (atomic_read(&current->mm->mm_users) > 1)
+               if (!thread_group_empty(current))
+                       return -EINVAL;
+       }
+       if (unshare_flags & (CLONE_SIGHAND | CLONE_VM)) {
+               if (atomic_read(&current->sighand->count) > 1)
+                       return -EINVAL;
+       }
+       if (unshare_flags & CLONE_VM) {
+               if (!current_is_single_threaded())
                        return -EINVAL;
        }
 
@@ -1941,20 +1963,21 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
        int err;
 
        /*
-        * If unsharing a user namespace must also unshare the thread.
+        * If unsharing a user namespace must also unshare the thread group
+        * and unshare the filesystem root and working directories.
         */
        if (unshare_flags & CLONE_NEWUSER)
                unshare_flags |= CLONE_THREAD | CLONE_FS;
-       /*
-        * If unsharing a thread from a thread group, must also unshare vm.
-        */
-       if (unshare_flags & CLONE_THREAD)
-               unshare_flags |= CLONE_VM;
        /*
         * If unsharing vm, must also unshare signal handlers.
         */
        if (unshare_flags & CLONE_VM)
                unshare_flags |= CLONE_SIGHAND;
+       /*
+        * If unsharing a signal handlers, must also unshare the signal queues.
+        */
+       if (unshare_flags & CLONE_SIGHAND)
+               unshare_flags |= CLONE_THREAD;
        /*
         * If unsharing namespace, must also unshare filesystem information.
         */