]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - kernel/kthread.c
coredump: clarify "unsafe core_pattern" warning
[mirror_ubuntu-bionic-kernel.git] / kernel / kthread.c
index be2cc1f9dd571b8407044de18710c8695e8af220..2318fba86277180a01aa18aa853badef4c914381 100644 (file)
@@ -53,20 +53,29 @@ enum KTHREAD_BITS {
        KTHREAD_IS_PARKED,
 };
 
-#define __to_kthread(vfork)    \
-       container_of(vfork, struct kthread, exited)
+static inline void set_kthread_struct(void *kthread)
+{
+       /*
+        * We abuse ->set_child_tid to avoid the new member and because it
+        * can't be wrongly copied by copy_process(). We also rely on fact
+        * that the caller can't exec, so PF_KTHREAD can't be cleared.
+        */
+       current->set_child_tid = (__force void __user *)kthread;
+}
 
 static inline struct kthread *to_kthread(struct task_struct *k)
 {
-       return __to_kthread(k->vfork_done);
+       WARN_ON(!(k->flags & PF_KTHREAD));
+       return (__force void *)k->set_child_tid;
 }
 
-static struct kthread *to_live_kthread(struct task_struct *k)
+void free_kthread_struct(struct task_struct *k)
 {
-       struct completion *vfork = ACCESS_ONCE(k->vfork_done);
-       if (likely(vfork) && try_get_task_stack(k))
-               return __to_kthread(vfork);
-       return NULL;
+       /*
+        * Can be NULL if this kthread was created by kernel_thread()
+        * or if kmalloc() in kthread() failed.
+        */
+       kfree(to_kthread(k));
 }
 
 /**
@@ -181,14 +190,11 @@ static int kthread(void *_create)
        int (*threadfn)(void *data) = create->threadfn;
        void *data = create->data;
        struct completion *done;
-       struct kthread self;
+       struct kthread *self;
        int ret;
 
-       self.flags = 0;
-       self.data = data;
-       init_completion(&self.exited);
-       init_completion(&self.parked);
-       current->vfork_done = &self.exited;
+       self = kmalloc(sizeof(*self), GFP_KERNEL);
+       set_kthread_struct(self);
 
        /* If user was SIGKILLed, I release the structure. */
        done = xchg(&create->done, NULL);
@@ -196,6 +202,19 @@ static int kthread(void *_create)
                kfree(create);
                do_exit(-EINTR);
        }
+
+       if (!self) {
+               create->result = ERR_PTR(-ENOMEM);
+               complete(done);
+               do_exit(-ENOMEM);
+       }
+
+       self->flags = 0;
+       self->data = data;
+       init_completion(&self->exited);
+       init_completion(&self->parked);
+       current->vfork_done = &self->exited;
+
        /* OK, tell user we're spawned, wait for stop or wakeup */
        __set_current_state(TASK_UNINTERRUPTIBLE);
        create->result = current;
@@ -203,12 +222,10 @@ static int kthread(void *_create)
        schedule();
 
        ret = -EINTR;
-
-       if (!test_bit(KTHREAD_SHOULD_STOP, &self.flags)) {
-               __kthread_parkme(&self);
+       if (!test_bit(KTHREAD_SHOULD_STOP, &self->flags)) {
+               __kthread_parkme(self);
                ret = threadfn(data);
        }
-       /* we can't just return, we must preserve "self" on stack */
        do_exit(ret);
 }
 
@@ -244,7 +261,8 @@ static void create_kthread(struct kthread_create_info *create)
        }
 }
 
-static struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data),
+static __printf(4, 0)
+struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data),
                                                    void *data, int node,
                                                    const char namefmt[],
                                                    va_list args)
@@ -409,8 +427,18 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
        return p;
 }
 
-static void __kthread_unpark(struct task_struct *k, struct kthread *kthread)
+/**
+ * kthread_unpark - unpark a thread created by kthread_create().
+ * @k:         thread created by kthread_create().
+ *
+ * Sets kthread_should_park() for @k to return false, wakes it, and
+ * waits for it to return. If the thread is marked percpu then its
+ * bound to the cpu again.
+ */
+void kthread_unpark(struct task_struct *k)
 {
+       struct kthread *kthread = to_kthread(k);
+
        clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
        /*
         * We clear the IS_PARKED bit here as we don't wait
@@ -428,24 +456,6 @@ static void __kthread_unpark(struct task_struct *k, struct kthread *kthread)
                wake_up_state(k, TASK_PARKED);
        }
 }
-
-/**
- * kthread_unpark - unpark a thread created by kthread_create().
- * @k:         thread created by kthread_create().
- *
- * Sets kthread_should_park() for @k to return false, wakes it, and
- * waits for it to return. If the thread is marked percpu then its
- * bound to the cpu again.
- */
-void kthread_unpark(struct task_struct *k)
-{
-       struct kthread *kthread = to_live_kthread(k);
-
-       if (kthread) {
-               __kthread_unpark(k, kthread);
-               put_task_stack(k);
-       }
-}
 EXPORT_SYMBOL_GPL(kthread_unpark);
 
 /**
@@ -462,21 +472,20 @@ EXPORT_SYMBOL_GPL(kthread_unpark);
  */
 int kthread_park(struct task_struct *k)
 {
-       struct kthread *kthread = to_live_kthread(k);
-       int ret = -ENOSYS;
-
-       if (kthread) {
-               if (!test_bit(KTHREAD_IS_PARKED, &kthread->flags)) {
-                       set_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
-                       if (k != current) {
-                               wake_up_process(k);
-                               wait_for_completion(&kthread->parked);
-                       }
+       struct kthread *kthread = to_kthread(k);
+
+       if (WARN_ON(k->flags & PF_EXITING))
+               return -ENOSYS;
+
+       if (!test_bit(KTHREAD_IS_PARKED, &kthread->flags)) {
+               set_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
+               if (k != current) {
+                       wake_up_process(k);
+                       wait_for_completion(&kthread->parked);
                }
-               put_task_stack(k);
-               ret = 0;
        }
-       return ret;
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(kthread_park);
 
@@ -503,14 +512,11 @@ int kthread_stop(struct task_struct *k)
        trace_sched_kthread_stop(k);
 
        get_task_struct(k);
-       kthread = to_live_kthread(k);
-       if (kthread) {
-               set_bit(KTHREAD_SHOULD_STOP, &kthread->flags);
-               __kthread_unpark(k, kthread);
-               wake_up_process(k);
-               wait_for_completion(&kthread->exited);
-               put_task_stack(k);
-       }
+       kthread = to_kthread(k);
+       set_bit(KTHREAD_SHOULD_STOP, &kthread->flags);
+       kthread_unpark(k);
+       wake_up_process(k);
+       wait_for_completion(&kthread->exited);
        ret = k->exit_code;
        put_task_struct(k);
 
@@ -630,12 +636,13 @@ repeat:
 }
 EXPORT_SYMBOL_GPL(kthread_worker_fn);
 
-static struct kthread_worker *
+static __printf(3, 0) struct kthread_worker *
 __kthread_create_worker(int cpu, unsigned int flags,
                        const char namefmt[], va_list args)
 {
        struct kthread_worker *worker;
        struct task_struct *task;
+       int node = -1;
 
        worker = kzalloc(sizeof(*worker), GFP_KERNEL);
        if (!worker)
@@ -643,25 +650,17 @@ __kthread_create_worker(int cpu, unsigned int flags,
 
        kthread_init_worker(worker);
 
-       if (cpu >= 0) {
-               char name[TASK_COMM_LEN];
-
-               /*
-                * kthread_create_worker_on_cpu() allows to pass a generic
-                * namefmt in compare with kthread_create_on_cpu. We need
-                * to format it here.
-                */
-               vsnprintf(name, sizeof(name), namefmt, args);
-               task = kthread_create_on_cpu(kthread_worker_fn, worker,
-                                            cpu, name);
-       } else {
-               task = __kthread_create_on_node(kthread_worker_fn, worker,
-                                               -1, namefmt, args);
-       }
+       if (cpu >= 0)
+               node = cpu_to_node(cpu);
 
+       task = __kthread_create_on_node(kthread_worker_fn, worker,
+                                               node, namefmt, args);
        if (IS_ERR(task))
                goto fail_task;
 
+       if (cpu >= 0)
+               kthread_bind(task, cpu);
+
        worker->flags = flags;
        worker->task = task;
        wake_up_process(task);