Add .open and .release handlers to mon_data kernfs files so a monitoring file holds a reference to its rdtgroup for the file's lifetime. Store the rdtgroup in of->priv on open and drop it on release. Provide rdtgroup_get()/rdtgroup_put() helpers.
This lets code that only has an open monitoring fd (e.g. the resctrl PMU event_init path) safely resolve the rdtgroup without having a kernfs active reference.
No functional change intended.
Signed-off-by: Jonathan Perry yonch@yonch.com --- fs/resctrl/internal.h | 2 ++ fs/resctrl/rdtgroup.c | 62 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+)
diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h index cf1fd82dc5a9..63fb4d6c21a7 100644 --- a/fs/resctrl/internal.h +++ b/fs/resctrl/internal.h @@ -360,6 +360,8 @@ void resctrl_mon_resource_exit(void); void mon_event_count(void *info);
int rdtgroup_mondata_show(struct seq_file *m, void *arg); +int rdtgroup_mondata_open(struct kernfs_open_file *of); +void rdtgroup_mondata_release(struct kernfs_open_file *of);
void mon_event_read(struct rmid_read *rr, struct rdt_resource *r, struct rdt_mon_domain *d, struct rdtgroup *rdtgrp, diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c index 0320360cd7a6..17b61dcfad07 100644 --- a/fs/resctrl/rdtgroup.c +++ b/fs/resctrl/rdtgroup.c @@ -332,6 +332,8 @@ static const struct kernfs_ops rdtgroup_kf_single_ops = { static const struct kernfs_ops kf_mondata_ops = { .atomic_write_len = PAGE_SIZE, .seq_show = rdtgroup_mondata_show, + .open = rdtgroup_mondata_open, + .release = rdtgroup_mondata_release, };
static bool is_cpu_list(struct kernfs_open_file *of) @@ -2512,12 +2514,26 @@ static struct rdtgroup *kernfs_to_rdtgroup(struct kernfs_node *kn) } }
+/* + * Convert an kernfs active reference to an rdtgroup reference. + */ static void rdtgroup_kn_get(struct rdtgroup *rdtgrp, struct kernfs_node *kn) { atomic_inc(&rdtgrp->waitcount); kernfs_break_active_protection(kn); }
+/* + * Get rdtgroup reference count from existing reference + */ +void rdtgroup_get(struct rdtgroup *rdtgrp) +{ + atomic_inc(&rdtgrp->waitcount); +} + +/* + * Decrement rdtgroup reference count, when converted from kernfs active ref + */ static void rdtgroup_kn_put(struct rdtgroup *rdtgrp, struct kernfs_node *kn) { if (atomic_dec_and_test(&rdtgrp->waitcount) && @@ -2532,6 +2548,20 @@ static void rdtgroup_kn_put(struct rdtgroup *rdtgrp, struct kernfs_node *kn) } }
+/* + * Decrement rdtgroup reference count + */ +void rdtgroup_put(struct rdtgroup *rdtgrp) +{ + 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); + rdtgroup_remove(rdtgrp); + } +} + struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn) { struct rdtgroup *rdtgrp = kernfs_to_rdtgroup(kn); @@ -3364,6 +3394,38 @@ static int mkdir_mondata_all(struct kernfs_node *parent_kn, return ret; }
+int rdtgroup_mondata_open(struct kernfs_open_file *of) +{ + struct rdtgroup *rdtgrp; + + rdtgrp = rdtgroup_kn_lock_live(of->kn); + if (!rdtgrp) { + rdtgroup_kn_unlock(of->kn); + return -ENOENT; + } + + /* + * resctrl relies an kernfs active references to guard access to struct + * rdtgroup from kernfs_open_file. Hold a reference in the file + * descriptor so perf_event_open() can retrieve the rdtgroup. + */ + rdtgroup_get(rdtgrp); + of->priv = rdtgrp; + + rdtgroup_kn_unlock(of->kn); + return 0; +} + +void rdtgroup_mondata_release(struct kernfs_open_file *of) +{ + struct rdtgroup *rdtgrp = of->priv; + + if (rdtgrp) { + rdtgroup_put(rdtgrp); + of->priv = NULL; + } +} + /** * cbm_ensure_valid - Enforce validity on provided CBM * @_val: Candidate CBM