Commit c7d9aac6 authored by Vikas Shivappa's avatar Vikas Shivappa Committed by Thomas Gleixner

x86/intel_rdt/cqm: Add mkdir support for RDT monitoring

Resource control groups can be created using mkdir in resctrl
fs(rdtgroup). In order to extend the resctrl interface to support
monitoring the control groups, extend the current mkdir to support
resource monitoring also.

This allows the rdtgroup created under the root directory to be able to
both control and monitor resources (ctrl_mon group). The ctrl_mon groups
are associated with one CLOSID like the legacy rdtgroups and one
RMID(Resource monitoring ID) as well. Hardware uses RMID to track the
resource usage. Once either of the CLOSID or RMID are exhausted, the
mkdir fails with -ENOSPC. If there are RMIDs in limbo list but not free
an -EBUSY is returned. User can also monitor a subset of the ctrl_mon
rdtgroup's tasks/cpus using the monitor groups. The monitor groups are
created using mkdir under the "mon_groups" directory in every ctrl_mon
group.

[Merged Tony's code: Removed a lot of common mkdir code, a fix to handling
of the list of the child rdtgroups and some cleanups in list
traversal. Also the changes to have similar alloc and free for CLOS/RMID
and return -EBUSY when RMIDs are in limbo and not free]
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
Signed-off-by: default avatarVikas Shivappa <vikas.shivappa@linux.intel.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Cc: ravi.v.shankar@intel.com
Cc: fenghua.yu@intel.com
Cc: peterz@infradead.org
Cc: eranian@google.com
Cc: vikas.shivappa@intel.com
Cc: ak@linux.intel.com
Cc: davidcc@google.com
Cc: reinette.chatre@intel.com
Link: http://lkml.kernel.org/r/1501017287-28083-14-git-send-email-vikas.shivappa@linux.intel.com
parent 65b4f403
...@@ -37,6 +37,25 @@ extern unsigned int intel_cqm_threshold; ...@@ -37,6 +37,25 @@ extern unsigned int intel_cqm_threshold;
extern bool rdt_alloc_capable; extern bool rdt_alloc_capable;
extern bool rdt_mon_capable; extern bool rdt_mon_capable;
extern unsigned int rdt_mon_features; extern unsigned int rdt_mon_features;
enum rdt_group_type {
RDTCTRL_GROUP = 0,
RDTMON_GROUP,
RDT_NUM_GROUP,
};
/**
* struct mongroup - store mon group's data in resctrl fs.
* @parent: parent rdtgrp
* @crdtgrp_list: child rdtgroup node list
* @rmid: rmid for this rdtgroup
*/
struct mongroup {
struct rdtgroup *parent;
struct list_head crdtgrp_list;
u32 rmid;
};
/** /**
* struct rdtgroup - store rdtgroup's data in resctrl file system. * struct rdtgroup - store rdtgroup's data in resctrl file system.
* @kn: kernfs node * @kn: kernfs node
...@@ -46,6 +65,9 @@ extern unsigned int rdt_mon_features; ...@@ -46,6 +65,9 @@ extern unsigned int rdt_mon_features;
* @flags: status bits * @flags: status bits
* @waitcount: how many cpus expect to find this * @waitcount: how many cpus expect to find this
* group when they acquire rdtgroup_mutex * group when they acquire rdtgroup_mutex
* @type: indicates type of this rdtgroup - either
* monitor only or ctrl_mon group
* @mon: mongroup related data
*/ */
struct rdtgroup { struct rdtgroup {
struct kernfs_node *kn; struct kernfs_node *kn;
...@@ -54,6 +76,8 @@ struct rdtgroup { ...@@ -54,6 +76,8 @@ struct rdtgroup {
struct cpumask cpu_mask; struct cpumask cpu_mask;
int flags; int flags;
atomic_t waitcount; atomic_t waitcount;
enum rdt_group_type type;
struct mongroup mon;
}; };
/* rdtgroup.flags */ /* rdtgroup.flags */
...@@ -306,6 +330,8 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of, ...@@ -306,6 +330,8 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
int rdtgroup_schemata_show(struct kernfs_open_file *of, int rdtgroup_schemata_show(struct kernfs_open_file *of,
struct seq_file *s, void *v); struct seq_file *s, void *v);
struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r); struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r);
int alloc_rmid(void);
void free_rmid(u32 rmid);
int rdt_get_mon_l3_config(struct rdt_resource *r); int rdt_get_mon_l3_config(struct rdt_resource *r);
#endif /* _ASM_X86_INTEL_RDT_H */ #endif /* _ASM_X86_INTEL_RDT_H */
...@@ -758,6 +758,39 @@ static int rdtgroup_create_info_dir(struct kernfs_node *parent_kn) ...@@ -758,6 +758,39 @@ static int rdtgroup_create_info_dir(struct kernfs_node *parent_kn)
return ret; return ret;
} }
static int
mongroup_create_dir(struct kernfs_node *parent_kn, struct rdtgroup *prgrp,
char *name, struct kernfs_node **dest_kn)
{
struct kernfs_node *kn;
int ret;
/* create the directory */
kn = kernfs_create_dir(parent_kn, name, parent_kn->mode, prgrp);
if (IS_ERR(kn))
return PTR_ERR(kn);
if (dest_kn)
*dest_kn = kn;
/*
* This extra ref will be put in kernfs_remove() and guarantees
* that @rdtgrp->kn is always accessible.
*/
kernfs_get(kn);
ret = rdtgroup_kn_set_ugid(kn);
if (ret)
goto out_destroy;
kernfs_activate(kn);
return 0;
out_destroy:
kernfs_remove(kn);
return ret;
}
static void l3_qos_cfg_update(void *arg) static void l3_qos_cfg_update(void *arg)
{ {
bool *enable = arg; bool *enable = arg;
...@@ -1085,7 +1118,7 @@ static struct file_system_type rdt_fs_type = { ...@@ -1085,7 +1118,7 @@ static struct file_system_type rdt_fs_type = {
static int mkdir_rdt_prepare(struct kernfs_node *parent_kn, static int mkdir_rdt_prepare(struct kernfs_node *parent_kn,
struct kernfs_node *prgrp_kn, struct kernfs_node *prgrp_kn,
const char *name, umode_t mode, const char *name, umode_t mode,
struct rdtgroup **r) enum rdt_group_type rtype, struct rdtgroup **r)
{ {
struct rdtgroup *prdtgrp, *rdtgrp; struct rdtgroup *prdtgrp, *rdtgrp;
struct kernfs_node *kn; struct kernfs_node *kn;
...@@ -1105,6 +1138,9 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn, ...@@ -1105,6 +1138,9 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn,
goto out_unlock; goto out_unlock;
} }
*r = rdtgrp; *r = rdtgrp;
rdtgrp->mon.parent = prdtgrp;
rdtgrp->type = rtype;
INIT_LIST_HEAD(&rdtgrp->mon.crdtgrp_list);
/* kernfs creates the directory for rdtgrp */ /* kernfs creates the directory for rdtgrp */
kn = kernfs_create_dir(parent_kn, name, mode, rdtgrp); kn = kernfs_create_dir(parent_kn, name, mode, rdtgrp);
...@@ -1127,10 +1163,17 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn, ...@@ -1127,10 +1163,17 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn,
goto out_destroy; goto out_destroy;
files = RFTYPE_BASE | RFTYPE_CTRL; files = RFTYPE_BASE | RFTYPE_CTRL;
files = RFTYPE_BASE | BIT(RF_CTRLSHIFT + rtype);
ret = rdtgroup_add_files(kn, files); ret = rdtgroup_add_files(kn, files);
if (ret) if (ret)
goto out_destroy; goto out_destroy;
if (rdt_mon_capable) {
ret = alloc_rmid();
if (ret < 0)
goto out_destroy;
rdtgrp->mon.rmid = ret;
}
kernfs_activate(kn); kernfs_activate(kn);
/* /*
...@@ -1150,14 +1193,46 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn, ...@@ -1150,14 +1193,46 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn,
static void mkdir_rdt_prepare_clean(struct rdtgroup *rgrp) static void mkdir_rdt_prepare_clean(struct rdtgroup *rgrp)
{ {
kernfs_remove(rgrp->kn); kernfs_remove(rgrp->kn);
free_rmid(rgrp->mon.rmid);
kfree(rgrp); kfree(rgrp);
} }
/*
* Create a monitor group under "mon_groups" directory of a control
* and monitor group(ctrl_mon). This is a resource group
* to monitor a subset of tasks and cpus in its parent ctrl_mon group.
*/
static int rdtgroup_mkdir_mon(struct kernfs_node *parent_kn,
struct kernfs_node *prgrp_kn,
const char *name,
umode_t mode)
{
struct rdtgroup *rdtgrp, *prgrp;
int ret;
ret = mkdir_rdt_prepare(parent_kn, prgrp_kn, name, mode, RDTMON_GROUP,
&rdtgrp);
if (ret)
return ret;
prgrp = rdtgrp->mon.parent;
rdtgrp->closid = prgrp->closid;
/*
* Add the rdtgrp to the list of rdtgrps the parent
* ctrl_mon group has to track.
*/
list_add_tail(&rdtgrp->mon.crdtgrp_list, &prgrp->mon.crdtgrp_list);
rdtgroup_kn_unlock(prgrp_kn);
return ret;
}
/* /*
* These are rdtgroups created under the root directory. Can be used * These are rdtgroups created under the root directory. Can be used
* to allocate resources. * to allocate and monitor resources.
*/ */
static int rdtgroup_mkdir_ctrl(struct kernfs_node *parent_kn, static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn,
struct kernfs_node *prgrp_kn, struct kernfs_node *prgrp_kn,
const char *name, umode_t mode) const char *name, umode_t mode)
{ {
...@@ -1166,7 +1241,8 @@ static int rdtgroup_mkdir_ctrl(struct kernfs_node *parent_kn, ...@@ -1166,7 +1241,8 @@ static int rdtgroup_mkdir_ctrl(struct kernfs_node *parent_kn,
u32 closid; u32 closid;
int ret; int ret;
ret = mkdir_rdt_prepare(parent_kn, prgrp_kn, name, mode, &rdtgrp); ret = mkdir_rdt_prepare(parent_kn, prgrp_kn, name, mode, RDTCTRL_GROUP,
&rdtgrp);
if (ret) if (ret)
return ret; return ret;
...@@ -1179,8 +1255,21 @@ static int rdtgroup_mkdir_ctrl(struct kernfs_node *parent_kn, ...@@ -1179,8 +1255,21 @@ static int rdtgroup_mkdir_ctrl(struct kernfs_node *parent_kn,
rdtgrp->closid = closid; rdtgrp->closid = closid;
list_add(&rdtgrp->rdtgroup_list, &rdt_all_groups); list_add(&rdtgrp->rdtgroup_list, &rdt_all_groups);
if (rdt_mon_capable) {
/*
* Create an empty mon_groups directory to hold the subset
* of tasks and cpus to monitor.
*/
ret = mongroup_create_dir(kn, NULL, "mon_groups", NULL);
if (ret)
goto out_id_free;
}
goto out_unlock; goto out_unlock;
out_id_free:
closid_free(closid);
list_del(&rdtgrp->rdtgroup_list);
out_common_fail: out_common_fail:
mkdir_rdt_prepare_clean(rdtgrp); mkdir_rdt_prepare_clean(rdtgrp);
out_unlock: out_unlock:
...@@ -1188,6 +1277,22 @@ static int rdtgroup_mkdir_ctrl(struct kernfs_node *parent_kn, ...@@ -1188,6 +1277,22 @@ static int rdtgroup_mkdir_ctrl(struct kernfs_node *parent_kn,
return ret; return ret;
} }
/*
* We allow creating mon groups only with in a directory called "mon_groups"
* which is present in every ctrl_mon group. Check if this is a valid
* "mon_groups" directory.
*
* 1. The directory should be named "mon_groups".
* 2. The mon group itself should "not" be named "mon_groups".
* This makes sure "mon_groups" directory always has a ctrl_mon group
* as parent.
*/
static bool is_mon_groups(struct kernfs_node *kn, const char *name)
{
return (!strcmp(kn->name, "mon_groups") &&
strcmp(name, "mon_groups"));
}
static int rdtgroup_mkdir(struct kernfs_node *parent_kn, const char *name, static int rdtgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
umode_t mode) umode_t mode)
{ {
...@@ -1197,10 +1302,18 @@ static int rdtgroup_mkdir(struct kernfs_node *parent_kn, const char *name, ...@@ -1197,10 +1302,18 @@ static int rdtgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
/* /*
* If the parent directory is the root directory and RDT * If the parent directory is the root directory and RDT
* allocation is supported, add a control rdtgroup. * allocation is supported, add a control and monitoring
* subdirectory
*/ */
if (rdt_alloc_capable && parent_kn == rdtgroup_default.kn) if (rdt_alloc_capable && parent_kn == rdtgroup_default.kn)
return rdtgroup_mkdir_ctrl(parent_kn, parent_kn, name, mode); return rdtgroup_mkdir_ctrl_mon(parent_kn, parent_kn, name, mode);
/*
* If RDT monitoring is supported and the parent directory is a valid
* "mon_groups" directory, add a monitoring subdirectory.
*/
if (rdt_mon_capable && is_mon_groups(parent_kn, name))
return rdtgroup_mkdir_mon(parent_kn, parent_kn->parent, name, mode);
return -EPERM; return -EPERM;
} }
...@@ -1280,6 +1393,10 @@ static int __init rdtgroup_setup_root(void) ...@@ -1280,6 +1393,10 @@ static int __init rdtgroup_setup_root(void)
mutex_lock(&rdtgroup_mutex); mutex_lock(&rdtgroup_mutex);
rdtgroup_default.closid = 0; rdtgroup_default.closid = 0;
rdtgroup_default.mon.rmid = 0;
rdtgroup_default.type = RDTCTRL_GROUP;
INIT_LIST_HEAD(&rdtgroup_default.mon.crdtgrp_list);
list_add(&rdtgroup_default.rdtgroup_list, &rdt_all_groups); list_add(&rdtgroup_default.rdtgroup_list, &rdt_all_groups);
ret = rdtgroup_add_files(rdt_root->kn, RF_CTRL_BASE); ret = rdtgroup_add_files(rdt_root->kn, RF_CTRL_BASE);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment