perf intel-pt: Use itrace error flags to suppress some errors
[linux-2.6-microblaze.git] / kernel / fork.c
index 1b94965..76d3f33 100644 (file)
@@ -359,7 +359,13 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig)
        struct vm_area_struct *new = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
 
        if (new) {
-               *new = *orig;
+               ASSERT_EXCLUSIVE_WRITER(orig->vm_flags);
+               ASSERT_EXCLUSIVE_WRITER(orig->vm_file);
+               /*
+                * orig->shared.rb may be modified concurrently, but the clone
+                * will be reinitialized.
+                */
+               *new = data_race(*orig);
                INIT_LIST_HEAD(&new->anon_vma_chain);
                new->vm_next = new->vm_prev = NULL;
        }
@@ -473,7 +479,6 @@ void free_task(struct task_struct *tsk)
 #endif
        rt_mutex_debug_task_free(tsk);
        ftrace_graph_exit_task(tsk);
-       put_seccomp_filter(tsk);
        arch_release_task_struct(tsk);
        if (tsk->flags & PF_KTHREAD)
                free_kthread_struct(tsk);
@@ -1474,7 +1479,7 @@ static int copy_files(unsigned long clone_flags, struct task_struct *tsk)
                goto out;
        }
 
-       newf = dup_fd(oldf, &error);
+       newf = dup_fd(oldf, NR_OPEN_MAX, &error);
        if (!newf)
                goto out;
 
@@ -1950,8 +1955,8 @@ static __latent_entropy struct task_struct *copy_process(
 
        rt_mutex_init_task(p);
 
+       lockdep_assert_irqs_enabled();
 #ifdef CONFIG_PROVE_LOCKING
-       DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
        DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
 #endif
        retval = -EAGAIN;
@@ -2031,19 +2036,11 @@ static __latent_entropy struct task_struct *copy_process(
        seqcount_init(&p->mems_allowed_seq);
 #endif
 #ifdef CONFIG_TRACE_IRQFLAGS
-       p->irq_events = 0;
-       p->hardirqs_enabled = 0;
-       p->hardirq_enable_ip = 0;
-       p->hardirq_enable_event = 0;
-       p->hardirq_disable_ip = _THIS_IP_;
-       p->hardirq_disable_event = 0;
-       p->softirqs_enabled = 1;
-       p->softirq_enable_ip = _THIS_IP_;
-       p->softirq_enable_event = 0;
-       p->softirq_disable_ip = 0;
-       p->softirq_disable_event = 0;
-       p->hardirq_context = 0;
-       p->softirq_context = 0;
+       memset(&p->irqtrace, 0, sizeof(p->irqtrace));
+       p->irqtrace.hardirq_disable_ip  = _THIS_IP_;
+       p->irqtrace.softirq_enable_ip   = _THIS_IP_;
+       p->softirqs_enabled             = 1;
+       p->softirq_context              = 0;
 #endif
 
        p->pagefault_disabled = 0;
@@ -2100,8 +2097,7 @@ static __latent_entropy struct task_struct *copy_process(
        retval = copy_io(clone_flags, p);
        if (retval)
                goto bad_fork_cleanup_namespaces;
-       retval = copy_thread_tls(clone_flags, args->stack, args->stack_size, p,
-                                args->tls);
+       retval = copy_thread(clone_flags, args->stack, args->stack_size, p, args->tls);
        if (retval)
                goto bad_fork_cleanup_io;
 
@@ -2300,6 +2296,7 @@ static __latent_entropy struct task_struct *copy_process(
        write_unlock_irq(&tasklist_lock);
 
        proc_fork_connector(p);
+       sched_post_fork(p);
        cgroup_post_fork(p, args);
        perf_event_fork(p);
 
@@ -2418,6 +2415,20 @@ long _do_fork(struct kernel_clone_args *args)
        int trace = 0;
        long nr;
 
+       /*
+        * For legacy clone() calls, CLONE_PIDFD uses the parent_tid argument
+        * to return the pidfd. Hence, CLONE_PIDFD and CLONE_PARENT_SETTID are
+        * mutually exclusive. With clone3() CLONE_PIDFD has grown a separate
+        * field in struct clone_args and it still doesn't make sense to have
+        * them both point at the same memory location. Performing this check
+        * here has the advantage that we don't need to have a separate helper
+        * to check for legacy clone().
+        */
+       if ((args->flags & CLONE_PIDFD) &&
+           (args->flags & CLONE_PARENT_SETTID) &&
+           (args->pidfd == args->parent_tid))
+               return -EINVAL;
+
        /*
         * Determine whether and which event to report to ptracer.  When
         * called from kernel_thread or CLONE_UNTRACED is explicitly
@@ -2475,42 +2486,6 @@ long _do_fork(struct kernel_clone_args *args)
        return nr;
 }
 
-bool legacy_clone_args_valid(const struct kernel_clone_args *kargs)
-{
-       /* clone(CLONE_PIDFD) uses parent_tidptr to return a pidfd */
-       if ((kargs->flags & CLONE_PIDFD) &&
-           (kargs->flags & CLONE_PARENT_SETTID))
-               return false;
-
-       return true;
-}
-
-#ifndef CONFIG_HAVE_COPY_THREAD_TLS
-/* For compatibility with architectures that call do_fork directly rather than
- * using the syscall entry points below. */
-long do_fork(unsigned long clone_flags,
-             unsigned long stack_start,
-             unsigned long stack_size,
-             int __user *parent_tidptr,
-             int __user *child_tidptr)
-{
-       struct kernel_clone_args args = {
-               .flags          = (lower_32_bits(clone_flags) & ~CSIGNAL),
-               .pidfd          = parent_tidptr,
-               .child_tid      = child_tidptr,
-               .parent_tid     = parent_tidptr,
-               .exit_signal    = (lower_32_bits(clone_flags) & CSIGNAL),
-               .stack          = stack_start,
-               .stack_size     = stack_size,
-       };
-
-       if (!legacy_clone_args_valid(&args))
-               return -EINVAL;
-
-       return _do_fork(&args);
-}
-#endif
-
 /*
  * Create a kernel thread.
  */
@@ -2589,24 +2564,12 @@ SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
                .tls            = tls,
        };
 
-       if (!legacy_clone_args_valid(&args))
-               return -EINVAL;
-
        return _do_fork(&args);
 }
 #endif
 
 #ifdef __ARCH_WANT_SYS_CLONE3
 
-/*
- * copy_thread implementations handle CLONE_SETTLS by reading the TLS value from
- * the registers containing the syscall arguments for clone. This doesn't work
- * with clone3 since the TLS value is passed in clone_args instead.
- */
-#ifndef CONFIG_HAVE_COPY_THREAD_TLS
-#error clone3 requires copy_thread_tls support in arch
-#endif
-
 noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,
                                              struct clone_args __user *uargs,
                                              size_t usize)
@@ -2903,14 +2866,15 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
 /*
  * Unshare file descriptor table if it is being shared
  */
-static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp)
+int unshare_fd(unsigned long unshare_flags, unsigned int max_fds,
+              struct files_struct **new_fdp)
 {
        struct files_struct *fd = current->files;
        int error = 0;
 
        if ((unshare_flags & CLONE_FILES) &&
            (fd && atomic_read(&fd->count) > 1)) {
-               *new_fdp = dup_fd(fd, &error);
+               *new_fdp = dup_fd(fd, max_fds, &error);
                if (!*new_fdp)
                        return error;
        }
@@ -2921,7 +2885,7 @@ static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp
 /*
  * unshare allows a process to 'unshare' part of the process
  * context which was originally shared using clone.  copy_*
- * functions used by do_fork() cannot be used here directly
+ * functions used by _do_fork() cannot be used here directly
  * because they modify an inactive task_struct that is being
  * constructed. Here we are modifying the current, active,
  * task_struct.
@@ -2970,7 +2934,7 @@ int ksys_unshare(unsigned long unshare_flags)
        err = unshare_fs(unshare_flags, &new_fs);
        if (err)
                goto bad_unshare_out;
-       err = unshare_fd(unshare_flags, &new_fd);
+       err = unshare_fd(unshare_flags, NR_OPEN_MAX, &new_fd);
        if (err)
                goto bad_unshare_cleanup_fs;
        err = unshare_userns(unshare_flags, &new_cred);
@@ -3059,7 +3023,7 @@ int unshare_files(struct files_struct **displaced)
        struct files_struct *copy = NULL;
        int error;
 
-       error = unshare_fd(CLONE_FILES, &copy);
+       error = unshare_fd(CLONE_FILES, NR_OPEN_MAX, &copy);
        if (error || !copy) {
                *displaced = NULL;
                return error;