2c91dc1bcd
This includes support for the CXL commands, and adds the following packages: cxl-cli, cxl-devel, cxl-libs. Resolves: rhbz#2132167
5596 lines
147 KiB
Diff
5596 lines
147 KiB
Diff
From 965fa02e372fe3a05acc9ae8379f6dd796b7346d Mon Sep 17 00:00:00 2001
|
|
From: Dan Williams <dan.j.williams@intel.com>
|
|
Date: Wed, 5 Jan 2022 13:32:26 -0800
|
|
Subject: [PATCH 077/217] util: Distribute 'filter' and 'json' helpers to
|
|
per-tool objects
|
|
|
|
In preparation for switching build systems, fix the long standing wart
|
|
of mixing ndctl, daxctl, and cxl 'filter' and 'json' utilities in the
|
|
top-level util/filter.[ch]. Distribute them to their respective
|
|
{ndctl,daxctl,cxl}/filter.{c,h} locations.
|
|
|
|
This also removes the naming collisions for util/json.h between util/
|
|
and ndct/util/. I.e. <util/json.h> is no longer ambiguous or subject to
|
|
being shadowed by the tool local "util" directory.
|
|
|
|
Unfortunately unwinding this caused a lot of code to move all at once.
|
|
The benefit is that now it is clear that ndctl is the only tool that
|
|
reaches across into the 'filter' and 'json' functionality of another
|
|
tool (daxctl).
|
|
|
|
Link: https://lore.kernel.org/r/164141834691.3990253.16681105368577841032.stgit@dwillia2-desk3.amr.corp.intel.com
|
|
Tested-by: Alison Schofield <alison.schofield@intel.com>
|
|
Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
|
|
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
|
|
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
|
|
---
|
|
Makefile.am | 1 -
|
|
Makefile.am.in | 3 -
|
|
cxl/Makefile.am | 3 +
|
|
cxl/filter.c | 25 +
|
|
cxl/filter.h | 7 +
|
|
cxl/json.c | 214 +++++
|
|
cxl/json.h | 8 +
|
|
cxl/list.c | 4 +-
|
|
cxl/memdev.c | 3 +-
|
|
daxctl/Makefile.am | 5 +
|
|
daxctl/device.c | 4 +-
|
|
daxctl/filter.c | 43 +
|
|
daxctl/filter.h | 12 +
|
|
daxctl/json.c | 245 ++++++
|
|
daxctl/json.h | 18 +
|
|
daxctl/list.c | 4 +-
|
|
ndctl/Makefile.am | 16 +-
|
|
ndctl/bus.c | 4 +-
|
|
ndctl/check.c | 2 +-
|
|
ndctl/dimm.c | 6 +-
|
|
{util => ndctl}/filter.c | 60 +-
|
|
{util => ndctl}/filter.h | 12 +-
|
|
ndctl/inject-error.c | 6 +-
|
|
ndctl/inject-smart.c | 6 +-
|
|
ndctl/{util => }/json-smart.c | 5 +-
|
|
ndctl/json.c | 1114 ++++++++++++++++++++++++
|
|
ndctl/json.h | 24 +
|
|
ndctl/{util => }/keys.c | 5 +-
|
|
ndctl/{util => }/keys.h | 0
|
|
ndctl/lib/libndctl.c | 2 +-
|
|
ndctl/lib/papr.c | 4 +-
|
|
ndctl/lib/private.h | 4 +-
|
|
ndctl/list.c | 5 +-
|
|
ndctl/load-keys.c | 7 +-
|
|
ndctl/monitor.c | 4 +-
|
|
ndctl/namespace.c | 6 +-
|
|
ndctl/region.c | 3 +-
|
|
test/Makefile.am | 22 +-
|
|
test/ack-shutdown-count-set.c | 2 +-
|
|
test/daxdev-errors.c | 2 +-
|
|
test/device-dax.c | 2 +-
|
|
test/dsm-fail.c | 4 +-
|
|
test/libndctl.c | 2 +-
|
|
test/list-smart-dimm.c | 6 +-
|
|
test/pmem_namespaces.c | 2 +-
|
|
test/revoke-devmem.c | 2 +-
|
|
util/help.c | 2 +-
|
|
util/json.c | 1542 +--------------------------------
|
|
util/json.h | 39 +-
|
|
49 files changed, 1820 insertions(+), 1701 deletions(-)
|
|
create mode 100644 cxl/filter.c
|
|
create mode 100644 cxl/filter.h
|
|
create mode 100644 cxl/json.c
|
|
create mode 100644 cxl/json.h
|
|
create mode 100644 daxctl/filter.c
|
|
create mode 100644 daxctl/filter.h
|
|
create mode 100644 daxctl/json.c
|
|
create mode 100644 daxctl/json.h
|
|
rename {util => ndctl}/filter.c (88%)
|
|
rename {util => ndctl}/filter.h (89%)
|
|
rename ndctl/{util => }/json-smart.c (99%)
|
|
create mode 100644 ndctl/json.c
|
|
create mode 100644 ndctl/json.h
|
|
rename ndctl/{util => }/keys.c (99%)
|
|
rename ndctl/{util => }/keys.h (100%)
|
|
|
|
diff -up ndctl-71.1/Makefile.am.in.orig ndctl-71.1/Makefile.am.in
|
|
--- ndctl-71.1/Makefile.am.in.orig 2022-10-07 15:50:40.071454550 -0400
|
|
+++ ndctl-71.1/Makefile.am.in 2022-10-07 15:51:03.900535680 -0400
|
|
@@ -9,9 +9,6 @@ AM_CPPFLAGS = \
|
|
-DLIBEXECDIR=\""$(libexecdir)"\" \
|
|
-DPREFIX=\""$(prefix)"\" \
|
|
-DNDCTL_MAN_PATH=\""$(mandir)"\" \
|
|
- -I${top_srcdir}/ndctl/lib \
|
|
- -I${top_srcdir}/ndctl \
|
|
- -I${top_srcdir}/cxl \
|
|
-I${top_srcdir}/ \
|
|
$(KMOD_CFLAGS) \
|
|
$(UDEV_CFLAGS) \
|
|
diff -up ndctl-71.1/Makefile.am.orig ndctl-71.1/Makefile.am
|
|
--- ndctl-71.1/Makefile.am.orig 2022-10-07 15:50:40.071454550 -0400
|
|
+++ ndctl-71.1/Makefile.am 2022-10-07 15:51:03.900535680 -0400
|
|
@@ -84,7 +84,6 @@ libutil_a_SOURCES = \
|
|
util/help.c \
|
|
util/strbuf.c \
|
|
util/wrapper.c \
|
|
- util/filter.c \
|
|
util/bitmap.c \
|
|
util/abspath.c \
|
|
util/iomem.c \
|
|
diff -up ndctl-71.1/cxl/Makefile.am.orig ndctl-71.1/cxl/Makefile.am
|
|
--- ndctl-71.1/cxl/Makefile.am.orig 2022-10-07 15:50:40.071454550 -0400
|
|
+++ ndctl-71.1/cxl/Makefile.am 2022-10-07 15:51:03.900535680 -0400
|
|
@@ -12,6 +12,9 @@ cxl_SOURCES =\
|
|
list.c \
|
|
memdev.c \
|
|
../util/json.c \
|
|
+ json.c \
|
|
+ filter.c \
|
|
+ filter.h \
|
|
builtin.h
|
|
|
|
cxl_LDADD =\
|
|
diff -up ndctl-71.1/cxl/filter.c.orig ndctl-71.1/cxl/filter.c
|
|
--- ndctl-71.1/cxl/filter.c.orig 2022-10-07 15:51:03.900535680 -0400
|
|
+++ ndctl-71.1/cxl/filter.c 2022-10-07 15:51:03.900535680 -0400
|
|
@@ -0,0 +1,25 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <cxl/libcxl.h>
|
|
+#include "filter.h"
|
|
+
|
|
+struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
|
|
+ const char *ident)
|
|
+{
|
|
+ int memdev_id;
|
|
+
|
|
+ if (!ident || strcmp(ident, "all") == 0)
|
|
+ return memdev;
|
|
+
|
|
+ if (strcmp(ident, cxl_memdev_get_devname(memdev)) == 0)
|
|
+ return memdev;
|
|
+
|
|
+ if ((sscanf(ident, "%d", &memdev_id) == 1
|
|
+ || sscanf(ident, "mem%d", &memdev_id) == 1)
|
|
+ && cxl_memdev_get_id(memdev) == memdev_id)
|
|
+ return memdev;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
diff -up ndctl-71.1/cxl/filter.h.orig ndctl-71.1/cxl/filter.h
|
|
--- ndctl-71.1/cxl/filter.h.orig 2022-10-07 15:51:03.901535684 -0400
|
|
+++ ndctl-71.1/cxl/filter.h 2022-10-07 15:51:03.901535684 -0400
|
|
@@ -0,0 +1,7 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */
|
|
+#ifndef _CXL_UTIL_FILTER_H_
|
|
+#define _CXL_UTIL_FILTER_H_
|
|
+struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
|
|
+ const char *ident);
|
|
+#endif /* _CXL_UTIL_FILTER_H_ */
|
|
diff -up ndctl-71.1/cxl/json.c.orig ndctl-71.1/cxl/json.c
|
|
--- ndctl-71.1/cxl/json.c.orig 2022-10-07 15:51:03.901535684 -0400
|
|
+++ ndctl-71.1/cxl/json.c 2022-10-07 15:51:03.901535684 -0400
|
|
@@ -0,0 +1,214 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
|
|
+#include <util/json.h>
|
|
+#include <uuid/uuid.h>
|
|
+#include <cxl/libcxl.h>
|
|
+#include <json-c/json.h>
|
|
+#include <json-c/printbuf.h>
|
|
+#include <ccan/short_types/short_types.h>
|
|
+
|
|
+#include "json.h"
|
|
+
|
|
+static struct json_object *util_cxl_memdev_health_to_json(
|
|
+ struct cxl_memdev *memdev, unsigned long flags)
|
|
+{
|
|
+ struct json_object *jhealth;
|
|
+ struct json_object *jobj;
|
|
+ struct cxl_cmd *cmd;
|
|
+ u32 field;
|
|
+ int rc;
|
|
+
|
|
+ jhealth = json_object_new_object();
|
|
+ if (!jhealth)
|
|
+ return NULL;
|
|
+ if (!memdev)
|
|
+ goto err_jobj;
|
|
+
|
|
+ cmd = cxl_cmd_new_get_health_info(memdev);
|
|
+ if (!cmd)
|
|
+ goto err_jobj;
|
|
+
|
|
+ rc = cxl_cmd_submit(cmd);
|
|
+ if (rc < 0)
|
|
+ goto err_cmd;
|
|
+ rc = cxl_cmd_get_mbox_status(cmd);
|
|
+ if (rc != 0)
|
|
+ goto err_cmd;
|
|
+
|
|
+ /* health_status fields */
|
|
+ rc = cxl_cmd_health_info_get_maintenance_needed(cmd);
|
|
+ jobj = json_object_new_boolean(rc);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "maintenance_needed", jobj);
|
|
+
|
|
+ rc = cxl_cmd_health_info_get_performance_degraded(cmd);
|
|
+ jobj = json_object_new_boolean(rc);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "performance_degraded", jobj);
|
|
+
|
|
+ rc = cxl_cmd_health_info_get_hw_replacement_needed(cmd);
|
|
+ jobj = json_object_new_boolean(rc);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "hw_replacement_needed", jobj);
|
|
+
|
|
+ /* media_status fields */
|
|
+ rc = cxl_cmd_health_info_get_media_normal(cmd);
|
|
+ jobj = json_object_new_boolean(rc);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "media_normal", jobj);
|
|
+
|
|
+ rc = cxl_cmd_health_info_get_media_not_ready(cmd);
|
|
+ jobj = json_object_new_boolean(rc);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "media_not_ready", jobj);
|
|
+
|
|
+ rc = cxl_cmd_health_info_get_media_persistence_lost(cmd);
|
|
+ jobj = json_object_new_boolean(rc);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "media_persistence_lost", jobj);
|
|
+
|
|
+ rc = cxl_cmd_health_info_get_media_data_lost(cmd);
|
|
+ jobj = json_object_new_boolean(rc);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "media_data_lost", jobj);
|
|
+
|
|
+ rc = cxl_cmd_health_info_get_media_powerloss_persistence_loss(cmd);
|
|
+ jobj = json_object_new_boolean(rc);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "media_powerloss_persistence_loss", jobj);
|
|
+
|
|
+ rc = cxl_cmd_health_info_get_media_shutdown_persistence_loss(cmd);
|
|
+ jobj = json_object_new_boolean(rc);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "media_shutdown_persistence_loss", jobj);
|
|
+
|
|
+ rc = cxl_cmd_health_info_get_media_persistence_loss_imminent(cmd);
|
|
+ jobj = json_object_new_boolean(rc);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "media_persistence_loss_imminent", jobj);
|
|
+
|
|
+ rc = cxl_cmd_health_info_get_media_powerloss_data_loss(cmd);
|
|
+ jobj = json_object_new_boolean(rc);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "media_powerloss_data_loss", jobj);
|
|
+
|
|
+ rc = cxl_cmd_health_info_get_media_shutdown_data_loss(cmd);
|
|
+ jobj = json_object_new_boolean(rc);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "media_shutdown_data_loss", jobj);
|
|
+
|
|
+ rc = cxl_cmd_health_info_get_media_data_loss_imminent(cmd);
|
|
+ jobj = json_object_new_boolean(rc);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "media_data_loss_imminent", jobj);
|
|
+
|
|
+ /* ext_status fields */
|
|
+ if (cxl_cmd_health_info_get_ext_life_used_normal(cmd))
|
|
+ jobj = json_object_new_string("normal");
|
|
+ else if (cxl_cmd_health_info_get_ext_life_used_warning(cmd))
|
|
+ jobj = json_object_new_string("warning");
|
|
+ else if (cxl_cmd_health_info_get_ext_life_used_critical(cmd))
|
|
+ jobj = json_object_new_string("critical");
|
|
+ else
|
|
+ jobj = json_object_new_string("unknown");
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "ext_life_used", jobj);
|
|
+
|
|
+ if (cxl_cmd_health_info_get_ext_temperature_normal(cmd))
|
|
+ jobj = json_object_new_string("normal");
|
|
+ else if (cxl_cmd_health_info_get_ext_temperature_warning(cmd))
|
|
+ jobj = json_object_new_string("warning");
|
|
+ else if (cxl_cmd_health_info_get_ext_temperature_critical(cmd))
|
|
+ jobj = json_object_new_string("critical");
|
|
+ else
|
|
+ jobj = json_object_new_string("unknown");
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "ext_temperature", jobj);
|
|
+
|
|
+ if (cxl_cmd_health_info_get_ext_corrected_volatile_normal(cmd))
|
|
+ jobj = json_object_new_string("normal");
|
|
+ else if (cxl_cmd_health_info_get_ext_corrected_volatile_warning(cmd))
|
|
+ jobj = json_object_new_string("warning");
|
|
+ else
|
|
+ jobj = json_object_new_string("unknown");
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "ext_corrected_volatile", jobj);
|
|
+
|
|
+ if (cxl_cmd_health_info_get_ext_corrected_persistent_normal(cmd))
|
|
+ jobj = json_object_new_string("normal");
|
|
+ else if (cxl_cmd_health_info_get_ext_corrected_persistent_warning(cmd))
|
|
+ jobj = json_object_new_string("warning");
|
|
+ else
|
|
+ jobj = json_object_new_string("unknown");
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "ext_corrected_persistent", jobj);
|
|
+
|
|
+ /* other fields */
|
|
+ field = cxl_cmd_health_info_get_life_used(cmd);
|
|
+ if (field != 0xff) {
|
|
+ jobj = json_object_new_int(field);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "life_used_percent", jobj);
|
|
+ }
|
|
+
|
|
+ field = cxl_cmd_health_info_get_temperature(cmd);
|
|
+ if (field != 0xffff) {
|
|
+ jobj = json_object_new_int(field);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "temperature", jobj);
|
|
+ }
|
|
+
|
|
+ field = cxl_cmd_health_info_get_dirty_shutdowns(cmd);
|
|
+ jobj = json_object_new_int64(field);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "dirty_shutdowns", jobj);
|
|
+
|
|
+ field = cxl_cmd_health_info_get_volatile_errors(cmd);
|
|
+ jobj = json_object_new_int64(field);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "volatile_errors", jobj);
|
|
+
|
|
+ field = cxl_cmd_health_info_get_pmem_errors(cmd);
|
|
+ jobj = json_object_new_int64(field);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "pmem_errors", jobj);
|
|
+
|
|
+ cxl_cmd_unref(cmd);
|
|
+ return jhealth;
|
|
+
|
|
+err_cmd:
|
|
+ cxl_cmd_unref(cmd);
|
|
+err_jobj:
|
|
+ json_object_put(jhealth);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
|
|
+ unsigned long flags)
|
|
+{
|
|
+ const char *devname = cxl_memdev_get_devname(memdev);
|
|
+ struct json_object *jdev, *jobj;
|
|
+
|
|
+ jdev = json_object_new_object();
|
|
+ if (!devname || !jdev)
|
|
+ return NULL;
|
|
+
|
|
+ jobj = json_object_new_string(devname);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdev, "memdev", jobj);
|
|
+
|
|
+ jobj = util_json_object_size(cxl_memdev_get_pmem_size(memdev), flags);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdev, "pmem_size", jobj);
|
|
+
|
|
+ jobj = util_json_object_size(cxl_memdev_get_ram_size(memdev), flags);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdev, "ram_size", jobj);
|
|
+
|
|
+ if (flags & UTIL_JSON_HEALTH) {
|
|
+ jobj = util_cxl_memdev_health_to_json(memdev, flags);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdev, "health", jobj);
|
|
+ }
|
|
+ return jdev;
|
|
+}
|
|
diff -up ndctl-71.1/cxl/json.h.orig ndctl-71.1/cxl/json.h
|
|
--- ndctl-71.1/cxl/json.h.orig 2022-10-07 15:51:03.901535684 -0400
|
|
+++ ndctl-71.1/cxl/json.h 2022-10-07 15:51:03.901535684 -0400
|
|
@@ -0,0 +1,8 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */
|
|
+#ifndef __CXL_UTIL_JSON_H__
|
|
+#define __CXL_UTIL_JSON_H__
|
|
+struct cxl_memdev;
|
|
+struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
|
|
+ unsigned long flags);
|
|
+#endif /* __CXL_UTIL_JSON_H__ */
|
|
diff -up ndctl-71.1/cxl/list.c.orig ndctl-71.1/cxl/list.c
|
|
--- ndctl-71.1/cxl/list.c.orig 2022-10-07 15:50:40.072454553 -0400
|
|
+++ ndctl-71.1/cxl/list.c 2022-10-07 15:51:03.901535684 -0400
|
|
@@ -6,12 +6,14 @@
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
#include <util/json.h>
|
|
-#include <util/filter.h>
|
|
#include <json-c/json.h>
|
|
#include <cxl/libcxl.h>
|
|
#include <util/parse-options.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
|
|
+#include "json.h"
|
|
+#include "filter.h"
|
|
+
|
|
static struct {
|
|
bool memdevs;
|
|
bool idle;
|
|
diff -up ndctl-71.1/cxl/memdev.c.orig ndctl-71.1/cxl/memdev.c
|
|
--- ndctl-71.1/cxl/memdev.c.orig 2022-10-07 15:50:40.072454553 -0400
|
|
+++ ndctl-71.1/cxl/memdev.c 2022-10-07 15:51:03.901535684 -0400
|
|
@@ -6,12 +6,13 @@
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
#include <util/log.h>
|
|
-#include <util/filter.h>
|
|
#include <cxl/libcxl.h>
|
|
#include <util/parse-options.h>
|
|
#include <ccan/minmax/minmax.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
|
|
+#include "filter.h"
|
|
+
|
|
struct action_context {
|
|
FILE *f_out;
|
|
FILE *f_in;
|
|
diff -up ndctl-71.1/daxctl/Makefile.am.orig ndctl-71.1/daxctl/Makefile.am
|
|
--- ndctl-71.1/daxctl/Makefile.am.orig 2022-10-07 15:50:40.073454556 -0400
|
|
+++ ndctl-71.1/daxctl/Makefile.am 2022-10-07 15:51:03.902535687 -0400
|
|
@@ -18,6 +18,11 @@ daxctl_SOURCES =\
|
|
migrate.c \
|
|
device.c \
|
|
../util/json.c \
|
|
+ ../util/json.h \
|
|
+ json.c \
|
|
+ json.h \
|
|
+ filter.c \
|
|
+ filter.h \
|
|
builtin.h
|
|
|
|
daxctl_LDADD =\
|
|
diff -up ndctl-71.1/daxctl/device.c.orig ndctl-71.1/daxctl/device.c
|
|
--- ndctl-71.1/daxctl/device.c.orig 2022-10-07 15:50:40.074454560 -0400
|
|
+++ ndctl-71.1/daxctl/device.c 2022-10-07 15:51:03.902535687 -0400
|
|
@@ -11,13 +11,15 @@
|
|
#include <sys/sysmacros.h>
|
|
#include <util/size.h>
|
|
#include <util/json.h>
|
|
-#include <util/filter.h>
|
|
#include <json-c/json.h>
|
|
#include <json-c/json_util.h>
|
|
#include <daxctl/libdaxctl.h>
|
|
#include <util/parse-options.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
|
|
+#include "filter.h"
|
|
+#include "json.h"
|
|
+
|
|
static struct {
|
|
const char *dev;
|
|
const char *mode;
|
|
diff -up ndctl-71.1/daxctl/filter.c.orig ndctl-71.1/daxctl/filter.c
|
|
--- ndctl-71.1/daxctl/filter.c.orig 2022-10-07 15:51:03.902535687 -0400
|
|
+++ ndctl-71.1/daxctl/filter.c 2022-10-07 15:51:03.902535687 -0400
|
|
@@ -0,0 +1,43 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <daxctl/libdaxctl.h>
|
|
+
|
|
+#include "filter.h"
|
|
+
|
|
+struct daxctl_dev *util_daxctl_dev_filter(struct daxctl_dev *dev,
|
|
+ const char *ident)
|
|
+{
|
|
+ struct daxctl_region *region = daxctl_dev_get_region(dev);
|
|
+ int region_id, dev_id;
|
|
+
|
|
+ if (!ident || strcmp(ident, "all") == 0)
|
|
+ return dev;
|
|
+
|
|
+ if (strcmp(ident, daxctl_dev_get_devname(dev)) == 0)
|
|
+ return dev;
|
|
+
|
|
+ if (sscanf(ident, "%d.%d", ®ion_id, &dev_id) == 2 &&
|
|
+ daxctl_region_get_id(region) == region_id &&
|
|
+ daxctl_dev_get_id(dev) == dev_id)
|
|
+ return dev;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct daxctl_region *util_daxctl_region_filter(struct daxctl_region *region,
|
|
+ const char *ident)
|
|
+{
|
|
+ int region_id;
|
|
+
|
|
+ if (!ident || strcmp(ident, "all") == 0)
|
|
+ return region;
|
|
+
|
|
+ if ((sscanf(ident, "%d", ®ion_id) == 1 ||
|
|
+ sscanf(ident, "region%d", ®ion_id) == 1) &&
|
|
+ daxctl_region_get_id(region) == region_id)
|
|
+ return region;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
diff -up ndctl-71.1/daxctl/filter.h.orig ndctl-71.1/daxctl/filter.h
|
|
--- ndctl-71.1/daxctl/filter.h.orig 2022-10-07 15:51:03.902535687 -0400
|
|
+++ ndctl-71.1/daxctl/filter.h 2022-10-07 15:51:03.902535687 -0400
|
|
@@ -0,0 +1,12 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */
|
|
+#ifndef _DAXCTL_UTIL_FILTER_H_
|
|
+#define _DAXCTL_UTIL_FILTER_H_
|
|
+#include <stdbool.h>
|
|
+#include <ccan/list/list.h>
|
|
+
|
|
+struct daxctl_dev *util_daxctl_dev_filter(struct daxctl_dev *dev,
|
|
+ const char *ident);
|
|
+struct daxctl_region *util_daxctl_region_filter(struct daxctl_region *region,
|
|
+ const char *ident);
|
|
+#endif /* _DAXCTL_UTIL_FILTER_H_ */
|
|
diff -up ndctl-71.1/daxctl/json.c.orig ndctl-71.1/daxctl/json.c
|
|
--- ndctl-71.1/daxctl/json.c.orig 2022-10-07 15:51:03.903535690 -0400
|
|
+++ ndctl-71.1/daxctl/json.c 2022-10-07 15:51:03.902535687 -0400
|
|
@@ -0,0 +1,245 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
|
|
+#include <limits.h>
|
|
+#include <string.h>
|
|
+#include <util/json.h>
|
|
+#include <uuid/uuid.h>
|
|
+#include <json-c/json.h>
|
|
+#include <json-c/printbuf.h>
|
|
+#include <daxctl/libdaxctl.h>
|
|
+
|
|
+#include "filter.h"
|
|
+#include "json.h"
|
|
+
|
|
+struct json_object *util_daxctl_dev_to_json(struct daxctl_dev *dev,
|
|
+ unsigned long flags)
|
|
+{
|
|
+ struct daxctl_memory *mem = daxctl_dev_get_memory(dev);
|
|
+ const char *devname = daxctl_dev_get_devname(dev);
|
|
+ struct json_object *jdev, *jobj, *jmappings = NULL;
|
|
+ struct daxctl_mapping *mapping = NULL;
|
|
+ int node, movable, align;
|
|
+
|
|
+ jdev = json_object_new_object();
|
|
+ if (!devname || !jdev)
|
|
+ return NULL;
|
|
+
|
|
+ jobj = json_object_new_string(devname);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdev, "chardev", jobj);
|
|
+
|
|
+ jobj = util_json_object_size(daxctl_dev_get_size(dev), flags);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdev, "size", jobj);
|
|
+
|
|
+ node = daxctl_dev_get_target_node(dev);
|
|
+ if (node >= 0) {
|
|
+ jobj = json_object_new_int(node);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdev, "target_node", jobj);
|
|
+ }
|
|
+
|
|
+ align = daxctl_dev_get_align(dev);
|
|
+ if (align > 0) {
|
|
+ jobj = util_json_object_size(daxctl_dev_get_align(dev), flags);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdev, "align", jobj);
|
|
+ }
|
|
+
|
|
+ if (mem)
|
|
+ jobj = json_object_new_string("system-ram");
|
|
+ else
|
|
+ jobj = json_object_new_string("devdax");
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdev, "mode", jobj);
|
|
+
|
|
+ if (mem && daxctl_dev_get_resource(dev) != 0) {
|
|
+ int num_sections = daxctl_memory_num_sections(mem);
|
|
+ int num_online = daxctl_memory_is_online(mem);
|
|
+
|
|
+ jobj = json_object_new_int(num_online);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdev, "online_memblocks", jobj);
|
|
+
|
|
+ jobj = json_object_new_int(num_sections);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdev, "total_memblocks", jobj);
|
|
+
|
|
+ movable = daxctl_memory_is_movable(mem);
|
|
+ if (movable == 1)
|
|
+ jobj = json_object_new_boolean(true);
|
|
+ else if (movable == 0)
|
|
+ jobj = json_object_new_boolean(false);
|
|
+ else
|
|
+ jobj = NULL;
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdev, "movable", jobj);
|
|
+ }
|
|
+
|
|
+ if (!daxctl_dev_is_enabled(dev)) {
|
|
+ jobj = json_object_new_string("disabled");
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdev, "state", jobj);
|
|
+ }
|
|
+
|
|
+ if (!(flags & UTIL_JSON_DAX_MAPPINGS))
|
|
+ return jdev;
|
|
+
|
|
+ daxctl_mapping_foreach(dev, mapping) {
|
|
+ struct json_object *jmapping;
|
|
+
|
|
+ if (!jmappings) {
|
|
+ jmappings = json_object_new_array();
|
|
+ if (!jmappings)
|
|
+ continue;
|
|
+
|
|
+ json_object_object_add(jdev, "mappings", jmappings);
|
|
+ }
|
|
+
|
|
+ jmapping = util_daxctl_mapping_to_json(mapping, flags);
|
|
+ if (!jmapping)
|
|
+ continue;
|
|
+ json_object_array_add(jmappings, jmapping);
|
|
+ }
|
|
+ return jdev;
|
|
+}
|
|
+
|
|
+struct json_object *util_daxctl_devs_to_list(struct daxctl_region *region,
|
|
+ struct json_object *jdevs, const char *ident,
|
|
+ unsigned long flags)
|
|
+{
|
|
+ struct daxctl_dev *dev;
|
|
+
|
|
+ daxctl_dev_foreach(region, dev) {
|
|
+ struct json_object *jdev;
|
|
+
|
|
+ if (!util_daxctl_dev_filter(dev, ident))
|
|
+ continue;
|
|
+
|
|
+ if (!(flags & (UTIL_JSON_IDLE|UTIL_JSON_CONFIGURED))
|
|
+ && !daxctl_dev_get_size(dev))
|
|
+ continue;
|
|
+
|
|
+ if (!jdevs) {
|
|
+ jdevs = json_object_new_array();
|
|
+ if (!jdevs)
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ jdev = util_daxctl_dev_to_json(dev, flags);
|
|
+ if (!jdev) {
|
|
+ json_object_put(jdevs);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ json_object_array_add(jdevs, jdev);
|
|
+ }
|
|
+
|
|
+ return jdevs;
|
|
+}
|
|
+
|
|
+struct json_object *util_daxctl_region_to_json(struct daxctl_region *region,
|
|
+ const char *ident, unsigned long flags)
|
|
+{
|
|
+ unsigned long align;
|
|
+ struct json_object *jregion, *jobj;
|
|
+ unsigned long long available_size, size;
|
|
+
|
|
+ jregion = json_object_new_object();
|
|
+ if (!jregion)
|
|
+ return NULL;
|
|
+
|
|
+ /*
|
|
+ * The flag indicates when we are being called by an agent that
|
|
+ * already knows about the parent device information.
|
|
+ */
|
|
+ if (!(flags & UTIL_JSON_DAX)) {
|
|
+ /* trim off the redundant /sys/devices prefix */
|
|
+ const char *path = daxctl_region_get_path(region);
|
|
+ int len = strlen("/sys/devices");
|
|
+ const char *trim = &path[len];
|
|
+
|
|
+ if (strncmp(path, "/sys/devices", len) != 0)
|
|
+ goto err;
|
|
+ jobj = json_object_new_string(trim);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jregion, "path", jobj);
|
|
+ }
|
|
+
|
|
+ jobj = json_object_new_int(daxctl_region_get_id(region));
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jregion, "id", jobj);
|
|
+
|
|
+ size = daxctl_region_get_size(region);
|
|
+ if (size < ULLONG_MAX) {
|
|
+ jobj = util_json_object_size(size, flags);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jregion, "size", jobj);
|
|
+ }
|
|
+
|
|
+ available_size = daxctl_region_get_available_size(region);
|
|
+ if (available_size) {
|
|
+ jobj = util_json_object_size(available_size, flags);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jregion, "available_size", jobj);
|
|
+ }
|
|
+
|
|
+ align = daxctl_region_get_align(region);
|
|
+ if (align < ULONG_MAX) {
|
|
+ jobj = json_object_new_int64(align);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jregion, "align", jobj);
|
|
+ }
|
|
+
|
|
+ if (!(flags & UTIL_JSON_DAX_DEVS))
|
|
+ return jregion;
|
|
+
|
|
+ jobj = util_daxctl_devs_to_list(region, NULL, ident, flags);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jregion, "devices", jobj);
|
|
+
|
|
+ return jregion;
|
|
+ err:
|
|
+ json_object_put(jregion);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct json_object *util_daxctl_mapping_to_json(struct daxctl_mapping *mapping,
|
|
+ unsigned long flags)
|
|
+{
|
|
+ struct json_object *jmapping = json_object_new_object();
|
|
+ struct json_object *jobj;
|
|
+
|
|
+ if (!jmapping)
|
|
+ return NULL;
|
|
+
|
|
+ jobj = util_json_object_hex(daxctl_mapping_get_offset(mapping), flags);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jmapping, "page_offset", jobj);
|
|
+
|
|
+ jobj = util_json_object_hex(daxctl_mapping_get_start(mapping), flags);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jmapping, "start", jobj);
|
|
+
|
|
+ jobj = util_json_object_hex(daxctl_mapping_get_end(mapping), flags);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jmapping, "end", jobj);
|
|
+
|
|
+ jobj = util_json_object_size(daxctl_mapping_get_size(mapping), flags);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jmapping, "size", jobj);
|
|
+
|
|
+ return jmapping;
|
|
+ err:
|
|
+ json_object_put(jmapping);
|
|
+ return NULL;
|
|
+}
|
|
diff -up ndctl-71.1/daxctl/json.h.orig ndctl-71.1/daxctl/json.h
|
|
--- ndctl-71.1/daxctl/json.h.orig 2022-10-07 15:51:03.905535697 -0400
|
|
+++ ndctl-71.1/daxctl/json.h 2022-10-07 15:51:03.904535694 -0400
|
|
@@ -0,0 +1,18 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */
|
|
+#ifndef __DAXCTL_JSON_H__
|
|
+#define __DAXCTL_JSON_H__
|
|
+#include <daxctl/libdaxctl.h>
|
|
+
|
|
+struct json_object *util_daxctl_mapping_to_json(struct daxctl_mapping *mapping,
|
|
+ unsigned long flags);
|
|
+struct daxctl_region;
|
|
+struct daxctl_dev;
|
|
+struct json_object *util_daxctl_region_to_json(struct daxctl_region *region,
|
|
+ const char *ident, unsigned long flags);
|
|
+struct json_object *util_daxctl_dev_to_json(struct daxctl_dev *dev,
|
|
+ unsigned long flags);
|
|
+struct json_object *util_daxctl_devs_to_list(struct daxctl_region *region,
|
|
+ struct json_object *jdevs, const char *ident,
|
|
+ unsigned long flags);
|
|
+#endif /* __CXL_UTIL_JSON_H__ */
|
|
diff -up ndctl-71.1/daxctl/list.c.orig ndctl-71.1/daxctl/list.c
|
|
--- ndctl-71.1/daxctl/list.c.orig 2022-10-07 15:50:40.075454563 -0400
|
|
+++ ndctl-71.1/daxctl/list.c 2022-10-07 15:51:03.905535697 -0400
|
|
@@ -6,12 +6,14 @@
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
#include <util/json.h>
|
|
-#include <util/filter.h>
|
|
#include <json-c/json.h>
|
|
#include <daxctl/libdaxctl.h>
|
|
#include <util/parse-options.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
|
|
+#include "filter.h"
|
|
+#include "json.h"
|
|
+
|
|
static struct {
|
|
bool devs;
|
|
bool regions;
|
|
diff -up ndctl-71.1/ndctl/Makefile.am.orig ndctl-71.1/ndctl/Makefile.am
|
|
--- ndctl-71.1/ndctl/Makefile.am.orig 2022-10-07 15:50:40.076454567 -0400
|
|
+++ ndctl-71.1/ndctl/Makefile.am 2022-10-07 15:51:03.905535697 -0400
|
|
@@ -19,13 +19,19 @@ ndctl_SOURCES = ndctl.c \
|
|
region.c \
|
|
dimm.c \
|
|
../util/log.c \
|
|
- ../util/filter.c \
|
|
- ../util/filter.h \
|
|
+ ../daxctl/filter.c \
|
|
+ ../daxctl/filter.h \
|
|
+ filter.c \
|
|
+ filter.h \
|
|
list.c \
|
|
../util/json.c \
|
|
../util/json.h \
|
|
- util/json-smart.c \
|
|
- util/keys.h \
|
|
+ ../daxctl/json.c \
|
|
+ ../daxctl/json.h \
|
|
+ json.c \
|
|
+ json.h \
|
|
+ json-smart.c \
|
|
+ keys.h \
|
|
inject-error.c \
|
|
inject-smart.c \
|
|
monitor.c \
|
|
@@ -36,7 +42,7 @@ ndctl_SOURCES = ndctl.c \
|
|
firmware-update.h
|
|
|
|
if ENABLE_KEYUTILS
|
|
-ndctl_SOURCES += util/keys.c \
|
|
+ndctl_SOURCES += keys.c \
|
|
load-keys.c
|
|
keys_configdir = $(ndctl_keysdir)
|
|
keys_config_DATA = $(ndctl_keysreadme)
|
|
diff -up ndctl-71.1/ndctl/bus.c.orig ndctl-71.1/ndctl/bus.c
|
|
--- ndctl-71.1/ndctl/bus.c.orig 2022-10-07 15:50:40.077454570 -0400
|
|
+++ ndctl-71.1/ndctl/bus.c 2022-10-07 15:51:03.905535697 -0400
|
|
@@ -8,12 +8,14 @@
|
|
#include <syslog.h>
|
|
#include <builtin.h>
|
|
#include <util/json.h>
|
|
-#include <util/filter.h>
|
|
#include <json-c/json.h>
|
|
#include <ndctl/libndctl.h>
|
|
#include <util/parse-options.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
|
|
+#include "filter.h"
|
|
+#include "json.h"
|
|
+
|
|
static struct {
|
|
bool verbose;
|
|
bool force;
|
|
diff -up ndctl-71.1/ndctl/check.c.orig ndctl-71.1/ndctl/check.c
|
|
--- ndctl-71.1/ndctl/check.c.orig 2022-10-07 15:50:40.078454573 -0400
|
|
+++ ndctl-71.1/ndctl/check.c 2022-10-07 15:51:03.906535700 -0400
|
|
@@ -8,7 +8,6 @@
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
-#include <ndctl.h>
|
|
#include <limits.h>
|
|
#include <stdbool.h>
|
|
#include <sys/mman.h>
|
|
@@ -20,6 +19,7 @@
|
|
#include <util/util.h>
|
|
#include <util/bitmap.h>
|
|
#include <util/fletcher.h>
|
|
+#include <ndctl/ndctl.h>
|
|
#include <ndctl/libndctl.h>
|
|
#include <ndctl/namespace.h>
|
|
#include <ccan/endian/endian.h>
|
|
diff -up ndctl-71.1/ndctl/dimm.c.orig ndctl-71.1/ndctl/dimm.c
|
|
--- ndctl-71.1/ndctl/dimm.c.orig 2022-10-07 15:50:40.078454573 -0400
|
|
+++ ndctl-71.1/ndctl/dimm.c 2022-10-07 15:51:03.907535704 -0400
|
|
@@ -11,7 +11,6 @@
|
|
#include <util/size.h>
|
|
#include <uuid/uuid.h>
|
|
#include <util/json.h>
|
|
-#include <util/filter.h>
|
|
#include <json-c/json.h>
|
|
#include <util/fletcher.h>
|
|
#include <ndctl/libndctl.h>
|
|
@@ -20,7 +19,10 @@
|
|
#include <ccan/minmax/minmax.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
#include <ndctl/firmware-update.h>
|
|
-#include <util/keys.h>
|
|
+
|
|
+#include "filter.h"
|
|
+#include "json.h"
|
|
+#include "keys.h"
|
|
|
|
static const char *cmd_name = "dimm";
|
|
static int err_count;
|
|
diff -up ndctl-71.1/ndctl/filter.c.orig ndctl-71.1/ndctl/filter.c
|
|
--- ndctl-71.1/ndctl/filter.c.orig 2022-10-07 15:51:03.928535775 -0400
|
|
+++ ndctl-71.1/ndctl/filter.c 2022-10-07 15:51:03.908535707 -0400
|
|
@@ -0,0 +1,468 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <stdlib.h>
|
|
+#include <limits.h>
|
|
+#include <unistd.h>
|
|
+#include <sys/stat.h>
|
|
+#include <util/util.h>
|
|
+#include <sys/types.h>
|
|
+#include <ndctl/ndctl.h>
|
|
+#include <ndctl/libndctl.h>
|
|
+
|
|
+#include "filter.h"
|
|
+
|
|
+struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *__ident)
|
|
+{
|
|
+ char *end = NULL, *ident, *save;
|
|
+ unsigned long bus_id, id;
|
|
+ const char *provider, *devname, *name;
|
|
+
|
|
+ if (!__ident)
|
|
+ return bus;
|
|
+
|
|
+ ident = strdup(__ident);
|
|
+ if (!ident)
|
|
+ return NULL;
|
|
+
|
|
+ for (name = strtok_r(ident, " ", &save); name;
|
|
+ name = strtok_r(NULL, " ", &save)) {
|
|
+ if (strcmp(name, "all") == 0)
|
|
+ break;
|
|
+
|
|
+ bus_id = strtoul(ident, &end, 0);
|
|
+ if (end == ident || end[0])
|
|
+ bus_id = ULONG_MAX;
|
|
+
|
|
+ provider = ndctl_bus_get_provider(bus);
|
|
+ devname = ndctl_bus_get_devname(bus);
|
|
+ id = ndctl_bus_get_id(bus);
|
|
+
|
|
+ if (bus_id < ULONG_MAX && bus_id == id)
|
|
+ break;
|
|
+
|
|
+ if (bus_id == ULONG_MAX && (strcmp(provider, name) == 0
|
|
+ || strcmp(devname, name) == 0))
|
|
+ break;
|
|
+ }
|
|
+ free(ident);
|
|
+
|
|
+ if (name)
|
|
+ return bus;
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct ndctl_region *util_region_filter(struct ndctl_region *region,
|
|
+ const char *__ident)
|
|
+{
|
|
+ char *end = NULL, *ident, *save;
|
|
+ const char *name, *region_name;
|
|
+ unsigned long region_id, id;
|
|
+
|
|
+ if (!__ident)
|
|
+ return region;
|
|
+
|
|
+ ident = strdup(__ident);
|
|
+ if (!ident)
|
|
+ return NULL;
|
|
+
|
|
+ for (name = strtok_r(ident, " ", &save); name;
|
|
+ name = strtok_r(NULL, " ", &save)) {
|
|
+ if (strcmp(name, "all") == 0)
|
|
+ break;
|
|
+
|
|
+ region_id = strtoul(ident, &end, 0);
|
|
+ if (end == ident || end[0])
|
|
+ region_id = ULONG_MAX;
|
|
+
|
|
+ region_name = ndctl_region_get_devname(region);
|
|
+ id = ndctl_region_get_id(region);
|
|
+
|
|
+ if (region_id < ULONG_MAX && region_id == id)
|
|
+ break;
|
|
+
|
|
+ if (region_id == ULONG_MAX && strcmp(region_name, name) == 0)
|
|
+ break;
|
|
+ }
|
|
+ free(ident);
|
|
+
|
|
+ if (name)
|
|
+ return region;
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct ndctl_namespace *util_namespace_filter(struct ndctl_namespace *ndns,
|
|
+ const char *__ident)
|
|
+{
|
|
+ struct ndctl_region *region = ndctl_namespace_get_region(ndns);
|
|
+ unsigned long region_id, ndns_id;
|
|
+ const char *name;
|
|
+ char *ident, *save;
|
|
+
|
|
+ if (!__ident)
|
|
+ return ndns;
|
|
+
|
|
+ ident = strdup(__ident);
|
|
+ if (!ident)
|
|
+ return NULL;
|
|
+
|
|
+ for (name = strtok_r(ident, " ", &save); name;
|
|
+ name = strtok_r(NULL, " ", &save)) {
|
|
+ if (strcmp(name, "all") == 0)
|
|
+ break;
|
|
+
|
|
+ if (strcmp(name, ndctl_namespace_get_devname(ndns)) == 0)
|
|
+ break;
|
|
+
|
|
+ if (sscanf(name, "%ld.%ld", ®ion_id, &ndns_id) == 2
|
|
+ && ndctl_region_get_id(region) == region_id
|
|
+ && ndctl_namespace_get_id(ndns) == ndns_id)
|
|
+ break;
|
|
+ }
|
|
+ free(ident);
|
|
+
|
|
+ if (name)
|
|
+ return ndns;
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct ndctl_dimm *util_dimm_filter(struct ndctl_dimm *dimm,
|
|
+ const char *__ident)
|
|
+{
|
|
+ char *end = NULL, *ident, *save;
|
|
+ const char *name, *dimm_name;
|
|
+ unsigned long dimm_id, id;
|
|
+
|
|
+ if (!__ident)
|
|
+ return dimm;
|
|
+
|
|
+ ident = strdup(__ident);
|
|
+ if (!ident)
|
|
+ return NULL;
|
|
+
|
|
+ for (name = strtok_r(ident, " ", &save); name;
|
|
+ name = strtok_r(NULL, " ", &save)) {
|
|
+ if (strcmp(name, "all") == 0)
|
|
+ break;
|
|
+
|
|
+ dimm_id = strtoul(ident, &end, 0);
|
|
+ if (end == ident || end[0])
|
|
+ dimm_id = ULONG_MAX;
|
|
+
|
|
+ dimm_name = ndctl_dimm_get_devname(dimm);
|
|
+ id = ndctl_dimm_get_id(dimm);
|
|
+
|
|
+ if (dimm_id < ULONG_MAX && dimm_id == id)
|
|
+ break;
|
|
+
|
|
+ if (dimm_id == ULONG_MAX && strcmp(dimm_name, name) == 0)
|
|
+ break;
|
|
+ }
|
|
+ free(ident);
|
|
+
|
|
+ if (name)
|
|
+ return dimm;
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct ndctl_bus *util_bus_filter_by_dimm(struct ndctl_bus *bus,
|
|
+ const char *ident)
|
|
+{
|
|
+ struct ndctl_dimm *dimm;
|
|
+
|
|
+ if (!ident || strcmp(ident, "all") == 0)
|
|
+ return bus;
|
|
+
|
|
+ ndctl_dimm_foreach(bus, dimm)
|
|
+ if (util_dimm_filter(dimm, ident))
|
|
+ return bus;
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct ndctl_bus *util_bus_filter_by_region(struct ndctl_bus *bus,
|
|
+ const char *ident)
|
|
+{
|
|
+ struct ndctl_region *region;
|
|
+
|
|
+ if (!ident || strcmp(ident, "all") == 0)
|
|
+ return bus;
|
|
+
|
|
+ ndctl_region_foreach(bus, region)
|
|
+ if (util_region_filter(region, ident))
|
|
+ return bus;
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct ndctl_bus *util_bus_filter_by_namespace(struct ndctl_bus *bus,
|
|
+ const char *ident)
|
|
+{
|
|
+ struct ndctl_region *region;
|
|
+ struct ndctl_namespace *ndns;
|
|
+
|
|
+ if (!ident || strcmp(ident, "all") == 0)
|
|
+ return bus;
|
|
+
|
|
+ ndctl_region_foreach(bus, region)
|
|
+ ndctl_namespace_foreach(region, ndns)
|
|
+ if (util_namespace_filter(ndns, ident))
|
|
+ return bus;
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct ndctl_region *util_region_filter_by_dimm(struct ndctl_region *region,
|
|
+ const char *ident)
|
|
+{
|
|
+ struct ndctl_dimm *dimm;
|
|
+
|
|
+ if (!ident || strcmp(ident, "all") == 0)
|
|
+ return region;
|
|
+
|
|
+ ndctl_dimm_foreach_in_region(region, dimm)
|
|
+ if (util_dimm_filter(dimm, ident))
|
|
+ return region;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct ndctl_dimm *util_dimm_filter_by_region(struct ndctl_dimm *dimm,
|
|
+ const char *ident)
|
|
+{
|
|
+ struct ndctl_bus *bus = ndctl_dimm_get_bus(dimm);
|
|
+ struct ndctl_region *region;
|
|
+ struct ndctl_dimm *check;
|
|
+
|
|
+ if (!ident || strcmp(ident, "all") == 0)
|
|
+ return dimm;
|
|
+
|
|
+ ndctl_region_foreach(bus, region) {
|
|
+ if (!util_region_filter(region, ident))
|
|
+ continue;
|
|
+ ndctl_dimm_foreach_in_region(region, check)
|
|
+ if (check == dimm)
|
|
+ return dimm;
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct ndctl_dimm *util_dimm_filter_by_namespace(struct ndctl_dimm *dimm,
|
|
+ const char *ident)
|
|
+{
|
|
+ struct ndctl_bus *bus = ndctl_dimm_get_bus(dimm);
|
|
+ struct ndctl_namespace *ndns;
|
|
+ struct ndctl_region *region;
|
|
+ struct ndctl_dimm *check;
|
|
+
|
|
+ if (!ident || strcmp(ident, "all") == 0)
|
|
+ return dimm;
|
|
+
|
|
+ ndctl_region_foreach(bus, region) {
|
|
+ ndctl_namespace_foreach(region, ndns) {
|
|
+ if (!util_namespace_filter(ndns, ident))
|
|
+ continue;
|
|
+ ndctl_dimm_foreach_in_region(region, check)
|
|
+ if (check == dimm)
|
|
+ return dimm;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct ndctl_dimm *util_dimm_filter_by_numa_node(struct ndctl_dimm *dimm,
|
|
+ int numa_node)
|
|
+{
|
|
+ struct ndctl_bus *bus = ndctl_dimm_get_bus(dimm);
|
|
+ struct ndctl_region *region;
|
|
+ struct ndctl_dimm *check;
|
|
+
|
|
+ if (numa_node == NUMA_NO_NODE)
|
|
+ return dimm;
|
|
+
|
|
+ ndctl_region_foreach(bus, region)
|
|
+ ndctl_dimm_foreach_in_region(region, check)
|
|
+ if (check == dimm &&
|
|
+ ndctl_region_get_numa_node(region) == numa_node)
|
|
+ return dimm;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct ndctl_region *util_region_filter_by_namespace(struct ndctl_region *region,
|
|
+ const char *ident)
|
|
+{
|
|
+ struct ndctl_namespace *ndns;
|
|
+
|
|
+ if (!ident || strcmp(ident, "all") == 0)
|
|
+ return region;
|
|
+
|
|
+ ndctl_namespace_foreach(region, ndns)
|
|
+ if (util_namespace_filter(ndns, ident))
|
|
+ return region;
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+enum ndctl_namespace_mode util_nsmode(const char *mode)
|
|
+{
|
|
+ if (!mode)
|
|
+ return NDCTL_NS_MODE_UNKNOWN;
|
|
+ if (strcasecmp(mode, "memory") == 0)
|
|
+ return NDCTL_NS_MODE_FSDAX;
|
|
+ if (strcasecmp(mode, "fsdax") == 0)
|
|
+ return NDCTL_NS_MODE_FSDAX;
|
|
+ if (strcasecmp(mode, "sector") == 0)
|
|
+ return NDCTL_NS_MODE_SECTOR;
|
|
+ if (strcasecmp(mode, "safe") == 0)
|
|
+ return NDCTL_NS_MODE_SECTOR;
|
|
+ if (strcasecmp(mode, "dax") == 0)
|
|
+ return NDCTL_NS_MODE_DEVDAX;
|
|
+ if (strcasecmp(mode, "devdax") == 0)
|
|
+ return NDCTL_NS_MODE_DEVDAX;
|
|
+ if (strcasecmp(mode, "raw") == 0)
|
|
+ return NDCTL_NS_MODE_RAW;
|
|
+
|
|
+ return NDCTL_NS_MODE_UNKNOWN;
|
|
+}
|
|
+
|
|
+const char *util_nsmode_name(enum ndctl_namespace_mode mode)
|
|
+{
|
|
+ static const char * const modes[] = {
|
|
+ [NDCTL_NS_MODE_FSDAX] = "fsdax",
|
|
+ [NDCTL_NS_MODE_DEVDAX] = "devdax",
|
|
+ [NDCTL_NS_MODE_RAW] = "raw",
|
|
+ [NDCTL_NS_MODE_SECTOR] = "sector",
|
|
+ [NDCTL_NS_MODE_UNKNOWN] = "unknown",
|
|
+ };
|
|
+
|
|
+ return modes[mode];
|
|
+}
|
|
+
|
|
+int util_filter_walk(struct ndctl_ctx *ctx, struct util_filter_ctx *fctx,
|
|
+ struct util_filter_params *param)
|
|
+{
|
|
+ struct ndctl_bus *bus;
|
|
+ unsigned int type = 0;
|
|
+ int numa_node = NUMA_NO_NODE;
|
|
+ char *end = NULL;
|
|
+
|
|
+ if (param->type && (strcmp(param->type, "pmem") != 0
|
|
+ && strcmp(param->type, "blk") != 0)) {
|
|
+ error("unknown type \"%s\" must be \"pmem\" or \"blk\"\n",
|
|
+ param->type);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (param->type) {
|
|
+ if (strcmp(param->type, "pmem") == 0)
|
|
+ type = ND_DEVICE_REGION_PMEM;
|
|
+ else
|
|
+ type = ND_DEVICE_REGION_BLK;
|
|
+ }
|
|
+
|
|
+ if (param->mode && util_nsmode(param->mode) == NDCTL_NS_MODE_UNKNOWN) {
|
|
+ error("invalid mode: '%s'\n", param->mode);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (param->numa_node && strcmp(param->numa_node, "all") != 0) {
|
|
+ struct stat st;
|
|
+
|
|
+ if (stat("/sys/devices/system/node", &st) != 0) {
|
|
+ error("This system does not support NUMA");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ numa_node = strtol(param->numa_node, &end, 0);
|
|
+ if (end == param->numa_node || end[0]) {
|
|
+ error("invalid numa_node: '%s'\n", param->numa_node);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ndctl_bus_foreach(ctx, bus) {
|
|
+ struct ndctl_region *region;
|
|
+ struct ndctl_dimm *dimm;
|
|
+
|
|
+ if (!util_bus_filter(bus, param->bus)
|
|
+ || !util_bus_filter_by_dimm(bus, param->dimm)
|
|
+ || !util_bus_filter_by_region(bus, param->region)
|
|
+ || !util_bus_filter_by_namespace(bus, param->namespace))
|
|
+ continue;
|
|
+
|
|
+ if (!fctx->filter_bus(bus, fctx))
|
|
+ continue;
|
|
+
|
|
+ ndctl_dimm_foreach(bus, dimm) {
|
|
+ if (!fctx->filter_dimm)
|
|
+ break;
|
|
+
|
|
+ if (!util_dimm_filter(dimm, param->dimm)
|
|
+ || !util_dimm_filter_by_region(dimm,
|
|
+ param->region)
|
|
+ || !util_dimm_filter_by_namespace(dimm,
|
|
+ param->namespace)
|
|
+ || !util_dimm_filter_by_numa_node(dimm,
|
|
+ numa_node))
|
|
+ continue;
|
|
+
|
|
+ fctx->filter_dimm(dimm, fctx);
|
|
+ }
|
|
+
|
|
+ ndctl_region_foreach(bus, region) {
|
|
+ struct ndctl_namespace *ndns;
|
|
+
|
|
+ if (!util_region_filter(region, param->region)
|
|
+ || !util_region_filter_by_dimm(region,
|
|
+ param->dimm)
|
|
+ || !util_region_filter_by_namespace(region,
|
|
+ param->namespace))
|
|
+ continue;
|
|
+
|
|
+ /*
|
|
+ * if numa_node attribute is not available for regions
|
|
+ * (which is true for pre 5.4 kernels), don't skip the
|
|
+ * region if namespace is also requested, let the
|
|
+ * namespace filter handle the NUMA node filtering.
|
|
+ */
|
|
+ if (numa_node != NUMA_NO_NODE &&
|
|
+ !ndctl_region_has_numa(region) &&
|
|
+ !fctx->filter_namespace) {
|
|
+ fprintf(stderr,
|
|
+ "This kernel does not provide NUMA node information per-region\n");
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (ndctl_region_has_numa(region) &&
|
|
+ numa_node != NUMA_NO_NODE &&
|
|
+ ndctl_region_get_numa_node(region) != numa_node)
|
|
+ continue;
|
|
+
|
|
+ if (type && ndctl_region_get_type(region) != type)
|
|
+ continue;
|
|
+
|
|
+ if (!fctx->filter_region(region, fctx))
|
|
+ continue;
|
|
+
|
|
+ ndctl_namespace_foreach(region, ndns) {
|
|
+ enum ndctl_namespace_mode mode;
|
|
+
|
|
+ if (!fctx->filter_namespace)
|
|
+ break;
|
|
+ if (!util_namespace_filter(ndns, param->namespace))
|
|
+ continue;
|
|
+
|
|
+ mode = ndctl_namespace_get_mode(ndns);
|
|
+ if (param->mode && util_nsmode(param->mode) != mode)
|
|
+ continue;
|
|
+
|
|
+ if (numa_node != NUMA_NO_NODE &&
|
|
+ ndctl_namespace_get_numa_node(ndns) != numa_node)
|
|
+ continue;
|
|
+
|
|
+ fctx->filter_namespace(ndns, fctx);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
diff -up ndctl-71.1/ndctl/filter.h.orig ndctl-71.1/ndctl/filter.h
|
|
--- ndctl-71.1/ndctl/filter.h.orig 2022-10-07 15:51:03.929535779 -0400
|
|
+++ ndctl-71.1/ndctl/filter.h 2022-10-07 15:51:03.908535707 -0400
|
|
@@ -0,0 +1,86 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */
|
|
+#ifndef _NDCTL_UTIL_FILTER_H_
|
|
+#define _NDCTL_UTIL_FILTER_H_
|
|
+#include <stdbool.h>
|
|
+#include <ccan/list/list.h>
|
|
+
|
|
+struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *ident);
|
|
+struct ndctl_region *util_region_filter(struct ndctl_region *region,
|
|
+ const char *ident);
|
|
+struct ndctl_namespace *util_namespace_filter(struct ndctl_namespace *ndns,
|
|
+ const char *ident);
|
|
+struct ndctl_dimm *util_dimm_filter(struct ndctl_dimm *dimm, const char *ident);
|
|
+struct ndctl_bus *util_bus_filter_by_dimm(struct ndctl_bus *bus,
|
|
+ const char *ident);
|
|
+struct ndctl_bus *util_bus_filter_by_region(struct ndctl_bus *bus,
|
|
+ const char *ident);
|
|
+struct ndctl_bus *util_bus_filter_by_namespace(struct ndctl_bus *bus,
|
|
+ const char *ident);
|
|
+struct ndctl_region *util_region_filter_by_dimm(struct ndctl_region *region,
|
|
+ const char *ident);
|
|
+struct ndctl_dimm *util_dimm_filter_by_region(struct ndctl_dimm *dimm,
|
|
+ const char *ident);
|
|
+struct ndctl_dimm *util_dimm_filter_by_namespace(struct ndctl_dimm *dimm,
|
|
+ const char *ident);
|
|
+struct ndctl_region *util_region_filter_by_namespace(struct ndctl_region *region,
|
|
+ const char *ident);
|
|
+
|
|
+enum ndctl_namespace_mode util_nsmode(const char *mode);
|
|
+const char *util_nsmode_name(enum ndctl_namespace_mode mode);
|
|
+
|
|
+struct json_object;
|
|
+
|
|
+/* json object hierarchy for the util_filter_walk() performed by cmd_list() */
|
|
+struct list_filter_arg {
|
|
+ struct json_object *jnamespaces;
|
|
+ struct json_object *jregions;
|
|
+ struct json_object *jdimms;
|
|
+ struct json_object *jbuses;
|
|
+ struct json_object *jregion;
|
|
+ struct json_object *jbus;
|
|
+ unsigned long flags;
|
|
+};
|
|
+
|
|
+struct monitor_filter_arg {
|
|
+ struct list_head dimms;
|
|
+ int maxfd_dimm;
|
|
+ int num_dimm;
|
|
+ unsigned long flags;
|
|
+};
|
|
+
|
|
+/*
|
|
+ * struct util_filter_ctx - control and callbacks for util_filter_walk()
|
|
+ * ->filter_bus() and ->filter_region() return bool because the
|
|
+ * child-object filter routines can not be called if the parent context
|
|
+ * is not established. ->filter_dimm() and ->filter_namespace() are leaf
|
|
+ * objects, so no child dependencies to check.
|
|
+ */
|
|
+struct util_filter_ctx {
|
|
+ bool (*filter_bus)(struct ndctl_bus *bus, struct util_filter_ctx *ctx);
|
|
+ void (*filter_dimm)(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx);
|
|
+ bool (*filter_region)(struct ndctl_region *region,
|
|
+ struct util_filter_ctx *ctx);
|
|
+ void (*filter_namespace)(struct ndctl_namespace *ndns,
|
|
+ struct util_filter_ctx *ctx);
|
|
+ union {
|
|
+ void *arg;
|
|
+ struct list_filter_arg *list;
|
|
+ struct monitor_filter_arg *monitor;
|
|
+ };
|
|
+};
|
|
+
|
|
+struct util_filter_params {
|
|
+ const char *bus;
|
|
+ const char *region;
|
|
+ const char *type;
|
|
+ const char *dimm;
|
|
+ const char *mode;
|
|
+ const char *namespace;
|
|
+ const char *numa_node;
|
|
+};
|
|
+
|
|
+struct ndctl_ctx;
|
|
+int util_filter_walk(struct ndctl_ctx *ctx, struct util_filter_ctx *fctx,
|
|
+ struct util_filter_params *param);
|
|
+#endif /* _NDCTL_UTIL_FILTER_H_ */
|
|
diff -up ndctl-71.1/ndctl/inject-error.c.orig ndctl-71.1/ndctl/inject-error.c
|
|
--- ndctl-71.1/ndctl/inject-error.c.orig 2022-10-07 15:50:40.081454584 -0400
|
|
+++ ndctl-71.1/ndctl/inject-error.c 2022-10-07 15:51:03.909535711 -0400
|
|
@@ -12,12 +12,11 @@
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
-#include <ndctl.h>
|
|
#include <util/log.h>
|
|
#include <util/size.h>
|
|
#include <util/json.h>
|
|
#include <json-c/json.h>
|
|
-#include <util/filter.h>
|
|
+#include <ndctl/ndctl.h>
|
|
#include <ndctl/libndctl.h>
|
|
#include <util/parse-options.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
@@ -26,6 +25,9 @@
|
|
#include <builtin.h>
|
|
#include <test.h>
|
|
|
|
+#include "filter.h"
|
|
+#include "json.h"
|
|
+
|
|
static bool verbose;
|
|
static struct parameters {
|
|
const char *bus;
|
|
diff -up ndctl-71.1/ndctl/inject-smart.c.orig ndctl-71.1/ndctl/inject-smart.c
|
|
--- ndctl-71.1/ndctl/inject-smart.c.orig 2022-10-07 15:50:40.081454584 -0400
|
|
+++ ndctl-71.1/ndctl/inject-smart.c 2022-10-07 15:51:03.910535714 -0400
|
|
@@ -13,12 +13,11 @@
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
-#include <ndctl.h>
|
|
#include <util/log.h>
|
|
#include <util/size.h>
|
|
#include <util/json.h>
|
|
#include <json-c/json.h>
|
|
-#include <util/filter.h>
|
|
+#include <ndctl/ndctl.h>
|
|
#include <ndctl/libndctl.h>
|
|
#include <util/parse-options.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
@@ -27,6 +26,9 @@
|
|
#include <builtin.h>
|
|
#include <test.h>
|
|
|
|
+#include "filter.h"
|
|
+#include "json.h"
|
|
+
|
|
static struct parameters {
|
|
const char *bus;
|
|
const char *dimm;
|
|
diff -up ndctl-71.1/ndctl/json-smart.c.orig ndctl-71.1/ndctl/json-smart.c
|
|
--- ndctl-71.1/ndctl/json-smart.c.orig 2022-10-07 15:51:03.929535779 -0400
|
|
+++ ndctl-71.1/ndctl/json-smart.c 2022-10-07 15:51:03.910535714 -0400
|
|
@@ -0,0 +1,214 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
|
|
+#include <limits.h>
|
|
+#include <uuid/uuid.h>
|
|
+#include <json-c/json.h>
|
|
+#include <ndctl/ndctl.h>
|
|
+#include <ndctl/libndctl.h>
|
|
+#include <ccan/array_size/array_size.h>
|
|
+
|
|
+#include "json.h"
|
|
+
|
|
+static void smart_threshold_to_json(struct ndctl_dimm *dimm,
|
|
+ struct json_object *jhealth)
|
|
+{
|
|
+ unsigned int alarm_control;
|
|
+ struct json_object *jobj;
|
|
+ struct ndctl_cmd *cmd;
|
|
+ int rc;
|
|
+
|
|
+ cmd = ndctl_dimm_cmd_new_smart_threshold(dimm);
|
|
+ if (!cmd)
|
|
+ return;
|
|
+
|
|
+ rc = ndctl_cmd_submit_xlat(cmd);
|
|
+ if (rc < 0)
|
|
+ goto out;
|
|
+
|
|
+ alarm_control = ndctl_cmd_smart_threshold_get_alarm_control(cmd);
|
|
+ if (alarm_control & ND_SMART_TEMP_TRIP) {
|
|
+ unsigned int temp;
|
|
+ double t;
|
|
+
|
|
+ jobj = json_object_new_boolean(true);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth,
|
|
+ "alarm_enabled_media_temperature", jobj);
|
|
+ temp = ndctl_cmd_smart_threshold_get_temperature(cmd);
|
|
+ t = ndctl_decode_smart_temperature(temp);
|
|
+ jobj = json_object_new_double(t);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth,
|
|
+ "temperature_threshold", jobj);
|
|
+ } else {
|
|
+ jobj = json_object_new_boolean(false);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth,
|
|
+ "alarm_enabled_media_temperature", jobj);
|
|
+ }
|
|
+
|
|
+ if (alarm_control & ND_SMART_CTEMP_TRIP) {
|
|
+ unsigned int temp;
|
|
+ double t;
|
|
+
|
|
+ jobj = json_object_new_boolean(true);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth,
|
|
+ "alarm_enabled_ctrl_temperature", jobj);
|
|
+ temp = ndctl_cmd_smart_threshold_get_ctrl_temperature(cmd);
|
|
+ t = ndctl_decode_smart_temperature(temp);
|
|
+ jobj = json_object_new_double(t);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth,
|
|
+ "controller_temperature_threshold", jobj);
|
|
+ } else {
|
|
+ jobj = json_object_new_boolean(false);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth,
|
|
+ "alarm_enabled_ctrl_temperature", jobj);
|
|
+ }
|
|
+
|
|
+ if (alarm_control & ND_SMART_SPARE_TRIP) {
|
|
+ unsigned int spares;
|
|
+
|
|
+ jobj = json_object_new_boolean(true);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth,
|
|
+ "alarm_enabled_spares", jobj);
|
|
+ spares = ndctl_cmd_smart_threshold_get_spares(cmd);
|
|
+ jobj = json_object_new_int(spares);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth,
|
|
+ "spares_threshold", jobj);
|
|
+ } else {
|
|
+ jobj = json_object_new_boolean(false);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth,
|
|
+ "alarm_enabled_spares", jobj);
|
|
+ }
|
|
+
|
|
+ out:
|
|
+ ndctl_cmd_unref(cmd);
|
|
+}
|
|
+
|
|
+struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm)
|
|
+{
|
|
+ struct json_object *jhealth = json_object_new_object();
|
|
+ struct json_object *jobj;
|
|
+ struct ndctl_cmd *cmd;
|
|
+ unsigned int flags;
|
|
+ int rc;
|
|
+
|
|
+ if (!jhealth)
|
|
+ return NULL;
|
|
+
|
|
+ cmd = ndctl_dimm_cmd_new_smart(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(jhealth, "health_state", jobj);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ flags = ndctl_cmd_smart_get_flags(cmd);
|
|
+ if (flags & ND_SMART_HEALTH_VALID) {
|
|
+ unsigned int health = ndctl_cmd_smart_get_health(cmd);
|
|
+
|
|
+ if (health & ND_SMART_FATAL_HEALTH)
|
|
+ jobj = json_object_new_string("fatal");
|
|
+ else if (health & ND_SMART_CRITICAL_HEALTH)
|
|
+ jobj = json_object_new_string("critical");
|
|
+ else if (health & ND_SMART_NON_CRITICAL_HEALTH)
|
|
+ jobj = json_object_new_string("non-critical");
|
|
+ else
|
|
+ jobj = json_object_new_string("ok");
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "health_state", jobj);
|
|
+ }
|
|
+
|
|
+ if (flags & ND_SMART_TEMP_VALID) {
|
|
+ unsigned int temp = ndctl_cmd_smart_get_temperature(cmd);
|
|
+ double t = ndctl_decode_smart_temperature(temp);
|
|
+
|
|
+ jobj = json_object_new_double(t);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "temperature_celsius", jobj);
|
|
+ }
|
|
+
|
|
+ if (flags & ND_SMART_CTEMP_VALID) {
|
|
+ unsigned int temp = ndctl_cmd_smart_get_ctrl_temperature(cmd);
|
|
+ double t = ndctl_decode_smart_temperature(temp);
|
|
+
|
|
+ jobj = json_object_new_double(t);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth,
|
|
+ "controller_temperature_celsius", jobj);
|
|
+ }
|
|
+
|
|
+ if (flags & ND_SMART_SPARES_VALID) {
|
|
+ unsigned int spares = ndctl_cmd_smart_get_spares(cmd);
|
|
+
|
|
+ jobj = json_object_new_int(spares);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "spares_percentage", jobj);
|
|
+ }
|
|
+
|
|
+ if (flags & ND_SMART_ALARM_VALID) {
|
|
+ unsigned int alarm_flags = ndctl_cmd_smart_get_alarm_flags(cmd);
|
|
+ bool temp_flag = !!(alarm_flags & ND_SMART_TEMP_TRIP);
|
|
+ bool ctrl_temp_flag = !!(alarm_flags & ND_SMART_CTEMP_TRIP);
|
|
+ bool spares_flag = !!(alarm_flags & ND_SMART_SPARE_TRIP);
|
|
+
|
|
+ jobj = json_object_new_boolean(temp_flag);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "alarm_temperature", jobj);
|
|
+
|
|
+ jobj = json_object_new_boolean(ctrl_temp_flag);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "alarm_controller_temperature", jobj);
|
|
+
|
|
+ jobj = json_object_new_boolean(spares_flag);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "alarm_spares", jobj);
|
|
+ }
|
|
+
|
|
+ smart_threshold_to_json(dimm, jhealth);
|
|
+
|
|
+ if (flags & ND_SMART_USED_VALID) {
|
|
+ unsigned int life_used = ndctl_cmd_smart_get_life_used(cmd);
|
|
+
|
|
+ jobj = json_object_new_int(life_used);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "life_used_percentage", jobj);
|
|
+ }
|
|
+
|
|
+ if (flags & ND_SMART_SHUTDOWN_VALID) {
|
|
+ unsigned int shutdown = ndctl_cmd_smart_get_shutdown_state(cmd);
|
|
+
|
|
+ jobj = json_object_new_string(shutdown ? "dirty" : "clean");
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "shutdown_state", jobj);
|
|
+ }
|
|
+
|
|
+ if (flags & ND_SMART_SHUTDOWN_COUNT_VALID) {
|
|
+ unsigned int shutdown = ndctl_cmd_smart_get_shutdown_count(cmd);
|
|
+
|
|
+ jobj = json_object_new_int(shutdown);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jhealth, "shutdown_count", jobj);
|
|
+ }
|
|
+
|
|
+ ndctl_cmd_unref(cmd);
|
|
+ return jhealth;
|
|
+ err:
|
|
+ json_object_put(jhealth);
|
|
+ jhealth = NULL;
|
|
+ out:
|
|
+ if (cmd)
|
|
+ ndctl_cmd_unref(cmd);
|
|
+ return jhealth;
|
|
+}
|
|
diff -up ndctl-71.1/ndctl/json.c.orig ndctl-71.1/ndctl/json.c
|
|
--- ndctl-71.1/ndctl/json.c.orig 2022-10-07 15:51:03.912535721 -0400
|
|
+++ ndctl-71.1/ndctl/json.c 2022-10-07 15:51:03.912535721 -0400
|
|
@@ -0,0 +1,1114 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
|
|
+#include <limits.h>
|
|
+#include <string.h>
|
|
+#include <util/json.h>
|
|
+#include <uuid/uuid.h>
|
|
+#include <json-c/json.h>
|
|
+#include <ndctl/libndctl.h>
|
|
+#include <json-c/printbuf.h>
|
|
+
|
|
+#include "json.h"
|
|
+#include "ndctl.h"
|
|
+#include "../daxctl/json.h"
|
|
+
|
|
+struct json_object *util_bus_to_json(struct ndctl_bus *bus, unsigned long flags)
|
|
+{
|
|
+ struct json_object *jbus = json_object_new_object();
|
|
+ struct json_object *jobj, *fw_obj = NULL;
|
|
+ int scrub;
|
|
+
|
|
+ if (!jbus)
|
|
+ return NULL;
|
|
+
|
|
+ jobj = json_object_new_string(ndctl_bus_get_provider(bus));
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jbus, "provider", jobj);
|
|
+
|
|
+ jobj = json_object_new_string(ndctl_bus_get_devname(bus));
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jbus, "dev", jobj);
|
|
+
|
|
+ scrub = ndctl_bus_get_scrub_state(bus);
|
|
+ if (scrub < 0)
|
|
+ return jbus;
|
|
+
|
|
+ jobj = json_object_new_string(scrub ? "active" : "idle");
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jbus, "scrub_state", jobj);
|
|
+
|
|
+ if (flags & UTIL_JSON_FIRMWARE) {
|
|
+ struct ndctl_dimm *dimm;
|
|
+
|
|
+ /*
|
|
+ * Skip displaying firmware activation capability if no
|
|
+ * DIMMs support firmware update.
|
|
+ */
|
|
+ ndctl_dimm_foreach(bus, dimm)
|
|
+ if (ndctl_dimm_fw_update_supported(dimm) == 0) {
|
|
+ fw_obj = json_object_new_object();
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (fw_obj) {
|
|
+ enum ndctl_fwa_state state;
|
|
+ enum ndctl_fwa_method method;
|
|
+
|
|
+ jobj = NULL;
|
|
+ method = ndctl_bus_get_fw_activate_method(bus);
|
|
+ if (method == NDCTL_FWA_METHOD_RESET)
|
|
+ jobj = json_object_new_string("reset");
|
|
+ if (method == NDCTL_FWA_METHOD_SUSPEND)
|
|
+ jobj = json_object_new_string("suspend");
|
|
+ if (method == NDCTL_FWA_METHOD_LIVE)
|
|
+ jobj = json_object_new_string("live");
|
|
+ if (jobj)
|
|
+ json_object_object_add(fw_obj, "activate_method", jobj);
|
|
+
|
|
+ jobj = NULL;
|
|
+ state = ndctl_bus_get_fw_activate_state(bus);
|
|
+ if (state == NDCTL_FWA_ARMED)
|
|
+ jobj = json_object_new_string("armed");
|
|
+ if (state == NDCTL_FWA_IDLE)
|
|
+ jobj = json_object_new_string("idle");
|
|
+ if (state == NDCTL_FWA_ARM_OVERFLOW)
|
|
+ jobj = json_object_new_string("overflow");
|
|
+ if (jobj)
|
|
+ json_object_object_add(fw_obj, "activate_state", jobj);
|
|
+
|
|
+ json_object_object_add(jbus, "firmware", fw_obj);
|
|
+ }
|
|
+
|
|
+ return jbus;
|
|
+ err:
|
|
+ json_object_put(jbus);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+struct json_object *util_dimm_firmware_to_json(struct ndctl_dimm *dimm,
|
|
+ unsigned long flags)
|
|
+{
|
|
+ struct json_object *jfirmware = json_object_new_object();
|
|
+ bool can_update, need_powercycle;
|
|
+ enum ndctl_fwa_result result;
|
|
+ enum ndctl_fwa_state state;
|
|
+ struct json_object *jobj;
|
|
+ struct ndctl_cmd *cmd;
|
|
+ uint64_t run, next;
|
|
+ int rc;
|
|
+
|
|
+ if (!jfirmware)
|
|
+ return NULL;
|
|
+
|
|
+ cmd = ndctl_dimm_cmd_new_fw_get_info(dimm);
|
|
+ if (!cmd)
|
|
+ goto err;
|
|
+
|
|
+ rc = ndctl_cmd_submit(cmd);
|
|
+ if ((rc < 0) || ndctl_cmd_fw_xlat_firmware_status(cmd) != FW_SUCCESS) {
|
|
+ jobj = util_json_object_hex(-1, flags);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jfirmware, "current_version",
|
|
+ jobj);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ run = ndctl_cmd_fw_info_get_run_version(cmd);
|
|
+ if (run == ULLONG_MAX) {
|
|
+ jobj = util_json_object_hex(-1, flags);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jfirmware, "current_version",
|
|
+ jobj);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ jobj = util_json_object_hex(run, flags);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jfirmware, "current_version", jobj);
|
|
+
|
|
+ rc = ndctl_dimm_fw_update_supported(dimm);
|
|
+ can_update = rc == 0;
|
|
+ jobj = json_object_new_boolean(can_update);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jfirmware, "can_update", jobj);
|
|
+
|
|
+
|
|
+ next = ndctl_cmd_fw_info_get_updated_version(cmd);
|
|
+ if (next == ULLONG_MAX) {
|
|
+ jobj = util_json_object_hex(-1, flags);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jfirmware, "next_version",
|
|
+ jobj);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (!next)
|
|
+ goto out;
|
|
+
|
|
+ jobj = util_json_object_hex(next, flags);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jfirmware,
|
|
+ "next_version", jobj);
|
|
+
|
|
+ state = ndctl_dimm_get_fw_activate_state(dimm);
|
|
+ switch (state) {
|
|
+ case NDCTL_FWA_IDLE:
|
|
+ jobj = json_object_new_string("idle");
|
|
+ break;
|
|
+ case NDCTL_FWA_ARMED:
|
|
+ jobj = json_object_new_string("armed");
|
|
+ break;
|
|
+ case NDCTL_FWA_BUSY:
|
|
+ jobj = json_object_new_string("busy");
|
|
+ break;
|
|
+ default:
|
|
+ jobj = NULL;
|
|
+ break;
|
|
+ }
|
|
+ if (jobj)
|
|
+ json_object_object_add(jfirmware, "activate_state", jobj);
|
|
+
|
|
+ result = ndctl_dimm_get_fw_activate_result(dimm);
|
|
+ switch (result) {
|
|
+ case NDCTL_FWA_RESULT_NONE:
|
|
+ case NDCTL_FWA_RESULT_SUCCESS:
|
|
+ case NDCTL_FWA_RESULT_NOTSTAGED:
|
|
+ /*
|
|
+ * If a 'next' firmware version is staged then this
|
|
+ * result is stale, if the activation succeeds that is
|
|
+ * indicated by not finding a 'next' entry.
|
|
+ */
|
|
+ need_powercycle = false;
|
|
+ break;
|
|
+ case NDCTL_FWA_RESULT_NEEDRESET:
|
|
+ case NDCTL_FWA_RESULT_FAIL:
|
|
+ default:
|
|
+ /*
|
|
+ * If the last activation failed, or if the activation
|
|
+ * result is unavailable it is always the case that the
|
|
+ * only remediation is powercycle.
|
|
+ */
|
|
+ need_powercycle = true;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (need_powercycle) {
|
|
+ jobj = json_object_new_boolean(true);
|
|
+ if (!jobj)
|
|
+ goto out;
|
|
+ json_object_object_add(jfirmware, "need_powercycle", jobj);
|
|
+ }
|
|
+
|
|
+ ndctl_cmd_unref(cmd);
|
|
+ return jfirmware;
|
|
+
|
|
+err:
|
|
+ json_object_put(jfirmware);
|
|
+ jfirmware = NULL;
|
|
+out:
|
|
+ if (cmd)
|
|
+ ndctl_cmd_unref(cmd);
|
|
+ return jfirmware;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm,
|
|
+ unsigned long flags)
|
|
+{
|
|
+ struct json_object *jdimm = json_object_new_object();
|
|
+ const char *id = ndctl_dimm_get_unique_id(dimm);
|
|
+ unsigned int handle = ndctl_dimm_get_handle(dimm);
|
|
+ unsigned short phys_id = ndctl_dimm_get_phys_id(dimm);
|
|
+ struct json_object *jobj;
|
|
+ enum ndctl_security_state sstate;
|
|
+
|
|
+ if (!jdimm)
|
|
+ return NULL;
|
|
+
|
|
+ jobj = json_object_new_string(ndctl_dimm_get_devname(dimm));
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jdimm, "dev", jobj);
|
|
+
|
|
+ if (id) {
|
|
+ jobj = json_object_new_string(id);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jdimm, "id", jobj);
|
|
+ }
|
|
+
|
|
+ if (handle < UINT_MAX) {
|
|
+ jobj = util_json_object_hex(handle, flags);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jdimm, "handle", jobj);
|
|
+ }
|
|
+
|
|
+ if (phys_id < USHRT_MAX) {
|
|
+ jobj = util_json_object_hex(phys_id, flags);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jdimm, "phys_id", jobj);
|
|
+ }
|
|
+
|
|
+ if (!ndctl_dimm_is_enabled(dimm)) {
|
|
+ jobj = json_object_new_string("disabled");
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jdimm, "state", jobj);
|
|
+ }
|
|
+
|
|
+ if (ndctl_dimm_failed_map(dimm)) {
|
|
+ jobj = json_object_new_boolean(true);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jdimm, "flag_failed_map", jobj);
|
|
+ }
|
|
+
|
|
+ if (ndctl_dimm_failed_save(dimm)) {
|
|
+ jobj = json_object_new_boolean(true);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jdimm, "flag_failed_save", jobj);
|
|
+ }
|
|
+
|
|
+ if (ndctl_dimm_failed_arm(dimm)) {
|
|
+ jobj = json_object_new_boolean(true);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jdimm, "flag_failed_arm", jobj);
|
|
+ }
|
|
+
|
|
+ if (ndctl_dimm_failed_restore(dimm)) {
|
|
+ jobj = json_object_new_boolean(true);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jdimm, "flag_failed_restore", jobj);
|
|
+ }
|
|
+
|
|
+ if (ndctl_dimm_failed_flush(dimm)) {
|
|
+ jobj = json_object_new_boolean(true);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jdimm, "flag_failed_flush", jobj);
|
|
+ }
|
|
+
|
|
+ if (ndctl_dimm_smart_pending(dimm)) {
|
|
+ jobj = json_object_new_boolean(true);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jdimm, "flag_smart_event", jobj);
|
|
+ }
|
|
+
|
|
+ sstate = ndctl_dimm_get_security(dimm);
|
|
+ if (sstate == NDCTL_SECURITY_DISABLED)
|
|
+ jobj = json_object_new_string("disabled");
|
|
+ else if (sstate == NDCTL_SECURITY_UNLOCKED)
|
|
+ jobj = json_object_new_string("unlocked");
|
|
+ else if (sstate == NDCTL_SECURITY_LOCKED)
|
|
+ jobj = json_object_new_string("locked");
|
|
+ else if (sstate == NDCTL_SECURITY_FROZEN)
|
|
+ jobj = json_object_new_string("frozen");
|
|
+ else if (sstate == NDCTL_SECURITY_OVERWRITE)
|
|
+ jobj = json_object_new_string("overwrite");
|
|
+ else
|
|
+ jobj = NULL;
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdimm, "security", jobj);
|
|
+
|
|
+ if (ndctl_dimm_security_is_frozen(dimm)) {
|
|
+ jobj = json_object_new_boolean(true);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jdimm, "security_frozen", jobj);
|
|
+ }
|
|
+
|
|
+ if (flags & UTIL_JSON_FIRMWARE) {
|
|
+ struct json_object *jfirmware;
|
|
+
|
|
+ jfirmware = util_dimm_firmware_to_json(dimm, flags);
|
|
+ if (jfirmware)
|
|
+ json_object_object_add(jdimm, "firmware", jfirmware);
|
|
+ }
|
|
+
|
|
+ return jdimm;
|
|
+ err:
|
|
+ json_object_put(jdimm);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+#define _SZ(get_max, get_elem, type) \
|
|
+static struct json_object *util_##type##_build_size_array(struct ndctl_##type *arg) \
|
|
+{ \
|
|
+ struct json_object *arr = json_object_new_array(); \
|
|
+ int i; \
|
|
+ \
|
|
+ if (!arr) \
|
|
+ return NULL; \
|
|
+ \
|
|
+ for (i = 0; i < get_max(arg); i++) { \
|
|
+ struct json_object *jobj; \
|
|
+ int64_t align; \
|
|
+ \
|
|
+ align = get_elem(arg, i); \
|
|
+ jobj = json_object_new_int64(align); \
|
|
+ if (!jobj) \
|
|
+ goto err; \
|
|
+ json_object_array_add(arr, jobj); \
|
|
+ } \
|
|
+ \
|
|
+ return arr; \
|
|
+err: \
|
|
+ json_object_put(arr); \
|
|
+ return NULL; \
|
|
+}
|
|
+#define SZ(type, kind) _SZ(ndctl_##type##_get_num_##kind##s, \
|
|
+ ndctl_##type##_get_supported_##kind, type)
|
|
+SZ(pfn, alignment)
|
|
+SZ(dax, alignment)
|
|
+SZ(btt, sector_size)
|
|
+
|
|
+struct json_object *util_region_capabilities_to_json(struct ndctl_region *region)
|
|
+{
|
|
+ struct json_object *jcaps, *jcap, *jobj;
|
|
+ struct ndctl_btt *btt = ndctl_region_get_btt_seed(region);
|
|
+ struct ndctl_pfn *pfn = ndctl_region_get_pfn_seed(region);
|
|
+ struct ndctl_dax *dax = ndctl_region_get_dax_seed(region);
|
|
+
|
|
+ if (!btt || !pfn || !dax)
|
|
+ return NULL;
|
|
+
|
|
+ jcaps = json_object_new_array();
|
|
+ if (!jcaps)
|
|
+ return NULL;
|
|
+
|
|
+ if (btt) {
|
|
+ jcap = json_object_new_object();
|
|
+ if (!jcap)
|
|
+ goto err;
|
|
+ json_object_array_add(jcaps, jcap);
|
|
+
|
|
+ jobj = json_object_new_string("sector");
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jcap, "mode", jobj);
|
|
+ jobj = util_btt_build_size_array(btt);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jcap, "sector_sizes", jobj);
|
|
+ }
|
|
+
|
|
+ if (pfn) {
|
|
+ jcap = json_object_new_object();
|
|
+ if (!jcap)
|
|
+ goto err;
|
|
+ json_object_array_add(jcaps, jcap);
|
|
+
|
|
+ jobj = json_object_new_string("fsdax");
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jcap, "mode", jobj);
|
|
+ jobj = util_pfn_build_size_array(pfn);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jcap, "alignments", jobj);
|
|
+ }
|
|
+
|
|
+ if (dax) {
|
|
+ jcap = json_object_new_object();
|
|
+ if (!jcap)
|
|
+ goto err;
|
|
+ json_object_array_add(jcaps, jcap);
|
|
+
|
|
+ jobj = json_object_new_string("devdax");
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jcap, "mode", jobj);
|
|
+ jobj = util_dax_build_size_array(dax);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jcap, "alignments", jobj);
|
|
+ }
|
|
+
|
|
+ return jcaps;
|
|
+err:
|
|
+ json_object_put(jcaps);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+
|
|
+static int compare_dimm_number(const void *p1, const void *p2)
|
|
+{
|
|
+ struct ndctl_dimm *dimm1 = *(struct ndctl_dimm **)p1;
|
|
+ struct ndctl_dimm *dimm2 = *(struct ndctl_dimm **)p2;
|
|
+ const char *dimm1_name = ndctl_dimm_get_devname(dimm1);
|
|
+ const char *dimm2_name = ndctl_dimm_get_devname(dimm2);
|
|
+ int num1, num2;
|
|
+
|
|
+ if (sscanf(dimm1_name, "nmem%d", &num1) != 1)
|
|
+ num1 = 0;
|
|
+ if (sscanf(dimm2_name, "nmem%d", &num2) != 1)
|
|
+ num2 = 0;
|
|
+
|
|
+ return num1 - num2;
|
|
+}
|
|
+
|
|
+static struct json_object *badblocks_to_jdimms(struct ndctl_region *region,
|
|
+ unsigned long long addr, unsigned long len)
|
|
+{
|
|
+ struct ndctl_bus *bus = ndctl_region_get_bus(region);
|
|
+ int count = ndctl_region_get_interleave_ways(region);
|
|
+ unsigned long long end = addr + len;
|
|
+ struct json_object *jdimms, *jobj;
|
|
+ struct ndctl_dimm **dimms, *dimm;
|
|
+ int found, i;
|
|
+
|
|
+ jdimms = json_object_new_array();
|
|
+ if (!jdimms)
|
|
+ return NULL;
|
|
+
|
|
+ dimms = calloc(count, sizeof(struct ndctl_dimm *));
|
|
+ if (!dimms)
|
|
+ goto err_dimms;
|
|
+
|
|
+ for (found = 0; found < count && addr < end; addr += 512) {
|
|
+ dimm = ndctl_bus_get_dimm_by_physical_address(bus, addr);
|
|
+ if (!dimm)
|
|
+ continue;
|
|
+
|
|
+ for (i = 0; i < count; i++)
|
|
+ if (dimms[i] == dimm)
|
|
+ break;
|
|
+ if (i >= count)
|
|
+ dimms[found++] = dimm;
|
|
+ }
|
|
+
|
|
+ if (!found)
|
|
+ goto err_found;
|
|
+
|
|
+ qsort(dimms, found, sizeof(dimm), compare_dimm_number);
|
|
+
|
|
+ for (i = 0; i < found; i++) {
|
|
+ const char *devname = ndctl_dimm_get_devname(dimms[i]);
|
|
+
|
|
+ jobj = json_object_new_string(devname);
|
|
+ if (!jobj)
|
|
+ break;
|
|
+ json_object_array_add(jdimms, jobj);
|
|
+ }
|
|
+
|
|
+ if (!i)
|
|
+ goto err_found;
|
|
+ free(dimms);
|
|
+ return jdimms;
|
|
+
|
|
+err_found:
|
|
+ free(dimms);
|
|
+err_dimms:
|
|
+ json_object_put(jdimms);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct json_object *util_region_badblocks_to_json(struct ndctl_region *region,
|
|
+ unsigned int *bb_count, unsigned long flags)
|
|
+{
|
|
+ struct json_object *jbb = NULL, *jbbs = NULL, *jobj;
|
|
+ struct badblock *bb;
|
|
+ int bbs = 0;
|
|
+
|
|
+ if (flags & UTIL_JSON_MEDIA_ERRORS) {
|
|
+ jbbs = json_object_new_array();
|
|
+ if (!jbbs)
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ ndctl_region_badblock_foreach(region, bb) {
|
|
+ struct json_object *jdimms;
|
|
+ unsigned long long addr;
|
|
+
|
|
+ bbs += bb->len;
|
|
+
|
|
+ /* recheck so we can still get the badblocks_count from above */
|
|
+ if (!(flags & UTIL_JSON_MEDIA_ERRORS))
|
|
+ continue;
|
|
+
|
|
+ /* get start address of region */
|
|
+ addr = ndctl_region_get_resource(region);
|
|
+ if (addr == ULLONG_MAX)
|
|
+ goto err_array;
|
|
+
|
|
+ /* get address of bad block */
|
|
+ addr += bb->offset << 9;
|
|
+
|
|
+ jbb = json_object_new_object();
|
|
+ if (!jbb)
|
|
+ goto err_array;
|
|
+
|
|
+ jobj = json_object_new_int64(bb->offset);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jbb, "offset", jobj);
|
|
+
|
|
+ jobj = json_object_new_int(bb->len);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jbb, "length", jobj);
|
|
+
|
|
+ jdimms = badblocks_to_jdimms(region, addr, bb->len << 9);
|
|
+ if (jdimms)
|
|
+ json_object_object_add(jbb, "dimms", jdimms);
|
|
+ json_object_array_add(jbbs, jbb);
|
|
+ }
|
|
+
|
|
+ *bb_count = bbs;
|
|
+
|
|
+ if (bbs)
|
|
+ return jbbs;
|
|
+
|
|
+ err:
|
|
+ json_object_put(jbb);
|
|
+ err_array:
|
|
+ json_object_put(jbbs);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static struct json_object *util_namespace_badblocks_to_json(
|
|
+ struct ndctl_namespace *ndns,
|
|
+ unsigned int *bb_count, unsigned long flags)
|
|
+{
|
|
+ struct json_object *jbb = NULL, *jbbs = NULL, *jobj;
|
|
+ struct badblock *bb;
|
|
+ int bbs = 0;
|
|
+
|
|
+ if (flags & UTIL_JSON_MEDIA_ERRORS) {
|
|
+ jbbs = json_object_new_array();
|
|
+ if (!jbbs)
|
|
+ return NULL;
|
|
+ } else
|
|
+ return NULL;
|
|
+
|
|
+ ndctl_namespace_badblock_foreach(ndns, bb) {
|
|
+ bbs += bb->len;
|
|
+
|
|
+ /* recheck so we can still get the badblocks_count from above */
|
|
+ if (!(flags & UTIL_JSON_MEDIA_ERRORS))
|
|
+ continue;
|
|
+
|
|
+ jbb = json_object_new_object();
|
|
+ if (!jbb)
|
|
+ goto err_array;
|
|
+
|
|
+ jobj = json_object_new_int64(bb->offset);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jbb, "offset", jobj);
|
|
+
|
|
+ jobj = json_object_new_int(bb->len);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jbb, "length", jobj);
|
|
+ json_object_array_add(jbbs, jbb);
|
|
+ }
|
|
+
|
|
+ *bb_count = bbs;
|
|
+
|
|
+ if (bbs)
|
|
+ return jbbs;
|
|
+
|
|
+ err:
|
|
+ json_object_put(jbb);
|
|
+ err_array:
|
|
+ json_object_put(jbbs);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static struct json_object *dev_badblocks_to_json(struct ndctl_region *region,
|
|
+ unsigned long long dev_begin, unsigned long long dev_size,
|
|
+ unsigned int *bb_count, unsigned long flags)
|
|
+{
|
|
+ struct json_object *jbb = NULL, *jbbs = NULL, *jobj;
|
|
+ unsigned long long region_begin, dev_end, offset;
|
|
+ unsigned int len, bbs = 0;
|
|
+ struct badblock *bb;
|
|
+
|
|
+ region_begin = ndctl_region_get_resource(region);
|
|
+ if (region_begin == ULLONG_MAX)
|
|
+ return NULL;
|
|
+
|
|
+ dev_end = dev_begin + dev_size - 1;
|
|
+
|
|
+ if (flags & UTIL_JSON_MEDIA_ERRORS) {
|
|
+ jbbs = json_object_new_array();
|
|
+ if (!jbbs)
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ ndctl_region_badblock_foreach(region, bb) {
|
|
+ unsigned long long bb_begin, bb_end, begin, end;
|
|
+ struct json_object *jdimms;
|
|
+
|
|
+ bb_begin = region_begin + (bb->offset << 9);
|
|
+ bb_end = bb_begin + (bb->len << 9) - 1;
|
|
+
|
|
+ if (bb_end <= dev_begin || bb_begin >= dev_end)
|
|
+ continue;
|
|
+
|
|
+ if (bb_begin < dev_begin)
|
|
+ begin = dev_begin;
|
|
+ else
|
|
+ begin = bb_begin;
|
|
+
|
|
+ if (bb_end > dev_end)
|
|
+ end = dev_end;
|
|
+ else
|
|
+ end = bb_end;
|
|
+
|
|
+ offset = (begin - dev_begin) >> 9;
|
|
+ len = (end - begin + 1) >> 9;
|
|
+
|
|
+ bbs += len;
|
|
+
|
|
+ /* recheck so we can still get the badblocks_count from above */
|
|
+ if (!(flags & UTIL_JSON_MEDIA_ERRORS))
|
|
+ continue;
|
|
+
|
|
+ jbb = json_object_new_object();
|
|
+ if (!jbb)
|
|
+ goto err_array;
|
|
+
|
|
+ jobj = json_object_new_int64(offset);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jbb, "offset", jobj);
|
|
+
|
|
+ jobj = json_object_new_int(len);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jbb, "length", jobj);
|
|
+
|
|
+ jdimms = badblocks_to_jdimms(region, begin, len << 9);
|
|
+ if (jdimms)
|
|
+ json_object_object_add(jbb, "dimms", jdimms);
|
|
+
|
|
+ json_object_array_add(jbbs, jbb);
|
|
+ }
|
|
+
|
|
+ *bb_count = bbs;
|
|
+
|
|
+ if (bbs)
|
|
+ return jbbs;
|
|
+
|
|
+ err:
|
|
+ json_object_put(jbb);
|
|
+ err_array:
|
|
+ json_object_put(jbbs);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static struct json_object *util_pfn_badblocks_to_json(struct ndctl_pfn *pfn,
|
|
+ unsigned int *bb_count, unsigned long flags)
|
|
+{
|
|
+ struct ndctl_region *region = ndctl_pfn_get_region(pfn);
|
|
+ unsigned long long pfn_begin, pfn_size;
|
|
+
|
|
+ pfn_begin = ndctl_pfn_get_resource(pfn);
|
|
+ if (pfn_begin == ULLONG_MAX) {
|
|
+ struct ndctl_namespace *ndns = ndctl_pfn_get_namespace(pfn);
|
|
+
|
|
+ return util_namespace_badblocks_to_json(ndns, bb_count, flags);
|
|
+ }
|
|
+
|
|
+ pfn_size = ndctl_pfn_get_size(pfn);
|
|
+ if (pfn_size == ULLONG_MAX)
|
|
+ return NULL;
|
|
+
|
|
+ return dev_badblocks_to_json(region, pfn_begin, pfn_size,
|
|
+ bb_count, flags);
|
|
+}
|
|
+
|
|
+static void util_btt_badblocks_to_json(struct ndctl_btt *btt,
|
|
+ unsigned int *bb_count)
|
|
+{
|
|
+ struct ndctl_region *region = ndctl_btt_get_region(btt);
|
|
+ struct ndctl_namespace *ndns = ndctl_btt_get_namespace(btt);
|
|
+ unsigned long long begin, size;
|
|
+
|
|
+ if (!ndns)
|
|
+ return;
|
|
+
|
|
+ begin = ndctl_namespace_get_resource(ndns);
|
|
+ if (begin == ULLONG_MAX)
|
|
+ return;
|
|
+
|
|
+ size = ndctl_namespace_get_size(ndns);
|
|
+ if (size == ULLONG_MAX)
|
|
+ return;
|
|
+
|
|
+ /*
|
|
+ * The dev_badblocks_to_json() for BTT is not accurate with
|
|
+ * respect to data vs metadata badblocks, and is only useful for
|
|
+ * a potential bb_count.
|
|
+ *
|
|
+ * FIXME: switch to native BTT badblocks representation
|
|
+ * when / if the kernel provides it.
|
|
+ */
|
|
+ dev_badblocks_to_json(region, begin, size, bb_count, 0);
|
|
+}
|
|
+static struct json_object *util_dax_badblocks_to_json(struct ndctl_dax *dax,
|
|
+ unsigned int *bb_count, unsigned long flags)
|
|
+{
|
|
+ struct ndctl_region *region = ndctl_dax_get_region(dax);
|
|
+ unsigned long long dax_begin, dax_size;
|
|
+
|
|
+ dax_begin = ndctl_dax_get_resource(dax);
|
|
+ if (dax_begin == ULLONG_MAX)
|
|
+ return NULL;
|
|
+
|
|
+ dax_size = ndctl_dax_get_size(dax);
|
|
+ if (dax_size == ULLONG_MAX)
|
|
+ return NULL;
|
|
+
|
|
+ return dev_badblocks_to_json(region, dax_begin, dax_size,
|
|
+ bb_count, flags);
|
|
+}
|
|
+
|
|
+static struct json_object *util_raw_uuid(struct ndctl_namespace *ndns)
|
|
+{
|
|
+ char buf[40];
|
|
+ uuid_t raw_uuid;
|
|
+
|
|
+ ndctl_namespace_get_uuid(ndns, raw_uuid);
|
|
+ if (uuid_is_null(raw_uuid))
|
|
+ return NULL;
|
|
+ uuid_unparse(raw_uuid, buf);
|
|
+ return json_object_new_string(buf);
|
|
+}
|
|
+
|
|
+static void util_raw_uuid_to_json(struct ndctl_namespace *ndns,
|
|
+ unsigned long flags,
|
|
+ struct json_object *jndns)
|
|
+{
|
|
+ struct json_object *jobj;
|
|
+
|
|
+ if (!(flags & UTIL_JSON_VERBOSE))
|
|
+ return;
|
|
+
|
|
+ jobj = util_raw_uuid(ndns);
|
|
+ if (!jobj)
|
|
+ return;
|
|
+ json_object_object_add(jndns, "raw_uuid", jobj);
|
|
+}
|
|
+
|
|
+struct json_object *util_namespace_to_json(struct ndctl_namespace *ndns,
|
|
+ unsigned long flags)
|
|
+{
|
|
+ struct json_object *jndns = json_object_new_object();
|
|
+ enum ndctl_pfn_loc loc = NDCTL_PFN_LOC_NONE;
|
|
+ struct json_object *jobj, *jbbs = NULL;
|
|
+ const char *locations[] = {
|
|
+ [NDCTL_PFN_LOC_NONE] = "none",
|
|
+ [NDCTL_PFN_LOC_RAM] = "mem",
|
|
+ [NDCTL_PFN_LOC_PMEM] = "dev",
|
|
+ };
|
|
+ unsigned long long size = ULLONG_MAX;
|
|
+ unsigned int sector_size = UINT_MAX;
|
|
+ enum ndctl_namespace_mode mode;
|
|
+ const char *bdev = NULL, *name;
|
|
+ unsigned int bb_count = 0;
|
|
+ struct ndctl_btt *btt;
|
|
+ struct ndctl_pfn *pfn;
|
|
+ struct ndctl_dax *dax;
|
|
+ unsigned long align = 0;
|
|
+ char buf[40];
|
|
+ uuid_t uuid;
|
|
+ int numa, target;
|
|
+
|
|
+ if (!jndns)
|
|
+ return NULL;
|
|
+
|
|
+ jobj = json_object_new_string(ndctl_namespace_get_devname(ndns));
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jndns, "dev", jobj);
|
|
+
|
|
+ btt = ndctl_namespace_get_btt(ndns);
|
|
+ dax = ndctl_namespace_get_dax(ndns);
|
|
+ pfn = ndctl_namespace_get_pfn(ndns);
|
|
+ mode = ndctl_namespace_get_mode(ndns);
|
|
+ switch (mode) {
|
|
+ case NDCTL_NS_MODE_MEMORY:
|
|
+ if (pfn) { /* dynamic memory mode */
|
|
+ size = ndctl_pfn_get_size(pfn);
|
|
+ loc = ndctl_pfn_get_location(pfn);
|
|
+ } else { /* native/static memory mode */
|
|
+ size = ndctl_namespace_get_size(ndns);
|
|
+ loc = NDCTL_PFN_LOC_RAM;
|
|
+ }
|
|
+ jobj = json_object_new_string("fsdax");
|
|
+ break;
|
|
+ case NDCTL_NS_MODE_DAX:
|
|
+ if (!dax)
|
|
+ goto err;
|
|
+ size = ndctl_dax_get_size(dax);
|
|
+ jobj = json_object_new_string("devdax");
|
|
+ loc = ndctl_dax_get_location(dax);
|
|
+ break;
|
|
+ case NDCTL_NS_MODE_SECTOR:
|
|
+ if (!btt)
|
|
+ goto err;
|
|
+ jobj = json_object_new_string("sector");
|
|
+ size = ndctl_btt_get_size(btt);
|
|
+ break;
|
|
+ case NDCTL_NS_MODE_RAW:
|
|
+ size = ndctl_namespace_get_size(ndns);
|
|
+ jobj = json_object_new_string("raw");
|
|
+ break;
|
|
+ default:
|
|
+ jobj = NULL;
|
|
+ }
|
|
+ if (jobj)
|
|
+ json_object_object_add(jndns, "mode", jobj);
|
|
+
|
|
+ if ((mode != NDCTL_NS_MODE_SECTOR) && (mode != NDCTL_NS_MODE_RAW)) {
|
|
+ jobj = json_object_new_string(locations[loc]);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jndns, "map", jobj);
|
|
+ }
|
|
+
|
|
+ if (size < ULLONG_MAX) {
|
|
+ jobj = util_json_object_size(size, flags);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jndns, "size", jobj);
|
|
+ }
|
|
+
|
|
+ if (btt) {
|
|
+ ndctl_btt_get_uuid(btt, uuid);
|
|
+ uuid_unparse(uuid, buf);
|
|
+ jobj = json_object_new_string(buf);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jndns, "uuid", jobj);
|
|
+ util_raw_uuid_to_json(ndns, flags, jndns);
|
|
+ bdev = ndctl_btt_get_block_device(btt);
|
|
+ } else if (pfn) {
|
|
+ align = ndctl_pfn_get_align(pfn);
|
|
+ ndctl_pfn_get_uuid(pfn, uuid);
|
|
+ uuid_unparse(uuid, buf);
|
|
+ jobj = json_object_new_string(buf);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jndns, "uuid", jobj);
|
|
+ util_raw_uuid_to_json(ndns, flags, jndns);
|
|
+ bdev = ndctl_pfn_get_block_device(pfn);
|
|
+ } else if (dax) {
|
|
+ struct daxctl_region *dax_region;
|
|
+
|
|
+ dax_region = ndctl_dax_get_daxctl_region(dax);
|
|
+ align = ndctl_dax_get_align(dax);
|
|
+ ndctl_dax_get_uuid(dax, uuid);
|
|
+ uuid_unparse(uuid, buf);
|
|
+ jobj = json_object_new_string(buf);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jndns, "uuid", jobj);
|
|
+ util_raw_uuid_to_json(ndns, flags, jndns);
|
|
+ if ((flags & UTIL_JSON_DAX) && dax_region) {
|
|
+ jobj = util_daxctl_region_to_json(dax_region, NULL,
|
|
+ flags);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jndns, "daxregion", jobj);
|
|
+ } else if (dax_region) {
|
|
+ struct daxctl_dev *dev;
|
|
+
|
|
+ /*
|
|
+ * We can only find/list these device-dax
|
|
+ * details when the instance is enabled.
|
|
+ */
|
|
+ dev = daxctl_dev_get_first(dax_region);
|
|
+ if (dev) {
|
|
+ name = daxctl_dev_get_devname(dev);
|
|
+ jobj = json_object_new_string(name);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jndns, "chardev", jobj);
|
|
+ }
|
|
+ }
|
|
+ } else if (ndctl_namespace_get_type(ndns) != ND_DEVICE_NAMESPACE_IO) {
|
|
+ ndctl_namespace_get_uuid(ndns, uuid);
|
|
+ uuid_unparse(uuid, buf);
|
|
+ jobj = json_object_new_string(buf);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jndns, "uuid", jobj);
|
|
+ bdev = ndctl_namespace_get_block_device(ndns);
|
|
+ } else
|
|
+ bdev = ndctl_namespace_get_block_device(ndns);
|
|
+
|
|
+ if (btt)
|
|
+ sector_size = ndctl_btt_get_sector_size(btt);
|
|
+ else if (!dax) {
|
|
+ sector_size = ndctl_namespace_get_sector_size(ndns);
|
|
+ if (!sector_size || sector_size == UINT_MAX)
|
|
+ sector_size = 512;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * The kernel will default to a 512 byte sector size on PMEM
|
|
+ * namespaces that don't explicitly have a sector size. This
|
|
+ * happens because they use pre-v1.2 labels or because they
|
|
+ * don't have a label space (devtype=nd_namespace_io).
|
|
+ */
|
|
+ if (sector_size < UINT_MAX) {
|
|
+ jobj = json_object_new_int(sector_size);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jndns, "sector_size", jobj);
|
|
+ }
|
|
+
|
|
+ if (align) {
|
|
+ jobj = json_object_new_int64(align);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jndns, "align", jobj);
|
|
+ }
|
|
+
|
|
+ if (bdev && bdev[0]) {
|
|
+ jobj = json_object_new_string(bdev);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jndns, "blockdev", jobj);
|
|
+ }
|
|
+
|
|
+ if (!ndctl_namespace_is_active(ndns)) {
|
|
+ jobj = json_object_new_string("disabled");
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jndns, "state", jobj);
|
|
+ }
|
|
+
|
|
+ name = ndctl_namespace_get_alt_name(ndns);
|
|
+ if (name && name[0]) {
|
|
+ jobj = json_object_new_string(name);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jndns, "name", jobj);
|
|
+ }
|
|
+
|
|
+ numa = ndctl_namespace_get_numa_node(ndns);
|
|
+ if (numa >= 0 && flags & UTIL_JSON_VERBOSE) {
|
|
+ jobj = json_object_new_int(numa);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jndns, "numa_node", jobj);
|
|
+ }
|
|
+
|
|
+ target = ndctl_namespace_get_target_node(ndns);
|
|
+ if (target >= 0 && flags & UTIL_JSON_VERBOSE) {
|
|
+ jobj = json_object_new_int(target);
|
|
+ if (jobj)
|
|
+ json_object_object_add(jndns, "target_node", jobj);
|
|
+ }
|
|
+
|
|
+ if (pfn)
|
|
+ jbbs = util_pfn_badblocks_to_json(pfn, &bb_count, flags);
|
|
+ else if (dax)
|
|
+ jbbs = util_dax_badblocks_to_json(dax, &bb_count, flags);
|
|
+ else if (btt)
|
|
+ util_btt_badblocks_to_json(btt, &bb_count);
|
|
+ else {
|
|
+ jbbs = util_region_badblocks_to_json(
|
|
+ ndctl_namespace_get_region(ndns), &bb_count,
|
|
+ flags);
|
|
+ if (!jbbs)
|
|
+ jbbs = util_namespace_badblocks_to_json(ndns, &bb_count,
|
|
+ flags);
|
|
+ }
|
|
+
|
|
+ if (bb_count) {
|
|
+ jobj = json_object_new_int(bb_count);
|
|
+ if (!jobj) {
|
|
+ json_object_put(jbbs);
|
|
+ goto err;
|
|
+ }
|
|
+ json_object_object_add(jndns, "badblock_count", jobj);
|
|
+ }
|
|
+
|
|
+ if ((flags & UTIL_JSON_MEDIA_ERRORS) && jbbs)
|
|
+ json_object_object_add(jndns, "badblocks", jbbs);
|
|
+
|
|
+ return jndns;
|
|
+ err:
|
|
+ json_object_put(jndns);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+
|
|
+struct json_object *util_mapping_to_json(struct ndctl_mapping *mapping,
|
|
+ unsigned long flags)
|
|
+{
|
|
+ struct json_object *jmapping = json_object_new_object();
|
|
+ struct ndctl_dimm *dimm = ndctl_mapping_get_dimm(mapping);
|
|
+ struct json_object *jobj;
|
|
+ int position;
|
|
+
|
|
+ if (!jmapping)
|
|
+ return NULL;
|
|
+
|
|
+ jobj = json_object_new_string(ndctl_dimm_get_devname(dimm));
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jmapping, "dimm", jobj);
|
|
+
|
|
+ jobj = util_json_object_hex(ndctl_mapping_get_offset(mapping), flags);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jmapping, "offset", jobj);
|
|
+
|
|
+ jobj = util_json_object_hex(ndctl_mapping_get_length(mapping), flags);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jmapping, "length", jobj);
|
|
+
|
|
+ position = ndctl_mapping_get_position(mapping);
|
|
+ if (position >= 0) {
|
|
+ jobj = json_object_new_int(position);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jmapping, "position", jobj);
|
|
+ }
|
|
+
|
|
+ return jmapping;
|
|
+ err:
|
|
+ json_object_put(jmapping);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+struct json_object *util_badblock_rec_to_json(u64 block, u64 count,
|
|
+ unsigned long flags)
|
|
+{
|
|
+ struct json_object *jerr = json_object_new_object();
|
|
+ struct json_object *jobj;
|
|
+
|
|
+ if (!jerr)
|
|
+ return NULL;
|
|
+
|
|
+ jobj = util_json_object_hex(block, flags);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jerr, "block", jobj);
|
|
+
|
|
+ jobj = util_json_object_hex(count, flags);
|
|
+ if (!jobj)
|
|
+ goto err;
|
|
+ json_object_object_add(jerr, "count", jobj);
|
|
+
|
|
+ return jerr;
|
|
+ err:
|
|
+ json_object_put(jerr);
|
|
+ return NULL;
|
|
+}
|
|
diff -up ndctl-71.1/ndctl/json.h.orig ndctl-71.1/ndctl/json.h
|
|
--- ndctl-71.1/ndctl/json.h.orig 2022-10-07 15:51:03.913535724 -0400
|
|
+++ ndctl-71.1/ndctl/json.h 2022-10-07 15:51:03.913535724 -0400
|
|
@@ -0,0 +1,24 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */
|
|
+#ifndef __NDCTL_UTIL_JSON_H__
|
|
+#define __NDCTL_UTIL_JSON_H__
|
|
+#include <ndctl/libndctl.h>
|
|
+#include <ccan/short_types/short_types.h>
|
|
+
|
|
+struct json_object *util_namespace_to_json(struct ndctl_namespace *ndns,
|
|
+ unsigned long flags);
|
|
+struct json_object *util_badblock_rec_to_json(u64 block, u64 count,
|
|
+ unsigned long flags);
|
|
+struct json_object *util_region_badblocks_to_json(struct ndctl_region *region,
|
|
+ unsigned int *bb_count, unsigned long flags);
|
|
+struct json_object *util_bus_to_json(struct ndctl_bus *bus,
|
|
+ unsigned long flags);
|
|
+struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm,
|
|
+ unsigned long flags);
|
|
+struct json_object *util_mapping_to_json(struct ndctl_mapping *mapping,
|
|
+ unsigned long flags);
|
|
+struct json_object *util_dimm_health_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);
|
|
+#endif /* __NDCTL_UTIL_JSON_H__ */
|
|
diff -up ndctl-71.1/ndctl/keys.c.orig ndctl-71.1/ndctl/keys.c
|
|
--- ndctl-71.1/ndctl/keys.c.orig 2022-10-07 15:51:03.930535782 -0400
|
|
+++ ndctl-71.1/ndctl/keys.c 2022-10-07 15:51:03.913535724 -0400
|
|
@@ -0,0 +1,667 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/* Copyright (C) 2018-2020 Intel Corporation. All rights reserved. */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <errno.h>
|
|
+#include <string.h>
|
|
+#include <stdlib.h>
|
|
+#include <unistd.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/types.h>
|
|
+#include <fcntl.h>
|
|
+#include <sys/param.h>
|
|
+#include <keyutils.h>
|
|
+#include <syslog.h>
|
|
+
|
|
+#include <ndctl/config.h>
|
|
+#include <ndctl/ndctl.h>
|
|
+#include <ndctl/libndctl.h>
|
|
+
|
|
+#include "keys.h"
|
|
+
|
|
+static int get_key_path(struct ndctl_dimm *dimm, char *path,
|
|
+ enum ndctl_key_type key_type)
|
|
+{
|
|
+ char hostname[HOST_NAME_MAX];
|
|
+ int rc;
|
|
+
|
|
+ rc = gethostname(hostname, HOST_NAME_MAX);
|
|
+ if (rc < 0) {
|
|
+ fprintf(stderr, "gethostname: %s\n", strerror(errno));
|
|
+ return -errno;
|
|
+ }
|
|
+
|
|
+ switch (key_type) {
|
|
+ case ND_USER_OLD_KEY:
|
|
+ rc = sprintf(path, "%s/nvdimm-old_%s_%s.blob",
|
|
+ NDCTL_KEYS_DIR,
|
|
+ ndctl_dimm_get_unique_id(dimm),
|
|
+ hostname);
|
|
+ break;
|
|
+ case ND_USER_KEY:
|
|
+ rc = sprintf(path, "%s/nvdimm_%s_%s.blob",
|
|
+ NDCTL_KEYS_DIR,
|
|
+ ndctl_dimm_get_unique_id(dimm),
|
|
+ hostname);
|
|
+ break;
|
|
+ case ND_MASTER_OLD_KEY:
|
|
+ rc = sprintf(path, "%s/nvdimm-master-old_%s_%s.blob",
|
|
+ NDCTL_KEYS_DIR,
|
|
+ ndctl_dimm_get_unique_id(dimm),
|
|
+ hostname);
|
|
+ break;
|
|
+ case ND_MASTER_KEY:
|
|
+ rc = sprintf(path, "%s/nvdimm-master_%s_%s.blob",
|
|
+ NDCTL_KEYS_DIR,
|
|
+ ndctl_dimm_get_unique_id(dimm),
|
|
+ hostname);
|
|
+ break;
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (rc < 0) {
|
|
+ fprintf(stderr, "error setting path: %s\n", strerror(errno));
|
|
+ return -errno;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int get_key_desc(struct ndctl_dimm *dimm, char *desc,
|
|
+ enum ndctl_key_type key_type)
|
|
+{
|
|
+ int rc;
|
|
+
|
|
+ switch (key_type) {
|
|
+ case ND_USER_OLD_KEY:
|
|
+ rc = sprintf(desc, "nvdimm-old:%s",
|
|
+ ndctl_dimm_get_unique_id(dimm));
|
|
+ break;
|
|
+ case ND_USER_KEY:
|
|
+ rc = sprintf(desc, "nvdimm:%s",
|
|
+ ndctl_dimm_get_unique_id(dimm));
|
|
+ break;
|
|
+ case ND_MASTER_OLD_KEY:
|
|
+ rc = sprintf(desc, "nvdimm-master-old:%s",
|
|
+ ndctl_dimm_get_unique_id(dimm));
|
|
+ break;
|
|
+ case ND_MASTER_KEY:
|
|
+ rc = sprintf(desc, "nvdimm-master:%s",
|
|
+ ndctl_dimm_get_unique_id(dimm));
|
|
+ break;
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (rc < 0) {
|
|
+ fprintf(stderr, "error setting key description: %s\n",
|
|
+ strerror(errno));
|
|
+ return -errno;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+char *ndctl_load_key_blob(const char *path, int *size, const char *postfix,
|
|
+ int dirfd, enum key_type key_type)
|
|
+{
|
|
+ struct stat st;
|
|
+ ssize_t read_bytes = 0;
|
|
+ int rc, fd;
|
|
+ char *blob, *pl, *rdptr;
|
|
+ char prefix[] = "load ";
|
|
+ bool need_prefix = false;
|
|
+
|
|
+ if (key_type == KEY_ENCRYPTED || key_type == KEY_TRUSTED)
|
|
+ need_prefix = true;
|
|
+
|
|
+ fd = openat(dirfd, path, O_RDONLY);
|
|
+ if (fd < 0) {
|
|
+ fprintf(stderr, "failed to open file %s: %s\n",
|
|
+ path, strerror(errno));
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ rc = fstat(fd, &st);
|
|
+ if (rc < 0) {
|
|
+ fprintf(stderr, "stat: %s\n", strerror(errno));
|
|
+ return NULL;
|
|
+ }
|
|
+ if ((st.st_mode & S_IFMT) != S_IFREG) {
|
|
+ fprintf(stderr, "%s not a regular file\n", path);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (st.st_size == 0 || st.st_size > 4096) {
|
|
+ fprintf(stderr, "Invalid blob file size\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ *size = st.st_size;
|
|
+ if (need_prefix)
|
|
+ *size += strlen(prefix);
|
|
+
|
|
+ /*
|
|
+ * We need to increment postfix and space.
|
|
+ * "keyhandle=" is 10 bytes, plus null termination.
|
|
+ */
|
|
+ if (postfix)
|
|
+ *size += strlen(postfix) + 10 + 1;
|
|
+ blob = malloc(*size);
|
|
+ if (!blob) {
|
|
+ fprintf(stderr, "Unable to allocate memory for blob\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (need_prefix) {
|
|
+ memcpy(blob, prefix, strlen(prefix));
|
|
+ pl = blob + strlen(prefix);
|
|
+ } else
|
|
+ pl = blob;
|
|
+
|
|
+ rdptr = pl;
|
|
+ do {
|
|
+ rc = read(fd, rdptr, st.st_size - read_bytes);
|
|
+ if (rc < 0) {
|
|
+ fprintf(stderr, "Failed to read from blob file: %s\n",
|
|
+ strerror(errno));
|
|
+ free(blob);
|
|
+ close(fd);
|
|
+ return NULL;
|
|
+ }
|
|
+ read_bytes += rc;
|
|
+ rdptr += rc;
|
|
+ } while (read_bytes != st.st_size);
|
|
+
|
|
+ close(fd);
|
|
+
|
|
+ if (postfix) {
|
|
+ pl += read_bytes;
|
|
+ *pl = ' ';
|
|
+ pl++;
|
|
+ rc = sprintf(pl, "keyhandle=%s", postfix);
|
|
+ }
|
|
+
|
|
+ return blob;
|
|
+}
|
|
+
|
|
+static key_serial_t dimm_check_key(struct ndctl_dimm *dimm,
|
|
+ enum ndctl_key_type key_type)
|
|
+{
|
|
+ char desc[ND_KEY_DESC_SIZE];
|
|
+ int rc;
|
|
+
|
|
+ rc = get_key_desc(dimm, desc, key_type);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ return keyctl_search(KEY_SPEC_USER_KEYRING, "encrypted", desc, 0);
|
|
+}
|
|
+
|
|
+static key_serial_t dimm_create_key(struct ndctl_dimm *dimm,
|
|
+ const char *kek, enum ndctl_key_type key_type)
|
|
+{
|
|
+ char desc[ND_KEY_DESC_SIZE];
|
|
+ char path[PATH_MAX];
|
|
+ char cmd[ND_KEY_CMD_SIZE];
|
|
+ key_serial_t key;
|
|
+ void *buffer;
|
|
+ int rc;
|
|
+ ssize_t size;
|
|
+ FILE *fp;
|
|
+ ssize_t wrote;
|
|
+ struct stat st;
|
|
+
|
|
+ if (ndctl_dimm_is_active(dimm)) {
|
|
+ fprintf(stderr, "regions active on %s, op failed\n",
|
|
+ ndctl_dimm_get_devname(dimm));
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ rc = get_key_desc(dimm, desc, key_type);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ /* make sure it's not already in the key ring */
|
|
+ key = keyctl_search(KEY_SPEC_USER_KEYRING, "encrypted", desc, 0);
|
|
+ if (key > 0) {
|
|
+ fprintf(stderr, "Error: key already present in user keyring\n");
|
|
+ return -EEXIST;
|
|
+ }
|
|
+
|
|
+ rc = get_key_path(dimm, path, key_type);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ rc = stat(path, &st);
|
|
+ if (rc == 0) {
|
|
+ fprintf(stderr, "%s already exists!\n", path);
|
|
+ return -EEXIST;
|
|
+ }
|
|
+
|
|
+ rc = sprintf(cmd, "new enc32 %s 32", kek);
|
|
+ if (rc < 0) {
|
|
+ fprintf(stderr, "sprintf: %s\n", strerror(errno));
|
|
+ return -errno;
|
|
+ }
|
|
+
|
|
+ key = add_key("encrypted", desc, cmd, strlen(cmd),
|
|
+ KEY_SPEC_USER_KEYRING);
|
|
+ if (key < 0) {
|
|
+ fprintf(stderr, "add_key failed: %s\n", strerror(errno));
|
|
+ return -errno;
|
|
+ }
|
|
+
|
|
+ size = keyctl_read_alloc(key, &buffer);
|
|
+ if (size < 0) {
|
|
+ fprintf(stderr, "keyctl_read_alloc failed: %s\n", strerror(errno));
|
|
+ keyctl_unlink(key, KEY_SPEC_USER_KEYRING);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ fp = fopen(path, "w");
|
|
+ if (!fp) {
|
|
+ rc = -errno;
|
|
+ fprintf(stderr, "Unable to open file %s: %s\n",
|
|
+ path, strerror(errno));
|
|
+ free(buffer);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ wrote = fwrite(buffer, 1, size, fp);
|
|
+ if (wrote != size) {
|
|
+ if (wrote == -1)
|
|
+ rc = -errno;
|
|
+ else
|
|
+ rc = -EIO;
|
|
+ fprintf(stderr, "Failed to write to %s: %s\n",
|
|
+ path, strerror(-rc));
|
|
+ fclose(fp);
|
|
+ free(buffer);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ fclose(fp);
|
|
+ free(buffer);
|
|
+ return key;
|
|
+}
|
|
+
|
|
+static key_serial_t dimm_load_key(struct ndctl_dimm *dimm,
|
|
+ enum ndctl_key_type key_type)
|
|
+{
|
|
+ key_serial_t key;
|
|
+ char desc[ND_KEY_DESC_SIZE];
|
|
+ char path[PATH_MAX];
|
|
+ int rc;
|
|
+ char *blob;
|
|
+ int size;
|
|
+
|
|
+ if (ndctl_dimm_is_active(dimm)) {
|
|
+ fprintf(stderr, "regions active on %s, op failed\n",
|
|
+ ndctl_dimm_get_devname(dimm));
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ rc = get_key_desc(dimm, desc, key_type);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ rc = get_key_path(dimm, path, key_type);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ blob = ndctl_load_key_blob(path, &size, NULL, -1, KEY_ENCRYPTED);
|
|
+ if (!blob)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ key = add_key("encrypted", desc, blob, size, KEY_SPEC_USER_KEYRING);
|
|
+ free(blob);
|
|
+ if (key < 0) {
|
|
+ fprintf(stderr, "add_key failed: %s\n", strerror(errno));
|
|
+ return -errno;
|
|
+ }
|
|
+
|
|
+ return key;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * The function will check to see if the existing key is there and remove
|
|
+ * from user key ring if it is. Rename the existing key blob to old key
|
|
+ * blob, and then attempt to inject the key as old key into the user key
|
|
+ * ring.
|
|
+ */
|
|
+static key_serial_t move_key_to_old(struct ndctl_dimm *dimm,
|
|
+ enum ndctl_key_type key_type)
|
|
+{
|
|
+ int rc;
|
|
+ key_serial_t key;
|
|
+ char old_path[PATH_MAX];
|
|
+ char new_path[PATH_MAX];
|
|
+ enum ndctl_key_type okey_type;
|
|
+
|
|
+ if (ndctl_dimm_is_active(dimm)) {
|
|
+ fprintf(stderr, "regions active on %s, op failed\n",
|
|
+ ndctl_dimm_get_devname(dimm));
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ key = dimm_check_key(dimm, key_type);
|
|
+ if (key > 0)
|
|
+ keyctl_unlink(key, KEY_SPEC_USER_KEYRING);
|
|
+
|
|
+ if (key_type == ND_USER_KEY)
|
|
+ okey_type = ND_USER_OLD_KEY;
|
|
+ else if (key_type == ND_MASTER_KEY)
|
|
+ okey_type = ND_MASTER_OLD_KEY;
|
|
+ else
|
|
+ return -EINVAL;
|
|
+
|
|
+ rc = get_key_path(dimm, old_path, key_type);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ rc = get_key_path(dimm, new_path, okey_type);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ rc = rename(old_path, new_path);
|
|
+ if (rc < 0) {
|
|
+ fprintf(stderr, "rename failed from %s to %s: %s\n",
|
|
+ old_path, new_path, strerror(errno));
|
|
+ return -errno;
|
|
+ }
|
|
+
|
|
+ return dimm_load_key(dimm, okey_type);
|
|
+}
|
|
+
|
|
+static int dimm_remove_key(struct ndctl_dimm *dimm,
|
|
+ enum ndctl_key_type key_type)
|
|
+{
|
|
+ key_serial_t key;
|
|
+ char path[PATH_MAX];
|
|
+ int rc;
|
|
+
|
|
+ key = dimm_check_key(dimm, key_type);
|
|
+ if (key > 0)
|
|
+ keyctl_unlink(key, KEY_SPEC_USER_KEYRING);
|
|
+
|
|
+ rc = get_key_path(dimm, path, key_type);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ rc = unlink(path);
|
|
+ if (rc < 0) {
|
|
+ fprintf(stderr, "delete file %s failed: %s\n",
|
|
+ path, strerror(errno));
|
|
+ return -errno;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int verify_kek(struct ndctl_dimm *dimm, const char *kek)
|
|
+{
|
|
+ char *type, *desc, *key_handle;
|
|
+ key_serial_t key;
|
|
+ int rc = 0;
|
|
+
|
|
+ key_handle = strdup(kek);
|
|
+ if (!key_handle)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ type = strtok(key_handle, ":");
|
|
+ if (!type) {
|
|
+ fprintf(stderr, "No key type found for kek handle\n");
|
|
+ rc = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (strcmp(type, "trusted") != 0 &&
|
|
+ strcmp(type, "user") != 0) {
|
|
+ fprintf(stderr, "No such key type: %s", type);
|
|
+ rc = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ desc = strtok(NULL, ":");
|
|
+ if (!desc) {
|
|
+ fprintf(stderr, "No description found for kek handle\n");
|
|
+ rc = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ key = keyctl_search(KEY_SPEC_USER_KEYRING, type, desc, 0);
|
|
+ if (key < 0) {
|
|
+ fprintf(stderr, "No key encryption key found\n");
|
|
+ rc = key;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ free(key_handle);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek,
|
|
+ enum ndctl_key_type key_type)
|
|
+{
|
|
+ key_serial_t key;
|
|
+ int rc;
|
|
+
|
|
+ rc = verify_kek(dimm, kek);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ key = dimm_create_key(dimm, kek, key_type);
|
|
+ if (key < 0)
|
|
+ return key;
|
|
+
|
|
+ if (key_type == ND_MASTER_KEY)
|
|
+ rc = ndctl_dimm_update_master_passphrase(dimm, 0, key);
|
|
+ else
|
|
+ rc = ndctl_dimm_update_passphrase(dimm, 0, key);
|
|
+ if (rc < 0) {
|
|
+ dimm_remove_key(dimm, key_type);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static char *get_current_kek(struct ndctl_dimm *dimm,
|
|
+ enum ndctl_key_type key_type)
|
|
+{
|
|
+ key_serial_t key;
|
|
+ char *key_buf;
|
|
+ long rc;
|
|
+ char *type, *desc;
|
|
+
|
|
+ key = dimm_check_key(dimm, key_type);
|
|
+ if (key < 0)
|
|
+ return NULL;
|
|
+
|
|
+ rc = keyctl_read_alloc(key, (void **)&key_buf);
|
|
+ if (rc < 0)
|
|
+ return NULL;
|
|
+
|
|
+ rc = sscanf(key_buf, "%ms %ms", &type, &desc);
|
|
+ if (rc < 0)
|
|
+ return NULL;
|
|
+
|
|
+ free(key_buf);
|
|
+ free(type);
|
|
+
|
|
+ return desc;
|
|
+}
|
|
+
|
|
+int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek,
|
|
+ enum ndctl_key_type key_type)
|
|
+{
|
|
+ int rc;
|
|
+ key_serial_t old_key, new_key;
|
|
+ char *current_kek = NULL;
|
|
+ enum ndctl_key_type okey_type;
|
|
+
|
|
+ if (kek) {
|
|
+ rc = verify_kek(dimm, kek);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+ } else { /* find current kek */
|
|
+ current_kek = get_current_kek(dimm, key_type);
|
|
+ if (!current_kek)
|
|
+ return -ENOKEY;
|
|
+ }
|
|
+
|
|
+ if (key_type == ND_USER_KEY)
|
|
+ okey_type = ND_USER_OLD_KEY;
|
|
+ else if (key_type == ND_MASTER_KEY)
|
|
+ okey_type = ND_MASTER_OLD_KEY;
|
|
+ else
|
|
+ return -EINVAL;
|
|
+
|
|
+ /*
|
|
+ * 1. check if current key is loaded and remove
|
|
+ * 2. move current key blob to old key blob
|
|
+ * 3. load old key blob
|
|
+ * 4. trigger change key with old and new key
|
|
+ * 5. remove old key
|
|
+ * 6. remove old key blob
|
|
+ */
|
|
+ old_key = move_key_to_old(dimm, key_type);
|
|
+ if (old_key < 0)
|
|
+ return old_key;
|
|
+
|
|
+ new_key = dimm_create_key(dimm, current_kek ? current_kek : kek,
|
|
+ key_type);
|
|
+ free(current_kek);
|
|
+ /* need to create new key here */
|
|
+ if (new_key < 0) {
|
|
+ new_key = dimm_load_key(dimm, key_type);
|
|
+ if (new_key < 0)
|
|
+ return new_key;
|
|
+ }
|
|
+
|
|
+ if (key_type == ND_MASTER_KEY)
|
|
+ rc = ndctl_dimm_update_master_passphrase(dimm,
|
|
+ old_key, new_key);
|
|
+ else
|
|
+ rc = ndctl_dimm_update_passphrase(dimm, old_key, new_key);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ rc = dimm_remove_key(dimm, okey_type);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static key_serial_t check_dimm_key(struct ndctl_dimm *dimm, bool need_key,
|
|
+ enum ndctl_key_type key_type)
|
|
+{
|
|
+ key_serial_t key;
|
|
+
|
|
+ key = dimm_check_key(dimm, key_type);
|
|
+ if (key < 0) {
|
|
+ key = dimm_load_key(dimm, key_type);
|
|
+ if (key < 0 && need_key) {
|
|
+ fprintf(stderr, "Unable to load key\n");
|
|
+ return -ENOKEY;
|
|
+ } else
|
|
+ key = 0;
|
|
+ }
|
|
+ return key;
|
|
+}
|
|
+
|
|
+static int run_key_op(struct ndctl_dimm *dimm,
|
|
+ key_serial_t key,
|
|
+ int (*run_op)(struct ndctl_dimm *, long), const char *name)
|
|
+{
|
|
+ int rc;
|
|
+
|
|
+ rc = run_op(dimm, key);
|
|
+ if (rc < 0) {
|
|
+ fprintf(stderr, "Failed %s for %s\n", name,
|
|
+ ndctl_dimm_get_devname(dimm));
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int discard_key(struct ndctl_dimm *dimm)
|
|
+{
|
|
+ int rc;
|
|
+
|
|
+ rc = dimm_remove_key(dimm, ND_USER_KEY);
|
|
+ if (rc < 0) {
|
|
+ fprintf(stderr, "Unable to cleanup key.\n");
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int ndctl_dimm_remove_key(struct ndctl_dimm *dimm)
|
|
+{
|
|
+ key_serial_t key;
|
|
+ int rc;
|
|
+
|
|
+ key = check_dimm_key(dimm, true, ND_USER_KEY);
|
|
+ if (key < 0)
|
|
+ return key;
|
|
+
|
|
+ rc = run_key_op(dimm, key, ndctl_dimm_disable_passphrase,
|
|
+ "remove passphrase");
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ return discard_key(dimm);
|
|
+}
|
|
+
|
|
+int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm,
|
|
+ enum ndctl_key_type key_type)
|
|
+{
|
|
+ key_serial_t key = 0;
|
|
+ int rc;
|
|
+
|
|
+ if (key_type != ND_ZERO_KEY) {
|
|
+ key = check_dimm_key(dimm, true, key_type);
|
|
+ if (key < 0)
|
|
+ return key;
|
|
+ }
|
|
+
|
|
+ if (key_type == ND_MASTER_KEY)
|
|
+ rc = run_key_op(dimm, key, ndctl_dimm_master_secure_erase,
|
|
+ "master crypto erase");
|
|
+ else if (key_type == ND_USER_KEY || key_type == ND_ZERO_KEY)
|
|
+ rc = run_key_op(dimm, key, ndctl_dimm_secure_erase,
|
|
+ "crypto erase");
|
|
+ else
|
|
+ rc = -EINVAL;
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ if (key_type == ND_USER_KEY)
|
|
+ return discard_key(dimm);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int ndctl_dimm_overwrite_key(struct ndctl_dimm *dimm)
|
|
+{
|
|
+ key_serial_t key;
|
|
+ int rc;
|
|
+
|
|
+ key = check_dimm_key(dimm, false, ND_USER_KEY);
|
|
+ if (key < 0)
|
|
+ return key;
|
|
+
|
|
+ rc = run_key_op(dimm, key, ndctl_dimm_overwrite,
|
|
+ "overwrite");
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff -up ndctl-71.1/ndctl/keys.h.orig ndctl-71.1/ndctl/keys.h
|
|
--- ndctl-71.1/ndctl/keys.h.orig 2022-10-07 15:51:03.930535782 -0400
|
|
+++ ndctl-71.1/ndctl/keys.h 2022-10-07 15:51:03.914535728 -0400
|
|
@@ -0,0 +1,67 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/* Copyright (C) 2019-2020 Intel Corporation. All rights reserved. */
|
|
+
|
|
+#ifndef _NDCTL_UTIL_KEYS_H_
|
|
+#define _NDCTL_UTIL_KEYS_H_
|
|
+
|
|
+enum ndctl_key_type {
|
|
+ ND_USER_KEY,
|
|
+ ND_USER_OLD_KEY,
|
|
+ ND_MASTER_KEY,
|
|
+ ND_MASTER_OLD_KEY,
|
|
+ ND_ZERO_KEY,
|
|
+};
|
|
+
|
|
+enum key_type {
|
|
+ KEY_USER = 0,
|
|
+ KEY_TRUSTED,
|
|
+ KEY_ENCRYPTED,
|
|
+};
|
|
+
|
|
+#ifdef ENABLE_KEYUTILS
|
|
+char *ndctl_load_key_blob(const char *path, int *size, const char *postfix,
|
|
+ int dirfd, enum key_type key_type);
|
|
+int ndctl_dimm_setup_key(struct ndctl_dimm *dimm, const char *kek,
|
|
+ enum ndctl_key_type key_type);
|
|
+int ndctl_dimm_update_key(struct ndctl_dimm *dimm, const char *kek,
|
|
+ enum ndctl_key_type key_type);
|
|
+int ndctl_dimm_remove_key(struct ndctl_dimm *dimm);
|
|
+int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm,
|
|
+ enum ndctl_key_type key_type);
|
|
+int ndctl_dimm_overwrite_key(struct ndctl_dimm *dimm);
|
|
+#else
|
|
+char *ndctl_load_key_blob(const char *path, int *size, const char *postfix,
|
|
+ int dirfd, enum key_type key_type)
|
|
+{
|
|
+ return NULL;
|
|
+}
|
|
+static inline int ndctl_dimm_setup_key(struct ndctl_dimm *dimm,
|
|
+ const char *kek, enum ndctl_key_type key_type)
|
|
+{
|
|
+ return -EOPNOTSUPP;
|
|
+}
|
|
+
|
|
+static inline int ndctl_dimm_update_key(struct ndctl_dimm *dimm,
|
|
+ const char *kek, enum ndctl_key_type key_type)
|
|
+{
|
|
+ return -EOPNOTSUPP;
|
|
+}
|
|
+
|
|
+static inline int ndctl_dimm_remove_key(struct ndctl_dimm *dimm)
|
|
+{
|
|
+ return -EOPNOTSUPP;
|
|
+}
|
|
+
|
|
+static inline int ndctl_dimm_secure_erase_key(struct ndctl_dimm *dimm,
|
|
+ enum ndctl_key_type key_type)
|
|
+{
|
|
+ return -EOPNOTSUPP;
|
|
+}
|
|
+
|
|
+static inline int ndctl_dimm_overwrite_key(struct ndctl_dimm *dimm)
|
|
+{
|
|
+ return -EOPNOTSUPP;
|
|
+}
|
|
+#endif /* ENABLE_KEYUTILS */
|
|
+
|
|
+#endif
|
|
diff -up ndctl-71.1/ndctl/lib/libndctl.c.orig ndctl-71.1/ndctl/lib/libndctl.c
|
|
--- ndctl-71.1/ndctl/lib/libndctl.c.orig 2022-10-07 15:50:40.085454597 -0400
|
|
+++ ndctl-71.1/ndctl/lib/libndctl.c 2022-10-07 15:51:03.915535731 -0400
|
|
@@ -20,10 +20,10 @@
|
|
#include <ccan/array_size/array_size.h>
|
|
#include <ccan/build_assert/build_assert.h>
|
|
|
|
-#include <ndctl.h>
|
|
#include <util/util.h>
|
|
#include <util/size.h>
|
|
#include <util/sysfs.h>
|
|
+#include <ndctl/ndctl.h>
|
|
#include <ndctl/libndctl.h>
|
|
#include <ndctl/namespace.h>
|
|
#include <daxctl/libdaxctl.h>
|
|
diff -up ndctl-71.1/ndctl/lib/papr.c.orig ndctl-71.1/ndctl/lib/papr.c
|
|
--- ndctl-71.1/ndctl/lib/papr.c.orig 2022-10-07 15:50:40.086454601 -0400
|
|
+++ ndctl-71.1/ndctl/lib/papr.c 2022-10-07 15:51:03.916535735 -0400
|
|
@@ -10,9 +10,9 @@
|
|
#include <stdlib.h>
|
|
#include <limits.h>
|
|
#include <util/log.h>
|
|
-#include <ndctl.h>
|
|
+#include <ndctl/ndctl.h>
|
|
#include <ndctl/libndctl.h>
|
|
-#include <lib/private.h>
|
|
+#include "private.h"
|
|
#include "papr.h"
|
|
|
|
/* Utility logging maros for simplify logging */
|
|
diff -up ndctl-71.1/ndctl/lib/private.h.orig ndctl-71.1/ndctl/lib/private.h
|
|
--- ndctl-71.1/ndctl/lib/private.h.orig 2022-10-07 15:50:40.086454601 -0400
|
|
+++ ndctl-71.1/ndctl/lib/private.h 2022-10-07 15:51:03.917535738 -0400
|
|
@@ -14,8 +14,9 @@
|
|
#include <ccan/list/list.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
|
|
-#include <ndctl.h>
|
|
+#include <ndctl/ndctl.h>
|
|
#include <ndctl/libndctl.h>
|
|
+#include <ndctl/libndctl-nfit.h>
|
|
#include <ccan/endian/endian.h>
|
|
#include <ccan/short_types/short_types.h>
|
|
#include "intel.h"
|
|
@@ -23,7 +24,6 @@
|
|
#include "msft.h"
|
|
#include "hyperv.h"
|
|
#include "papr.h"
|
|
-#include "libndctl-nfit.h"
|
|
|
|
struct nvdimm_data {
|
|
struct ndctl_cmd *cmd_read;
|
|
diff -up ndctl-71.1/ndctl/list.c.orig ndctl-71.1/ndctl/list.c
|
|
--- ndctl-71.1/ndctl/list.c.orig 2022-10-07 15:50:40.087454604 -0400
|
|
+++ ndctl-71.1/ndctl/list.c 2022-10-07 15:51:03.917535738 -0400
|
|
@@ -7,13 +7,14 @@
|
|
#include <limits.h>
|
|
|
|
#include <util/json.h>
|
|
-#include <util/filter.h>
|
|
#include <json-c/json.h>
|
|
#include <ndctl/libndctl.h>
|
|
#include <util/parse-options.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
|
|
-#include <ndctl.h>
|
|
+#include "ndctl.h"
|
|
+#include "filter.h"
|
|
+#include "json.h"
|
|
|
|
static struct {
|
|
bool buses;
|
|
diff -up ndctl-71.1/ndctl/load-keys.c.orig ndctl-71.1/ndctl/load-keys.c
|
|
--- ndctl-71.1/ndctl/load-keys.c.orig 2022-10-07 15:50:40.087454604 -0400
|
|
+++ ndctl-71.1/ndctl/load-keys.c 2022-10-07 15:51:03.917535738 -0400
|
|
@@ -12,13 +12,14 @@
|
|
#include <fcntl.h>
|
|
#include <keyutils.h>
|
|
#include <util/json.h>
|
|
-#include <util/filter.h>
|
|
#include <json-c/json.h>
|
|
+#include <ndctl/ndctl.h>
|
|
#include <ndctl/libndctl.h>
|
|
#include <util/parse-options.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
-#include <util/keys.h>
|
|
-#include <ndctl.h>
|
|
+
|
|
+#include "filter.h"
|
|
+#include "keys.h"
|
|
|
|
static struct parameters {
|
|
const char *key_path;
|
|
diff -up ndctl-71.1/ndctl/monitor.c.orig ndctl-71.1/ndctl/monitor.c
|
|
--- ndctl-71.1/ndctl/monitor.c.orig 2022-10-07 15:50:40.087454604 -0400
|
|
+++ ndctl-71.1/ndctl/monitor.c 2022-10-07 15:51:03.917535738 -0400
|
|
@@ -7,7 +7,6 @@
|
|
#include <time.h>
|
|
#include <dirent.h>
|
|
#include <util/json.h>
|
|
-#include <util/filter.h>
|
|
#include <util/util.h>
|
|
#include <util/parse-options.h>
|
|
#include <util/strbuf.h>
|
|
@@ -26,6 +25,9 @@
|
|
#endif
|
|
#include <util/log.h>
|
|
|
|
+#include "filter.h"
|
|
+#include "json.h"
|
|
+
|
|
static struct monitor {
|
|
const char *log;
|
|
const char *config_file;
|
|
diff -up ndctl-71.1/ndctl/namespace.c.orig ndctl-71.1/ndctl/namespace.c
|
|
--- ndctl-71.1/ndctl/namespace.c.orig 2022-10-07 15:50:40.088454607 -0400
|
|
+++ ndctl-71.1/ndctl/namespace.c 2022-10-07 15:51:03.918535741 -0400
|
|
@@ -9,7 +9,6 @@
|
|
#include <limits.h>
|
|
#include <syslog.h>
|
|
|
|
-#include <ndctl.h>
|
|
#include "action.h"
|
|
#include "namespace.h"
|
|
#include <sys/stat.h>
|
|
@@ -20,11 +19,14 @@
|
|
#include <util/size.h>
|
|
#include <util/json.h>
|
|
#include <json-c/json.h>
|
|
-#include <util/filter.h>
|
|
+#include <ndctl/ndctl.h>
|
|
#include <ndctl/libndctl.h>
|
|
#include <util/parse-options.h>
|
|
#include <ccan/minmax/minmax.h>
|
|
|
|
+#include "filter.h"
|
|
+#include "json.h"
|
|
+
|
|
static bool verbose;
|
|
static bool force;
|
|
static bool repair;
|
|
diff -up ndctl-71.1/ndctl/region.c.orig ndctl-71.1/ndctl/region.c
|
|
--- ndctl-71.1/ndctl/region.c.orig 2022-10-07 15:50:40.088454607 -0400
|
|
+++ ndctl-71.1/ndctl/region.c 2022-10-07 15:51:03.918535741 -0400
|
|
@@ -5,10 +5,11 @@
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include "action.h"
|
|
-#include <util/filter.h>
|
|
#include <util/parse-options.h>
|
|
#include <ndctl/libndctl.h>
|
|
|
|
+#include "filter.h"
|
|
+
|
|
static struct {
|
|
const char *bus;
|
|
const char *type;
|
|
diff -up ndctl-71.1/ndctl/util/json-smart.c.orig ndctl-71.1/ndctl/util/json-smart.c
|
|
diff -up ndctl-71.1/ndctl/util/keys.c.orig ndctl-71.1/ndctl/util/keys.c
|
|
diff -up ndctl-71.1/ndctl/util/keys.h.orig ndctl-71.1/ndctl/util/keys.h
|
|
diff -up ndctl-71.1/test/Makefile.am.orig ndctl-71.1/test/Makefile.am
|
|
--- ndctl-71.1/test/Makefile.am.orig 2022-10-07 15:50:40.088454607 -0400
|
|
+++ ndctl-71.1/test/Makefile.am 2022-10-07 15:51:03.919535745 -0400
|
|
@@ -80,12 +80,19 @@ testcore =\
|
|
libndctl_SOURCES = libndctl.c $(testcore)
|
|
libndctl_LDADD = $(LIBNDCTL_LIB) $(UUID_LIBS) $(KMOD_LIBS)
|
|
|
|
+namespace_core =\
|
|
+ ../ndctl/namespace.c \
|
|
+ ../ndctl/filter.c \
|
|
+ ../ndctl/check.c \
|
|
+ ../util/json.c \
|
|
+ ../ndctl/json.c \
|
|
+ ../daxctl/filter.c \
|
|
+ ../daxctl/json.c
|
|
+
|
|
dsm_fail_SOURCES =\
|
|
dsm-fail.c \
|
|
$(testcore) \
|
|
- ../ndctl/namespace.c \
|
|
- ../ndctl/check.c \
|
|
- ../util/json.c
|
|
+ $(namespace_core)
|
|
|
|
dsm_fail_LDADD = $(LIBNDCTL_LIB) \
|
|
$(KMOD_LIBS) \
|
|
@@ -122,9 +129,7 @@ device_dax_SOURCES = \
|
|
dax-dev.c \
|
|
dax-pmd.c \
|
|
$(testcore) \
|
|
- ../ndctl/namespace.c \
|
|
- ../ndctl/check.c \
|
|
- ../util/json.c
|
|
+ $(namespace_core)
|
|
|
|
if ENABLE_POISON
|
|
dax_pmd_SOURCES += dax-poison.c
|
|
@@ -153,7 +158,10 @@ smart_listen_LDADD = $(LIBNDCTL_LIB)
|
|
|
|
list_smart_dimm_SOURCES = \
|
|
list-smart-dimm.c \
|
|
- ../util/json.c
|
|
+ ../ndctl/filter.c \
|
|
+ ../util/json.c \
|
|
+ ../ndctl/json.c
|
|
+
|
|
list_smart_dimm_LDADD = \
|
|
$(LIBNDCTL_LIB) \
|
|
$(JSON_LIBS) \
|
|
diff -up ndctl-71.1/test/ack-shutdown-count-set.c.orig ndctl-71.1/test/ack-shutdown-count-set.c
|
|
--- ndctl-71.1/test/ack-shutdown-count-set.c.orig 2022-10-07 15:50:40.089454611 -0400
|
|
+++ ndctl-71.1/test/ack-shutdown-count-set.c 2022-10-07 15:51:03.919535745 -0400
|
|
@@ -15,7 +15,7 @@
|
|
|
|
#include <ccan/array_size/array_size.h>
|
|
#include <ndctl/libndctl.h>
|
|
-#include <ndctl.h>
|
|
+#include <ndctl/ndctl.h>
|
|
#include <test.h>
|
|
|
|
static int test_dimm(struct ndctl_dimm *dimm)
|
|
diff -up ndctl-71.1/test/daxdev-errors.c.orig ndctl-71.1/test/daxdev-errors.c
|
|
--- ndctl-71.1/test/daxdev-errors.c.orig 2022-10-07 15:50:40.090454614 -0400
|
|
+++ ndctl-71.1/test/daxdev-errors.c 2022-10-07 15:51:03.920535748 -0400
|
|
@@ -23,7 +23,7 @@
|
|
#include <daxctl/libdaxctl.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
#include <ndctl/libndctl.h>
|
|
-#include <ndctl.h>
|
|
+#include <ndctl/ndctl.h>
|
|
|
|
#define fail() fprintf(stderr, "%s: failed at: %d\n", __func__, __LINE__)
|
|
|
|
diff -up ndctl-71.1/test/device-dax.c.orig ndctl-71.1/test/device-dax.c
|
|
--- ndctl-71.1/test/device-dax.c.orig 2022-10-07 15:50:40.090454614 -0400
|
|
+++ ndctl-71.1/test/device-dax.c 2022-10-07 15:51:03.921535752 -0400
|
|
@@ -20,7 +20,7 @@
|
|
#include <daxctl/libdaxctl.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
|
|
-#include <builtin.h>
|
|
+#include <ndctl/builtin.h>
|
|
#include <test.h>
|
|
|
|
static sigjmp_buf sj_env;
|
|
diff -up ndctl-71.1/test/dsm-fail.c.orig ndctl-71.1/test/dsm-fail.c
|
|
--- ndctl-71.1/test/dsm-fail.c.orig 2022-10-07 15:50:40.091454617 -0400
|
|
+++ ndctl-71.1/test/dsm-fail.c 2022-10-07 15:51:03.921535752 -0400
|
|
@@ -14,8 +14,8 @@
|
|
|
|
#include <ccan/array_size/array_size.h>
|
|
#include <ndctl/libndctl.h>
|
|
-#include <builtin.h>
|
|
-#include <ndctl.h>
|
|
+#include <ndctl/builtin.h>
|
|
+#include <ndctl/ndctl.h>
|
|
#include <test.h>
|
|
|
|
#define DIMM_PATH "/sys/devices/platform/nfit_test.0/nfit_test_dimm/test_dimm0"
|
|
diff -up ndctl-71.1/test/libndctl.c.orig ndctl-71.1/test/libndctl.c
|
|
--- ndctl-71.1/test/libndctl.c.orig 2022-10-07 15:50:40.092454621 -0400
|
|
+++ ndctl-71.1/test/libndctl.c 2022-10-07 15:51:03.922535755 -0400
|
|
@@ -21,7 +21,7 @@
|
|
#include <ccan/array_size/array_size.h>
|
|
#include <ndctl/libndctl.h>
|
|
#include <daxctl/libdaxctl.h>
|
|
-#include <ndctl.h>
|
|
+#include <ndctl/ndctl.h>
|
|
#include <test.h>
|
|
|
|
#define BLKROGET _IO(0x12,94) /* get read-only status (0 = read_write) */
|
|
diff -up ndctl-71.1/test/list-smart-dimm.c.orig ndctl-71.1/test/list-smart-dimm.c
|
|
--- ndctl-71.1/test/list-smart-dimm.c.orig 2022-10-07 15:50:40.093454624 -0400
|
|
+++ ndctl-71.1/test/list-smart-dimm.c 2022-10-07 15:51:03.923535758 -0400
|
|
@@ -3,11 +3,13 @@
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <util/json.h>
|
|
-#include <util/filter.h>
|
|
#include <json-c/json.h>
|
|
#include <ndctl/libndctl.h>
|
|
#include <util/parse-options.h>
|
|
-#include <ndctl.h>
|
|
+
|
|
+#include <ndctl/filter.h>
|
|
+#include <ndctl/ndctl.h>
|
|
+#include <ndctl/json.h>
|
|
|
|
struct util_filter_params param;
|
|
static int did_fail;
|
|
diff -up ndctl-71.1/test/pmem_namespaces.c.orig ndctl-71.1/test/pmem_namespaces.c
|
|
--- ndctl-71.1/test/pmem_namespaces.c.orig 2022-10-07 15:50:40.093454624 -0400
|
|
+++ ndctl-71.1/test/pmem_namespaces.c 2022-10-07 15:51:03.923535758 -0400
|
|
@@ -3,6 +3,7 @@
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <linux/fs.h>
|
|
+#include <ndctl/ndctl.h>
|
|
#include <ndctl/libndctl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
@@ -18,7 +19,6 @@
|
|
#include <test.h>
|
|
|
|
#include <ccan/array_size/array_size.h>
|
|
-#include <ndctl.h>
|
|
|
|
#define err(msg)\
|
|
fprintf(stderr, "%s:%d: %s (%s)\n", __func__, __LINE__, msg, strerror(errno))
|
|
diff -up ndctl-71.1/test/revoke-devmem.c.orig ndctl-71.1/test/revoke-devmem.c
|
|
--- ndctl-71.1/test/revoke-devmem.c.orig 2022-10-07 15:50:40.094454628 -0400
|
|
+++ ndctl-71.1/test/revoke-devmem.c 2022-10-07 15:51:03.924535762 -0400
|
|
@@ -19,7 +19,7 @@
|
|
#include <ndctl/libndctl.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
|
|
-#include <builtin.h>
|
|
+#include <ndctl/builtin.h>
|
|
#include <test.h>
|
|
|
|
static sigjmp_buf sj_env;
|
|
diff -up ndctl-71.1/util/filter.c.orig ndctl-71.1/util/filter.c
|
|
diff -up ndctl-71.1/util/filter.h.orig ndctl-71.1/util/filter.h
|
|
diff -up ndctl-71.1/util/help.c.orig ndctl-71.1/util/help.c
|
|
--- ndctl-71.1/util/help.c.orig 2022-10-07 15:50:40.095454631 -0400
|
|
+++ ndctl-71.1/util/help.c 2022-10-07 15:51:03.925535765 -0400
|
|
@@ -14,7 +14,7 @@
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
-#include <builtin.h>
|
|
+#include <ndctl/builtin.h>
|
|
#include <util/strbuf.h>
|
|
#include <util/parse-options.h>
|
|
|
|
diff -up ndctl-71.1/util/json.c.orig ndctl-71.1/util/json.c
|
|
--- ndctl-71.1/util/json.c.orig 2022-10-07 15:50:40.096454635 -0400
|
|
+++ ndctl-71.1/util/json.c 2022-10-07 15:51:03.926535769 -0400
|
|
@@ -2,17 +2,10 @@
|
|
// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
+#include <stdio.h>
|
|
#include <util/json.h>
|
|
-#include <util/filter.h>
|
|
-#include <uuid/uuid.h>
|
|
#include <json-c/json.h>
|
|
#include <json-c/printbuf.h>
|
|
-#include <ndctl/libndctl.h>
|
|
-#include <daxctl/libdaxctl.h>
|
|
-#include <cxl/libcxl.h>
|
|
-#include <ccan/array_size/array_size.h>
|
|
-#include <ccan/short_types/short_types.h>
|
|
-#include <ndctl.h>
|
|
|
|
/* adapted from mdadm::human_size_brief() */
|
|
static int display_size(struct json_object *jobj, struct printbuf *pbuf,
|
|
@@ -112,1536 +105,3 @@ void util_display_json_array(FILE *f_out
|
|
}
|
|
json_object_put(jarray);
|
|
}
|
|
-
|
|
-struct json_object *util_bus_to_json(struct ndctl_bus *bus, unsigned long flags)
|
|
-{
|
|
- struct json_object *jbus = json_object_new_object();
|
|
- struct json_object *jobj, *fw_obj = NULL;
|
|
- int scrub;
|
|
-
|
|
- if (!jbus)
|
|
- return NULL;
|
|
-
|
|
- jobj = json_object_new_string(ndctl_bus_get_provider(bus));
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jbus, "provider", jobj);
|
|
-
|
|
- jobj = json_object_new_string(ndctl_bus_get_devname(bus));
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jbus, "dev", jobj);
|
|
-
|
|
- scrub = ndctl_bus_get_scrub_state(bus);
|
|
- if (scrub < 0)
|
|
- return jbus;
|
|
-
|
|
- jobj = json_object_new_string(scrub ? "active" : "idle");
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jbus, "scrub_state", jobj);
|
|
-
|
|
- if (flags & UTIL_JSON_FIRMWARE) {
|
|
- struct ndctl_dimm *dimm;
|
|
-
|
|
- /*
|
|
- * Skip displaying firmware activation capability if no
|
|
- * DIMMs support firmware update.
|
|
- */
|
|
- ndctl_dimm_foreach(bus, dimm)
|
|
- if (ndctl_dimm_fw_update_supported(dimm) == 0) {
|
|
- fw_obj = json_object_new_object();
|
|
- break;
|
|
- }
|
|
- }
|
|
-
|
|
- if (fw_obj) {
|
|
- enum ndctl_fwa_state state;
|
|
- enum ndctl_fwa_method method;
|
|
-
|
|
- jobj = NULL;
|
|
- method = ndctl_bus_get_fw_activate_method(bus);
|
|
- if (method == NDCTL_FWA_METHOD_RESET)
|
|
- jobj = json_object_new_string("reset");
|
|
- if (method == NDCTL_FWA_METHOD_SUSPEND)
|
|
- jobj = json_object_new_string("suspend");
|
|
- if (method == NDCTL_FWA_METHOD_LIVE)
|
|
- jobj = json_object_new_string("live");
|
|
- if (jobj)
|
|
- json_object_object_add(fw_obj, "activate_method", jobj);
|
|
-
|
|
- jobj = NULL;
|
|
- state = ndctl_bus_get_fw_activate_state(bus);
|
|
- if (state == NDCTL_FWA_ARMED)
|
|
- jobj = json_object_new_string("armed");
|
|
- if (state == NDCTL_FWA_IDLE)
|
|
- jobj = json_object_new_string("idle");
|
|
- if (state == NDCTL_FWA_ARM_OVERFLOW)
|
|
- jobj = json_object_new_string("overflow");
|
|
- if (jobj)
|
|
- json_object_object_add(fw_obj, "activate_state", jobj);
|
|
-
|
|
- json_object_object_add(jbus, "firmware", fw_obj);
|
|
- }
|
|
-
|
|
- return jbus;
|
|
- err:
|
|
- json_object_put(jbus);
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-struct json_object *util_dimm_firmware_to_json(struct ndctl_dimm *dimm,
|
|
- unsigned long flags)
|
|
-{
|
|
- struct json_object *jfirmware = json_object_new_object();
|
|
- bool can_update, need_powercycle;
|
|
- enum ndctl_fwa_result result;
|
|
- enum ndctl_fwa_state state;
|
|
- struct json_object *jobj;
|
|
- struct ndctl_cmd *cmd;
|
|
- uint64_t run, next;
|
|
- int rc;
|
|
-
|
|
- if (!jfirmware)
|
|
- return NULL;
|
|
-
|
|
- cmd = ndctl_dimm_cmd_new_fw_get_info(dimm);
|
|
- if (!cmd)
|
|
- goto err;
|
|
-
|
|
- rc = ndctl_cmd_submit(cmd);
|
|
- if ((rc < 0) || ndctl_cmd_fw_xlat_firmware_status(cmd) != FW_SUCCESS) {
|
|
- jobj = util_json_object_hex(-1, flags);
|
|
- if (jobj)
|
|
- json_object_object_add(jfirmware, "current_version",
|
|
- jobj);
|
|
- goto out;
|
|
- }
|
|
-
|
|
- run = ndctl_cmd_fw_info_get_run_version(cmd);
|
|
- if (run == ULLONG_MAX) {
|
|
- jobj = util_json_object_hex(-1, flags);
|
|
- if (jobj)
|
|
- json_object_object_add(jfirmware, "current_version",
|
|
- jobj);
|
|
- goto out;
|
|
- }
|
|
-
|
|
- jobj = util_json_object_hex(run, flags);
|
|
- if (jobj)
|
|
- json_object_object_add(jfirmware, "current_version", jobj);
|
|
-
|
|
- rc = ndctl_dimm_fw_update_supported(dimm);
|
|
- can_update = rc == 0;
|
|
- jobj = json_object_new_boolean(can_update);
|
|
- if (jobj)
|
|
- json_object_object_add(jfirmware, "can_update", jobj);
|
|
-
|
|
-
|
|
- next = ndctl_cmd_fw_info_get_updated_version(cmd);
|
|
- if (next == ULLONG_MAX) {
|
|
- jobj = util_json_object_hex(-1, flags);
|
|
- if (jobj)
|
|
- json_object_object_add(jfirmware, "next_version",
|
|
- jobj);
|
|
- goto out;
|
|
- }
|
|
-
|
|
- if (!next)
|
|
- goto out;
|
|
-
|
|
- jobj = util_json_object_hex(next, flags);
|
|
- if (jobj)
|
|
- json_object_object_add(jfirmware,
|
|
- "next_version", jobj);
|
|
-
|
|
- state = ndctl_dimm_get_fw_activate_state(dimm);
|
|
- switch (state) {
|
|
- case NDCTL_FWA_IDLE:
|
|
- jobj = json_object_new_string("idle");
|
|
- break;
|
|
- case NDCTL_FWA_ARMED:
|
|
- jobj = json_object_new_string("armed");
|
|
- break;
|
|
- case NDCTL_FWA_BUSY:
|
|
- jobj = json_object_new_string("busy");
|
|
- break;
|
|
- default:
|
|
- jobj = NULL;
|
|
- break;
|
|
- }
|
|
- if (jobj)
|
|
- json_object_object_add(jfirmware, "activate_state", jobj);
|
|
-
|
|
- result = ndctl_dimm_get_fw_activate_result(dimm);
|
|
- switch (result) {
|
|
- case NDCTL_FWA_RESULT_NONE:
|
|
- case NDCTL_FWA_RESULT_SUCCESS:
|
|
- case NDCTL_FWA_RESULT_NOTSTAGED:
|
|
- /*
|
|
- * If a 'next' firmware version is staged then this
|
|
- * result is stale, if the activation succeeds that is
|
|
- * indicated by not finding a 'next' entry.
|
|
- */
|
|
- need_powercycle = false;
|
|
- break;
|
|
- case NDCTL_FWA_RESULT_NEEDRESET:
|
|
- case NDCTL_FWA_RESULT_FAIL:
|
|
- default:
|
|
- /*
|
|
- * If the last activation failed, or if the activation
|
|
- * result is unavailable it is always the case that the
|
|
- * only remediation is powercycle.
|
|
- */
|
|
- need_powercycle = true;
|
|
- break;
|
|
- }
|
|
-
|
|
- if (need_powercycle) {
|
|
- jobj = json_object_new_boolean(true);
|
|
- if (!jobj)
|
|
- goto out;
|
|
- json_object_object_add(jfirmware, "need_powercycle", jobj);
|
|
- }
|
|
-
|
|
- ndctl_cmd_unref(cmd);
|
|
- return jfirmware;
|
|
-
|
|
-err:
|
|
- json_object_put(jfirmware);
|
|
- jfirmware = NULL;
|
|
-out:
|
|
- if (cmd)
|
|
- ndctl_cmd_unref(cmd);
|
|
- return jfirmware;
|
|
-}
|
|
-
|
|
-struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm,
|
|
- unsigned long flags)
|
|
-{
|
|
- struct json_object *jdimm = json_object_new_object();
|
|
- const char *id = ndctl_dimm_get_unique_id(dimm);
|
|
- unsigned int handle = ndctl_dimm_get_handle(dimm);
|
|
- unsigned short phys_id = ndctl_dimm_get_phys_id(dimm);
|
|
- struct json_object *jobj;
|
|
- enum ndctl_security_state sstate;
|
|
-
|
|
- if (!jdimm)
|
|
- return NULL;
|
|
-
|
|
- jobj = json_object_new_string(ndctl_dimm_get_devname(dimm));
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jdimm, "dev", jobj);
|
|
-
|
|
- if (id) {
|
|
- jobj = json_object_new_string(id);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jdimm, "id", jobj);
|
|
- }
|
|
-
|
|
- if (handle < UINT_MAX) {
|
|
- jobj = util_json_object_hex(handle, flags);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jdimm, "handle", jobj);
|
|
- }
|
|
-
|
|
- if (phys_id < USHRT_MAX) {
|
|
- jobj = util_json_object_hex(phys_id, flags);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jdimm, "phys_id", jobj);
|
|
- }
|
|
-
|
|
- if (!ndctl_dimm_is_enabled(dimm)) {
|
|
- jobj = json_object_new_string("disabled");
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jdimm, "state", jobj);
|
|
- }
|
|
-
|
|
- if (ndctl_dimm_failed_map(dimm)) {
|
|
- jobj = json_object_new_boolean(true);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jdimm, "flag_failed_map", jobj);
|
|
- }
|
|
-
|
|
- if (ndctl_dimm_failed_save(dimm)) {
|
|
- jobj = json_object_new_boolean(true);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jdimm, "flag_failed_save", jobj);
|
|
- }
|
|
-
|
|
- if (ndctl_dimm_failed_arm(dimm)) {
|
|
- jobj = json_object_new_boolean(true);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jdimm, "flag_failed_arm", jobj);
|
|
- }
|
|
-
|
|
- if (ndctl_dimm_failed_restore(dimm)) {
|
|
- jobj = json_object_new_boolean(true);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jdimm, "flag_failed_restore", jobj);
|
|
- }
|
|
-
|
|
- if (ndctl_dimm_failed_flush(dimm)) {
|
|
- jobj = json_object_new_boolean(true);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jdimm, "flag_failed_flush", jobj);
|
|
- }
|
|
-
|
|
- if (ndctl_dimm_smart_pending(dimm)) {
|
|
- jobj = json_object_new_boolean(true);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jdimm, "flag_smart_event", jobj);
|
|
- }
|
|
-
|
|
- sstate = ndctl_dimm_get_security(dimm);
|
|
- if (sstate == NDCTL_SECURITY_DISABLED)
|
|
- jobj = json_object_new_string("disabled");
|
|
- else if (sstate == NDCTL_SECURITY_UNLOCKED)
|
|
- jobj = json_object_new_string("unlocked");
|
|
- else if (sstate == NDCTL_SECURITY_LOCKED)
|
|
- jobj = json_object_new_string("locked");
|
|
- else if (sstate == NDCTL_SECURITY_FROZEN)
|
|
- jobj = json_object_new_string("frozen");
|
|
- else if (sstate == NDCTL_SECURITY_OVERWRITE)
|
|
- jobj = json_object_new_string("overwrite");
|
|
- else
|
|
- jobj = NULL;
|
|
- if (jobj)
|
|
- json_object_object_add(jdimm, "security", jobj);
|
|
-
|
|
- if (ndctl_dimm_security_is_frozen(dimm)) {
|
|
- jobj = json_object_new_boolean(true);
|
|
- if (jobj)
|
|
- json_object_object_add(jdimm, "security_frozen", jobj);
|
|
- }
|
|
-
|
|
- if (flags & UTIL_JSON_FIRMWARE) {
|
|
- struct json_object *jfirmware;
|
|
-
|
|
- jfirmware = util_dimm_firmware_to_json(dimm, flags);
|
|
- if (jfirmware)
|
|
- json_object_object_add(jdimm, "firmware", jfirmware);
|
|
- }
|
|
-
|
|
- return jdimm;
|
|
- err:
|
|
- json_object_put(jdimm);
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-struct json_object *util_daxctl_dev_to_json(struct daxctl_dev *dev,
|
|
- unsigned long flags)
|
|
-{
|
|
- struct daxctl_memory *mem = daxctl_dev_get_memory(dev);
|
|
- const char *devname = daxctl_dev_get_devname(dev);
|
|
- struct json_object *jdev, *jobj, *jmappings = NULL;
|
|
- struct daxctl_mapping *mapping = NULL;
|
|
- int node, movable, align;
|
|
-
|
|
- jdev = json_object_new_object();
|
|
- if (!devname || !jdev)
|
|
- return NULL;
|
|
-
|
|
- jobj = json_object_new_string(devname);
|
|
- if (jobj)
|
|
- json_object_object_add(jdev, "chardev", jobj);
|
|
-
|
|
- jobj = util_json_object_size(daxctl_dev_get_size(dev), flags);
|
|
- if (jobj)
|
|
- json_object_object_add(jdev, "size", jobj);
|
|
-
|
|
- node = daxctl_dev_get_target_node(dev);
|
|
- if (node >= 0) {
|
|
- jobj = json_object_new_int(node);
|
|
- if (jobj)
|
|
- json_object_object_add(jdev, "target_node", jobj);
|
|
- }
|
|
-
|
|
- align = daxctl_dev_get_align(dev);
|
|
- if (align > 0) {
|
|
- jobj = util_json_object_size(daxctl_dev_get_align(dev), flags);
|
|
- if (jobj)
|
|
- json_object_object_add(jdev, "align", jobj);
|
|
- }
|
|
-
|
|
- if (mem)
|
|
- jobj = json_object_new_string("system-ram");
|
|
- else
|
|
- jobj = json_object_new_string("devdax");
|
|
- if (jobj)
|
|
- json_object_object_add(jdev, "mode", jobj);
|
|
-
|
|
- if (mem && daxctl_dev_get_resource(dev) != 0) {
|
|
- int num_sections = daxctl_memory_num_sections(mem);
|
|
- int num_online = daxctl_memory_is_online(mem);
|
|
-
|
|
- jobj = json_object_new_int(num_online);
|
|
- if (jobj)
|
|
- json_object_object_add(jdev, "online_memblocks", jobj);
|
|
-
|
|
- jobj = json_object_new_int(num_sections);
|
|
- if (jobj)
|
|
- json_object_object_add(jdev, "total_memblocks", jobj);
|
|
-
|
|
- movable = daxctl_memory_is_movable(mem);
|
|
- if (movable == 1)
|
|
- jobj = json_object_new_boolean(true);
|
|
- else if (movable == 0)
|
|
- jobj = json_object_new_boolean(false);
|
|
- else
|
|
- jobj = NULL;
|
|
- if (jobj)
|
|
- json_object_object_add(jdev, "movable", jobj);
|
|
- }
|
|
-
|
|
- if (!daxctl_dev_is_enabled(dev)) {
|
|
- jobj = json_object_new_string("disabled");
|
|
- if (jobj)
|
|
- json_object_object_add(jdev, "state", jobj);
|
|
- }
|
|
-
|
|
- if (!(flags & UTIL_JSON_DAX_MAPPINGS))
|
|
- return jdev;
|
|
-
|
|
- daxctl_mapping_foreach(dev, mapping) {
|
|
- struct json_object *jmapping;
|
|
-
|
|
- if (!jmappings) {
|
|
- jmappings = json_object_new_array();
|
|
- if (!jmappings)
|
|
- continue;
|
|
-
|
|
- json_object_object_add(jdev, "mappings", jmappings);
|
|
- }
|
|
-
|
|
- jmapping = util_daxctl_mapping_to_json(mapping, flags);
|
|
- if (!jmapping)
|
|
- continue;
|
|
- json_object_array_add(jmappings, jmapping);
|
|
- }
|
|
- return jdev;
|
|
-}
|
|
-
|
|
-struct json_object *util_daxctl_devs_to_list(struct daxctl_region *region,
|
|
- struct json_object *jdevs, const char *ident,
|
|
- unsigned long flags)
|
|
-{
|
|
- struct daxctl_dev *dev;
|
|
-
|
|
- daxctl_dev_foreach(region, dev) {
|
|
- struct json_object *jdev;
|
|
-
|
|
- if (!util_daxctl_dev_filter(dev, ident))
|
|
- continue;
|
|
-
|
|
- if (!(flags & (UTIL_JSON_IDLE|UTIL_JSON_CONFIGURED))
|
|
- && !daxctl_dev_get_size(dev))
|
|
- continue;
|
|
-
|
|
- if (!jdevs) {
|
|
- jdevs = json_object_new_array();
|
|
- if (!jdevs)
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- jdev = util_daxctl_dev_to_json(dev, flags);
|
|
- if (!jdev) {
|
|
- json_object_put(jdevs);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- json_object_array_add(jdevs, jdev);
|
|
- }
|
|
-
|
|
- return jdevs;
|
|
-}
|
|
-
|
|
-#define _SZ(get_max, get_elem, type) \
|
|
-static struct json_object *util_##type##_build_size_array(struct ndctl_##type *arg) \
|
|
-{ \
|
|
- struct json_object *arr = json_object_new_array(); \
|
|
- int i; \
|
|
- \
|
|
- if (!arr) \
|
|
- return NULL; \
|
|
- \
|
|
- for (i = 0; i < get_max(arg); i++) { \
|
|
- struct json_object *jobj; \
|
|
- int64_t align; \
|
|
- \
|
|
- align = get_elem(arg, i); \
|
|
- jobj = json_object_new_int64(align); \
|
|
- if (!jobj) \
|
|
- goto err; \
|
|
- json_object_array_add(arr, jobj); \
|
|
- } \
|
|
- \
|
|
- return arr; \
|
|
-err: \
|
|
- json_object_put(arr); \
|
|
- return NULL; \
|
|
-}
|
|
-#define SZ(type, kind) _SZ(ndctl_##type##_get_num_##kind##s, \
|
|
- ndctl_##type##_get_supported_##kind, type)
|
|
-SZ(pfn, alignment)
|
|
-SZ(dax, alignment)
|
|
-SZ(btt, sector_size)
|
|
-
|
|
-struct json_object *util_region_capabilities_to_json(struct ndctl_region *region)
|
|
-{
|
|
- struct json_object *jcaps, *jcap, *jobj;
|
|
- struct ndctl_btt *btt = ndctl_region_get_btt_seed(region);
|
|
- struct ndctl_pfn *pfn = ndctl_region_get_pfn_seed(region);
|
|
- struct ndctl_dax *dax = ndctl_region_get_dax_seed(region);
|
|
-
|
|
- if (!btt || !pfn || !dax)
|
|
- return NULL;
|
|
-
|
|
- jcaps = json_object_new_array();
|
|
- if (!jcaps)
|
|
- return NULL;
|
|
-
|
|
- if (btt) {
|
|
- jcap = json_object_new_object();
|
|
- if (!jcap)
|
|
- goto err;
|
|
- json_object_array_add(jcaps, jcap);
|
|
-
|
|
- jobj = json_object_new_string("sector");
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jcap, "mode", jobj);
|
|
- jobj = util_btt_build_size_array(btt);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jcap, "sector_sizes", jobj);
|
|
- }
|
|
-
|
|
- if (pfn) {
|
|
- jcap = json_object_new_object();
|
|
- if (!jcap)
|
|
- goto err;
|
|
- json_object_array_add(jcaps, jcap);
|
|
-
|
|
- jobj = json_object_new_string("fsdax");
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jcap, "mode", jobj);
|
|
- jobj = util_pfn_build_size_array(pfn);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jcap, "alignments", jobj);
|
|
- }
|
|
-
|
|
- if (dax) {
|
|
- jcap = json_object_new_object();
|
|
- if (!jcap)
|
|
- goto err;
|
|
- json_object_array_add(jcaps, jcap);
|
|
-
|
|
- jobj = json_object_new_string("devdax");
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jcap, "mode", jobj);
|
|
- jobj = util_dax_build_size_array(dax);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jcap, "alignments", jobj);
|
|
- }
|
|
-
|
|
- return jcaps;
|
|
-err:
|
|
- json_object_put(jcaps);
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-struct json_object *util_daxctl_region_to_json(struct daxctl_region *region,
|
|
- const char *ident, unsigned long flags)
|
|
-{
|
|
- unsigned long align;
|
|
- struct json_object *jregion, *jobj;
|
|
- unsigned long long available_size, size;
|
|
-
|
|
- jregion = json_object_new_object();
|
|
- if (!jregion)
|
|
- return NULL;
|
|
-
|
|
- /*
|
|
- * The flag indicates when we are being called by an agent that
|
|
- * already knows about the parent device information.
|
|
- */
|
|
- if (!(flags & UTIL_JSON_DAX)) {
|
|
- /* trim off the redundant /sys/devices prefix */
|
|
- const char *path = daxctl_region_get_path(region);
|
|
- int len = strlen("/sys/devices");
|
|
- const char *trim = &path[len];
|
|
-
|
|
- if (strncmp(path, "/sys/devices", len) != 0)
|
|
- goto err;
|
|
- jobj = json_object_new_string(trim);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jregion, "path", jobj);
|
|
- }
|
|
-
|
|
- jobj = json_object_new_int(daxctl_region_get_id(region));
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jregion, "id", jobj);
|
|
-
|
|
- size = daxctl_region_get_size(region);
|
|
- if (size < ULLONG_MAX) {
|
|
- jobj = util_json_object_size(size, flags);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jregion, "size", jobj);
|
|
- }
|
|
-
|
|
- available_size = daxctl_region_get_available_size(region);
|
|
- if (available_size) {
|
|
- jobj = util_json_object_size(available_size, flags);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jregion, "available_size", jobj);
|
|
- }
|
|
-
|
|
- align = daxctl_region_get_align(region);
|
|
- if (align < ULONG_MAX) {
|
|
- jobj = json_object_new_int64(align);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jregion, "align", jobj);
|
|
- }
|
|
-
|
|
- if (!(flags & UTIL_JSON_DAX_DEVS))
|
|
- return jregion;
|
|
-
|
|
- jobj = util_daxctl_devs_to_list(region, NULL, ident, flags);
|
|
- if (jobj)
|
|
- json_object_object_add(jregion, "devices", jobj);
|
|
-
|
|
- return jregion;
|
|
- err:
|
|
- json_object_put(jregion);
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-static int compare_dimm_number(const void *p1, const void *p2)
|
|
-{
|
|
- struct ndctl_dimm *dimm1 = *(struct ndctl_dimm **)p1;
|
|
- struct ndctl_dimm *dimm2 = *(struct ndctl_dimm **)p2;
|
|
- const char *dimm1_name = ndctl_dimm_get_devname(dimm1);
|
|
- const char *dimm2_name = ndctl_dimm_get_devname(dimm2);
|
|
- int num1, num2;
|
|
-
|
|
- if (sscanf(dimm1_name, "nmem%d", &num1) != 1)
|
|
- num1 = 0;
|
|
- if (sscanf(dimm2_name, "nmem%d", &num2) != 1)
|
|
- num2 = 0;
|
|
-
|
|
- return num1 - num2;
|
|
-}
|
|
-
|
|
-static struct json_object *badblocks_to_jdimms(struct ndctl_region *region,
|
|
- unsigned long long addr, unsigned long len)
|
|
-{
|
|
- struct ndctl_bus *bus = ndctl_region_get_bus(region);
|
|
- int count = ndctl_region_get_interleave_ways(region);
|
|
- unsigned long long end = addr + len;
|
|
- struct json_object *jdimms, *jobj;
|
|
- struct ndctl_dimm **dimms, *dimm;
|
|
- int found, i;
|
|
-
|
|
- jdimms = json_object_new_array();
|
|
- if (!jdimms)
|
|
- return NULL;
|
|
-
|
|
- dimms = calloc(count, sizeof(struct ndctl_dimm *));
|
|
- if (!dimms)
|
|
- goto err_dimms;
|
|
-
|
|
- for (found = 0; found < count && addr < end; addr += 512) {
|
|
- dimm = ndctl_bus_get_dimm_by_physical_address(bus, addr);
|
|
- if (!dimm)
|
|
- continue;
|
|
-
|
|
- for (i = 0; i < count; i++)
|
|
- if (dimms[i] == dimm)
|
|
- break;
|
|
- if (i >= count)
|
|
- dimms[found++] = dimm;
|
|
- }
|
|
-
|
|
- if (!found)
|
|
- goto err_found;
|
|
-
|
|
- qsort(dimms, found, sizeof(dimm), compare_dimm_number);
|
|
-
|
|
- for (i = 0; i < found; i++) {
|
|
- const char *devname = ndctl_dimm_get_devname(dimms[i]);
|
|
-
|
|
- jobj = json_object_new_string(devname);
|
|
- if (!jobj)
|
|
- break;
|
|
- json_object_array_add(jdimms, jobj);
|
|
- }
|
|
-
|
|
- if (!i)
|
|
- goto err_found;
|
|
- free(dimms);
|
|
- return jdimms;
|
|
-
|
|
-err_found:
|
|
- free(dimms);
|
|
-err_dimms:
|
|
- json_object_put(jdimms);
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-struct json_object *util_region_badblocks_to_json(struct ndctl_region *region,
|
|
- unsigned int *bb_count, unsigned long flags)
|
|
-{
|
|
- struct json_object *jbb = NULL, *jbbs = NULL, *jobj;
|
|
- struct badblock *bb;
|
|
- int bbs = 0;
|
|
-
|
|
- if (flags & UTIL_JSON_MEDIA_ERRORS) {
|
|
- jbbs = json_object_new_array();
|
|
- if (!jbbs)
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- ndctl_region_badblock_foreach(region, bb) {
|
|
- struct json_object *jdimms;
|
|
- unsigned long long addr;
|
|
-
|
|
- bbs += bb->len;
|
|
-
|
|
- /* recheck so we can still get the badblocks_count from above */
|
|
- if (!(flags & UTIL_JSON_MEDIA_ERRORS))
|
|
- continue;
|
|
-
|
|
- /* get start address of region */
|
|
- addr = ndctl_region_get_resource(region);
|
|
- if (addr == ULLONG_MAX)
|
|
- goto err_array;
|
|
-
|
|
- /* get address of bad block */
|
|
- addr += bb->offset << 9;
|
|
-
|
|
- jbb = json_object_new_object();
|
|
- if (!jbb)
|
|
- goto err_array;
|
|
-
|
|
- jobj = json_object_new_int64(bb->offset);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jbb, "offset", jobj);
|
|
-
|
|
- jobj = json_object_new_int(bb->len);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jbb, "length", jobj);
|
|
-
|
|
- jdimms = badblocks_to_jdimms(region, addr, bb->len << 9);
|
|
- if (jdimms)
|
|
- json_object_object_add(jbb, "dimms", jdimms);
|
|
- json_object_array_add(jbbs, jbb);
|
|
- }
|
|
-
|
|
- *bb_count = bbs;
|
|
-
|
|
- if (bbs)
|
|
- return jbbs;
|
|
-
|
|
- err:
|
|
- json_object_put(jbb);
|
|
- err_array:
|
|
- json_object_put(jbbs);
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-static struct json_object *util_namespace_badblocks_to_json(
|
|
- struct ndctl_namespace *ndns,
|
|
- unsigned int *bb_count, unsigned long flags)
|
|
-{
|
|
- struct json_object *jbb = NULL, *jbbs = NULL, *jobj;
|
|
- struct badblock *bb;
|
|
- int bbs = 0;
|
|
-
|
|
- if (flags & UTIL_JSON_MEDIA_ERRORS) {
|
|
- jbbs = json_object_new_array();
|
|
- if (!jbbs)
|
|
- return NULL;
|
|
- } else
|
|
- return NULL;
|
|
-
|
|
- ndctl_namespace_badblock_foreach(ndns, bb) {
|
|
- bbs += bb->len;
|
|
-
|
|
- /* recheck so we can still get the badblocks_count from above */
|
|
- if (!(flags & UTIL_JSON_MEDIA_ERRORS))
|
|
- continue;
|
|
-
|
|
- jbb = json_object_new_object();
|
|
- if (!jbb)
|
|
- goto err_array;
|
|
-
|
|
- jobj = json_object_new_int64(bb->offset);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jbb, "offset", jobj);
|
|
-
|
|
- jobj = json_object_new_int(bb->len);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jbb, "length", jobj);
|
|
- json_object_array_add(jbbs, jbb);
|
|
- }
|
|
-
|
|
- *bb_count = bbs;
|
|
-
|
|
- if (bbs)
|
|
- return jbbs;
|
|
-
|
|
- err:
|
|
- json_object_put(jbb);
|
|
- err_array:
|
|
- json_object_put(jbbs);
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-static struct json_object *dev_badblocks_to_json(struct ndctl_region *region,
|
|
- unsigned long long dev_begin, unsigned long long dev_size,
|
|
- unsigned int *bb_count, unsigned long flags)
|
|
-{
|
|
- struct json_object *jbb = NULL, *jbbs = NULL, *jobj;
|
|
- unsigned long long region_begin, dev_end, offset;
|
|
- unsigned int len, bbs = 0;
|
|
- struct badblock *bb;
|
|
-
|
|
- region_begin = ndctl_region_get_resource(region);
|
|
- if (region_begin == ULLONG_MAX)
|
|
- return NULL;
|
|
-
|
|
- dev_end = dev_begin + dev_size - 1;
|
|
-
|
|
- if (flags & UTIL_JSON_MEDIA_ERRORS) {
|
|
- jbbs = json_object_new_array();
|
|
- if (!jbbs)
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- ndctl_region_badblock_foreach(region, bb) {
|
|
- unsigned long long bb_begin, bb_end, begin, end;
|
|
- struct json_object *jdimms;
|
|
-
|
|
- bb_begin = region_begin + (bb->offset << 9);
|
|
- bb_end = bb_begin + (bb->len << 9) - 1;
|
|
-
|
|
- if (bb_end <= dev_begin || bb_begin >= dev_end)
|
|
- continue;
|
|
-
|
|
- if (bb_begin < dev_begin)
|
|
- begin = dev_begin;
|
|
- else
|
|
- begin = bb_begin;
|
|
-
|
|
- if (bb_end > dev_end)
|
|
- end = dev_end;
|
|
- else
|
|
- end = bb_end;
|
|
-
|
|
- offset = (begin - dev_begin) >> 9;
|
|
- len = (end - begin + 1) >> 9;
|
|
-
|
|
- bbs += len;
|
|
-
|
|
- /* recheck so we can still get the badblocks_count from above */
|
|
- if (!(flags & UTIL_JSON_MEDIA_ERRORS))
|
|
- continue;
|
|
-
|
|
- jbb = json_object_new_object();
|
|
- if (!jbb)
|
|
- goto err_array;
|
|
-
|
|
- jobj = json_object_new_int64(offset);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jbb, "offset", jobj);
|
|
-
|
|
- jobj = json_object_new_int(len);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jbb, "length", jobj);
|
|
-
|
|
- jdimms = badblocks_to_jdimms(region, begin, len << 9);
|
|
- if (jdimms)
|
|
- json_object_object_add(jbb, "dimms", jdimms);
|
|
-
|
|
- json_object_array_add(jbbs, jbb);
|
|
- }
|
|
-
|
|
- *bb_count = bbs;
|
|
-
|
|
- if (bbs)
|
|
- return jbbs;
|
|
-
|
|
- err:
|
|
- json_object_put(jbb);
|
|
- err_array:
|
|
- json_object_put(jbbs);
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-static struct json_object *util_pfn_badblocks_to_json(struct ndctl_pfn *pfn,
|
|
- unsigned int *bb_count, unsigned long flags)
|
|
-{
|
|
- struct ndctl_region *region = ndctl_pfn_get_region(pfn);
|
|
- unsigned long long pfn_begin, pfn_size;
|
|
-
|
|
- pfn_begin = ndctl_pfn_get_resource(pfn);
|
|
- if (pfn_begin == ULLONG_MAX) {
|
|
- struct ndctl_namespace *ndns = ndctl_pfn_get_namespace(pfn);
|
|
-
|
|
- return util_namespace_badblocks_to_json(ndns, bb_count, flags);
|
|
- }
|
|
-
|
|
- pfn_size = ndctl_pfn_get_size(pfn);
|
|
- if (pfn_size == ULLONG_MAX)
|
|
- return NULL;
|
|
-
|
|
- return dev_badblocks_to_json(region, pfn_begin, pfn_size,
|
|
- bb_count, flags);
|
|
-}
|
|
-
|
|
-static void util_btt_badblocks_to_json(struct ndctl_btt *btt,
|
|
- unsigned int *bb_count)
|
|
-{
|
|
- struct ndctl_region *region = ndctl_btt_get_region(btt);
|
|
- struct ndctl_namespace *ndns = ndctl_btt_get_namespace(btt);
|
|
- unsigned long long begin, size;
|
|
-
|
|
- if (!ndns)
|
|
- return;
|
|
-
|
|
- begin = ndctl_namespace_get_resource(ndns);
|
|
- if (begin == ULLONG_MAX)
|
|
- return;
|
|
-
|
|
- size = ndctl_namespace_get_size(ndns);
|
|
- if (size == ULLONG_MAX)
|
|
- return;
|
|
-
|
|
- /*
|
|
- * The dev_badblocks_to_json() for BTT is not accurate with
|
|
- * respect to data vs metadata badblocks, and is only useful for
|
|
- * a potential bb_count.
|
|
- *
|
|
- * FIXME: switch to native BTT badblocks representation
|
|
- * when / if the kernel provides it.
|
|
- */
|
|
- dev_badblocks_to_json(region, begin, size, bb_count, 0);
|
|
-}
|
|
-
|
|
-static struct json_object *util_dax_badblocks_to_json(struct ndctl_dax *dax,
|
|
- unsigned int *bb_count, unsigned long flags)
|
|
-{
|
|
- struct ndctl_region *region = ndctl_dax_get_region(dax);
|
|
- unsigned long long dax_begin, dax_size;
|
|
-
|
|
- dax_begin = ndctl_dax_get_resource(dax);
|
|
- if (dax_begin == ULLONG_MAX)
|
|
- return NULL;
|
|
-
|
|
- dax_size = ndctl_dax_get_size(dax);
|
|
- if (dax_size == ULLONG_MAX)
|
|
- return NULL;
|
|
-
|
|
- return dev_badblocks_to_json(region, dax_begin, dax_size,
|
|
- bb_count, flags);
|
|
-}
|
|
-
|
|
-static struct json_object *util_raw_uuid(struct ndctl_namespace *ndns)
|
|
-{
|
|
- char buf[40];
|
|
- uuid_t raw_uuid;
|
|
-
|
|
- ndctl_namespace_get_uuid(ndns, raw_uuid);
|
|
- if (uuid_is_null(raw_uuid))
|
|
- return NULL;
|
|
- uuid_unparse(raw_uuid, buf);
|
|
- return json_object_new_string(buf);
|
|
-}
|
|
-
|
|
-static void util_raw_uuid_to_json(struct ndctl_namespace *ndns,
|
|
- unsigned long flags,
|
|
- struct json_object *jndns)
|
|
-{
|
|
- struct json_object *jobj;
|
|
-
|
|
- if (!(flags & UTIL_JSON_VERBOSE))
|
|
- return;
|
|
-
|
|
- jobj = util_raw_uuid(ndns);
|
|
- if (!jobj)
|
|
- return;
|
|
- json_object_object_add(jndns, "raw_uuid", jobj);
|
|
-}
|
|
-
|
|
-struct json_object *util_namespace_to_json(struct ndctl_namespace *ndns,
|
|
- unsigned long flags)
|
|
-{
|
|
- struct json_object *jndns = json_object_new_object();
|
|
- enum ndctl_pfn_loc loc = NDCTL_PFN_LOC_NONE;
|
|
- struct json_object *jobj, *jbbs = NULL;
|
|
- const char *locations[] = {
|
|
- [NDCTL_PFN_LOC_NONE] = "none",
|
|
- [NDCTL_PFN_LOC_RAM] = "mem",
|
|
- [NDCTL_PFN_LOC_PMEM] = "dev",
|
|
- };
|
|
- unsigned long long size = ULLONG_MAX;
|
|
- unsigned int sector_size = UINT_MAX;
|
|
- enum ndctl_namespace_mode mode;
|
|
- const char *bdev = NULL, *name;
|
|
- unsigned int bb_count = 0;
|
|
- struct ndctl_btt *btt;
|
|
- struct ndctl_pfn *pfn;
|
|
- struct ndctl_dax *dax;
|
|
- unsigned long align = 0;
|
|
- char buf[40];
|
|
- uuid_t uuid;
|
|
- int numa, target;
|
|
-
|
|
- if (!jndns)
|
|
- return NULL;
|
|
-
|
|
- jobj = json_object_new_string(ndctl_namespace_get_devname(ndns));
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jndns, "dev", jobj);
|
|
-
|
|
- btt = ndctl_namespace_get_btt(ndns);
|
|
- dax = ndctl_namespace_get_dax(ndns);
|
|
- pfn = ndctl_namespace_get_pfn(ndns);
|
|
- mode = ndctl_namespace_get_mode(ndns);
|
|
- switch (mode) {
|
|
- case NDCTL_NS_MODE_MEMORY:
|
|
- if (pfn) { /* dynamic memory mode */
|
|
- size = ndctl_pfn_get_size(pfn);
|
|
- loc = ndctl_pfn_get_location(pfn);
|
|
- } else { /* native/static memory mode */
|
|
- size = ndctl_namespace_get_size(ndns);
|
|
- loc = NDCTL_PFN_LOC_RAM;
|
|
- }
|
|
- jobj = json_object_new_string("fsdax");
|
|
- break;
|
|
- case NDCTL_NS_MODE_DAX:
|
|
- if (!dax)
|
|
- goto err;
|
|
- size = ndctl_dax_get_size(dax);
|
|
- jobj = json_object_new_string("devdax");
|
|
- loc = ndctl_dax_get_location(dax);
|
|
- break;
|
|
- case NDCTL_NS_MODE_SECTOR:
|
|
- if (!btt)
|
|
- goto err;
|
|
- jobj = json_object_new_string("sector");
|
|
- size = ndctl_btt_get_size(btt);
|
|
- break;
|
|
- case NDCTL_NS_MODE_RAW:
|
|
- size = ndctl_namespace_get_size(ndns);
|
|
- jobj = json_object_new_string("raw");
|
|
- break;
|
|
- default:
|
|
- jobj = NULL;
|
|
- }
|
|
- if (jobj)
|
|
- json_object_object_add(jndns, "mode", jobj);
|
|
-
|
|
- if ((mode != NDCTL_NS_MODE_SECTOR) && (mode != NDCTL_NS_MODE_RAW)) {
|
|
- jobj = json_object_new_string(locations[loc]);
|
|
- if (jobj)
|
|
- json_object_object_add(jndns, "map", jobj);
|
|
- }
|
|
-
|
|
- if (size < ULLONG_MAX) {
|
|
- jobj = util_json_object_size(size, flags);
|
|
- if (jobj)
|
|
- json_object_object_add(jndns, "size", jobj);
|
|
- }
|
|
-
|
|
- if (btt) {
|
|
- ndctl_btt_get_uuid(btt, uuid);
|
|
- uuid_unparse(uuid, buf);
|
|
- jobj = json_object_new_string(buf);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jndns, "uuid", jobj);
|
|
- util_raw_uuid_to_json(ndns, flags, jndns);
|
|
- bdev = ndctl_btt_get_block_device(btt);
|
|
- } else if (pfn) {
|
|
- align = ndctl_pfn_get_align(pfn);
|
|
- ndctl_pfn_get_uuid(pfn, uuid);
|
|
- uuid_unparse(uuid, buf);
|
|
- jobj = json_object_new_string(buf);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jndns, "uuid", jobj);
|
|
- util_raw_uuid_to_json(ndns, flags, jndns);
|
|
- bdev = ndctl_pfn_get_block_device(pfn);
|
|
- } else if (dax) {
|
|
- struct daxctl_region *dax_region;
|
|
-
|
|
- dax_region = ndctl_dax_get_daxctl_region(dax);
|
|
- align = ndctl_dax_get_align(dax);
|
|
- ndctl_dax_get_uuid(dax, uuid);
|
|
- uuid_unparse(uuid, buf);
|
|
- jobj = json_object_new_string(buf);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jndns, "uuid", jobj);
|
|
- util_raw_uuid_to_json(ndns, flags, jndns);
|
|
- if ((flags & UTIL_JSON_DAX) && dax_region) {
|
|
- jobj = util_daxctl_region_to_json(dax_region, NULL,
|
|
- flags);
|
|
- if (jobj)
|
|
- json_object_object_add(jndns, "daxregion", jobj);
|
|
- } else if (dax_region) {
|
|
- struct daxctl_dev *dev;
|
|
-
|
|
- /*
|
|
- * We can only find/list these device-dax
|
|
- * details when the instance is enabled.
|
|
- */
|
|
- dev = daxctl_dev_get_first(dax_region);
|
|
- if (dev) {
|
|
- name = daxctl_dev_get_devname(dev);
|
|
- jobj = json_object_new_string(name);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jndns, "chardev", jobj);
|
|
- }
|
|
- }
|
|
- } else if (ndctl_namespace_get_type(ndns) != ND_DEVICE_NAMESPACE_IO) {
|
|
- ndctl_namespace_get_uuid(ndns, uuid);
|
|
- uuid_unparse(uuid, buf);
|
|
- jobj = json_object_new_string(buf);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jndns, "uuid", jobj);
|
|
- bdev = ndctl_namespace_get_block_device(ndns);
|
|
- } else
|
|
- bdev = ndctl_namespace_get_block_device(ndns);
|
|
-
|
|
- if (btt)
|
|
- sector_size = ndctl_btt_get_sector_size(btt);
|
|
- else if (!dax) {
|
|
- sector_size = ndctl_namespace_get_sector_size(ndns);
|
|
- if (!sector_size || sector_size == UINT_MAX)
|
|
- sector_size = 512;
|
|
- }
|
|
-
|
|
- /*
|
|
- * The kernel will default to a 512 byte sector size on PMEM
|
|
- * namespaces that don't explicitly have a sector size. This
|
|
- * happens because they use pre-v1.2 labels or because they
|
|
- * don't have a label space (devtype=nd_namespace_io).
|
|
- */
|
|
- if (sector_size < UINT_MAX) {
|
|
- jobj = json_object_new_int(sector_size);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jndns, "sector_size", jobj);
|
|
- }
|
|
-
|
|
- if (align) {
|
|
- jobj = json_object_new_int64(align);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jndns, "align", jobj);
|
|
- }
|
|
-
|
|
- if (bdev && bdev[0]) {
|
|
- jobj = json_object_new_string(bdev);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jndns, "blockdev", jobj);
|
|
- }
|
|
-
|
|
- if (!ndctl_namespace_is_active(ndns)) {
|
|
- jobj = json_object_new_string("disabled");
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jndns, "state", jobj);
|
|
- }
|
|
-
|
|
- name = ndctl_namespace_get_alt_name(ndns);
|
|
- if (name && name[0]) {
|
|
- jobj = json_object_new_string(name);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jndns, "name", jobj);
|
|
- }
|
|
-
|
|
- numa = ndctl_namespace_get_numa_node(ndns);
|
|
- if (numa >= 0 && flags & UTIL_JSON_VERBOSE) {
|
|
- jobj = json_object_new_int(numa);
|
|
- if (jobj)
|
|
- json_object_object_add(jndns, "numa_node", jobj);
|
|
- }
|
|
-
|
|
- target = ndctl_namespace_get_target_node(ndns);
|
|
- if (target >= 0 && flags & UTIL_JSON_VERBOSE) {
|
|
- jobj = json_object_new_int(target);
|
|
- if (jobj)
|
|
- json_object_object_add(jndns, "target_node", jobj);
|
|
- }
|
|
-
|
|
- if (pfn)
|
|
- jbbs = util_pfn_badblocks_to_json(pfn, &bb_count, flags);
|
|
- else if (dax)
|
|
- jbbs = util_dax_badblocks_to_json(dax, &bb_count, flags);
|
|
- else if (btt)
|
|
- util_btt_badblocks_to_json(btt, &bb_count);
|
|
- else {
|
|
- jbbs = util_region_badblocks_to_json(
|
|
- ndctl_namespace_get_region(ndns), &bb_count,
|
|
- flags);
|
|
- if (!jbbs)
|
|
- jbbs = util_namespace_badblocks_to_json(ndns, &bb_count,
|
|
- flags);
|
|
- }
|
|
-
|
|
- if (bb_count) {
|
|
- jobj = json_object_new_int(bb_count);
|
|
- if (!jobj) {
|
|
- json_object_put(jbbs);
|
|
- goto err;
|
|
- }
|
|
- json_object_object_add(jndns, "badblock_count", jobj);
|
|
- }
|
|
-
|
|
- if ((flags & UTIL_JSON_MEDIA_ERRORS) && jbbs)
|
|
- json_object_object_add(jndns, "badblocks", jbbs);
|
|
-
|
|
- return jndns;
|
|
- err:
|
|
- json_object_put(jndns);
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-struct json_object *util_mapping_to_json(struct ndctl_mapping *mapping,
|
|
- unsigned long flags)
|
|
-{
|
|
- struct json_object *jmapping = json_object_new_object();
|
|
- struct ndctl_dimm *dimm = ndctl_mapping_get_dimm(mapping);
|
|
- struct json_object *jobj;
|
|
- int position;
|
|
-
|
|
- if (!jmapping)
|
|
- return NULL;
|
|
-
|
|
- jobj = json_object_new_string(ndctl_dimm_get_devname(dimm));
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jmapping, "dimm", jobj);
|
|
-
|
|
- jobj = util_json_object_hex(ndctl_mapping_get_offset(mapping), flags);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jmapping, "offset", jobj);
|
|
-
|
|
- jobj = util_json_object_hex(ndctl_mapping_get_length(mapping), flags);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jmapping, "length", jobj);
|
|
-
|
|
- position = ndctl_mapping_get_position(mapping);
|
|
- if (position >= 0) {
|
|
- jobj = json_object_new_int(position);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jmapping, "position", jobj);
|
|
- }
|
|
-
|
|
- return jmapping;
|
|
- err:
|
|
- json_object_put(jmapping);
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-struct json_object *util_daxctl_mapping_to_json(struct daxctl_mapping *mapping,
|
|
- unsigned long flags)
|
|
-{
|
|
- struct json_object *jmapping = json_object_new_object();
|
|
- struct json_object *jobj;
|
|
-
|
|
- if (!jmapping)
|
|
- return NULL;
|
|
-
|
|
- jobj = util_json_object_hex(daxctl_mapping_get_offset(mapping), flags);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jmapping, "page_offset", jobj);
|
|
-
|
|
- jobj = util_json_object_hex(daxctl_mapping_get_start(mapping), flags);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jmapping, "start", jobj);
|
|
-
|
|
- jobj = util_json_object_hex(daxctl_mapping_get_end(mapping), flags);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jmapping, "end", jobj);
|
|
-
|
|
- jobj = util_json_object_size(daxctl_mapping_get_size(mapping), flags);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jmapping, "size", jobj);
|
|
-
|
|
- return jmapping;
|
|
- err:
|
|
- json_object_put(jmapping);
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-struct json_object *util_badblock_rec_to_json(u64 block, u64 count,
|
|
- unsigned long flags)
|
|
-{
|
|
- struct json_object *jerr = json_object_new_object();
|
|
- struct json_object *jobj;
|
|
-
|
|
- if (!jerr)
|
|
- return NULL;
|
|
-
|
|
- jobj = util_json_object_hex(block, flags);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jerr, "block", jobj);
|
|
-
|
|
- jobj = util_json_object_hex(count, flags);
|
|
- if (!jobj)
|
|
- goto err;
|
|
- json_object_object_add(jerr, "count", jobj);
|
|
-
|
|
- return jerr;
|
|
- err:
|
|
- json_object_put(jerr);
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-static struct json_object *util_cxl_memdev_health_to_json(
|
|
- struct cxl_memdev *memdev, unsigned long flags)
|
|
-{
|
|
- struct json_object *jhealth;
|
|
- struct json_object *jobj;
|
|
- struct cxl_cmd *cmd;
|
|
- u32 field;
|
|
- int rc;
|
|
-
|
|
- jhealth = json_object_new_object();
|
|
- if (!jhealth)
|
|
- return NULL;
|
|
- if (!memdev)
|
|
- goto err_jobj;
|
|
-
|
|
- cmd = cxl_cmd_new_get_health_info(memdev);
|
|
- if (!cmd)
|
|
- goto err_jobj;
|
|
-
|
|
- rc = cxl_cmd_submit(cmd);
|
|
- if (rc < 0)
|
|
- goto err_cmd;
|
|
- rc = cxl_cmd_get_mbox_status(cmd);
|
|
- if (rc != 0)
|
|
- goto err_cmd;
|
|
-
|
|
- /* health_status fields */
|
|
- rc = cxl_cmd_health_info_get_maintenance_needed(cmd);
|
|
- jobj = json_object_new_boolean(rc);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "maintenance_needed", jobj);
|
|
-
|
|
- rc = cxl_cmd_health_info_get_performance_degraded(cmd);
|
|
- jobj = json_object_new_boolean(rc);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "performance_degraded", jobj);
|
|
-
|
|
- rc = cxl_cmd_health_info_get_hw_replacement_needed(cmd);
|
|
- jobj = json_object_new_boolean(rc);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "hw_replacement_needed", jobj);
|
|
-
|
|
- /* media_status fields */
|
|
- rc = cxl_cmd_health_info_get_media_normal(cmd);
|
|
- jobj = json_object_new_boolean(rc);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "media_normal", jobj);
|
|
-
|
|
- rc = cxl_cmd_health_info_get_media_not_ready(cmd);
|
|
- jobj = json_object_new_boolean(rc);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "media_not_ready", jobj);
|
|
-
|
|
- rc = cxl_cmd_health_info_get_media_persistence_lost(cmd);
|
|
- jobj = json_object_new_boolean(rc);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "media_persistence_lost", jobj);
|
|
-
|
|
- rc = cxl_cmd_health_info_get_media_data_lost(cmd);
|
|
- jobj = json_object_new_boolean(rc);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "media_data_lost", jobj);
|
|
-
|
|
- rc = cxl_cmd_health_info_get_media_powerloss_persistence_loss(cmd);
|
|
- jobj = json_object_new_boolean(rc);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "media_powerloss_persistence_loss", jobj);
|
|
-
|
|
- rc = cxl_cmd_health_info_get_media_shutdown_persistence_loss(cmd);
|
|
- jobj = json_object_new_boolean(rc);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "media_shutdown_persistence_loss", jobj);
|
|
-
|
|
- rc = cxl_cmd_health_info_get_media_persistence_loss_imminent(cmd);
|
|
- jobj = json_object_new_boolean(rc);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "media_persistence_loss_imminent", jobj);
|
|
-
|
|
- rc = cxl_cmd_health_info_get_media_powerloss_data_loss(cmd);
|
|
- jobj = json_object_new_boolean(rc);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "media_powerloss_data_loss", jobj);
|
|
-
|
|
- rc = cxl_cmd_health_info_get_media_shutdown_data_loss(cmd);
|
|
- jobj = json_object_new_boolean(rc);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "media_shutdown_data_loss", jobj);
|
|
-
|
|
- rc = cxl_cmd_health_info_get_media_data_loss_imminent(cmd);
|
|
- jobj = json_object_new_boolean(rc);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "media_data_loss_imminent", jobj);
|
|
-
|
|
- /* ext_status fields */
|
|
- if (cxl_cmd_health_info_get_ext_life_used_normal(cmd))
|
|
- jobj = json_object_new_string("normal");
|
|
- else if (cxl_cmd_health_info_get_ext_life_used_warning(cmd))
|
|
- jobj = json_object_new_string("warning");
|
|
- else if (cxl_cmd_health_info_get_ext_life_used_critical(cmd))
|
|
- jobj = json_object_new_string("critical");
|
|
- else
|
|
- jobj = json_object_new_string("unknown");
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "ext_life_used", jobj);
|
|
-
|
|
- if (cxl_cmd_health_info_get_ext_temperature_normal(cmd))
|
|
- jobj = json_object_new_string("normal");
|
|
- else if (cxl_cmd_health_info_get_ext_temperature_warning(cmd))
|
|
- jobj = json_object_new_string("warning");
|
|
- else if (cxl_cmd_health_info_get_ext_temperature_critical(cmd))
|
|
- jobj = json_object_new_string("critical");
|
|
- else
|
|
- jobj = json_object_new_string("unknown");
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "ext_temperature", jobj);
|
|
-
|
|
- if (cxl_cmd_health_info_get_ext_corrected_volatile_normal(cmd))
|
|
- jobj = json_object_new_string("normal");
|
|
- else if (cxl_cmd_health_info_get_ext_corrected_volatile_warning(cmd))
|
|
- jobj = json_object_new_string("warning");
|
|
- else
|
|
- jobj = json_object_new_string("unknown");
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "ext_corrected_volatile", jobj);
|
|
-
|
|
- if (cxl_cmd_health_info_get_ext_corrected_persistent_normal(cmd))
|
|
- jobj = json_object_new_string("normal");
|
|
- else if (cxl_cmd_health_info_get_ext_corrected_persistent_warning(cmd))
|
|
- jobj = json_object_new_string("warning");
|
|
- else
|
|
- jobj = json_object_new_string("unknown");
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "ext_corrected_persistent", jobj);
|
|
-
|
|
- /* other fields */
|
|
- field = cxl_cmd_health_info_get_life_used(cmd);
|
|
- if (field != 0xff) {
|
|
- jobj = json_object_new_int(field);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "life_used_percent", jobj);
|
|
- }
|
|
-
|
|
- field = cxl_cmd_health_info_get_temperature(cmd);
|
|
- if (field != 0xffff) {
|
|
- jobj = json_object_new_int(field);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "temperature", jobj);
|
|
- }
|
|
-
|
|
- field = cxl_cmd_health_info_get_dirty_shutdowns(cmd);
|
|
- jobj = json_object_new_int64(field);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "dirty_shutdowns", jobj);
|
|
-
|
|
- field = cxl_cmd_health_info_get_volatile_errors(cmd);
|
|
- jobj = json_object_new_int64(field);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "volatile_errors", jobj);
|
|
-
|
|
- field = cxl_cmd_health_info_get_pmem_errors(cmd);
|
|
- jobj = json_object_new_int64(field);
|
|
- if (jobj)
|
|
- json_object_object_add(jhealth, "pmem_errors", jobj);
|
|
-
|
|
- cxl_cmd_unref(cmd);
|
|
- return jhealth;
|
|
-
|
|
-err_cmd:
|
|
- cxl_cmd_unref(cmd);
|
|
-err_jobj:
|
|
- json_object_put(jhealth);
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
|
|
- unsigned long flags)
|
|
-{
|
|
- const char *devname = cxl_memdev_get_devname(memdev);
|
|
- struct json_object *jdev, *jobj;
|
|
-
|
|
- jdev = json_object_new_object();
|
|
- if (!devname || !jdev)
|
|
- return NULL;
|
|
-
|
|
- jobj = json_object_new_string(devname);
|
|
- if (jobj)
|
|
- json_object_object_add(jdev, "memdev", jobj);
|
|
-
|
|
- jobj = util_json_object_size(cxl_memdev_get_pmem_size(memdev), flags);
|
|
- if (jobj)
|
|
- json_object_object_add(jdev, "pmem_size", jobj);
|
|
-
|
|
- jobj = util_json_object_size(cxl_memdev_get_ram_size(memdev), flags);
|
|
- if (jobj)
|
|
- json_object_object_add(jdev, "ram_size", jobj);
|
|
-
|
|
- if (flags & UTIL_JSON_HEALTH) {
|
|
- jobj = util_cxl_memdev_health_to_json(memdev, flags);
|
|
- if (jobj)
|
|
- json_object_object_add(jdev, "health", jobj);
|
|
- }
|
|
- return jdev;
|
|
-}
|
|
diff -up ndctl-71.1/util/json.h.orig ndctl-71.1/util/json.h
|
|
--- ndctl-71.1/util/json.h.orig 2022-10-07 15:50:40.097454638 -0400
|
|
+++ ndctl-71.1/util/json.h 2022-10-07 15:51:03.927535772 -0400
|
|
@@ -1,12 +1,9 @@
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */
|
|
-#ifndef __NDCTL_JSON_H__
|
|
-#define __NDCTL_JSON_H__
|
|
+#ifndef __UTIL_JSON_H__
|
|
+#define __UTIL_JSON_H__
|
|
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
-#include <ndctl/libndctl.h>
|
|
-#include <daxctl/libdaxctl.h>
|
|
-#include <ccan/short_types/short_types.h>
|
|
|
|
enum util_json_flags {
|
|
UTIL_JSON_IDLE = (1 << 0),
|
|
@@ -25,38 +22,8 @@ enum util_json_flags {
|
|
struct json_object;
|
|
void util_display_json_array(FILE *f_out, struct json_object *jarray,
|
|
unsigned long flags);
|
|
-struct json_object *util_bus_to_json(struct ndctl_bus *bus,
|
|
- unsigned long flags);
|
|
-struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm,
|
|
- unsigned long flags);
|
|
-struct json_object *util_mapping_to_json(struct ndctl_mapping *mapping,
|
|
- unsigned long flags);
|
|
-struct json_object *util_daxctl_mapping_to_json(struct daxctl_mapping *mapping,
|
|
- unsigned long flags);
|
|
-struct json_object *util_namespace_to_json(struct ndctl_namespace *ndns,
|
|
- unsigned long flags);
|
|
-struct json_object *util_badblock_rec_to_json(u64 block, u64 count,
|
|
- unsigned long flags);
|
|
-struct daxctl_region;
|
|
-struct daxctl_dev;
|
|
-struct json_object *util_region_badblocks_to_json(struct ndctl_region *region,
|
|
- unsigned int *bb_count, unsigned long flags);
|
|
-struct json_object *util_daxctl_region_to_json(struct daxctl_region *region,
|
|
- const char *ident, unsigned long flags);
|
|
-struct json_object *util_daxctl_dev_to_json(struct daxctl_dev *dev,
|
|
- unsigned long flags);
|
|
-struct json_object *util_daxctl_devs_to_list(struct daxctl_region *region,
|
|
- struct json_object *jdevs, const char *ident,
|
|
- unsigned long flags);
|
|
struct json_object *util_json_object_size(unsigned long long size,
|
|
unsigned long flags);
|
|
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_firmware_to_json(struct ndctl_dimm *dimm,
|
|
- unsigned long flags);
|
|
-struct json_object *util_region_capabilities_to_json(struct ndctl_region *region);
|
|
-struct cxl_memdev;
|
|
-struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
|
|
- unsigned long flags);
|
|
-#endif /* __NDCTL_JSON_H__ */
|
|
+#endif /* __UTIL_JSON_H__ */
|