All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vaibhav Jain <vaibhav@linux.ibm.com>
To: linux-nvdimm@lists.01.org
Cc: Vaibhav Jain <vaibhav@linux.ibm.com>,
	"Aneesh Kumar K . V" <aneesh.kumar@linux.ibm.com>
Subject: [ndctl RFC-PATCH 1/4] ndctl,libndctl: Implement new dimm-ops 'new_stats' and 'get_stat'
Date: Mon, 18 May 2020 16:50:20 +0530	[thread overview]
Message-ID: <20200518112023.147139-2-vaibhav@linux.ibm.com> (raw)
In-Reply-To: <20200518112023.147139-1-vaibhav@linux.ibm.com>

Do necessary ndctl, libndctl changes to add support for two new dimm-ops
namely 'new_stats' and 'get_stat' that can be implemented by dimm
providers to expose dimm statistics for e.g "Controller Reset Count"
etc, to ndctl. These dimm-ops are called when newly introduced command
line argument '-S' or '--stats' is provided on with ndctl-list
command.

Following are the semantics of these new dimm-ops:

* struct ndctl_cmd *(*new_stats)(struct ndctl_dimm *):

  Return a ndctl command that can be sent to libnvdimm to fetch
  dimm-stats from kernel. On successful submission
  'dimm_ops->smart_get_flags' is called to check if ND_SMART_STATS_VALID
  flag is set which indicates dimm-stats successfully fetched from
  libnvdimm.

* int (*get_stat)(struct ndctl_cmd *, struct ndctl_dimm_stat *):

  If ND_SMART_STATS_VALID flag was returned for a command from
  'dimm-ops->smart_get_flags' then this dimm-op is called to
  incrementally retrieve dimm-stats. For each call the dimm-op
  implementer is expected to populate the provided instance of 'struct
  ndctl_dimm_stat *' with a info on name, type and value of a
  dimm-stat. In case no more dimm-stats are available the dimm-op
  should return an error.

The newly introduced 'struct ndctl_dimm_stat' holds Name, type and
value information of a single dimm-stat. The ndctl_dimm_stat.type
information is used to appropriately format the dimm-stat value in the
json output.

The patch also updates 'util/json-smart.c' introducing new function
util_dimm_stats_to_json() thats called when '--stats' command line arg
is provided, and it drives the calls to dimm-ops 'new_stats' and
'get_stat'. The function does follows this sequence:

1. Generates a new json-object named 'stats' in the json output
2. Use 'dimm_ops->new_stats' to get a ndctl_cmd instance.
3. Submit the command to libndctl.
4. In case of successful submission, retrieve flags associated with the
   command.
4. In case flag ND_SMART_STATS_VALID use dimm-op 'get_stat' to retrieve
   available dimm-stats.
5. Creates new json-object for each 'struct ndctl_dimm_stat' returned
   from dimm-op 'get_stat' based on the type of dimm-stat.
6. Adds the above create json-object as child node of the 'stats'
   json-object.
7. Return the 'stats' json object from the function.

Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
---
 Documentation/ndctl/ndctl-list.txt | 24 ++++++++++
 ndctl/lib/libndctl.sym             |  5 ++
 ndctl/lib/private.h                |  6 +++
 ndctl/lib/smart.c                  | 26 +++++++++++
 ndctl/libndctl.h                   | 23 ++++++++++
 ndctl/list.c                       |  9 ++++
 ndctl/util/json-smart.c            | 73 ++++++++++++++++++++++++++++++
 util/json.h                        |  1 +
 8 files changed, 167 insertions(+)

diff --git a/Documentation/ndctl/ndctl-list.txt b/Documentation/ndctl/ndctl-list.txt
index 7c7e3ac9d05c..4ba58b96fb74 100644
--- a/Documentation/ndctl/ndctl-list.txt
+++ b/Documentation/ndctl/ndctl-list.txt
@@ -129,6 +129,30 @@ include::xable-bus-options.txt[]
     "shutdown_state":"clean"
   }
 }
+-S::
+--stats::
+	Include dimm statistics in the listing. For example:
+[verse]
+{
+  "dev":"nmem0"
+  "stats":{
+    "Controller Reset Count":2,
+    "Controller Reset Elapsed Time":50800,
+    "Power-on Seconds":51400,
+    "Critical Resource Utilization":"0%",
+    "Host Load Count":4056485,
+    "Host Store Count":8956850,
+    "Host Load Duration":765053890,
+    "Host Store Duration":715390700,
+    "Media Read Count":0,
+    "Media Write Count":6178,
+    "Media Read Duration":0,
+    "Media Write Duration":9468375,
+    "Cache Read Hit Count":4056485,
+    "Cache Write Hit Count":8432554,
+    "Fast Write Count":8959962
+  }
+}
 
 -F::
 --firmware::
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index ac575a23d035..5b8eabc1b9d5 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -431,3 +431,8 @@ LIBNDCTL_23 {
 	ndctl_region_get_align;
 	ndctl_region_set_align;
 } LIBNDCTL_22;
+
+LIBNDCTL_24 {
+	ndctl_dimm_cmd_new_stats;
+	ndctl_dimm_get_stat;
+} LIBNDCTL_23;
\ No newline at end of file
diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h
index 679e359a1070..c4d1f42f7ac2 100644
--- a/ndctl/lib/private.h
+++ b/ndctl/lib/private.h
@@ -238,6 +238,7 @@ struct ndctl_namespace {
  * @status: negative if failed, 0 if success, > 0 if never submitted
  * @get_firmware_status: per command firmware status field retrieval
  * @iter: iterator for multi-xfer commands
+ * @private_data: Used by dimm-provider to store private data
  * @source: source cmd of an inherited iter.total_buf
  *
  * For dynamically sized commands like 'get_config', 'set_config', or
@@ -266,6 +267,7 @@ struct ndctl_cmd {
 		u32 total_xfer;
 		int dir;
 	} iter;
+	void *private_data;
 	struct ndctl_cmd *source;
 	union {
 		struct nd_cmd_ars_cap ars_cap[0];
@@ -352,6 +354,10 @@ struct ndctl_dimm_ops {
 	int (*dimm_init)(struct ndctl_dimm *);
 	/* Called just before struct ndctl_dimm is de-allocated */
 	void (*dimm_uninit)(struct ndctl_dimm *);
+	/* Return a command to fetch dimm stats */
+	struct ndctl_cmd *(*new_stats)(struct ndctl_dimm *);
+	/* Return a single dimm-stat from the command until error */
+	int (*get_stat)(struct ndctl_cmd *, struct ndctl_dimm_stat *);
 };
 
 extern struct ndctl_dimm_ops * const intel_dimm_ops;
diff --git a/ndctl/lib/smart.c b/ndctl/lib/smart.c
index 0e180cff5a3e..fbb1248c08a9 100644
--- a/ndctl/lib/smart.c
+++ b/ndctl/lib/smart.c
@@ -31,6 +31,32 @@ NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart(
 		return NULL;
 }
 
+NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_stats(
+		struct ndctl_dimm *dimm)
+{
+	struct ndctl_dimm_ops *ops = dimm->ops;
+
+	if (ops && ops->new_stats)
+		return ops->new_stats(dimm);
+	else
+		return NULL;
+}
+
+NDCTL_EXPORT int ndctl_dimm_get_stat(struct ndctl_cmd *cmd,
+				      struct ndctl_dimm_stat * stat)
+{
+	struct ndctl_dimm_ops *ops;
+
+	if (!cmd || !cmd->dimm)
+		return -EINVAL;
+	ops = cmd->dimm->ops;
+
+	if (ops && ops->get_stat)
+		return ops->get_stat(cmd, stat);
+	else
+		return -ENOENT;
+}
+
 NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart_threshold(
 		struct ndctl_dimm *dimm)
 {
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index daf11b8ce4ea..9fab2097a920 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -247,6 +247,7 @@ int ndctl_cmd_ars_stat_get_flag_overflow(struct ndctl_cmd *ars_stat);
 #define ND_SMART_ALARM_VALID	(1 << 9)
 #define ND_SMART_SHUTDOWN_VALID	(1 << 10)
 #define ND_SMART_VENDOR_VALID	(1 << 11)
+#define ND_SMART_STATS_VALID	(1 << 12)
 #define ND_SMART_SPARE_TRIP	(1 << 0)
 #define ND_SMART_MTEMP_TRIP	(1 << 1)
 #define ND_SMART_TEMP_TRIP	ND_SMART_MTEMP_TRIP
@@ -341,6 +342,28 @@ int ndctl_cmd_get_status(struct ndctl_cmd *cmd);
 unsigned int ndctl_cmd_get_firmware_status(struct ndctl_cmd *cmd);
 int ndctl_cmd_submit(struct ndctl_cmd *cmd);
 
+/* Holds a single dimm stat which can be retrived */
+struct ndctl_dimm_stat {
+        const char *name;
+        enum {
+		STAT_TYPE_BOOL,
+		STAT_TYPE_INT,
+		STAT_TYPE_INT64,
+		STAT_TYPE_DOUBLE,
+		STAT_TYPE_STR,
+		STAT_TYPE_PERCENT,
+	} type;
+	union {
+		bool bool_val;
+		int int_val;
+		long long int64_val;
+		double double_val;
+		char str_val[32];
+	} val;
+};
+
+struct ndctl_cmd *ndctl_dimm_cmd_new_stats(struct ndctl_dimm *dimm);
+int ndctl_dimm_get_stat(struct ndctl_cmd *cmd, struct ndctl_dimm_stat *stat);
 struct badblock {
 	unsigned long long offset;
 	unsigned int len;
diff --git a/ndctl/list.c b/ndctl/list.c
index 31fb1b9593a2..cda3493c2ffc 100644
--- a/ndctl/list.c
+++ b/ndctl/list.c
@@ -32,6 +32,7 @@ static struct {
 	bool namespaces;
 	bool idle;
 	bool health;
+	bool stats;
 	bool dax;
 	bool media_errors;
 	bool human;
@@ -367,6 +368,13 @@ static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx)
 		}
 	}
 
+	if (list.stats) {
+		struct json_object *jstats;
+
+		jstats = util_dimm_stats_to_json(dimm);
+		json_object_object_add(jdimm, "stats", jstats);
+	}
+
 	if (list.firmware) {
 		struct json_object *jfirmware;
 
@@ -479,6 +487,7 @@ int cmd_list(int argc, const char **argv, struct ndctl_ctx *ctx)
 		OPT_BOOLEAN('D', "dimms", &list.dimms, "include dimm info"),
 		OPT_BOOLEAN('F', "firmware", &list.firmware, "include firmware info"),
 		OPT_BOOLEAN('H', "health", &list.health, "include dimm health"),
+		OPT_BOOLEAN('S', "stats", &list.stats, "include dimm stats"),
 		OPT_BOOLEAN('R', "regions", &list.regions,
 				"include region info"),
 		OPT_BOOLEAN('N', "namespaces", &list.namespaces,
diff --git a/ndctl/util/json-smart.c b/ndctl/util/json-smart.c
index a9bd17b37b4e..1312439453ee 100644
--- a/ndctl/util/json-smart.c
+++ b/ndctl/util/json-smart.c
@@ -221,3 +221,76 @@ struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm)
 		ndctl_cmd_unref(cmd);
 	return jhealth;
 }
+
+struct json_object *util_dimm_stats_to_json(struct ndctl_dimm *dimm)
+{
+	struct json_object *jstat = json_object_new_object();
+	struct json_object *jobj;
+	struct ndctl_cmd *cmd;
+	struct ndctl_dimm_stat stat = { 0 };
+	char format_buffer[32] = { 0 };
+	int rc;
+	unsigned int flags;
+
+	if (!jstat)
+		return NULL;
+
+	cmd = ndctl_dimm_cmd_new_stats(dimm);
+	if (!cmd)
+		goto err;
+
+	rc = ndctl_cmd_submit_xlat(cmd);
+	if (rc < 0) {
+		jobj = json_object_new_string("unknown");
+		if (jobj)
+			json_object_object_add(jstat, "stats", jobj);
+		goto out;
+	}
+
+	/* Check if any stats are reported */
+	flags = ndctl_cmd_smart_get_flags(cmd);
+	if (!(flags & ND_SMART_STATS_VALID))
+		goto out;
+
+	/* Iterate through the reported stats list */
+	while (ndctl_dimm_get_stat(cmd, &stat) == 0) {
+		switch(stat.type) {
+		case STAT_TYPE_BOOL:
+			jobj = json_object_new_boolean(stat.val.bool_val);
+			break;
+		case STAT_TYPE_INT:
+			jobj = json_object_new_int(stat.val.int_val);
+			break;
+		case STAT_TYPE_INT64:
+			jobj = json_object_new_int64(stat.val.int64_val);
+			break;
+		case STAT_TYPE_DOUBLE:
+			jobj = json_object_new_double(stat.val.double_val);
+			break;
+		case STAT_TYPE_STR:
+			jobj = json_object_new_string(stat.val.str_val);
+			break;
+		case STAT_TYPE_PERCENT:
+			snprintf(format_buffer, sizeof(format_buffer) - 1,
+				 "%u%%",stat.val.int_val);
+			format_buffer[sizeof(format_buffer) - 1] = '\0';
+			jobj = json_object_new_string(format_buffer);
+			break;
+		default:
+			jobj = json_object_new_string("unknown-type");
+			break;
+		};
+
+		if (jobj)
+			json_object_object_add(jstat, stat.name, jobj);
+	}
+	ndctl_cmd_unref(cmd);
+	return jstat;
+ err:
+	json_object_put(jstat);
+	jstat = NULL;
+ out:
+	if (cmd)
+		ndctl_cmd_unref(cmd);
+	return jstat;
+}
diff --git a/util/json.h b/util/json.h
index 6d39d3aa4693..e678596e1aab 100644
--- a/util/json.h
+++ b/util/json.h
@@ -56,6 +56,7 @@ struct json_object *util_json_object_size(unsigned long long size,
 struct json_object *util_json_object_hex(unsigned long long val,
 		unsigned long flags);
 struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm);
+struct json_object *util_dimm_stats_to_json(struct ndctl_dimm *dimm);
 struct json_object *util_dimm_firmware_to_json(struct ndctl_dimm *dimm,
 		unsigned long flags);
 struct json_object *util_region_capabilities_to_json(struct ndctl_region *region);
-- 
2.26.2
_______________________________________________
Linux-nvdimm mailing list -- linux-nvdimm@lists.01.org
To unsubscribe send an email to linux-nvdimm-leave@lists.01.org

  reply	other threads:[~2020-05-18 11:20 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-18 11:20 [ndctl RFC-PATCH 0/4] Add support for reporting PAPR NVDIMM Statistics Vaibhav Jain
2020-05-18 11:20 ` Vaibhav Jain [this message]
2020-05-18 11:20 ` [ndctl RFC-PATCH 2/4] papr_scm: Add support for fetching dimm-stats Vaibhav Jain
2020-05-18 11:20 ` [ndctl RFC-PATCH 3/4] papr_scm: Implement parsing and clean-up for fetched dimm stats Vaibhav Jain
2020-05-18 11:20 ` [ndctl RFC-PATCH 4/4] papr_scm: Implement dimm op 'get_stat' Vaibhav Jain

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200518112023.147139-2-vaibhav@linux.ibm.com \
    --to=vaibhav@linux.ibm.com \
    --cc=aneesh.kumar@linux.ibm.com \
    --cc=linux-nvdimm@lists.01.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.