Skip to content

Commit 60cf5e1

Browse files
Fenghua YuKAGA-KOKO
authored andcommitted
x86/intel_rdt: Add mkdir to resctrl file system
Resource control groups are represented as directories in the resctrl file system. The root directory describes the default resources available to tasks that have not been assigned specific resources. Other directories can be created at the root level to make new resource groups. It is not permitted to make directories within other directories. Hardware uses a CLOSID (Class of service ID) to determine which resource limits are currently in effect. The exact number available is enumerated by CPUID leaf 0x10, but on current implementations it is a small number. We implement a simple bitmask allocator for CLOSIDs. Each resource control group uses one CLOSID, which limits the total number of directories that can be created. Resource groups can be removed using rmdir. 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 4e978d0 commit 60cf5e1

File tree

2 files changed

+240
-0
lines changed

2 files changed

+240
-0
lines changed

arch/x86/include/asm/intel_rdt.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,20 @@
1414
* @kn: kernfs node
1515
* @rdtgroup_list: linked list for all rdtgroups
1616
* @closid: closid for this rdtgroup
17+
* @flags: status bits
18+
* @waitcount: how many cpus expect to find this
1719
*/
1820
struct rdtgroup {
1921
struct kernfs_node *kn;
2022
struct list_head rdtgroup_list;
2123
int closid;
24+
int flags;
25+
atomic_t waitcount;
2226
};
2327

28+
/* rdtgroup.flags */
29+
#define RDT_DELETED 1
30+
2431
/* List of all resource groups */
2532
extern struct list_head rdt_all_groups;
2633

@@ -156,4 +163,6 @@ union cpuid_0x10_1_edx {
156163
};
157164

158165
void rdt_cbm_update(void *arg);
166+
struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn);
167+
void rdtgroup_kn_unlock(struct kernfs_node *kn);
159168
#endif /* _ASM_X86_INTEL_RDT_H */

arch/x86/kernel/cpu/intel_rdt_rdtgroup.c

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@
2626
#include <linux/seq_file.h>
2727
#include <linux/sched.h>
2828
#include <linux/slab.h>
29+
#include <linux/cpu.h>
2930

3031
#include <uapi/linux/magic.h>
3132

3233
#include <asm/intel_rdt.h>
34+
#include <asm/intel_rdt_common.h>
3335

3436
DEFINE_STATIC_KEY_FALSE(rdt_enable_key);
3537
struct kernfs_root *rdt_root;
@@ -39,6 +41,55 @@ LIST_HEAD(rdt_all_groups);
3941
/* Kernel fs node for "info" directory under root */
4042
static struct kernfs_node *kn_info;
4143

44+
/*
45+
* Trivial allocator for CLOSIDs. Since h/w only supports a small number,
46+
* we can keep a bitmap of free CLOSIDs in a single integer.
47+
*
48+
* Using a global CLOSID across all resources has some advantages and
49+
* some drawbacks:
50+
* + We can simply set "current->closid" to assign a task to a resource
51+
* group.
52+
* + Context switch code can avoid extra memory references deciding which
53+
* CLOSID to load into the PQR_ASSOC MSR
54+
* - We give up some options in configuring resource groups across multi-socket
55+
* systems.
56+
* - Our choices on how to configure each resource become progressively more
57+
* limited as the number of resources grows.
58+
*/
59+
static int closid_free_map;
60+
61+
static void closid_init(void)
62+
{
63+
struct rdt_resource *r;
64+
int rdt_min_closid = 32;
65+
66+
/* Compute rdt_min_closid across all resources */
67+
for_each_enabled_rdt_resource(r)
68+
rdt_min_closid = min(rdt_min_closid, r->num_closid);
69+
70+
closid_free_map = BIT_MASK(rdt_min_closid) - 1;
71+
72+
/* CLOSID 0 is always reserved for the default group */
73+
closid_free_map &= ~1;
74+
}
75+
76+
int closid_alloc(void)
77+
{
78+
int closid = ffs(closid_free_map);
79+
80+
if (closid == 0)
81+
return -ENOSPC;
82+
closid--;
83+
closid_free_map &= ~(1 << closid);
84+
85+
return closid;
86+
}
87+
88+
static void closid_free(int closid)
89+
{
90+
closid_free_map |= 1 << closid;
91+
}
92+
4293
/* set uid and gid of rdtgroup dirs and files to that of the creator */
4394
static int rdtgroup_kn_set_ugid(struct kernfs_node *kn)
4495
{
@@ -287,6 +338,54 @@ static int parse_rdtgroupfs_options(char *data)
287338
return ret;
288339
}
289340

341+
/*
342+
* We don't allow rdtgroup directories to be created anywhere
343+
* except the root directory. Thus when looking for the rdtgroup
344+
* structure for a kernfs node we are either looking at a directory,
345+
* in which case the rdtgroup structure is pointed at by the "priv"
346+
* field, otherwise we have a file, and need only look to the parent
347+
* to find the rdtgroup.
348+
*/
349+
static struct rdtgroup *kernfs_to_rdtgroup(struct kernfs_node *kn)
350+
{
351+
if (kernfs_type(kn) == KERNFS_DIR)
352+
return kn->priv;
353+
else
354+
return kn->parent->priv;
355+
}
356+
357+
struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn)
358+
{
359+
struct rdtgroup *rdtgrp = kernfs_to_rdtgroup(kn);
360+
361+
atomic_inc(&rdtgrp->waitcount);
362+
kernfs_break_active_protection(kn);
363+
364+
mutex_lock(&rdtgroup_mutex);
365+
366+
/* Was this group deleted while we waited? */
367+
if (rdtgrp->flags & RDT_DELETED)
368+
return NULL;
369+
370+
return rdtgrp;
371+
}
372+
373+
void rdtgroup_kn_unlock(struct kernfs_node *kn)
374+
{
375+
struct rdtgroup *rdtgrp = kernfs_to_rdtgroup(kn);
376+
377+
mutex_unlock(&rdtgroup_mutex);
378+
379+
if (atomic_dec_and_test(&rdtgrp->waitcount) &&
380+
(rdtgrp->flags & RDT_DELETED)) {
381+
kernfs_unbreak_active_protection(kn);
382+
kernfs_put(kn);
383+
kfree(rdtgrp);
384+
} else {
385+
kernfs_unbreak_active_protection(kn);
386+
}
387+
}
388+
290389
static struct dentry *rdt_mount(struct file_system_type *fs_type,
291390
int flags, const char *unused_dev_name,
292391
void *data)
@@ -309,6 +408,8 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type,
309408
goto out_cdp;
310409
}
311410

411+
closid_init();
412+
312413
ret = rdtgroup_create_info_dir(rdtgroup_default.kn);
313414
if (ret)
314415
goto out_cdp;
@@ -367,11 +468,40 @@ static int reset_all_cbms(struct rdt_resource *r)
367468
return 0;
368469
}
369470

471+
/*
472+
* MSR_IA32_PQR_ASSOC is scoped per logical CPU, so all updates
473+
* are always in thread context.
474+
*/
475+
static void rdt_reset_pqr_assoc_closid(void *v)
476+
{
477+
struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
478+
479+
state->closid = 0;
480+
wrmsr(MSR_IA32_PQR_ASSOC, state->rmid, 0);
481+
}
482+
370483
/*
371484
* Forcibly remove all of subdirectories under root.
372485
*/
373486
static void rmdir_all_sub(void)
374487
{
488+
struct rdtgroup *rdtgrp, *tmp;
489+
490+
get_cpu();
491+
/* Reset PQR_ASSOC MSR on this cpu. */
492+
rdt_reset_pqr_assoc_closid(NULL);
493+
/* Reset PQR_ASSOC MSR on the rest of cpus. */
494+
smp_call_function_many(cpu_online_mask, rdt_reset_pqr_assoc_closid,
495+
NULL, 1);
496+
put_cpu();
497+
list_for_each_entry_safe(rdtgrp, tmp, &rdt_all_groups, rdtgroup_list) {
498+
/* Remove each rdtgroup other than root */
499+
if (rdtgrp == &rdtgroup_default)
500+
continue;
501+
kernfs_remove(rdtgrp->kn);
502+
list_del(&rdtgrp->rdtgroup_list);
503+
kfree(rdtgrp);
504+
}
375505
kernfs_remove(kn_info);
376506
}
377507

@@ -397,7 +527,108 @@ static struct file_system_type rdt_fs_type = {
397527
.kill_sb = rdt_kill_sb,
398528
};
399529

530+
static int rdtgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
531+
umode_t mode)
532+
{
533+
struct rdtgroup *parent, *rdtgrp;
534+
struct kernfs_node *kn;
535+
int ret, closid;
536+
537+
/* Only allow mkdir in the root directory */
538+
if (parent_kn != rdtgroup_default.kn)
539+
return -EPERM;
540+
541+
/* Do not accept '\n' to avoid unparsable situation. */
542+
if (strchr(name, '\n'))
543+
return -EINVAL;
544+
545+
parent = rdtgroup_kn_lock_live(parent_kn);
546+
if (!parent) {
547+
ret = -ENODEV;
548+
goto out_unlock;
549+
}
550+
551+
ret = closid_alloc();
552+
if (ret < 0)
553+
goto out_unlock;
554+
closid = ret;
555+
556+
/* allocate the rdtgroup. */
557+
rdtgrp = kzalloc(sizeof(*rdtgrp), GFP_KERNEL);
558+
if (!rdtgrp) {
559+
ret = -ENOSPC;
560+
goto out_closid_free;
561+
}
562+
rdtgrp->closid = closid;
563+
list_add(&rdtgrp->rdtgroup_list, &rdt_all_groups);
564+
565+
/* kernfs creates the directory for rdtgrp */
566+
kn = kernfs_create_dir(parent->kn, name, mode, rdtgrp);
567+
if (IS_ERR(kn)) {
568+
ret = PTR_ERR(kn);
569+
goto out_cancel_ref;
570+
}
571+
rdtgrp->kn = kn;
572+
573+
/*
574+
* kernfs_remove() will drop the reference count on "kn" which
575+
* will free it. But we still need it to stick around for the
576+
* rdtgroup_kn_unlock(kn} call below. Take one extra reference
577+
* here, which will be dropped inside rdtgroup_kn_unlock().
578+
*/
579+
kernfs_get(kn);
580+
581+
ret = rdtgroup_kn_set_ugid(kn);
582+
if (ret)
583+
goto out_destroy;
584+
585+
kernfs_activate(kn);
586+
587+
ret = 0;
588+
goto out_unlock;
589+
590+
out_destroy:
591+
kernfs_remove(rdtgrp->kn);
592+
out_cancel_ref:
593+
list_del(&rdtgrp->rdtgroup_list);
594+
kfree(rdtgrp);
595+
out_closid_free:
596+
closid_free(closid);
597+
out_unlock:
598+
rdtgroup_kn_unlock(parent_kn);
599+
return ret;
600+
}
601+
602+
static int rdtgroup_rmdir(struct kernfs_node *kn)
603+
{
604+
struct rdtgroup *rdtgrp;
605+
int ret = 0;
606+
607+
rdtgrp = rdtgroup_kn_lock_live(kn);
608+
if (!rdtgrp) {
609+
rdtgroup_kn_unlock(kn);
610+
return -ENOENT;
611+
}
612+
613+
rdtgrp->flags = RDT_DELETED;
614+
closid_free(rdtgrp->closid);
615+
list_del(&rdtgrp->rdtgroup_list);
616+
617+
/*
618+
* one extra hold on this, will drop when we kfree(rdtgrp)
619+
* in rdtgroup_kn_unlock()
620+
*/
621+
kernfs_get(kn);
622+
kernfs_remove(rdtgrp->kn);
623+
624+
rdtgroup_kn_unlock(kn);
625+
626+
return ret;
627+
}
628+
400629
static struct kernfs_syscall_ops rdtgroup_kf_syscall_ops = {
630+
.mkdir = rdtgroup_mkdir,
631+
.rmdir = rdtgroup_rmdir,
401632
};
402633

403634
static int __init rdtgroup_setup_root(void)

0 commit comments

Comments
 (0)