Re: [RFC PATCH 1/7] core/metricfs: Create metricfs, standardized files under debugfs.

2020-08-07 Thread Greg KH
debugfs interaction nits:

On Fri, Aug 07, 2020 at 02:29:10PM -0700, Jonathan Adams wrote:
> +static struct dentry *metricfs_init_dentry(void)
> +{
> + static int once;
> +
> + if (d_metricfs)
> + return d_metricfs;
> +
> + if (!debugfs_initialized())
> + return NULL;
> +
> + d_metricfs = debugfs_create_dir("metricfs", NULL);
> +
> + if (!d_metricfs && !once) {

As it is impossible for d_metricfs to ever be NULL, why are you checking
it?

> + once = 1;
> + pr_warn("Could not create debugfs directory 'metricfs'\n");

There is a pr_warn_once I think, but again, how can this ever trigger?

> + return NULL;
> + }
> +
> + return d_metricfs;
> +}
> +
> +/* We always cast in and out to struct dentry. */
> +struct metricfs_subsys {
> + struct dentry dentry;
> +};
> +
> +static struct dentry *metricfs_create_file(const char *name,
> +mode_t mode,
> +struct dentry *parent,
> +void *data,
> +const struct file_operations *fops)
> +{
> + struct dentry *ret;
> +
> + ret = debugfs_create_file(name, mode, parent, data, fops);
> + if (!ret)
> + pr_warn("Could not create debugfs '%s' entry\n", name);

As ret can never be NULL, why check?

There is no need to ever check debugfs return values, just keep on
going, that's the design of it.

thanks,

greg k-h


[RFC PATCH 1/7] core/metricfs: Create metricfs, standardized files under debugfs.

2020-08-07 Thread Jonathan Adams
From: Justin TerAvest 

Metricfs is a standardized set of files and directories under debugfs,
with a kernel API designed to be simpler than exporting new files under
sysfs. Type and field information is reported so that a userspace daemon
can easily process the information.

The statistics live under debugfs, in a tree rooted at:

/sys/kernel/debug/metricfs

Each metric is a directory, with four files in it.  This patch includes
a single "metricfs_presence" metric, whose files look like:
/sys/kernel/debug/metricfs:
 metricfs_presence/annotations
  DESCRIPTION A\ basic\ presence\ metric.
 metricfs_presence/fields
  value
  int
 metricfs_presence/values
  1
 metricfs_presence/version
  1

Statistics can have zero, one, or two 'fields', which are keys for the
table of metric values.  With no fields, you have a simple statistic as
above, with one field you have a 1-dimensional table of string -> value,
and with two fields you have a 2-dimensional table of
{string, string} -> value.

When a statistic's 'values' file is opened, we pre-allocate a 64k buffer
and call the statistic's callback to fill it with data, truncating if
the buffer overflows.

Statistic creators can create a hierarchy for their statistics using
metricfs_create_subsys().

Signed-off-by: Justin TerAvest 
[jwad...@google.com: Forward ported to v5.8, cleaned up and modernized
code significantly]
Signed-off-by: Jonathan Adams 

---

notes:
* To go upstream, this will need documentation and a MAINTAINERS update.
* It's not clear what the "version" file is for; it's vestigial and
should probably be removed.

jwad...@google.com: Forward ported to v5.8, removed some google-isms and
cleaned up some anachronisms (atomic->refcount, moving to
kvmalloc(), using POISON_POINTER_DELTA, made more functions static,
made 'emitter_fn' into an explicit union instead of a void *),
renamed 'struct emitter -> metric_emitter' and renamed
some funcs for consistency.
---
 include/linux/metricfs.h   | 103 ++
 kernel/Makefile|   2 +
 kernel/metricfs.c  | 727 +
 kernel/metricfs_examples.c | 151 
 lib/Kconfig.debug  |  18 +
 5 files changed, 1001 insertions(+)
 create mode 100644 include/linux/metricfs.h
 create mode 100644 kernel/metricfs.c
 create mode 100644 kernel/metricfs_examples.c

diff --git a/include/linux/metricfs.h b/include/linux/metricfs.h
new file mode 100644
index ..65a1baa8e8c1
--- /dev/null
+++ b/include/linux/metricfs.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _METRICFS_H_
+#define _METRICFS_H_
+
+#include 
+#include 
+#include 
+
+struct metric;
+struct metricfs_subsys;
+
+#define METRIC_EXPORT_GENERIC(name, desc, fname0, fname1, fn, is_str, 
cumulative) \
+static struct metric *metric_##name; \
+void metric_init_##name(struct metricfs_subsys *parent) \
+{ \
+   metric_##name = metric_register(__stringify(name), (parent), (desc), \
+   (fname0), (fname1), (fn), (is_str), \
+   (cumulative), THIS_MODULE); \
+} \
+void metric_exit_##name(void) \
+{ \
+   metric_unregister(metric_##name); \
+}
+
+/*
+ * Metricfs only deals with two types: int64_t and const char*.
+ *
+ * If a metric has fewer than two fields, pass NULL for the field name
+ * arguments.
+ *
+ * The metric does not take ownership of any of the strings passed in.
+ *
+ * See kernel/metricfs_examples.c for a set of example metrics, with
+ * corresponding output.
+ *
+ * METRIC_EXPORT_INT - An integer-valued metric.
+ * METRIC_EXPORT_COUNTER - An integer-valued cumulative metric.
+ * METRIC_EXPORT_STR - A string-valued metric.
+ */
+#define METRIC_EXPORT_INT(name, desc, fname0, fname1, fn) \
+   METRIC_EXPORT_GENERIC(name, (desc), (fname0), (fname1), (fn), \
+   false, false)
+#define METRIC_EXPORT_COUNTER(name, desc, fname0, fname1, fn) \
+   METRIC_EXPORT_GENERIC(name, (desc), (fname0), (fname1), (fn), \
+   false, true)
+#define METRIC_EXPORT_STR(name, desc, fname0, fname1, fn) \
+   METRIC_EXPORT_GENERIC(name, (desc), (fname0), (fname1), (fn), \
+   true, false)
+
+/* Subsystem support. */
+/* Pass NULL as 'parent' to create a new top-level subsystem. */
+struct metricfs_subsys *metricfs_create_subsys(const char *name,
+   struct metricfs_subsys *parent);
+void metricfs_destroy_subsys(struct metricfs_subsys *d);
+
+/*
+ * An opaque struct that metric emit functions use to keep our internal
+ * state.
+ */
+struct metric_emitter;
+
+/* The number of non-NULL arguments passed to EMIT macros must match the number
+ * of arguments passed to the EXPORT macro for a given metric.
+ *
+ * Failure to do so will cause data to be mangled (or dropped) by userspace or
+ * Monarch.
+ */
+#define METRIC_EMIT_INT(e, v, f0, f1) \
+   metric

[RFC PATCH 1/7] core/metricfs: Create metricfs, standardized files under debugfs.

2020-08-05 Thread Jonathan Adams
From: Justin TerAvest 

Metricfs is a standardized set of files and directories under debugfs,
with a kernel API designed to be simpler than exporting new files under
sysfs. Type and field information is reported so that a userspace daemon
can easily process the information.

The statistics live under debugfs, in a tree rooted at:

/sys/kernel/debug/metricfs

Each metric is a directory, with four files in it.  This patch includes
a single "metricfs_presence" metric, whose files look like:
/sys/kernel/debug/metricfs:
 metricfs_presence/annotations
  DESCRIPTION A\ basic\ presence\ metric.
 metricfs_presence/fields
  value
  int
 metricfs_presence/values
  1
 metricfs_presence/version
  1

Statistics can have zero, one, or two 'fields', which are keys for the
table of metric values.  With no fields, you have a simple statistic as
above, with one field you have a 1-dimensional table of string -> value,
and with two fields you have a 2-dimensional table of
{string, string} -> value.

When a statistic's 'values' file is opened, we pre-allocate a 64k buffer
and call the statistic's callback to fill it with data, truncating if
the buffer overflows.

Statistic creators can create a hierarchy for their statistics using
metricfs_create_subsys().

Signed-off-by: Justin TerAvest 
[jwad...@google.com: Forward ported to v5.8, cleaned up and modernized
code significantly]
Signed-off-by: Jonathan Adams 

---

notes:
* To go upstream, this will need documentation and a MAINTAINERS update.
* It's not clear what the "version" file is for; it's vestigial and
should probably be removed.

jwad...@google.com: Forward ported to v5.8, removed some google-isms and
cleaned up some anachronisms (atomic->refcount, moving to
kvmalloc(), using POISON_POINTER_DELTA, made more functions static,
made 'emitter_fn' into an explicit union instead of a void *),
renamed 'struct emitter -> metric_emitter' and renamed
some funcs for consistency.
---
 include/linux/metricfs.h   | 103 ++
 kernel/Makefile|   2 +
 kernel/metricfs.c  | 727 +
 kernel/metricfs_examples.c | 151 
 lib/Kconfig.debug  |  18 +
 5 files changed, 1001 insertions(+)
 create mode 100644 include/linux/metricfs.h
 create mode 100644 kernel/metricfs.c
 create mode 100644 kernel/metricfs_examples.c

diff --git a/include/linux/metricfs.h b/include/linux/metricfs.h
new file mode 100644
index ..65a1baa8e8c1
--- /dev/null
+++ b/include/linux/metricfs.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _METRICFS_H_
+#define _METRICFS_H_
+
+#include 
+#include 
+#include 
+
+struct metric;
+struct metricfs_subsys;
+
+#define METRIC_EXPORT_GENERIC(name, desc, fname0, fname1, fn, is_str, 
cumulative) \
+static struct metric *metric_##name; \
+void metric_init_##name(struct metricfs_subsys *parent) \
+{ \
+   metric_##name = metric_register(__stringify(name), (parent), (desc), \
+   (fname0), (fname1), (fn), (is_str), \
+   (cumulative), THIS_MODULE); \
+} \
+void metric_exit_##name(void) \
+{ \
+   metric_unregister(metric_##name); \
+}
+
+/*
+ * Metricfs only deals with two types: int64_t and const char*.
+ *
+ * If a metric has fewer than two fields, pass NULL for the field name
+ * arguments.
+ *
+ * The metric does not take ownership of any of the strings passed in.
+ *
+ * See kernel/metricfs_examples.c for a set of example metrics, with
+ * corresponding output.
+ *
+ * METRIC_EXPORT_INT - An integer-valued metric.
+ * METRIC_EXPORT_COUNTER - An integer-valued cumulative metric.
+ * METRIC_EXPORT_STR - A string-valued metric.
+ */
+#define METRIC_EXPORT_INT(name, desc, fname0, fname1, fn) \
+   METRIC_EXPORT_GENERIC(name, (desc), (fname0), (fname1), (fn), \
+   false, false)
+#define METRIC_EXPORT_COUNTER(name, desc, fname0, fname1, fn) \
+   METRIC_EXPORT_GENERIC(name, (desc), (fname0), (fname1), (fn), \
+   false, true)
+#define METRIC_EXPORT_STR(name, desc, fname0, fname1, fn) \
+   METRIC_EXPORT_GENERIC(name, (desc), (fname0), (fname1), (fn), \
+   true, false)
+
+/* Subsystem support. */
+/* Pass NULL as 'parent' to create a new top-level subsystem. */
+struct metricfs_subsys *metricfs_create_subsys(const char *name,
+   struct metricfs_subsys *parent);
+void metricfs_destroy_subsys(struct metricfs_subsys *d);
+
+/*
+ * An opaque struct that metric emit functions use to keep our internal
+ * state.
+ */
+struct metric_emitter;
+
+/* The number of non-NULL arguments passed to EMIT macros must match the number
+ * of arguments passed to the EXPORT macro for a given metric.
+ *
+ * Failure to do so will cause data to be mangled (or dropped) by userspace or
+ * Monarch.
+ */
+#define METRIC_EMIT_INT(e, v, f0, f1) \
+   metric