Skip to content

Commit e02737d

Browse files
Fenghua YuKAGA-KOKO
authored andcommitted
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 <[email protected]> Cc: "Ravi V Shankar" <[email protected]> Cc: "Tony Luck" <[email protected]> Cc: "Shaohua Li" <[email protected]> Cc: "Sai Prakhya" <[email protected]> Cc: "Peter Zijlstra" <[email protected]> Cc: "Stephane Eranian" <[email protected]> Cc: "Dave Hansen" <[email protected]> Cc: "David Carrillo-Cisneros" <[email protected]> Cc: "Nilay Vaish" <[email protected]> Cc: "Vikas Shivappa" <[email protected]> Cc: "Ingo Molnar" <[email protected]> Cc: "Borislav Petkov" <[email protected]> Cc: "H. Peter Anvin" <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Thomas Gleixner <[email protected]>
1 parent 12e0110 commit e02737d

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed

arch/x86/kernel/cpu/intel_rdt_rdtgroup.c

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <linux/sched.h>
2929
#include <linux/slab.h>
3030
#include <linux/cpu.h>
31+
#include <linux/task_work.h>
3132

3233
#include <uapi/linux/magic.h>
3334

@@ -267,6 +268,162 @@ static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
267268
return ret ?: nbytes;
268269
}
269270

271+
struct task_move_callback {
272+
struct callback_head work;
273+
struct rdtgroup *rdtgrp;
274+
};
275+
276+
static void move_myself(struct callback_head *head)
277+
{
278+
struct task_move_callback *callback;
279+
struct rdtgroup *rdtgrp;
280+
281+
callback = container_of(head, struct task_move_callback, work);
282+
rdtgrp = callback->rdtgrp;
283+
284+
/*
285+
* If resource group was deleted before this task work callback
286+
* was invoked, then assign the task to root group and free the
287+
* resource group.
288+
*/
289+
if (atomic_dec_and_test(&rdtgrp->waitcount) &&
290+
(rdtgrp->flags & RDT_DELETED)) {
291+
current->closid = 0;
292+
kfree(rdtgrp);
293+
}
294+
295+
kfree(callback);
296+
}
297+
298+
static int __rdtgroup_move_task(struct task_struct *tsk,
299+
struct rdtgroup *rdtgrp)
300+
{
301+
struct task_move_callback *callback;
302+
int ret;
303+
304+
callback = kzalloc(sizeof(*callback), GFP_KERNEL);
305+
if (!callback)
306+
return -ENOMEM;
307+
callback->work.func = move_myself;
308+
callback->rdtgrp = rdtgrp;
309+
310+
/*
311+
* Take a refcount, so rdtgrp cannot be freed before the
312+
* callback has been invoked.
313+
*/
314+
atomic_inc(&rdtgrp->waitcount);
315+
ret = task_work_add(tsk, &callback->work, true);
316+
if (ret) {
317+
/*
318+
* Task is exiting. Drop the refcount and free the callback.
319+
* No need to check the refcount as the group cannot be
320+
* deleted before the write function unlocks rdtgroup_mutex.
321+
*/
322+
atomic_dec(&rdtgrp->waitcount);
323+
kfree(callback);
324+
} else {
325+
tsk->closid = rdtgrp->closid;
326+
}
327+
return ret;
328+
}
329+
330+
static int rdtgroup_task_write_permission(struct task_struct *task,
331+
struct kernfs_open_file *of)
332+
{
333+
const struct cred *tcred = get_task_cred(task);
334+
const struct cred *cred = current_cred();
335+
int ret = 0;
336+
337+
/*
338+
* Even if we're attaching all tasks in the thread group, we only
339+
* need to check permissions on one of them.
340+
*/
341+
if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
342+
!uid_eq(cred->euid, tcred->uid) &&
343+
!uid_eq(cred->euid, tcred->suid))
344+
ret = -EPERM;
345+
346+
put_cred(tcred);
347+
return ret;
348+
}
349+
350+
static int rdtgroup_move_task(pid_t pid, struct rdtgroup *rdtgrp,
351+
struct kernfs_open_file *of)
352+
{
353+
struct task_struct *tsk;
354+
int ret;
355+
356+
rcu_read_lock();
357+
if (pid) {
358+
tsk = find_task_by_vpid(pid);
359+
if (!tsk) {
360+
rcu_read_unlock();
361+
return -ESRCH;
362+
}
363+
} else {
364+
tsk = current;
365+
}
366+
367+
get_task_struct(tsk);
368+
rcu_read_unlock();
369+
370+
ret = rdtgroup_task_write_permission(tsk, of);
371+
if (!ret)
372+
ret = __rdtgroup_move_task(tsk, rdtgrp);
373+
374+
put_task_struct(tsk);
375+
return ret;
376+
}
377+
378+
static ssize_t rdtgroup_tasks_write(struct kernfs_open_file *of,
379+
char *buf, size_t nbytes, loff_t off)
380+
{
381+
struct rdtgroup *rdtgrp;
382+
int ret = 0;
383+
pid_t pid;
384+
385+
if (kstrtoint(strstrip(buf), 0, &pid) || pid < 0)
386+
return -EINVAL;
387+
rdtgrp = rdtgroup_kn_lock_live(of->kn);
388+
389+
if (rdtgrp)
390+
ret = rdtgroup_move_task(pid, rdtgrp, of);
391+
else
392+
ret = -ENOENT;
393+
394+
rdtgroup_kn_unlock(of->kn);
395+
396+
return ret ?: nbytes;
397+
}
398+
399+
static void show_rdt_tasks(struct rdtgroup *r, struct seq_file *s)
400+
{
401+
struct task_struct *p, *t;
402+
403+
rcu_read_lock();
404+
for_each_process_thread(p, t) {
405+
if (t->closid == r->closid)
406+
seq_printf(s, "%d\n", t->pid);
407+
}
408+
rcu_read_unlock();
409+
}
410+
411+
static int rdtgroup_tasks_show(struct kernfs_open_file *of,
412+
struct seq_file *s, void *v)
413+
{
414+
struct rdtgroup *rdtgrp;
415+
int ret = 0;
416+
417+
rdtgrp = rdtgroup_kn_lock_live(of->kn);
418+
if (rdtgrp)
419+
show_rdt_tasks(rdtgrp, s);
420+
else
421+
ret = -ENOENT;
422+
rdtgroup_kn_unlock(of->kn);
423+
424+
return ret;
425+
}
426+
270427
/* Files in each rdtgroup */
271428
static struct rftype rdtgroup_base_files[] = {
272429
{
@@ -276,6 +433,13 @@ static struct rftype rdtgroup_base_files[] = {
276433
.write = rdtgroup_cpus_write,
277434
.seq_show = rdtgroup_cpus_show,
278435
},
436+
{
437+
.name = "tasks",
438+
.mode = 0644,
439+
.kf_ops = &rdtgroup_kf_single_ops,
440+
.write = rdtgroup_tasks_write,
441+
.seq_show = rdtgroup_tasks_show,
442+
},
279443
};
280444

281445
static int rdt_num_closids_show(struct kernfs_open_file *of,
@@ -592,6 +756,13 @@ static void rdt_reset_pqr_assoc_closid(void *v)
592756
static void rmdir_all_sub(void)
593757
{
594758
struct rdtgroup *rdtgrp, *tmp;
759+
struct task_struct *p, *t;
760+
761+
/* move all tasks to default resource group */
762+
read_lock(&tasklist_lock);
763+
for_each_process_thread(p, t)
764+
t->closid = 0;
765+
read_unlock(&tasklist_lock);
595766

596767
get_cpu();
597768
/* Reset PQR_ASSOC MSR on this cpu. */
@@ -712,6 +883,7 @@ static int rdtgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
712883

713884
static int rdtgroup_rmdir(struct kernfs_node *kn)
714885
{
886+
struct task_struct *p, *t;
715887
struct rdtgroup *rdtgrp;
716888
int cpu, ret = 0;
717889

@@ -721,6 +893,14 @@ static int rdtgroup_rmdir(struct kernfs_node *kn)
721893
return -ENOENT;
722894
}
723895

896+
/* Give any tasks back to the default group */
897+
read_lock(&tasklist_lock);
898+
for_each_process_thread(p, t) {
899+
if (t->closid == rdtgrp->closid)
900+
t->closid = 0;
901+
}
902+
read_unlock(&tasklist_lock);
903+
724904
/* Give any CPUs back to the default group */
725905
cpumask_or(&rdtgroup_default.cpu_mask,
726906
&rdtgroup_default.cpu_mask, &rdtgrp->cpu_mask);

include/linux/sched.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1791,6 +1791,9 @@ struct task_struct {
17911791
/* cg_list protected by css_set_lock and tsk->alloc_lock */
17921792
struct list_head cg_list;
17931793
#endif
1794+
#ifdef CONFIG_INTEL_RDT_A
1795+
int closid;
1796+
#endif
17941797
#ifdef CONFIG_FUTEX
17951798
struct robust_list_head __user *robust_list;
17961799
#ifdef CONFIG_COMPAT

0 commit comments

Comments
 (0)