From patchwork Thu Jan 28 22:52:45 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 8154861 Return-Path: X-Original-To: patchwork-linux-nvdimm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 421379F38B for ; Thu, 28 Jan 2016 22:53:14 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8F895202FE for ; Thu, 28 Jan 2016 22:53:12 +0000 (UTC) Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id DA12720256 for ; Thu, 28 Jan 2016 22:53:10 +0000 (UTC) Received: from ml01.vlan14.01.org (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id CA2861A1E13; Thu, 28 Jan 2016 14:53:10 -0800 (PST) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by ml01.01.org (Postfix) with ESMTP id 0050D1A1DD1 for ; Thu, 28 Jan 2016 14:53:09 -0800 (PST) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga101.fm.intel.com with ESMTP; 28 Jan 2016 14:53:09 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.22,360,1449561600"; d="scan'208";a="903421928" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.136]) by fmsmga002.fm.intel.com with ESMTP; 28 Jan 2016 14:53:10 -0800 Subject: [ndctl PATCH 09/13] ndctl: 'list' command From: Dan Williams To: linux-nvdimm@lists.01.org Date: Thu, 28 Jan 2016 14:52:45 -0800 Message-ID: <20160128225245.17855.47023.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <20160128225157.17855.5190.stgit@dwillia2-desk3.amr.corp.intel.com> References: <20160128225157.17855.5190.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.17.1-9-g687f MIME-Version: 1.0 X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Dump the nvdimm device topology (buses, dimms, regions, namespaces) and related attributes in json format. Signed-off-by: Dan Williams --- Documentation/Makefile.am | 3 Documentation/ndctl-list.txt | 86 ++++++++++ Makefile.am | 7 + builtin-list.c | 367 ++++++++++++++++++++++++++++++++++++++++++ builtin.h | 1 configure.ac | 1 contrib/ndctl.spec.in | 1 ndctl.c | 1 util/json.c | 208 ++++++++++++++++++++++++ util/json.h | 11 + 10 files changed, 683 insertions(+), 3 deletions(-) create mode 100644 Documentation/ndctl-list.txt create mode 100644 builtin-list.c create mode 100644 util/json.c create mode 100644 util/json.h diff --git a/Documentation/Makefile.am b/Documentation/Makefile.am index 51d186505b44..a168cec100c8 100644 --- a/Documentation/Makefile.am +++ b/Documentation/Makefile.am @@ -5,7 +5,8 @@ man1_MANS = \ ndctl-disable-region.1 \ ndctl-enable-namespace.1 \ ndctl-disable-namespace.1 \ - ndctl-create-namespace.1 + ndctl-create-namespace.1 \ + ndctl-list.1 XML_DEPS = \ $(top_srcdir)/version.m4 \ diff --git a/Documentation/ndctl-list.txt b/Documentation/ndctl-list.txt new file mode 100644 index 000000000000..53847c56236e --- /dev/null +++ b/Documentation/ndctl-list.txt @@ -0,0 +1,86 @@ +ndctl-list(1) +============= + +NAME +---- +ndctl-list - dump the platform nvdimm device topology in json + +SYNOPSIS +-------- +[verse] +'ndctl list' [] + +Walk all the nvdimm buses in the system and list all attached devices +along with some of their major attributes. + +Options can be specified to limit the output to devices of a certain +class. Where the classes are buses, dimms, regions, and namespaces. By +default, 'ndctl list' with no options is equivalent to: +[verse] +ndctl list --namespaces --bus=all --region=all + +EXAMPLE +------- +[verse] +# ndctl list --buses --namespaces + +["literal"] +{ + "provider":"nfit_test.1", + "dev":"ndbus2", + "namespaces":[ + { + "dev":"namespace9.0", + "mode":"raw", + "size":33554432, + "blockdev":"pmem9" + } + ] +} +{ + "provider":"nfit_test.0", + "dev":"ndbus1" +} +{ + "provider":"e820", + "dev":"ndbus0", + "namespaces":[ + { + "dev":"namespace0.0", + "mode":"memory", + "size":8589934592, + "blockdev":"pmem0" + } + ] +} + +OPTIONS +------- +-r:: +--region=:: +include::xable-region-options.txt[] + +-B:: +--buses:: + Include bus info in the listing + +-D:: +--dimms:: + Include dimm info in the listing + +-R:: +--regions:: + Include region info in the listing + +-N:: +--namespaces:: + Include namespace info in the listing. Namespace info is + included by default, specify '--no-namespaces' to omit. + +-i:: +--idle:: + Include idle (not enabled) devices in the listing + +SEE ALSO +-------- +linkndctl:ndctl-create-namespace[1] diff --git a/Makefile.am b/Makefile.am index 28437488ab93..63e7301e99b8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,7 +15,8 @@ AM_CPPFLAGS = \ -I${top_srcdir}/ \ $(KMOD_CFLAGS) \ $(UDEV_CFLAGS) \ - $(UUID_CFLAGS) + $(UUID_CFLAGS) \ + $(JSON_CFLAGS) AM_CFLAGS = ${my_CFLAGS} \ -fvisibility=hidden \ @@ -66,12 +67,14 @@ ndctl_SOURCES = ndctl.c \ builtin-create-nfit.c \ builtin-xaction-namespace.c \ builtin-xable-region.c \ + builtin-list.c \ builtin-test.c \ builtin-help.c \ builtin-zero-labels.c \ util/parse-options.c \ util/parse-options.h \ util/usage.c \ + util/json.c \ util/size.c \ util/strbuf.c \ util/wrapper.c \ @@ -91,7 +94,7 @@ ndctl_SOURCES += test/blk_namespaces.c \ ndctl_SOURCES += builtin-bat.c endif -ndctl_LDADD = lib/libndctl.la $(UUID_LIBS) $(KMOD_LIBS) +ndctl_LDADD = lib/libndctl.la $(UUID_LIBS) $(KMOD_LIBS) $(JSON_LIBS) noinst_LIBRARIES = libccan.a libccan_a_SOURCES = \ diff --git a/builtin-list.c b/builtin-list.c new file mode 100644 index 000000000000..12a6d32b124a --- /dev/null +++ b/builtin-list.c @@ -0,0 +1,367 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_NDCTL_H +#include +#else +#include +#endif + +static struct { + bool buses; + bool dimms; + bool regions; + bool namespaces; + bool idle; +} list = { + .namespaces = true, +}; + +static struct { + const char *bus; + const char *region; +} param; + +static int did_fail; +static int jflag = JSON_C_TO_STRING_PRETTY; + +#define fail(fmt, ...) \ +do { \ + did_fail = 1; \ + fprintf(stderr, "ndctl-%s:%s:%d: " fmt, \ + VERSION, __func__, __LINE__, ##__VA_ARGS__); \ +} while (0) + +static struct json_object *list_namespaces(struct ndctl_region *region, + struct json_object *container, struct json_object *jnamespaces, + bool continue_array) +{ + struct ndctl_namespace *ndns; + + ndctl_namespace_foreach(region, ndns) { + struct json_object *jndns; + + /* are we emitting namespaces? */ + if (!list.namespaces) + break; + + if (!list.idle && !util_namespace_active(ndns)) + continue; + + if (!jnamespaces) { + jnamespaces = json_object_new_array(); + if (!jnamespaces) { + fail("\n"); + continue; + } + + if (container) + json_object_object_add(container, "namespaces", + jnamespaces); + } + + jndns = util_namespace_to_json(ndns); + if (!jndns) { + fail("\n"); + continue; + } + + json_object_array_add(jnamespaces, jndns); + } + + /* + * We we are collecting namespaces anonymously across the + * platform / bus + */ + if (continue_array) + return jnamespaces; + return NULL; +} + +static struct json_object *region_to_json(struct ndctl_region *region) +{ + struct json_object *jregion = json_object_new_object(); + struct json_object *jobj, *jmappings = NULL; + struct ndctl_interleave_set *iset; + struct ndctl_mapping *mapping; + + if (!jregion) + return NULL; + + jobj = json_object_new_string(ndctl_region_get_devname(region)); + if (!jobj) + goto err; + json_object_object_add(jregion, "dev", jobj); + + jobj = json_object_new_int64(ndctl_region_get_size(region)); + if (!jobj) + goto err; + json_object_object_add(jregion, "size", jobj); + + jobj = json_object_new_int64(ndctl_region_get_available_size(region)); + if (!jobj) + goto err; + json_object_object_add(jregion, "available_size", jobj); + + switch (ndctl_region_get_type(region)) { + case ND_DEVICE_REGION_PMEM: + jobj = json_object_new_string("pmem"); + break; + case ND_DEVICE_REGION_BLK: + jobj = json_object_new_string("blk"); + break; + default: + jobj = NULL; + } + if (!jobj) + goto err; + json_object_object_add(jregion, "type", jobj); + + iset = ndctl_region_get_interleave_set(region); + if (iset) { + jobj = json_object_new_int64( + ndctl_interleave_set_get_cookie(iset)); + if (!jobj) + fail("\n"); + else + json_object_object_add(jregion, "iset_id", jobj); + } + + ndctl_mapping_foreach(region, mapping) { + struct ndctl_dimm *dimm = ndctl_mapping_get_dimm(mapping); + struct json_object *jmapping; + + if (!list.dimms) + break; + + if (!list.idle && !ndctl_dimm_is_enabled(dimm)) + continue; + + if (!jmappings) { + jmappings = json_object_new_array(); + if (!jmappings) { + fail("\n"); + continue; + } + json_object_object_add(jregion, "mappings", jmappings); + } + + jmapping = util_mapping_to_json(mapping); + if (!jmapping) { + fail("\n"); + continue; + } + json_object_array_add(jmappings, jmapping); + } + + if (!ndctl_region_is_enabled(region)) { + jobj = json_object_new_string("disabled"); + if (!jobj) + goto err; + json_object_object_add(jregion, "state", jobj); + } + + list_namespaces(region, jregion, NULL, false); + return jregion; + err: + fail("\n"); + json_object_put(jregion); + return NULL; +} + +static void display_array(struct json_object *jarray) +{ + if (json_object_array_length(jarray) > 1) + printf("%s\n", json_object_to_json_string_ext(jarray, jflag)); + else { + struct json_object *jobj; + + jobj = json_object_array_get_idx(jarray, 0); + printf("%s\n", json_object_to_json_string_ext(jobj, jflag)); + } + json_object_put(jarray); +} + +int cmd_list(int argc, const char **argv) +{ + const struct option options[] = { + OPT_STRING('b', "bus", ¶m.bus, "bus-id", "filter by bus"), + OPT_STRING('r', "region", ¶m.region, "region-id", + "filter by region"), + OPT_BOOLEAN('B', "buses", &list.buses, "include bus info"), + OPT_BOOLEAN('D', "dimms", &list.dimms, "include dimm info"), + OPT_BOOLEAN('R', "regions", &list.regions, + "include region info"), + OPT_BOOLEAN('N', "namespaces", &list.namespaces, + "include namespace info (default)"), + OPT_BOOLEAN('i', "idle", &list.idle, "include idle devices"), + OPT_END(), + }; + const char * const u[] = { + "ndctl list []", + NULL + }; + struct json_object *jnamespaces = NULL; + struct json_object *jregions = NULL; + struct json_object *jdimms = NULL; + struct json_object *jbuses = NULL; + struct ndctl_ctx *ctx; + struct ndctl_bus *bus; + int i, rc; + + argc = parse_options(argc, argv, options, u, 0); + for (i = 0; i < argc; i++) + error("unknown parameter \"%s\"\n", argv[i]); + if (argc) + usage_with_options(u, options); + + rc = ndctl_new(&ctx); + if (rc < 0) + return rc; + + ndctl_bus_foreach(ctx, bus) { + struct json_object *jbus = NULL; + struct ndctl_region *region; + struct ndctl_dimm *dimm; + + if (!util_bus_filter(bus, param.bus)) + continue; + + if (list.buses) { + if (!jbuses) { + jbuses = json_object_new_array(); + if (!jbuses) { + fail("\n"); + continue; + } + } + + jbus = util_bus_to_json(bus); + if (!jbus) { + fail("\n"); + continue; + } + json_object_array_add(jbuses, jbus); + } + + ndctl_dimm_foreach(bus, dimm) { + struct json_object *jdimm; + + /* are we emitting dimms? */ + if (!list.dimms) + break; + + if (!list.idle && !ndctl_dimm_is_enabled(dimm)) + continue; + + if (!jdimms) { + jdimms = json_object_new_array(); + if (!jdimms) { + fail("\n"); + continue; + } + + if (jbus) + json_object_object_add(jbus, "dimms", jdimms); + } + + jdimm = util_dimm_to_json(dimm); + if (!jdimm) { + fail("\n"); + continue; + } + + /* + * Without a bus we are collecting dimms anonymously + * across the platform. + */ + json_object_array_add(jdimms, jdimm); + } + + ndctl_region_foreach(bus, region) { + struct json_object *jregion; + + if (!util_region_filter(region, param.region)) + continue; + + if (!list.regions) { + jnamespaces = list_namespaces(region, jbus, + jnamespaces, true); + continue; + } + + if (!list.idle && !ndctl_region_is_enabled(region)) + continue; + + if (!jregions) { + jregions = json_object_new_array(); + if (!jregions) { + fail("\n"); + continue; + } + + if (jbus) + json_object_object_add(jbus, "regions", + jregions); + } + + jregion = region_to_json(region); + if (!jregion) { + fail("\n"); + continue; + } + + /* + * Without a bus we are collecting regions anonymously + * across the platform. + */ + json_object_array_add(jregions, jregion); + } + + if (jbuses) { + jdimms = NULL; + jregions = NULL; + jnamespaces = NULL; + } + } + + if (jbuses) + display_array(jbuses); + else if ((!!jdimms + !!jregions + !!jnamespaces) > 1) { + struct json_object *jplatform = json_object_new_object(); + + if (!jplatform) { + fail("\n"); + return -ENOMEM; + } + + if (jdimms) + json_object_object_add(jplatform, "dimms", jdimms); + if (jregions) + json_object_object_add(jplatform, "regions", jregions); + if (jnamespaces) + json_object_object_add(jplatform, "namespaces", + jnamespaces); + printf("%s\n", json_object_to_json_string_ext(jplatform, + jflag)); + json_object_put(jplatform); + } else if (jdimms) + display_array(jdimms); + else if (jregions) + display_array(jregions); + else if (jnamespaces) + display_array(jnamespaces); + + if (did_fail) + return -ENOMEM; + return 0; +} diff --git a/builtin.h b/builtin.h index 27ff248a6d84..bec95556a524 100644 --- a/builtin.h +++ b/builtin.h @@ -16,6 +16,7 @@ int cmd_enable_region(int argc, const char **argv); int cmd_disable_region(int argc, const char **argv); int cmd_zero_labels(int argc, const char **argv); int cmd_help(int argc, const char **argv); +int cmd_list(int argc, const char **argv); #ifdef ENABLE_TEST int cmd_test(int argc, const char **argv); #endif diff --git a/configure.ac b/configure.ac index 5f25b56aca9a..3f61b6de250e 100644 --- a/configure.ac +++ b/configure.ac @@ -82,6 +82,7 @@ AM_CONDITIONAL([ENABLE_DESTRUCTIVE], [test "x$enable_destructive" = "xyes"]) PKG_CHECK_MODULES([KMOD], [libkmod]) PKG_CHECK_MODULES([UDEV], [libudev]) PKG_CHECK_MODULES([UUID], [uuid]) +PKG_CHECK_MODULES([JSON], [json-c]) AC_ARG_ENABLE([local], AS_HELP_STRING([--enable-local], [build with local ndctl.h @<:@default=system@:>@]), diff --git a/contrib/ndctl.spec.in b/contrib/ndctl.spec.in index bb224a13b151..9a1acd48760d 100644 --- a/contrib/ndctl.spec.in +++ b/contrib/ndctl.spec.in @@ -21,6 +21,7 @@ BuildRequires: pkgconfig BuildRequires: pkgconfig(libkmod) BuildRequires: pkgconfig(libudev) BuildRequires: pkgconfig(uuid) +BuildRequires: pkgconfig(json-c) %description Utility library for managing the "libnvdimm" subsystem. The "libnvdimm" diff --git a/ndctl.c b/ndctl.c index 0c117d7fbd2f..8fadc6b2e305 100644 --- a/ndctl.c +++ b/ndctl.c @@ -30,6 +30,7 @@ static struct cmd_struct commands[] = { { "enable-region", cmd_enable_region }, { "disable-region", cmd_disable_region }, { "zero-labels", cmd_zero_labels }, + { "list", cmd_list }, { "help", cmd_help }, #ifdef ENABLE_TEST { "test", cmd_test }, diff --git a/util/json.c b/util/json.c new file mode 100644 index 000000000000..b9a5e75164d8 --- /dev/null +++ b/util/json.c @@ -0,0 +1,208 @@ +#include +#include +#include +#include +#include + +#ifdef HAVE_NDCTL_H +#include +#else +#include +#endif + +struct json_object *util_bus_to_json(struct ndctl_bus *bus) +{ + struct json_object *jbus = json_object_new_object(); + struct json_object *jobj; + + 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); + + return jbus; + err: + json_object_put(jbus); + return NULL; +} + +struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm) +{ + struct json_object *jdimm = json_object_new_object(); + struct json_object *jobj; + + 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 (!ndctl_dimm_is_enabled(dimm)) { + jobj = json_object_new_string("disabled"); + if (!jobj) + goto err; + json_object_object_add(jdimm, "state", jobj); + } + + return jdimm; + err: + json_object_put(jdimm); + return NULL; +} + +bool util_namespace_active(struct ndctl_namespace *ndns) +{ + struct ndctl_btt *btt = ndctl_namespace_get_btt(ndns); + struct ndctl_pfn *pfn = ndctl_namespace_get_pfn(ndns); + + if ((btt && ndctl_btt_is_enabled(btt)) + || (pfn && ndctl_pfn_is_enabled(pfn)) + || (!btt && !pfn + && ndctl_namespace_is_enabled(ndns))) + return true; + return false; +} + +struct json_object *util_namespace_to_json(struct ndctl_namespace *ndns) +{ + struct json_object *jndns = json_object_new_object(); + struct json_object *jobj; + const char *bdev = NULL; + struct ndctl_btt *btt; + struct ndctl_pfn *pfn; + char buf[40]; + uuid_t uuid; + + 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); + + switch (ndctl_namespace_get_mode(ndns)) { + case NDCTL_NS_MODE_MEMORY: + jobj = json_object_new_string("memory"); + break; + case NDCTL_NS_MODE_SAFE: + jobj = json_object_new_string("sector"); + break; + case NDCTL_NS_MODE_RAW: + jobj = json_object_new_string("raw"); + break; + default: + jobj = NULL; + } + if (jobj) + json_object_object_add(jndns, "mode", jobj); + + jobj = json_object_new_int64(ndctl_namespace_get_size(ndns)); + if (!jobj) + goto err; + json_object_object_add(jndns, "size", jobj); + + btt = ndctl_namespace_get_btt(ndns); + pfn = ndctl_namespace_get_pfn(ndns); + 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); + + jobj = json_object_new_int(ndctl_btt_get_sector_size(btt)); + if (!jobj) + goto err; + json_object_object_add(jndns, "sector_size", jobj); + + bdev = ndctl_btt_get_block_device(btt); + } else if (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); + bdev = ndctl_pfn_get_block_device(pfn); + } else if (ndctl_namespace_get_type(ndns) != ND_DEVICE_NAMESPACE_IO) { + const char *name; + + 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); + + name = ndctl_namespace_get_alt_name(ndns); + if (name[0]) { + jobj = json_object_new_string(name); + if (!jobj) + goto err; + json_object_object_add(jndns, "name", jobj); + } + bdev = ndctl_namespace_get_block_device(ndns); + } else + bdev = ndctl_namespace_get_block_device(ndns); + + if (bdev && bdev[0]) { + jobj = json_object_new_string(bdev); + if (!jobj) + goto err; + json_object_object_add(jndns, "blockdev", jobj); + } + + if (!util_namespace_active(ndns)) { + jobj = json_object_new_string("disabled"); + if (!jobj) + goto err; + json_object_object_add(jndns, "state", jobj); + } + + return jndns; + err: + json_object_put(jndns); + return NULL; +} + +struct json_object *util_mapping_to_json(struct ndctl_mapping *mapping) +{ + struct json_object *jmapping = json_object_new_object(); + struct ndctl_dimm *dimm = ndctl_mapping_get_dimm(mapping); + struct json_object *jobj; + + 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 = json_object_new_int64(ndctl_mapping_get_offset(mapping)); + if (!jobj) + goto err; + json_object_object_add(jmapping, "offset", jobj); + + jobj = json_object_new_int64(ndctl_mapping_get_length(mapping)); + if (!jobj) + goto err; + json_object_object_add(jmapping, "length", jobj); + + return jmapping; + err: + json_object_put(jmapping); + return NULL; +} diff --git a/util/json.h b/util/json.h new file mode 100644 index 000000000000..653bbd9beef1 --- /dev/null +++ b/util/json.h @@ -0,0 +1,11 @@ +#ifndef __NDCTL_JSON_H__ +#define __NDCTL_JSON_H__ +#include +#include + +bool util_namespace_active(struct ndctl_namespace *ndns); +struct json_object *util_bus_to_json(struct ndctl_bus *bus); +struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm); +struct json_object *util_mapping_to_json(struct ndctl_mapping *mapping); +struct json_object *util_namespace_to_json(struct ndctl_namespace *ndns); +#endif /* __NDCTL_JSON_H__ */