Merge branch 'work.iov_iter' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[sfrench/cifs-2.6.git] / kernel / kthread.c
index ba3992c8c3753bcc0785ecf998e457d21c013873..8af313081b0d9a7f626f6b3b496119737e9e89a6 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/freezer.h>
 #include <linux/ptrace.h>
 #include <linux/uaccess.h>
-#include <linux/cgroup.h>
 #include <trace/events/sched.h>
 
 static DEFINE_SPINLOCK(kthread_create_lock);
@@ -47,6 +46,9 @@ struct kthread {
        void *data;
        struct completion parked;
        struct completion exited;
+#ifdef CONFIG_BLK_CGROUP
+       struct cgroup_subsys_state *blkcg_css;
+#endif
 };
 
 enum KTHREAD_BITS {
@@ -74,11 +76,17 @@ static inline struct kthread *to_kthread(struct task_struct *k)
 
 void free_kthread_struct(struct task_struct *k)
 {
+       struct kthread *kthread;
+
        /*
         * Can be NULL if this kthread was created by kernel_thread()
         * or if kmalloc() in kthread() failed.
         */
-       kfree(to_kthread(k));
+       kthread = to_kthread(k);
+#ifdef CONFIG_BLK_CGROUP
+       WARN_ON_ONCE(kthread && kthread->blkcg_css);
+#endif
+       kfree(kthread);
 }
 
 /**
@@ -196,7 +204,7 @@ static int kthread(void *_create)
        struct kthread *self;
        int ret;
 
-       self = kmalloc(sizeof(*self), GFP_KERNEL);
+       self = kzalloc(sizeof(*self), GFP_KERNEL);
        set_kthread_struct(self);
 
        /* If user was SIGKILLed, I release the structure. */
@@ -212,7 +220,6 @@ static int kthread(void *_create)
                do_exit(-ENOMEM);
        }
 
-       self->flags = 0;
        self->data = data;
        init_completion(&self->exited);
        init_completion(&self->parked);
@@ -1152,3 +1159,54 @@ void kthread_destroy_worker(struct kthread_worker *worker)
        kfree(worker);
 }
 EXPORT_SYMBOL(kthread_destroy_worker);
+
+#ifdef CONFIG_BLK_CGROUP
+/**
+ * kthread_associate_blkcg - associate blkcg to current kthread
+ * @css: the cgroup info
+ *
+ * Current thread must be a kthread. The thread is running jobs on behalf of
+ * other threads. In some cases, we expect the jobs attach cgroup info of
+ * original threads instead of that of current thread. This function stores
+ * original thread's cgroup info in current kthread context for later
+ * retrieval.
+ */
+void kthread_associate_blkcg(struct cgroup_subsys_state *css)
+{
+       struct kthread *kthread;
+
+       if (!(current->flags & PF_KTHREAD))
+               return;
+       kthread = to_kthread(current);
+       if (!kthread)
+               return;
+
+       if (kthread->blkcg_css) {
+               css_put(kthread->blkcg_css);
+               kthread->blkcg_css = NULL;
+       }
+       if (css) {
+               css_get(css);
+               kthread->blkcg_css = css;
+       }
+}
+EXPORT_SYMBOL(kthread_associate_blkcg);
+
+/**
+ * kthread_blkcg - get associated blkcg css of current kthread
+ *
+ * Current thread must be a kthread.
+ */
+struct cgroup_subsys_state *kthread_blkcg(void)
+{
+       struct kthread *kthread;
+
+       if (current->flags & PF_KTHREAD) {
+               kthread = to_kthread(current);
+               if (kthread)
+                       return kthread->blkcg_css;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(kthread_blkcg);
+#endif