x86/intel_rdt: Add "info" files to resctrl file system
authorFenghua Yu <fenghua.yu@intel.com>
Fri, 28 Oct 2016 22:04:43 +0000 (15:04 -0700)
committerThomas Gleixner <tglx@linutronix.de>
Mon, 31 Oct 2016 01:10:14 +0000 (19:10 -0600)
For the convenience of applications we make the decoded values of some
of the CPUID values available in read-only (0444) files.

Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Cc: "Ravi V Shankar" <ravi.v.shankar@intel.com>
Cc: "Tony Luck" <tony.luck@intel.com>
Cc: "Shaohua Li" <shli@fb.com>
Cc: "Sai Prakhya" <sai.praneeth.prakhya@intel.com>
Cc: "Peter Zijlstra" <peterz@infradead.org>
Cc: "Stephane Eranian" <eranian@google.com>
Cc: "Dave Hansen" <dave.hansen@intel.com>
Cc: "David Carrillo-Cisneros" <davidcc@google.com>
Cc: "Nilay Vaish" <nilayvaish@gmail.com>
Cc: "Vikas Shivappa" <vikas.shivappa@linux.intel.com>
Cc: "Ingo Molnar" <mingo@elte.hu>
Cc: "Borislav Petkov" <bp@suse.de>
Cc: "H. Peter Anvin" <h.peter.anvin@intel.com>
Link: http://lkml.kernel.org/r/1477692289-37412-5-git-send-email-fenghua.yu@intel.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
arch/x86/include/asm/intel_rdt.h
arch/x86/kernel/cpu/intel_rdt_rdtgroup.c

index 09d00e6f7ad65122c5a520392ca36471463ed5d7..5b7b3f6f1f96b8e9190d196593f30814affa3032 100644 (file)
@@ -26,6 +26,30 @@ extern struct list_head rdt_all_groups;
 
 int __init rdtgroup_init(void);
 
+/**
+ * struct rftype - describe each file in the resctrl file system
+ * @name: file name
+ * @mode: access mode
+ * @kf_ops: operations
+ * @seq_show: show content of the file
+ * @write: write to the file
+ */
+struct rftype {
+       char                    *name;
+       umode_t                 mode;
+       struct kernfs_ops       *kf_ops;
+
+       int (*seq_show)(struct kernfs_open_file *of,
+                       struct seq_file *sf, void *v);
+       /*
+        * write() is the generic write callback which maps directly to
+        * kernfs write operation and overrides all other operations.
+        * Maximum write size is determined by ->max_write_len.
+        */
+       ssize_t (*write)(struct kernfs_open_file *of,
+                        char *buf, size_t nbytes, loff_t off);
+};
+
 /**
  * struct rdt_resource - attributes of an RDT resource
  * @enabled:                   Is this feature enabled on this machine
index 106e4ce8f7e04b5f3bc27f127691eb40263ad584..fbb42e79b10a02631322447df303443f2757b138 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/fs.h>
 #include <linux/sysfs.h>
 #include <linux/kernfs.h>
+#include <linux/seq_file.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 
 #include <uapi/linux/magic.h>
@@ -34,6 +36,176 @@ struct kernfs_root *rdt_root;
 struct rdtgroup rdtgroup_default;
 LIST_HEAD(rdt_all_groups);
 
+/* Kernel fs node for "info" directory under root */
+static struct kernfs_node *kn_info;
+
+/* set uid and gid of rdtgroup dirs and files to that of the creator */
+static int rdtgroup_kn_set_ugid(struct kernfs_node *kn)
+{
+       struct iattr iattr = { .ia_valid = ATTR_UID | ATTR_GID,
+                               .ia_uid = current_fsuid(),
+                               .ia_gid = current_fsgid(), };
+
+       if (uid_eq(iattr.ia_uid, GLOBAL_ROOT_UID) &&
+           gid_eq(iattr.ia_gid, GLOBAL_ROOT_GID))
+               return 0;
+
+       return kernfs_setattr(kn, &iattr);
+}
+
+static int rdtgroup_add_file(struct kernfs_node *parent_kn, struct rftype *rft)
+{
+       struct kernfs_node *kn;
+       int ret;
+
+       kn = __kernfs_create_file(parent_kn, rft->name, rft->mode,
+                                 0, rft->kf_ops, rft, NULL, NULL);
+       if (IS_ERR(kn))
+               return PTR_ERR(kn);
+
+       ret = rdtgroup_kn_set_ugid(kn);
+       if (ret) {
+               kernfs_remove(kn);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rdtgroup_add_files(struct kernfs_node *kn, struct rftype *rfts,
+                             int len)
+{
+       struct rftype *rft;
+       int ret;
+
+       lockdep_assert_held(&rdtgroup_mutex);
+
+       for (rft = rfts; rft < rfts + len; rft++) {
+               ret = rdtgroup_add_file(kn, rft);
+               if (ret)
+                       goto error;
+       }
+
+       return 0;
+error:
+       pr_warn("Failed to add %s, err=%d\n", rft->name, ret);
+       while (--rft >= rfts)
+               kernfs_remove_by_name(kn, rft->name);
+       return ret;
+}
+
+static int rdtgroup_seqfile_show(struct seq_file *m, void *arg)
+{
+       struct kernfs_open_file *of = m->private;
+       struct rftype *rft = of->kn->priv;
+
+       if (rft->seq_show)
+               return rft->seq_show(of, m, arg);
+       return 0;
+}
+
+static ssize_t rdtgroup_file_write(struct kernfs_open_file *of, char *buf,
+                                  size_t nbytes, loff_t off)
+{
+       struct rftype *rft = of->kn->priv;
+
+       if (rft->write)
+               return rft->write(of, buf, nbytes, off);
+
+       return -EINVAL;
+}
+
+static struct kernfs_ops rdtgroup_kf_single_ops = {
+       .atomic_write_len       = PAGE_SIZE,
+       .write                  = rdtgroup_file_write,
+       .seq_show               = rdtgroup_seqfile_show,
+};
+
+static int rdt_num_closids_show(struct kernfs_open_file *of,
+                               struct seq_file *seq, void *v)
+{
+       struct rdt_resource *r = of->kn->parent->priv;
+
+       seq_printf(seq, "%d\n", r->num_closid);
+
+       return 0;
+}
+
+static int rdt_cbm_mask_show(struct kernfs_open_file *of,
+                            struct seq_file *seq, void *v)
+{
+       struct rdt_resource *r = of->kn->parent->priv;
+
+       seq_printf(seq, "%x\n", r->max_cbm);
+
+       return 0;
+}
+
+/* rdtgroup information files for one cache resource. */
+static struct rftype res_info_files[] = {
+       {
+               .name           = "num_closids",
+               .mode           = 0444,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .seq_show       = rdt_num_closids_show,
+       },
+       {
+               .name           = "cbm_mask",
+               .mode           = 0444,
+               .kf_ops         = &rdtgroup_kf_single_ops,
+               .seq_show       = rdt_cbm_mask_show,
+       },
+};
+
+static int rdtgroup_create_info_dir(struct kernfs_node *parent_kn)
+{
+       struct kernfs_node *kn_subdir;
+       struct rdt_resource *r;
+       int ret;
+
+       /* create the directory */
+       kn_info = kernfs_create_dir(parent_kn, "info", parent_kn->mode, NULL);
+       if (IS_ERR(kn_info))
+               return PTR_ERR(kn_info);
+       kernfs_get(kn_info);
+
+       for_each_enabled_rdt_resource(r) {
+               kn_subdir = kernfs_create_dir(kn_info, r->name,
+                                             kn_info->mode, r);
+               if (IS_ERR(kn_subdir)) {
+                       ret = PTR_ERR(kn_subdir);
+                       goto out_destroy;
+               }
+               kernfs_get(kn_subdir);
+               ret = rdtgroup_kn_set_ugid(kn_subdir);
+               if (ret)
+                       goto out_destroy;
+               ret = rdtgroup_add_files(kn_subdir, res_info_files,
+                                        ARRAY_SIZE(res_info_files));
+               if (ret)
+                       goto out_destroy;
+               kernfs_activate(kn_subdir);
+       }
+
+       /*
+        * This extra ref will be put in kernfs_remove() and guarantees
+        * that @rdtgrp->kn is always accessible.
+        */
+       kernfs_get(kn_info);
+
+       ret = rdtgroup_kn_set_ugid(kn_info);
+       if (ret)
+               goto out_destroy;
+
+       kernfs_activate(kn_info);
+
+       return 0;
+
+out_destroy:
+       kernfs_remove(kn_info);
+       return ret;
+}
+
 static void l3_qos_cfg_update(void *arg)
 {
        bool *enable = arg;
@@ -137,6 +309,10 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type,
                goto out_cdp;
        }
 
+       ret = rdtgroup_create_info_dir(rdtgroup_default.kn);
+       if (ret)
+               goto out_cdp;
+
        dentry = kernfs_mount(fs_type, flags, rdt_root,
                              RDTGROUP_SUPER_MAGIC, NULL);
        if (IS_ERR(dentry))
@@ -191,6 +367,14 @@ static int reset_all_cbms(struct rdt_resource *r)
        return 0;
 }
 
+/*
+ * Forcibly remove all of subdirectories under root.
+ */
+static void rmdir_all_sub(void)
+{
+       kernfs_remove(kn_info);
+}
+
 static void rdt_kill_sb(struct super_block *sb)
 {
        struct rdt_resource *r;
@@ -201,6 +385,7 @@ static void rdt_kill_sb(struct super_block *sb)
        for_each_enabled_rdt_resource(r)
                reset_all_cbms(r);
        cdp_disable();
+       rmdir_all_sub();
        static_branch_disable(&rdt_enable_key);
        kernfs_kill_sb(sb);
        mutex_unlock(&rdtgroup_mutex);