x86/intel_rdt: Add tasks files
The root directory all subdirectories are automatically populated with a read/write (mode 0644) file named "tasks". When read it will show all the task IDs assigned to the resource group. Tasks can be added (one at a time) to a group by writing the task ID to the file. E.g. Membership in a resource group is indicated by a new field in the task_struct "int closid" which holds the CLOSID for each task. The default resource group uses CLOSID=0 which means that all existing tasks when the resctrl file system is mounted belong to the default group. If a group is removed, tasks which are members of that group are moved to the default group. Signed-off-by: Fenghua Yu <fenghua.yu@intel.com> Cc: "Ravi V Shankar" <ravi.v.shankar@intel.com> Cc: "Tony Luck" <tony.luck@intel.com> Cc: "Shaohua Li" <shli@fb.com> Cc: "Sai Prakhya" <sai.praneeth.prakhya@intel.com> Cc: "Peter Zijlstra" <peterz@infradead.org> Cc: "Stephane Eranian" <eranian@google.com> Cc: "Dave Hansen" <dave.hansen@intel.com> Cc: "David Carrillo-Cisneros" <davidcc@google.com> Cc: "Nilay Vaish" <nilayvaish@gmail.com> Cc: "Vikas Shivappa" <vikas.shivappa@linux.intel.com> Cc: "Ingo Molnar" <mingo@elte.hu> Cc: "Borislav Petkov" <bp@suse.de> Cc: "H. Peter Anvin" <h.peter.anvin@intel.com> Link: http://lkml.kernel.org/r/1477692289-37412-8-git-send-email-fenghua.yu@intel.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
Родитель
12e0110c11
Коммит
e02737d5b8
|
@ -28,6 +28,7 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/task_work.h>
|
||||
|
||||
#include <uapi/linux/magic.h>
|
||||
|
||||
|
@ -267,6 +268,162 @@ unlock:
|
|||
return ret ?: nbytes;
|
||||
}
|
||||
|
||||
struct task_move_callback {
|
||||
struct callback_head work;
|
||||
struct rdtgroup *rdtgrp;
|
||||
};
|
||||
|
||||
static void move_myself(struct callback_head *head)
|
||||
{
|
||||
struct task_move_callback *callback;
|
||||
struct rdtgroup *rdtgrp;
|
||||
|
||||
callback = container_of(head, struct task_move_callback, work);
|
||||
rdtgrp = callback->rdtgrp;
|
||||
|
||||
/*
|
||||
* If resource group was deleted before this task work callback
|
||||
* was invoked, then assign the task to root group and free the
|
||||
* resource group.
|
||||
*/
|
||||
if (atomic_dec_and_test(&rdtgrp->waitcount) &&
|
||||
(rdtgrp->flags & RDT_DELETED)) {
|
||||
current->closid = 0;
|
||||
kfree(rdtgrp);
|
||||
}
|
||||
|
||||
kfree(callback);
|
||||
}
|
||||
|
||||
static int __rdtgroup_move_task(struct task_struct *tsk,
|
||||
struct rdtgroup *rdtgrp)
|
||||
{
|
||||
struct task_move_callback *callback;
|
||||
int ret;
|
||||
|
||||
callback = kzalloc(sizeof(*callback), GFP_KERNEL);
|
||||
if (!callback)
|
||||
return -ENOMEM;
|
||||
callback->work.func = move_myself;
|
||||
callback->rdtgrp = rdtgrp;
|
||||
|
||||
/*
|
||||
* Take a refcount, so rdtgrp cannot be freed before the
|
||||
* callback has been invoked.
|
||||
*/
|
||||
atomic_inc(&rdtgrp->waitcount);
|
||||
ret = task_work_add(tsk, &callback->work, true);
|
||||
if (ret) {
|
||||
/*
|
||||
* Task is exiting. Drop the refcount and free the callback.
|
||||
* No need to check the refcount as the group cannot be
|
||||
* deleted before the write function unlocks rdtgroup_mutex.
|
||||
*/
|
||||
atomic_dec(&rdtgrp->waitcount);
|
||||
kfree(callback);
|
||||
} else {
|
||||
tsk->closid = rdtgrp->closid;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rdtgroup_task_write_permission(struct task_struct *task,
|
||||
struct kernfs_open_file *of)
|
||||
{
|
||||
const struct cred *tcred = get_task_cred(task);
|
||||
const struct cred *cred = current_cred();
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Even if we're attaching all tasks in the thread group, we only
|
||||
* need to check permissions on one of them.
|
||||
*/
|
||||
if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
|
||||
!uid_eq(cred->euid, tcred->uid) &&
|
||||
!uid_eq(cred->euid, tcred->suid))
|
||||
ret = -EPERM;
|
||||
|
||||
put_cred(tcred);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rdtgroup_move_task(pid_t pid, struct rdtgroup *rdtgrp,
|
||||
struct kernfs_open_file *of)
|
||||
{
|
||||
struct task_struct *tsk;
|
||||
int ret;
|
||||
|
||||
rcu_read_lock();
|
||||
if (pid) {
|
||||
tsk = find_task_by_vpid(pid);
|
||||
if (!tsk) {
|
||||
rcu_read_unlock();
|
||||
return -ESRCH;
|
||||
}
|
||||
} else {
|
||||
tsk = current;
|
||||
}
|
||||
|
||||
get_task_struct(tsk);
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = rdtgroup_task_write_permission(tsk, of);
|
||||
if (!ret)
|
||||
ret = __rdtgroup_move_task(tsk, rdtgrp);
|
||||
|
||||
put_task_struct(tsk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t rdtgroup_tasks_write(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
struct rdtgroup *rdtgrp;
|
||||
int ret = 0;
|
||||
pid_t pid;
|
||||
|
||||
if (kstrtoint(strstrip(buf), 0, &pid) || pid < 0)
|
||||
return -EINVAL;
|
||||
rdtgrp = rdtgroup_kn_lock_live(of->kn);
|
||||
|
||||
if (rdtgrp)
|
||||
ret = rdtgroup_move_task(pid, rdtgrp, of);
|
||||
else
|
||||
ret = -ENOENT;
|
||||
|
||||
rdtgroup_kn_unlock(of->kn);
|
||||
|
||||
return ret ?: nbytes;
|
||||
}
|
||||
|
||||
static void show_rdt_tasks(struct rdtgroup *r, struct seq_file *s)
|
||||
{
|
||||
struct task_struct *p, *t;
|
||||
|
||||
rcu_read_lock();
|
||||
for_each_process_thread(p, t) {
|
||||
if (t->closid == r->closid)
|
||||
seq_printf(s, "%d\n", t->pid);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static int rdtgroup_tasks_show(struct kernfs_open_file *of,
|
||||
struct seq_file *s, void *v)
|
||||
{
|
||||
struct rdtgroup *rdtgrp;
|
||||
int ret = 0;
|
||||
|
||||
rdtgrp = rdtgroup_kn_lock_live(of->kn);
|
||||
if (rdtgrp)
|
||||
show_rdt_tasks(rdtgrp, s);
|
||||
else
|
||||
ret = -ENOENT;
|
||||
rdtgroup_kn_unlock(of->kn);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Files in each rdtgroup */
|
||||
static struct rftype rdtgroup_base_files[] = {
|
||||
{
|
||||
|
@ -276,6 +433,13 @@ static struct rftype rdtgroup_base_files[] = {
|
|||
.write = rdtgroup_cpus_write,
|
||||
.seq_show = rdtgroup_cpus_show,
|
||||
},
|
||||
{
|
||||
.name = "tasks",
|
||||
.mode = 0644,
|
||||
.kf_ops = &rdtgroup_kf_single_ops,
|
||||
.write = rdtgroup_tasks_write,
|
||||
.seq_show = rdtgroup_tasks_show,
|
||||
},
|
||||
};
|
||||
|
||||
static int rdt_num_closids_show(struct kernfs_open_file *of,
|
||||
|
@ -592,6 +756,13 @@ static void rdt_reset_pqr_assoc_closid(void *v)
|
|||
static void rmdir_all_sub(void)
|
||||
{
|
||||
struct rdtgroup *rdtgrp, *tmp;
|
||||
struct task_struct *p, *t;
|
||||
|
||||
/* move all tasks to default resource group */
|
||||
read_lock(&tasklist_lock);
|
||||
for_each_process_thread(p, t)
|
||||
t->closid = 0;
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
get_cpu();
|
||||
/* Reset PQR_ASSOC MSR on this cpu. */
|
||||
|
@ -712,6 +883,7 @@ out_unlock:
|
|||
|
||||
static int rdtgroup_rmdir(struct kernfs_node *kn)
|
||||
{
|
||||
struct task_struct *p, *t;
|
||||
struct rdtgroup *rdtgrp;
|
||||
int cpu, ret = 0;
|
||||
|
||||
|
@ -721,6 +893,14 @@ static int rdtgroup_rmdir(struct kernfs_node *kn)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Give any tasks back to the default group */
|
||||
read_lock(&tasklist_lock);
|
||||
for_each_process_thread(p, t) {
|
||||
if (t->closid == rdtgrp->closid)
|
||||
t->closid = 0;
|
||||
}
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
/* Give any CPUs back to the default group */
|
||||
cpumask_or(&rdtgroup_default.cpu_mask,
|
||||
&rdtgroup_default.cpu_mask, &rdtgrp->cpu_mask);
|
||||
|
|
|
@ -1791,6 +1791,9 @@ struct task_struct {
|
|||
/* cg_list protected by css_set_lock and tsk->alloc_lock */
|
||||
struct list_head cg_list;
|
||||
#endif
|
||||
#ifdef CONFIG_INTEL_RDT_A
|
||||
int closid;
|
||||
#endif
|
||||
#ifdef CONFIG_FUTEX
|
||||
struct robust_list_head __user *robust_list;
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
|
Загрузка…
Ссылка в новой задаче