Skip to content

Commit

Permalink
Merge tag 'x86_cache_for_v6.5' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/tip/tip

Pull x86 resource control updates from Borislav Petkov:

 - Implement a rename operation in resctrlfs to facilitate handling of
   application containers with dynamically changing task lists

 - When reading the tasks file, show the tasks' pid which are only in
   the current namespace as opposed to showing the pids from the init
   namespace too

 - Other fixes and improvements

* tag 'x86_cache_for_v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  Documentation/x86: Documentation for MON group move feature
  x86/resctrl: Implement rename op for mon groups
  x86/resctrl: Factor rdtgroup lock for multi-file ops
  x86/resctrl: Only show tasks' pid in current pid namespace
  • Loading branch information
torvalds committed Jun 26, 2023
2 parents 5903513 + e0a6ede commit 3e5822e
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 15 deletions.
7 changes: 7 additions & 0 deletions Documentation/arch/x86/resctrl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,13 @@ Removing a directory will move all tasks and cpus owned by the group it
represents to the parent. Removing one of the created CTRL_MON groups
will automatically remove all MON groups below it.

Moving MON group directories to a new parent CTRL_MON group is supported
for the purpose of changing the resource allocations of a MON group
without impacting its monitoring data or assigned tasks. This operation
is not allowed for MON groups which monitor CPUs. No other move
operation is currently allowed other than simply renaming a CTRL_MON or
MON group.

All groups contain the following files:

"tasks":
Expand Down
171 changes: 156 additions & 15 deletions arch/x86/kernel/cpu/resctrl/rdtgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -726,11 +726,15 @@ static ssize_t rdtgroup_tasks_write(struct kernfs_open_file *of,
static void show_rdt_tasks(struct rdtgroup *r, struct seq_file *s)
{
struct task_struct *p, *t;
pid_t pid;

rcu_read_lock();
for_each_process_thread(p, t) {
if (is_closid_match(t, r) || is_rmid_match(t, r))
seq_printf(s, "%d\n", t->pid);
if (is_closid_match(t, r) || is_rmid_match(t, r)) {
pid = task_pid_vnr(t);
if (pid)
seq_printf(s, "%d\n", pid);
}
}
rcu_read_unlock();
}
Expand Down Expand Up @@ -2301,15 +2305,34 @@ static struct rdtgroup *kernfs_to_rdtgroup(struct kernfs_node *kn)
}
}

static void rdtgroup_kn_get(struct rdtgroup *rdtgrp, struct kernfs_node *kn)
{
atomic_inc(&rdtgrp->waitcount);
kernfs_break_active_protection(kn);
}

static void rdtgroup_kn_put(struct rdtgroup *rdtgrp, struct kernfs_node *kn)
{
if (atomic_dec_and_test(&rdtgrp->waitcount) &&
(rdtgrp->flags & RDT_DELETED)) {
if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP ||
rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED)
rdtgroup_pseudo_lock_remove(rdtgrp);
kernfs_unbreak_active_protection(kn);
rdtgroup_remove(rdtgrp);
} else {
kernfs_unbreak_active_protection(kn);
}
}

struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn)
{
struct rdtgroup *rdtgrp = kernfs_to_rdtgroup(kn);

if (!rdtgrp)
return NULL;

atomic_inc(&rdtgrp->waitcount);
kernfs_break_active_protection(kn);
rdtgroup_kn_get(rdtgrp, kn);

mutex_lock(&rdtgroup_mutex);

Expand All @@ -2328,17 +2351,7 @@ void rdtgroup_kn_unlock(struct kernfs_node *kn)
return;

mutex_unlock(&rdtgroup_mutex);

if (atomic_dec_and_test(&rdtgrp->waitcount) &&
(rdtgrp->flags & RDT_DELETED)) {
if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP ||
rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED)
rdtgroup_pseudo_lock_remove(rdtgrp);
kernfs_unbreak_active_protection(kn);
rdtgroup_remove(rdtgrp);
} else {
kernfs_unbreak_active_protection(kn);
}
rdtgroup_kn_put(rdtgrp, kn);
}

static int mkdir_mondata_all(struct kernfs_node *parent_kn,
Expand Down Expand Up @@ -3505,6 +3518,133 @@ static int rdtgroup_rmdir(struct kernfs_node *kn)
return ret;
}

/**
* mongrp_reparent() - replace parent CTRL_MON group of a MON group
* @rdtgrp: the MON group whose parent should be replaced
* @new_prdtgrp: replacement parent CTRL_MON group for @rdtgrp
* @cpus: cpumask provided by the caller for use during this call
*
* Replaces the parent CTRL_MON group for a MON group, resulting in all member
* tasks' CLOSID immediately changing to that of the new parent group.
* Monitoring data for the group is unaffected by this operation.
*/
static void mongrp_reparent(struct rdtgroup *rdtgrp,
struct rdtgroup *new_prdtgrp,
cpumask_var_t cpus)
{
struct rdtgroup *prdtgrp = rdtgrp->mon.parent;

WARN_ON(rdtgrp->type != RDTMON_GROUP);
WARN_ON(new_prdtgrp->type != RDTCTRL_GROUP);

/* Nothing to do when simply renaming a MON group. */
if (prdtgrp == new_prdtgrp)
return;

WARN_ON(list_empty(&prdtgrp->mon.crdtgrp_list));
list_move_tail(&rdtgrp->mon.crdtgrp_list,
&new_prdtgrp->mon.crdtgrp_list);

rdtgrp->mon.parent = new_prdtgrp;
rdtgrp->closid = new_prdtgrp->closid;

/* Propagate updated closid to all tasks in this group. */
rdt_move_group_tasks(rdtgrp, rdtgrp, cpus);

update_closid_rmid(cpus, NULL);
}

static int rdtgroup_rename(struct kernfs_node *kn,
struct kernfs_node *new_parent, const char *new_name)
{
struct rdtgroup *new_prdtgrp;
struct rdtgroup *rdtgrp;
cpumask_var_t tmpmask;
int ret;

rdtgrp = kernfs_to_rdtgroup(kn);
new_prdtgrp = kernfs_to_rdtgroup(new_parent);
if (!rdtgrp || !new_prdtgrp)
return -ENOENT;

/* Release both kernfs active_refs before obtaining rdtgroup mutex. */
rdtgroup_kn_get(rdtgrp, kn);
rdtgroup_kn_get(new_prdtgrp, new_parent);

mutex_lock(&rdtgroup_mutex);

rdt_last_cmd_clear();

/*
* Don't allow kernfs_to_rdtgroup() to return a parent rdtgroup if
* either kernfs_node is a file.
*/
if (kernfs_type(kn) != KERNFS_DIR ||
kernfs_type(new_parent) != KERNFS_DIR) {
rdt_last_cmd_puts("Source and destination must be directories");
ret = -EPERM;
goto out;
}

if ((rdtgrp->flags & RDT_DELETED) || (new_prdtgrp->flags & RDT_DELETED)) {
ret = -ENOENT;
goto out;
}

if (rdtgrp->type != RDTMON_GROUP || !kn->parent ||
!is_mon_groups(kn->parent, kn->name)) {
rdt_last_cmd_puts("Source must be a MON group\n");
ret = -EPERM;
goto out;
}

if (!is_mon_groups(new_parent, new_name)) {
rdt_last_cmd_puts("Destination must be a mon_groups subdirectory\n");
ret = -EPERM;
goto out;
}

/*
* If the MON group is monitoring CPUs, the CPUs must be assigned to the
* current parent CTRL_MON group and therefore cannot be assigned to
* the new parent, making the move illegal.
*/
if (!cpumask_empty(&rdtgrp->cpu_mask) &&
rdtgrp->mon.parent != new_prdtgrp) {
rdt_last_cmd_puts("Cannot move a MON group that monitors CPUs\n");
ret = -EPERM;
goto out;
}

/*
* Allocate the cpumask for use in mongrp_reparent() to avoid the
* possibility of failing to allocate it after kernfs_rename() has
* succeeded.
*/
if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL)) {
ret = -ENOMEM;
goto out;
}

/*
* Perform all input validation and allocations needed to ensure
* mongrp_reparent() will succeed before calling kernfs_rename(),
* otherwise it would be necessary to revert this call if
* mongrp_reparent() failed.
*/
ret = kernfs_rename(kn, new_parent, new_name);
if (!ret)
mongrp_reparent(rdtgrp, new_prdtgrp, tmpmask);

free_cpumask_var(tmpmask);

out:
mutex_unlock(&rdtgroup_mutex);
rdtgroup_kn_put(rdtgrp, kn);
rdtgroup_kn_put(new_prdtgrp, new_parent);
return ret;
}

static int rdtgroup_show_options(struct seq_file *seq, struct kernfs_root *kf)
{
if (resctrl_arch_get_cdp_enabled(RDT_RESOURCE_L3))
Expand All @@ -3522,6 +3662,7 @@ static int rdtgroup_show_options(struct seq_file *seq, struct kernfs_root *kf)
static struct kernfs_syscall_ops rdtgroup_kf_syscall_ops = {
.mkdir = rdtgroup_mkdir,
.rmdir = rdtgroup_rmdir,
.rename = rdtgroup_rename,
.show_options = rdtgroup_show_options,
};

Expand Down

0 comments on commit 3e5822e

Please sign in to comment.