diff options
author | Tony Luck <tony.luck@intel.com> | 2023-09-13 16:45:14 -0700 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2023-09-19 14:13:59 -0700 |
commit | 5f17ce154cce86d2a5de5599418d9f8226db3172 (patch) | |
tree | c8e972d4311a98c3575c03caa949998181d36daf | |
parent | edb3b594f3573000420d57343b9023707f774b03 (diff) | |
download | linux-5f17ce154cce86d2a5de5599418d9f8226db3172.tar.gz |
resctrl2: Add "write()" operation to tasks file
Writing a task id to the "tasks" file in a resctrl group assigns
that task to that group.
Signed-off-by: Tony Luck <tony.luck@intel.com>
-rw-r--r-- | arch/x86/include/asm/resctrl.h | 7 | ||||
-rw-r--r-- | fs/resctrl2/internal.h | 2 | ||||
-rw-r--r-- | fs/resctrl2/kernfs.c | 31 | ||||
-rw-r--r-- | fs/resctrl2/tasks.c | 74 |
4 files changed, 114 insertions, 0 deletions
diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h index 1fc8dea4f3d090..cc18045027b3d1 100644 --- a/arch/x86/include/asm/resctrl.h +++ b/arch/x86/include/asm/resctrl.h @@ -116,6 +116,13 @@ static inline bool arch_is_resctrl_id_match(struct task_struct *t, struct resctr return is_closid_match(t, rg); } +static inline bool arch_set_task_ids(struct task_struct *t, struct resctrl_group *rg) +{ + WRITE_ONCE(t->resctrl_ids, rg->resctrl_ids); + + return true; +} + #else static inline void resctrl_sched_in(struct task_struct *tsk) {} diff --git a/fs/resctrl2/internal.h b/fs/resctrl2/internal.h index a0a92b0e78643a..55e1c53768203b 100644 --- a/fs/resctrl2/internal.h +++ b/fs/resctrl2/internal.h @@ -52,6 +52,8 @@ struct info_file_info { struct core_file_info { struct resctrl_group *rg; int (*show)(struct seq_file *sf, struct resctrl_group *rg); + ssize_t (*write)(char *buf, size_t nbytes, struct resctrl_group *rg, + struct kernfs_open_file *of); }; #define RESCTRL_GROUP 5 diff --git a/fs/resctrl2/kernfs.c b/fs/resctrl2/kernfs.c index 69ba3479dccdaa..aaf4d271f4bf6d 100644 --- a/fs/resctrl2/kernfs.c +++ b/fs/resctrl2/kernfs.c @@ -38,9 +38,40 @@ out: return ret; } +static ssize_t resctrl_file_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, loff_t off) +{ + struct resctrl_node_info *rni; + struct core_file_info *cfi; + int ret = -EOPNOTSUPP; + + rni = resctrl_kn_lock_live(of->kn); + + if (!rni) { + ret = -ENOENT; + goto out; + } + + switch (rni->type) { + case RESCTRL_COREFILE: + cfi = (struct core_file_info *)&rni->priv; + if (cfi->write) + ret = cfi->write(buf, nbytes, cfi->rg, of); + break; + default: + ret = -EOPNOTSUPP; + break; + } +out: + resctrl_kn_unlock(of->kn); + + return ret ?: nbytes; +} + struct kernfs_ops resctrl_file_ops = { .atomic_write_len = PAGE_SIZE, .seq_show = resctrl_file_show, + .write = resctrl_file_write, }; /* Set uid and gid of dirs and files to that of the creator */ diff --git a/fs/resctrl2/tasks.c b/fs/resctrl2/tasks.c index f7765cbff84836..b3817a9b7e1b75 100644 --- a/fs/resctrl2/tasks.c +++ b/fs/resctrl2/tasks.c @@ -26,6 +26,79 @@ static int tasks_seq_show(struct seq_file *m, struct resctrl_group *rg) return 0; } +static int __resctrl_move_task(struct task_struct *tsk, + struct resctrl_group *rg) +{ + /* If the task is already in group, no need to move the task. */ + if (tsk->resctrl_ids == rg->resctrl_ids) + return 0; + + /* Change ID in task structure first */ + if (!arch_set_task_ids(tsk, rg)) + return -EINVAL; + + return 0; +} + +static int resctrl_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 resctrl_move_task(pid_t pid, struct resctrl_group *rg, 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 = resctrl_task_write_permission(tsk, of); + if (!ret) + ret = __resctrl_move_task(tsk, rg); + + put_task_struct(tsk); + return ret; +} + +static ssize_t tasks_write(char *buf, size_t nbytes, struct resctrl_group *rg, + struct kernfs_open_file *of) +{ + pid_t pid; + + if (kstrtoint(strstrip(buf), 0, &pid) || pid < 0) + return -EINVAL; + + return resctrl_move_task(pid, rg, of); +} + bool resctrl_add_task_file(struct kernfs_node *parent_kn) { struct resctrl_node_info *rni, *prni; @@ -38,6 +111,7 @@ bool resctrl_add_task_file(struct kernfs_node *parent_kn) cfi = (struct core_file_info *)&rni->priv; cfi->rg = (struct resctrl_group *)&prni->priv; cfi->show = tasks_seq_show; + cfi->write = tasks_write; return true; } |