Merge tag 'x86_cache_for_v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 cache resource control updates from Borislav Petkov: - Misc cleanups to the resctrl code in preparation for the ARM side (James Morse) - Add support for controlling per-thread memory bandwidth throttling delay values on hw which supports it (Fenghua Yu) * tag 'x86_cache_for_v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/resctrl: Enable user to view thread or core throttling mode x86/resctrl: Enumerate per-thread MBA controls cacheinfo: Move resctrl's get_cache_id() to the cacheinfo header file x86/resctrl: Add struct rdt_cache::arch_has_{sparse, empty}_bitmaps x86/resctrl: Merge AMD/Intel parse_bw() calls x86/resctrl: Add struct rdt_membw::arch_needs_linear to explain AMD/Intel MBA difference x86/resctrl: Use is_closid_match() in more places x86/resctrl: Include pid.h x86/resctrl: Use container_of() in delayed_work handlers x86/resctrl: Fix stale comment x86/resctrl: Remove struct rdt_membw::max_delay x86/resctrl: Remove unused struct mbm_state::chunks_bw
此提交包含在:
@@ -168,6 +168,7 @@ struct rdt_resource rdt_resources_all[] = {
|
||||
.name = "MB",
|
||||
.domains = domain_init(RDT_RESOURCE_MBA),
|
||||
.cache_level = 3,
|
||||
.parse_ctrlval = parse_bw,
|
||||
.format_str = "%d=%*u",
|
||||
.fflags = RFTYPE_RES_MB,
|
||||
},
|
||||
@@ -254,22 +255,30 @@ static bool __get_mem_config_intel(struct rdt_resource *r)
|
||||
{
|
||||
union cpuid_0x10_3_eax eax;
|
||||
union cpuid_0x10_x_edx edx;
|
||||
u32 ebx, ecx;
|
||||
u32 ebx, ecx, max_delay;
|
||||
|
||||
cpuid_count(0x00000010, 3, &eax.full, &ebx, &ecx, &edx.full);
|
||||
r->num_closid = edx.split.cos_max + 1;
|
||||
r->membw.max_delay = eax.split.max_delay + 1;
|
||||
max_delay = eax.split.max_delay + 1;
|
||||
r->default_ctrl = MAX_MBA_BW;
|
||||
r->membw.arch_needs_linear = true;
|
||||
if (ecx & MBA_IS_LINEAR) {
|
||||
r->membw.delay_linear = true;
|
||||
r->membw.min_bw = MAX_MBA_BW - r->membw.max_delay;
|
||||
r->membw.bw_gran = MAX_MBA_BW - r->membw.max_delay;
|
||||
r->membw.min_bw = MAX_MBA_BW - max_delay;
|
||||
r->membw.bw_gran = MAX_MBA_BW - max_delay;
|
||||
} else {
|
||||
if (!rdt_get_mb_table(r))
|
||||
return false;
|
||||
r->membw.arch_needs_linear = false;
|
||||
}
|
||||
r->data_width = 3;
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_PER_THREAD_MBA))
|
||||
r->membw.throttle_mode = THREAD_THROTTLE_PER_THREAD;
|
||||
else
|
||||
r->membw.throttle_mode = THREAD_THROTTLE_MAX;
|
||||
thread_throttle_mode_init();
|
||||
|
||||
r->alloc_capable = true;
|
||||
r->alloc_enabled = true;
|
||||
|
||||
@@ -288,7 +297,13 @@ static bool __rdt_get_mem_config_amd(struct rdt_resource *r)
|
||||
|
||||
/* AMD does not use delay */
|
||||
r->membw.delay_linear = false;
|
||||
r->membw.arch_needs_linear = false;
|
||||
|
||||
/*
|
||||
* AMD does not use memory delay throttle model to control
|
||||
* the allocation like Intel does.
|
||||
*/
|
||||
r->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
|
||||
r->membw.min_bw = 0;
|
||||
r->membw.bw_gran = 1;
|
||||
/* Max value is 2048, Data width should be 4 in decimal */
|
||||
@@ -346,19 +361,6 @@ static void rdt_get_cdp_l2_config(void)
|
||||
rdt_get_cdp_config(RDT_RESOURCE_L2, RDT_RESOURCE_L2CODE);
|
||||
}
|
||||
|
||||
static int get_cache_id(int cpu, int level)
|
||||
{
|
||||
struct cpu_cacheinfo *ci = get_cpu_cacheinfo(cpu);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ci->num_leaves; i++) {
|
||||
if (ci->info_list[i].level == level)
|
||||
return ci->info_list[i].id;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
mba_wrmsr_amd(struct rdt_domain *d, struct msr_param *m, struct rdt_resource *r)
|
||||
{
|
||||
@@ -556,7 +558,7 @@ static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_domain *d)
|
||||
*/
|
||||
static void domain_add_cpu(int cpu, struct rdt_resource *r)
|
||||
{
|
||||
int id = get_cache_id(cpu, r->cache_level);
|
||||
int id = get_cpu_cacheinfo_id(cpu, r->cache_level);
|
||||
struct list_head *add_pos = NULL;
|
||||
struct rdt_domain *d;
|
||||
|
||||
@@ -602,7 +604,7 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
|
||||
|
||||
static void domain_remove_cpu(int cpu, struct rdt_resource *r)
|
||||
{
|
||||
int id = get_cache_id(cpu, r->cache_level);
|
||||
int id = get_cpu_cacheinfo_id(cpu, r->cache_level);
|
||||
struct rdt_domain *d;
|
||||
|
||||
d = rdt_find_domain(r, id, NULL);
|
||||
@@ -918,12 +920,12 @@ static __init void rdt_init_res_defs_intel(void)
|
||||
r->rid == RDT_RESOURCE_L3CODE ||
|
||||
r->rid == RDT_RESOURCE_L2 ||
|
||||
r->rid == RDT_RESOURCE_L2DATA ||
|
||||
r->rid == RDT_RESOURCE_L2CODE)
|
||||
r->cbm_validate = cbm_validate_intel;
|
||||
else if (r->rid == RDT_RESOURCE_MBA) {
|
||||
r->rid == RDT_RESOURCE_L2CODE) {
|
||||
r->cache.arch_has_sparse_bitmaps = false;
|
||||
r->cache.arch_has_empty_bitmaps = false;
|
||||
} else if (r->rid == RDT_RESOURCE_MBA) {
|
||||
r->msr_base = MSR_IA32_MBA_THRTL_BASE;
|
||||
r->msr_update = mba_wrmsr_intel;
|
||||
r->parse_ctrlval = parse_bw_intel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -938,12 +940,12 @@ static __init void rdt_init_res_defs_amd(void)
|
||||
r->rid == RDT_RESOURCE_L3CODE ||
|
||||
r->rid == RDT_RESOURCE_L2 ||
|
||||
r->rid == RDT_RESOURCE_L2DATA ||
|
||||
r->rid == RDT_RESOURCE_L2CODE)
|
||||
r->cbm_validate = cbm_validate_amd;
|
||||
else if (r->rid == RDT_RESOURCE_MBA) {
|
||||
r->rid == RDT_RESOURCE_L2CODE) {
|
||||
r->cache.arch_has_sparse_bitmaps = true;
|
||||
r->cache.arch_has_empty_bitmaps = true;
|
||||
} else if (r->rid == RDT_RESOURCE_MBA) {
|
||||
r->msr_base = MSR_IA32_MBA_BW_BASE;
|
||||
r->msr_update = mba_wrmsr_amd;
|
||||
r->parse_ctrlval = parse_bw_amd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -21,53 +21,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Check whether MBA bandwidth percentage value is correct. The value is
|
||||
* checked against the minimum and maximum bandwidth values specified by
|
||||
* the hardware. The allocated bandwidth percentage is rounded to the next
|
||||
* control step available on the hardware.
|
||||
*/
|
||||
static bool bw_validate_amd(char *buf, unsigned long *data,
|
||||
struct rdt_resource *r)
|
||||
{
|
||||
unsigned long bw;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul(buf, 10, &bw);
|
||||
if (ret) {
|
||||
rdt_last_cmd_printf("Non-decimal digit in MB value %s\n", buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bw < r->membw.min_bw || bw > r->default_ctrl) {
|
||||
rdt_last_cmd_printf("MB value %ld out of range [%d,%d]\n", bw,
|
||||
r->membw.min_bw, r->default_ctrl);
|
||||
return false;
|
||||
}
|
||||
|
||||
*data = roundup(bw, (unsigned long)r->membw.bw_gran);
|
||||
return true;
|
||||
}
|
||||
|
||||
int parse_bw_amd(struct rdt_parse_data *data, struct rdt_resource *r,
|
||||
struct rdt_domain *d)
|
||||
{
|
||||
unsigned long bw_val;
|
||||
|
||||
if (d->have_new_ctrl) {
|
||||
rdt_last_cmd_printf("Duplicate domain %d\n", d->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!bw_validate_amd(data->buf, &bw_val, r))
|
||||
return -EINVAL;
|
||||
|
||||
d->new_ctrl = bw_val;
|
||||
d->have_new_ctrl = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether MBA bandwidth percentage value is correct. The value is
|
||||
* checked against the minimum and max bandwidth values specified by the
|
||||
@@ -82,7 +35,7 @@ static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r)
|
||||
/*
|
||||
* Only linear delay values is supported for current Intel SKUs.
|
||||
*/
|
||||
if (!r->membw.delay_linear) {
|
||||
if (!r->membw.delay_linear && r->membw.arch_needs_linear) {
|
||||
rdt_last_cmd_puts("No support for non-linear MB domains\n");
|
||||
return false;
|
||||
}
|
||||
@@ -104,8 +57,8 @@ static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r)
|
||||
return true;
|
||||
}
|
||||
|
||||
int parse_bw_intel(struct rdt_parse_data *data, struct rdt_resource *r,
|
||||
struct rdt_domain *d)
|
||||
int parse_bw(struct rdt_parse_data *data, struct rdt_resource *r,
|
||||
struct rdt_domain *d)
|
||||
{
|
||||
unsigned long bw_val;
|
||||
|
||||
@@ -123,12 +76,14 @@ int parse_bw_intel(struct rdt_parse_data *data, struct rdt_resource *r,
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether a cache bit mask is valid. The SDM says:
|
||||
* Check whether a cache bit mask is valid.
|
||||
* For Intel the SDM says:
|
||||
* Please note that all (and only) contiguous '1' combinations
|
||||
* are allowed (e.g. FFFFH, 0FF0H, 003CH, etc.).
|
||||
* Additionally Haswell requires at least two bits set.
|
||||
* AMD allows non-contiguous bitmasks.
|
||||
*/
|
||||
bool cbm_validate_intel(char *buf, u32 *data, struct rdt_resource *r)
|
||||
static bool cbm_validate(char *buf, u32 *data, struct rdt_resource *r)
|
||||
{
|
||||
unsigned long first_bit, zero_bit, val;
|
||||
unsigned int cbm_len = r->cache.cbm_len;
|
||||
@@ -140,7 +95,8 @@ bool cbm_validate_intel(char *buf, u32 *data, struct rdt_resource *r)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (val == 0 || val > r->default_ctrl) {
|
||||
if ((!r->cache.arch_has_empty_bitmaps && val == 0) ||
|
||||
val > r->default_ctrl) {
|
||||
rdt_last_cmd_puts("Mask out of range\n");
|
||||
return false;
|
||||
}
|
||||
@@ -148,7 +104,9 @@ bool cbm_validate_intel(char *buf, u32 *data, struct rdt_resource *r)
|
||||
first_bit = find_first_bit(&val, cbm_len);
|
||||
zero_bit = find_next_zero_bit(&val, cbm_len, first_bit);
|
||||
|
||||
if (find_next_bit(&val, cbm_len, zero_bit) < cbm_len) {
|
||||
/* Are non-contiguous bitmaps allowed? */
|
||||
if (!r->cache.arch_has_sparse_bitmaps &&
|
||||
(find_next_bit(&val, cbm_len, zero_bit) < cbm_len)) {
|
||||
rdt_last_cmd_printf("The mask %lx has non-consecutive 1-bits\n", val);
|
||||
return false;
|
||||
}
|
||||
@@ -163,30 +121,6 @@ bool cbm_validate_intel(char *buf, u32 *data, struct rdt_resource *r)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether a cache bit mask is valid. AMD allows non-contiguous
|
||||
* bitmasks
|
||||
*/
|
||||
bool cbm_validate_amd(char *buf, u32 *data, struct rdt_resource *r)
|
||||
{
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul(buf, 16, &val);
|
||||
if (ret) {
|
||||
rdt_last_cmd_printf("Non-hex character in the mask %s\n", buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (val > r->default_ctrl) {
|
||||
rdt_last_cmd_puts("Mask out of range\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
*data = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read one cache bit mask (hex). Check that it is valid for the current
|
||||
* resource type.
|
||||
@@ -212,7 +146,7 @@ int parse_cbm(struct rdt_parse_data *data, struct rdt_resource *r,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!r->cbm_validate(data->buf, &cbm_val, r))
|
||||
if (!cbm_validate(data->buf, &cbm_val, r))
|
||||
return -EINVAL;
|
||||
|
||||
if ((rdtgrp->mode == RDT_MODE_EXCLUSIVE ||
|
||||
|
@@ -283,7 +283,6 @@ struct rftype {
|
||||
* struct mbm_state - status for each MBM counter in each domain
|
||||
* @chunks: Total data moved (multiply by rdt_group.mon_scale to get bytes)
|
||||
* @prev_msr Value of IA32_QM_CTR for this RMID last time we read it
|
||||
* @chunks_bw Total local data moved. Used for bandwidth calculation
|
||||
* @prev_bw_msr:Value of previous IA32_QM_CTR for bandwidth counting
|
||||
* @prev_bw The most recent bandwidth in MBps
|
||||
* @delta_bw Difference between the current and previous bandwidth
|
||||
@@ -292,7 +291,6 @@ struct rftype {
|
||||
struct mbm_state {
|
||||
u64 chunks;
|
||||
u64 prev_msr;
|
||||
u64 chunks_bw;
|
||||
u64 prev_bw_msr;
|
||||
u32 prev_bw;
|
||||
u32 delta_bw;
|
||||
@@ -360,6 +358,8 @@ struct msr_param {
|
||||
* in a cache bit mask
|
||||
* @shareable_bits: Bitmask of shareable resource with other
|
||||
* executing entities
|
||||
* @arch_has_sparse_bitmaps: True if a bitmap like f00f is valid.
|
||||
* @arch_has_empty_bitmaps: True if the '0' bitmap is valid.
|
||||
*/
|
||||
struct rdt_cache {
|
||||
unsigned int cbm_len;
|
||||
@@ -367,25 +367,43 @@ struct rdt_cache {
|
||||
unsigned int cbm_idx_mult;
|
||||
unsigned int cbm_idx_offset;
|
||||
unsigned int shareable_bits;
|
||||
bool arch_has_sparse_bitmaps;
|
||||
bool arch_has_empty_bitmaps;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum membw_throttle_mode - System's memory bandwidth throttling mode
|
||||
* @THREAD_THROTTLE_UNDEFINED: Not relevant to the system
|
||||
* @THREAD_THROTTLE_MAX: Memory bandwidth is throttled at the core
|
||||
* always using smallest bandwidth percentage
|
||||
* assigned to threads, aka "max throttling"
|
||||
* @THREAD_THROTTLE_PER_THREAD: Memory bandwidth is throttled at the thread
|
||||
*/
|
||||
enum membw_throttle_mode {
|
||||
THREAD_THROTTLE_UNDEFINED = 0,
|
||||
THREAD_THROTTLE_MAX,
|
||||
THREAD_THROTTLE_PER_THREAD,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rdt_membw - Memory bandwidth allocation related data
|
||||
* @max_delay: Max throttle delay. Delay is the hardware
|
||||
* representation for memory bandwidth.
|
||||
* @min_bw: Minimum memory bandwidth percentage user can request
|
||||
* @bw_gran: Granularity at which the memory bandwidth is allocated
|
||||
* @delay_linear: True if memory B/W delay is in linear scale
|
||||
* @arch_needs_linear: True if we can't configure non-linear resources
|
||||
* @throttle_mode: Bandwidth throttling mode when threads request
|
||||
* different memory bandwidths
|
||||
* @mba_sc: True if MBA software controller(mba_sc) is enabled
|
||||
* @mb_map: Mapping of memory B/W percentage to memory B/W delay
|
||||
*/
|
||||
struct rdt_membw {
|
||||
u32 max_delay;
|
||||
u32 min_bw;
|
||||
u32 bw_gran;
|
||||
u32 delay_linear;
|
||||
bool mba_sc;
|
||||
u32 *mb_map;
|
||||
u32 min_bw;
|
||||
u32 bw_gran;
|
||||
u32 delay_linear;
|
||||
bool arch_needs_linear;
|
||||
enum membw_throttle_mode throttle_mode;
|
||||
bool mba_sc;
|
||||
u32 *mb_map;
|
||||
};
|
||||
|
||||
static inline bool is_llc_occupancy_enabled(void)
|
||||
@@ -437,7 +455,6 @@ struct rdt_parse_data {
|
||||
* @cache: Cache allocation related data
|
||||
* @format_str: Per resource format string to show domain value
|
||||
* @parse_ctrlval: Per resource function pointer to parse control values
|
||||
* @cbm_validate Cache bitmask validate function
|
||||
* @evt_list: List of monitoring events
|
||||
* @num_rmid: Number of RMIDs available
|
||||
* @mon_scale: cqm counter * mon_scale = occupancy in bytes
|
||||
@@ -464,7 +481,6 @@ struct rdt_resource {
|
||||
int (*parse_ctrlval)(struct rdt_parse_data *data,
|
||||
struct rdt_resource *r,
|
||||
struct rdt_domain *d);
|
||||
bool (*cbm_validate)(char *buf, u32 *data, struct rdt_resource *r);
|
||||
struct list_head evt_list;
|
||||
int num_rmid;
|
||||
unsigned int mon_scale;
|
||||
@@ -474,10 +490,8 @@ struct rdt_resource {
|
||||
|
||||
int parse_cbm(struct rdt_parse_data *data, struct rdt_resource *r,
|
||||
struct rdt_domain *d);
|
||||
int parse_bw_intel(struct rdt_parse_data *data, struct rdt_resource *r,
|
||||
struct rdt_domain *d);
|
||||
int parse_bw_amd(struct rdt_parse_data *data, struct rdt_resource *r,
|
||||
struct rdt_domain *d);
|
||||
int parse_bw(struct rdt_parse_data *data, struct rdt_resource *r,
|
||||
struct rdt_domain *d);
|
||||
|
||||
extern struct mutex rdtgroup_mutex;
|
||||
|
||||
@@ -609,8 +623,7 @@ void cqm_setup_limbo_handler(struct rdt_domain *dom, unsigned long delay_ms);
|
||||
void cqm_handle_limbo(struct work_struct *work);
|
||||
bool has_busy_rmid(struct rdt_resource *r, struct rdt_domain *d);
|
||||
void __check_limbo(struct rdt_domain *d, bool force_free);
|
||||
bool cbm_validate_intel(char *buf, u32 *data, struct rdt_resource *r);
|
||||
bool cbm_validate_amd(char *buf, u32 *data, struct rdt_resource *r);
|
||||
void rdt_domain_reconfigure_cdp(struct rdt_resource *r);
|
||||
void __init thread_throttle_mode_init(void);
|
||||
|
||||
#endif /* _ASM_X86_RESCTRL_INTERNAL_H */
|
||||
|
@@ -279,8 +279,7 @@ static void mbm_bw_count(u32 rmid, struct rmid_read *rr)
|
||||
return;
|
||||
|
||||
chunks = mbm_overflow_count(m->prev_bw_msr, tval, rr->r->mbm_width);
|
||||
m->chunks_bw += chunks;
|
||||
m->chunks = m->chunks_bw;
|
||||
m->chunks += chunks;
|
||||
cur_bw = (chunks * r->mon_scale) >> 20;
|
||||
|
||||
if (m->delta_comp)
|
||||
@@ -478,19 +477,13 @@ void cqm_handle_limbo(struct work_struct *work)
|
||||
mutex_lock(&rdtgroup_mutex);
|
||||
|
||||
r = &rdt_resources_all[RDT_RESOURCE_L3];
|
||||
d = get_domain_from_cpu(cpu, r);
|
||||
|
||||
if (!d) {
|
||||
pr_warn_once("Failure to get domain for limbo worker\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
d = container_of(work, struct rdt_domain, cqm_limbo.work);
|
||||
|
||||
__check_limbo(d, false);
|
||||
|
||||
if (has_busy_rmid(r, d))
|
||||
schedule_delayed_work_on(cpu, &d->cqm_limbo, delay);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&rdtgroup_mutex);
|
||||
}
|
||||
|
||||
@@ -520,10 +513,7 @@ void mbm_handle_overflow(struct work_struct *work)
|
||||
goto out_unlock;
|
||||
|
||||
r = &rdt_resources_all[RDT_RESOURCE_L3];
|
||||
|
||||
d = get_domain_from_cpu(cpu, r);
|
||||
if (!d)
|
||||
goto out_unlock;
|
||||
d = container_of(work, struct rdt_domain, mbm_over.work);
|
||||
|
||||
list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) {
|
||||
mbm_update(r, d, prgrp->mon.rmid);
|
||||
|
@@ -592,6 +592,18 @@ static int __rdtgroup_move_task(struct task_struct *tsk,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool is_closid_match(struct task_struct *t, struct rdtgroup *r)
|
||||
{
|
||||
return (rdt_alloc_capable &&
|
||||
(r->type == RDTCTRL_GROUP) && (t->closid == r->closid));
|
||||
}
|
||||
|
||||
static bool is_rmid_match(struct task_struct *t, struct rdtgroup *r)
|
||||
{
|
||||
return (rdt_mon_capable &&
|
||||
(r->type == RDTMON_GROUP) && (t->rmid == r->mon.rmid));
|
||||
}
|
||||
|
||||
/**
|
||||
* rdtgroup_tasks_assigned - Test if tasks have been assigned to resource group
|
||||
* @r: Resource group
|
||||
@@ -607,8 +619,7 @@ int rdtgroup_tasks_assigned(struct rdtgroup *r)
|
||||
|
||||
rcu_read_lock();
|
||||
for_each_process_thread(p, t) {
|
||||
if ((r->type == RDTCTRL_GROUP && t->closid == r->closid) ||
|
||||
(r->type == RDTMON_GROUP && t->rmid == r->mon.rmid)) {
|
||||
if (is_closid_match(t, r) || is_rmid_match(t, r)) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
@@ -706,8 +717,7 @@ static void show_rdt_tasks(struct rdtgroup *r, struct seq_file *s)
|
||||
|
||||
rcu_read_lock();
|
||||
for_each_process_thread(p, t) {
|
||||
if ((r->type == RDTCTRL_GROUP && t->closid == r->closid) ||
|
||||
(r->type == RDTMON_GROUP && t->rmid == r->mon.rmid))
|
||||
if (is_closid_match(t, r) || is_rmid_match(t, r))
|
||||
seq_printf(s, "%d\n", t->pid);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
@@ -1017,6 +1027,19 @@ static int max_threshold_occ_show(struct kernfs_open_file *of,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdt_thread_throttle_mode_show(struct kernfs_open_file *of,
|
||||
struct seq_file *seq, void *v)
|
||||
{
|
||||
struct rdt_resource *r = of->kn->parent->priv;
|
||||
|
||||
if (r->membw.throttle_mode == THREAD_THROTTLE_PER_THREAD)
|
||||
seq_puts(seq, "per-thread\n");
|
||||
else
|
||||
seq_puts(seq, "max\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t max_threshold_occ_write(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
@@ -1513,6 +1536,17 @@ static struct rftype res_common_files[] = {
|
||||
.seq_show = rdt_delay_linear_show,
|
||||
.fflags = RF_CTRL_INFO | RFTYPE_RES_MB,
|
||||
},
|
||||
/*
|
||||
* Platform specific which (if any) capabilities are provided by
|
||||
* thread_throttle_mode. Defer "fflags" initialization to platform
|
||||
* discovery.
|
||||
*/
|
||||
{
|
||||
.name = "thread_throttle_mode",
|
||||
.mode = 0444,
|
||||
.kf_ops = &rdtgroup_kf_single_ops,
|
||||
.seq_show = rdt_thread_throttle_mode_show,
|
||||
},
|
||||
{
|
||||
.name = "max_threshold_occupancy",
|
||||
.mode = 0644,
|
||||
@@ -1583,7 +1617,7 @@ static int rdtgroup_add_files(struct kernfs_node *kn, unsigned long fflags)
|
||||
lockdep_assert_held(&rdtgroup_mutex);
|
||||
|
||||
for (rft = rfts; rft < rfts + len; rft++) {
|
||||
if ((fflags & rft->fflags) == rft->fflags) {
|
||||
if (rft->fflags && ((fflags & rft->fflags) == rft->fflags)) {
|
||||
ret = rdtgroup_add_file(kn, rft);
|
||||
if (ret)
|
||||
goto error;
|
||||
@@ -1600,6 +1634,33 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct rftype *rdtgroup_get_rftype_by_name(const char *name)
|
||||
{
|
||||
struct rftype *rfts, *rft;
|
||||
int len;
|
||||
|
||||
rfts = res_common_files;
|
||||
len = ARRAY_SIZE(res_common_files);
|
||||
|
||||
for (rft = rfts; rft < rfts + len; rft++) {
|
||||
if (!strcmp(rft->name, name))
|
||||
return rft;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void __init thread_throttle_mode_init(void)
|
||||
{
|
||||
struct rftype *rft;
|
||||
|
||||
rft = rdtgroup_get_rftype_by_name("thread_throttle_mode");
|
||||
if (!rft)
|
||||
return;
|
||||
|
||||
rft->fflags = RF_CTRL_INFO | RFTYPE_RES_MB;
|
||||
}
|
||||
|
||||
/**
|
||||
* rdtgroup_kn_mode_restrict - Restrict user access to named resctrl file
|
||||
* @r: The resource group with which the file is associated.
|
||||
@@ -2245,18 +2306,6 @@ static int reset_all_ctrls(struct rdt_resource *r)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_closid_match(struct task_struct *t, struct rdtgroup *r)
|
||||
{
|
||||
return (rdt_alloc_capable &&
|
||||
(r->type == RDTCTRL_GROUP) && (t->closid == r->closid));
|
||||
}
|
||||
|
||||
static bool is_rmid_match(struct task_struct *t, struct rdtgroup *r)
|
||||
{
|
||||
return (rdt_mon_capable &&
|
||||
(r->type == RDTMON_GROUP) && (t->rmid == r->mon.rmid));
|
||||
}
|
||||
|
||||
/*
|
||||
* Move tasks from one to the other group. If @from is NULL, then all tasks
|
||||
* in the systems are moved unconditionally (used for teardown).
|
||||
@@ -3196,7 +3245,7 @@ int __init rdtgroup_init(void)
|
||||
* It may also be ok since that would enable debugging of RDT before
|
||||
* resctrl is mounted.
|
||||
* The reason why the debugfs directory is created here and not in
|
||||
* rdt_mount() is because rdt_mount() takes rdtgroup_mutex and
|
||||
* rdt_get_tree() is because rdt_get_tree() takes rdtgroup_mutex and
|
||||
* during the debugfs directory creation also &sb->s_type->i_mutex_key
|
||||
* (the lockdep class of inode->i_rwsem). Other filesystem
|
||||
* interactions (eg. SyS_getdents) have the lock ordering:
|
||||
|
新增問題並參考
封鎖使用者