x86/debug: Fix DR_STEP vs ptrace_get_debugreg(6)
[linux-2.6-microblaze.git] / fs / io-wq.c
index 0a182f1..02894df 100644 (file)
 #include <linux/fs_struct.h>
 #include <linux/task_work.h>
 #include <linux/blk-cgroup.h>
+#include <linux/audit.h>
+#include <linux/cpu.h>
 
+#include "../kernel/sched/sched.h"
 #include "io-wq.h"
 
 #define WORKER_IDLE_TIMEOUT    (5 * HZ)
@@ -122,9 +125,13 @@ struct io_wq {
        refcount_t refs;
        struct completion done;
 
+       struct hlist_node cpuhp_node;
+
        refcount_t use_refs;
 };
 
+static enum cpuhp_state io_wq_online;
+
 static bool io_worker_get(struct io_worker *worker)
 {
        return refcount_inc_not_zero(&worker->ref);
@@ -186,7 +193,8 @@ static bool __io_worker_unuse(struct io_wqe *wqe, struct io_worker *worker)
                worker->blkcg_css = NULL;
        }
 #endif
-
+       if (current->signal->rlim[RLIMIT_FSIZE].rlim_cur != RLIM_INFINITY)
+               current->signal->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
        return dropped_lock;
 }
 
@@ -429,14 +437,10 @@ static void io_wq_switch_mm(struct io_worker *worker, struct io_wq_work *work)
                mmput(worker->mm);
                worker->mm = NULL;
        }
-       if (!work->mm)
-               return;
 
-       if (mmget_not_zero(work->mm)) {
-               kthread_use_mm(work->mm);
-               worker->mm = work->mm;
-               /* hang on to this mm */
-               work->mm = NULL;
+       if (mmget_not_zero(work->identity->mm)) {
+               kthread_use_mm(work->identity->mm);
+               worker->mm = work->identity->mm;
                return;
        }
 
@@ -448,9 +452,11 @@ static inline void io_wq_switch_blkcg(struct io_worker *worker,
                                      struct io_wq_work *work)
 {
 #ifdef CONFIG_BLK_CGROUP
-       if (work->blkcg_css != worker->blkcg_css) {
-               kthread_associate_blkcg(work->blkcg_css);
-               worker->blkcg_css = work->blkcg_css;
+       if (!(work->flags & IO_WQ_WORK_BLKCG))
+               return;
+       if (work->identity->blkcg_css != worker->blkcg_css) {
+               kthread_associate_blkcg(work->identity->blkcg_css);
+               worker->blkcg_css = work->identity->blkcg_css;
        }
 #endif
 }
@@ -458,9 +464,9 @@ static inline void io_wq_switch_blkcg(struct io_worker *worker,
 static void io_wq_switch_creds(struct io_worker *worker,
                               struct io_wq_work *work)
 {
-       const struct cred *old_creds = override_creds(work->creds);
+       const struct cred *old_creds = override_creds(work->identity->creds);
 
-       worker->cur_creds = work->creds;
+       worker->cur_creds = work->identity->creds;
        if (worker->saved_creds)
                put_cred(old_creds); /* creds set by previous switch */
        else
@@ -470,20 +476,29 @@ static void io_wq_switch_creds(struct io_worker *worker,
 static void io_impersonate_work(struct io_worker *worker,
                                struct io_wq_work *work)
 {
-       if (work->files && current->files != work->files) {
+       if ((work->flags & IO_WQ_WORK_FILES) &&
+           current->files != work->identity->files) {
                task_lock(current);
-               current->files = work->files;
-               current->nsproxy = work->nsproxy;
+               current->files = work->identity->files;
+               current->nsproxy = work->identity->nsproxy;
                task_unlock(current);
        }
-       if (work->fs && current->fs != work->fs)
-               current->fs = work->fs;
-       if (work->mm != worker->mm)
+       if ((work->flags & IO_WQ_WORK_FS) && current->fs != work->identity->fs)
+               current->fs = work->identity->fs;
+       if ((work->flags & IO_WQ_WORK_MM) && work->identity->mm != worker->mm)
                io_wq_switch_mm(worker, work);
-       if (worker->cur_creds != work->creds)
+       if ((work->flags & IO_WQ_WORK_CREDS) &&
+           worker->cur_creds != work->identity->creds)
                io_wq_switch_creds(worker, work);
-       current->signal->rlim[RLIMIT_FSIZE].rlim_cur = work->fsize;
+       if (work->flags & IO_WQ_WORK_FSIZE)
+               current->signal->rlim[RLIMIT_FSIZE].rlim_cur = work->identity->fsize;
+       else if (current->signal->rlim[RLIMIT_FSIZE].rlim_cur != RLIM_INFINITY)
+               current->signal->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
        io_wq_switch_blkcg(worker, work);
+#ifdef CONFIG_AUDIT
+       current->loginuid = work->identity->loginuid;
+       current->sessionid = work->identity->sessionid;
+#endif
 }
 
 static void io_assign_current_work(struct io_worker *worker,
@@ -496,6 +511,11 @@ static void io_assign_current_work(struct io_worker *worker,
                cond_resched();
        }
 
+#ifdef CONFIG_AUDIT
+       current->loginuid = KUIDT_INIT(AUDIT_UID_UNSET);
+       current->sessionid = AUDIT_SID_UNSET;
+#endif
+
        spin_lock_irq(&worker->lock);
        worker->cur_work = work;
        spin_unlock_irq(&worker->lock);
@@ -676,6 +696,7 @@ static bool create_io_worker(struct io_wq *wq, struct io_wqe *wqe, int index)
                kfree(worker);
                return false;
        }
+       kthread_bind_mask(worker->task, cpumask_of_node(wqe->node));
 
        raw_spin_lock_irq(&wqe->lock);
        hlist_nulls_add_head_rcu(&worker->nulls_node, &wqe->free_list);
@@ -1076,10 +1097,12 @@ struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data)
                return ERR_PTR(-ENOMEM);
 
        wq->wqes = kcalloc(nr_node_ids, sizeof(struct io_wqe *), GFP_KERNEL);
-       if (!wq->wqes) {
-               kfree(wq);
-               return ERR_PTR(-ENOMEM);
-       }
+       if (!wq->wqes)
+               goto err_wq;
+
+       ret = cpuhp_state_add_instance_nocalls(io_wq_online, &wq->cpuhp_node);
+       if (ret)
+               goto err_wqes;
 
        wq->free_work = data->free_work;
        wq->do_work = data->do_work;
@@ -1087,6 +1110,7 @@ struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data)
        /* caller must already hold a reference to this */
        wq->user = data->user;
 
+       ret = -ENOMEM;
        for_each_node(node) {
                struct io_wqe *wqe;
                int alloc_node = node;
@@ -1130,9 +1154,12 @@ struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data)
        ret = PTR_ERR(wq->manager);
        complete(&wq->done);
 err:
+       cpuhp_state_remove_instance_nocalls(io_wq_online, &wq->cpuhp_node);
        for_each_node(node)
                kfree(wq->wqes[node]);
+err_wqes:
        kfree(wq->wqes);
+err_wq:
        kfree(wq);
        return ERR_PTR(ret);
 }
@@ -1149,6 +1176,8 @@ static void __io_wq_destroy(struct io_wq *wq)
 {
        int node;
 
+       cpuhp_state_remove_instance_nocalls(io_wq_online, &wq->cpuhp_node);
+
        set_bit(IO_WQ_BIT_EXIT, &wq->state);
        if (wq->manager)
                kthread_stop(wq->manager);
@@ -1176,3 +1205,41 @@ struct task_struct *io_wq_get_task(struct io_wq *wq)
 {
        return wq->manager;
 }
+
+static bool io_wq_worker_affinity(struct io_worker *worker, void *data)
+{
+       struct task_struct *task = worker->task;
+       struct rq_flags rf;
+       struct rq *rq;
+
+       rq = task_rq_lock(task, &rf);
+       do_set_cpus_allowed(task, cpumask_of_node(worker->wqe->node));
+       task->flags |= PF_NO_SETAFFINITY;
+       task_rq_unlock(rq, task, &rf);
+       return false;
+}
+
+static int io_wq_cpu_online(unsigned int cpu, struct hlist_node *node)
+{
+       struct io_wq *wq = hlist_entry_safe(node, struct io_wq, cpuhp_node);
+       int i;
+
+       rcu_read_lock();
+       for_each_node(i)
+               io_wq_for_each_worker(wq->wqes[i], io_wq_worker_affinity, NULL);
+       rcu_read_unlock();
+       return 0;
+}
+
+static __init int io_wq_init(void)
+{
+       int ret;
+
+       ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "io-wq/online",
+                                       io_wq_cpu_online, NULL);
+       if (ret < 0)
+               return ret;
+       io_wq_online = ret;
+       return 0;
+}
+subsys_initcall(io_wq_init);