* [ndctl PATCH v3 08/16] ndctl/test: Fix support for missing dax_pmem_compat module
From: Dan Williams @ 2022-01-05 21:32 UTC (permalink / raw)
To: vishal.l.verma; +Cc: nvdimm, linux-cxl
In-Reply-To: <164141829899.3990253.17547886681174580434.stgit@dwillia2-desk3.amr.corp.intel.com>
The kernel is moving to drop CONFIG_DEV_DAX_PMEM_COMPAT. Update
ndctl_test_init() to not error out if dax_pmem_compat is missing. It seems
that the original implementation of support for missing dax_pmem_compat was
broken, or since that time newer versions of kmod_module_new_from_name() no
longer fail when the module is missing.
Fixes: b7991dbc22f3 ("ndctl/test: Relax dax_pmem_compat requirement")
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
test/core.c | 25 +++++++++++--------------
1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/test/core.c b/test/core.c
index dc1405d75c49..5d1aa23723f1 100644
--- a/test/core.c
+++ b/test/core.c
@@ -120,7 +120,6 @@ int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
"nfit",
"device_dax",
"dax_pmem",
- "dax_pmem_core",
"dax_pmem_compat",
"libnvdimm",
"nd_btt",
@@ -180,29 +179,27 @@ int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
/*
* Skip device-dax bus-model modules on pre-v5.1
*/
- if ((strcmp(name, "dax_pmem_core") == 0
- || strcmp(name, "dax_pmem_compat") == 0)
- && !ndctl_test_attempt(test,
- KERNEL_VERSION(5, 1, 0)))
+ if ((strcmp(name, "dax_pmem_compat") == 0) &&
+ !ndctl_test_attempt(test, KERNEL_VERSION(5, 1, 0)))
continue;
retry:
rc = kmod_module_new_from_name(*ctx, name, mod);
-
- /*
- * dax_pmem_compat is not required, missing is ok,
- * present-but-production is not ok.
- */
- if (rc && strcmp(name, "dax_pmem_compat") == 0)
- continue;
-
if (rc) {
- log_err(&log_ctx, "%s.ko: missing\n", name);
+ log_err(&log_ctx, "failed to interrogate %s.ko\n",
+ name);
break;
}
path = kmod_module_get_path(*mod);
if (!path) {
+ /*
+ * dax_pmem_compat is not required, missing is
+ * ok, present-but-production is not ok.
+ */
+ if (strcmp(name, "dax_pmem_compat") == 0)
+ continue;
+
if (family != NVDIMM_FAMILY_INTEL &&
(strcmp(name, "nfit") == 0 ||
strcmp(name, "nd_e820") == 0))
^ permalink raw reply related
* [ndctl PATCH v3 07/16] ndctl: Deprecate BLK aperture support
From: Dan Williams @ 2022-01-05 21:32 UTC (permalink / raw)
To: vishal.l.verma; +Cc: nvdimm, linux-cxl
In-Reply-To: <164141829899.3990253.17547886681174580434.stgit@dwillia2-desk3.amr.corp.intel.com>
The kernel is dropping its BLK aperture support, so deprecate the same in
ndctl. The options will still be supported, and the library calls will not
be deleted in case code needs them to compile. However the documentation
and the tests for BLK mode can be removed.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
.gitignore | 4
Documentation/ndctl/labels-description.txt | 5
Documentation/ndctl/ndctl-create-namespace.txt | 29 +-
Documentation/ndctl/ndctl-init-labels.txt | 7
Documentation/ndctl/ndctl-list.txt | 4
Documentation/ndctl/region-description.txt | 10 -
README.md | 1
contrib/nfit_test_depmod.conf | 1
ndctl/Makefile.am | 6
ndctl/bat.c | 5
ndctl/test.c | 11 -
test.h | 3
test/Makefile.am | 31 --
test/blk-exhaust.sh | 30 --
test/blk_namespaces.c | 357 ------------------------
test/core.c | 1
test/create.sh | 13 -
test/dpa-alloc.c | 326 ----------------------
test/libndctl.c | 198 ++-----------
test/multi-pmem.c | 285 -------------------
test/parent-uuid.c | 254 -----------------
21 files changed, 51 insertions(+), 1530 deletions(-)
delete mode 100755 test/blk-exhaust.sh
delete mode 100644 test/blk_namespaces.c
delete mode 100644 test/dpa-alloc.c
delete mode 100644 test/multi-pmem.c
delete mode 100644 test/parent-uuid.c
diff --git a/.gitignore b/.gitignore
index 6468c7a91f06..6b19d90a12f1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,20 +42,16 @@ cscope*.out
tags
test/*.log
test/*.trs
-test/blk-ns
test/dax-dev
test/dax-errors
test/dax-pmd
test/daxdev-errors
test/device-dax
-test/dpa-alloc
test/dsm-fail
test/hugetlb
test/image
test/libndctl
test/mmap
-test/multi-pmem
-test/parent-uuid
test/pmem-ns
test/smart-listen
test/smart-notify
diff --git a/Documentation/ndctl/labels-description.txt b/Documentation/ndctl/labels-description.txt
index 6244a49a9d3f..a246edcd369b 100644
--- a/Documentation/ndctl/labels-description.txt
+++ b/Documentation/ndctl/labels-description.txt
@@ -3,6 +3,5 @@
DESCRIPTION
-----------
The namespace label area is a small persistent partition of capacity
-available on some NVDIMM devices. The label area is used to resolve
-aliasing between 'pmem' and 'blk' capacity by delineating namespace
-boundaries.
+available on some NVDIMM devices. The label area is used to provision
+one, or more, namespaces from regions.
diff --git a/Documentation/ndctl/ndctl-create-namespace.txt b/Documentation/ndctl/ndctl-create-namespace.txt
index 92a89dd71e82..afb085efc6e7 100644
--- a/Documentation/ndctl/ndctl-create-namespace.txt
+++ b/Documentation/ndctl/ndctl-create-namespace.txt
@@ -28,27 +28,17 @@ ndctl create-namespace -f -e namespace0.0 --mode=sector
OPTIONS
-------
--t::
---type=::
- Create a 'pmem' or 'blk' namespace (subject to available
- capacity). A pmem namespace supports the dax (direct access)
- capability to linkndctl:mmap[2] persistent memory directly into
- a process address space. A blk namespace access persistent
- memory through a block-window-aperture. Compared to pmem it
- supports a traditional storage error model (EIO on error rather
- than a cpu exception on a bad memory access), but it does not
- support dax.
-
-m::
--mode=::
- "raw": expose the namespace capacity directly with
- limitations. Neither a raw pmem namepace nor raw blk
- namespace support sector atomicity by default (see "sector"
- mode below). A raw pmem namespace may have limited to no dax
- support depending the kernel. In other words operations like
- direct-I/O targeting a dax buffer may fail for a pmem
- namespace in raw mode or indirect through a page-cache buffer.
- See "fsdax" and "devdax" mode for dax operation.
+ limitations. A raw pmem namepace namespace does not support
+ sector atomicity (see "sector" mode below). A raw pmem
+ namespace may have limited to no dax support depending the
+ kernel. In other words operations like direct-I/O targeting a
+ dax buffer may fail for a pmem namespace in raw mode or
+ indirect through a page-cache buffer. See "fsdax" and
+ "devdax" mode for dax operation.
+
- "sector": persistent memory, given that it is byte
addressable, does not support sector atomicity. The
@@ -206,8 +196,7 @@ OPTIONS
* NVDIMM does not support labels
* The NVDIMM supports labels, but the Label Index Block (see
- UEFI 2.7) is not present and there is no capacity aliasing
- between 'blk' and 'pmem' regions.
+ UEFI 2.7) is not present.
- In the latter case the configuration can be upgraded to
labelled operation by writing an index block on all DIMMs in a
diff --git a/Documentation/ndctl/ndctl-init-labels.txt b/Documentation/ndctl/ndctl-init-labels.txt
index 733ef0ebddfa..73685b3336b3 100644
--- a/Documentation/ndctl/ndctl-init-labels.txt
+++ b/Documentation/ndctl/ndctl-init-labels.txt
@@ -13,10 +13,9 @@ SYNOPSIS
'ndctl init-labels' <nmem0> [<nmem1>..<nmemN>] [<options>]
include::labels-description.txt[]
-By default, and in kernels prior to v4.10, the kernel only honors labels
-when a DIMM aliases PMEM and BLK capacity. Starting with v4.10 the
-kernel will honor labels for sub-dividing PMEM if all the DIMMs in an
-interleave set / region have a valid namespace index block.
+Starting with v4.10 the kernel will honor labels for sub-dividing PMEM
+if all the DIMMs in an interleave set / region have a valid namespace
+index block.
This command can be used to initialize the namespace index block if it
is missing or reinitialize it if it is damaged. Note that
diff --git a/Documentation/ndctl/ndctl-list.txt b/Documentation/ndctl/ndctl-list.txt
index b8d517d784b4..2922f10e06c7 100644
--- a/Documentation/ndctl/ndctl-list.txt
+++ b/Documentation/ndctl/ndctl-list.txt
@@ -82,10 +82,6 @@ include::xable-bus-options.txt[]
'X.Y'. Limit the namespace list to the single identified device
if present.
--t::
---type=::
- Filter listing by region type ('pmem' or 'blk')
-
-m::
--mode=::
Filter listing by the mode ('raw', 'fsdax', 'sector' or 'devdax')
diff --git a/Documentation/ndctl/region-description.txt b/Documentation/ndctl/region-description.txt
index c14416a3be69..ce268a015b83 100644
--- a/Documentation/ndctl/region-description.txt
+++ b/Documentation/ndctl/region-description.txt
@@ -2,9 +2,7 @@
DESCRIPTION
-----------
-A generic REGION device is registered for each PMEM range or
-BLK-aperture set. LIBNVDIMM provides a built-in driver for these REGION
-devices. This driver is responsible for reconciling the aliased DPA
-mappings across all regions, parsing the LABEL, if present, and then
-emitting NAMESPACE devices with the resolved/exclusive DPA-boundaries
-for the nd_pmem or nd_blk device driver to consume.
+A generic REGION device is registered for each PMEM range /
+interleave-set. LIBNVDIMM provides a built-in driver for these REGION
+devices. This driver is responsible for parsing namespace labels and
+instantiating PMEM namespaces for each coherent set of labels.
diff --git a/README.md b/README.md
index 89dfc8798603..6f36a6d9410c 100644
--- a/README.md
+++ b/README.md
@@ -110,7 +110,6 @@ override dax_pmem * extra
override dax_pmem_core * extra
override dax_pmem_compat * extra
override libnvdimm * extra
-override nd_blk * extra
override nd_btt * extra
override nd_e820 * extra
override nd_pmem * extra
diff --git a/contrib/nfit_test_depmod.conf b/contrib/nfit_test_depmod.conf
index 9f8498e58ff3..0e0574e03670 100644
--- a/contrib/nfit_test_depmod.conf
+++ b/contrib/nfit_test_depmod.conf
@@ -5,7 +5,6 @@ override dax_pmem * extra
override dax_pmem_core * extra
override dax_pmem_compat * extra
override libnvdimm * extra
-override nd_blk * extra
override nd_btt * extra
override nd_e820 * extra
override nd_pmem * extra
diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am
index 4e995108e96a..93b682e8b202 100644
--- a/ndctl/Makefile.am
+++ b/ndctl/Makefile.am
@@ -45,8 +45,7 @@ endif
EXTRA_DIST += keys.readme monitor.conf ndctl-monitor.service ndctl.conf
if ENABLE_DESTRUCTIVE
-ndctl_SOURCES += ../test/blk_namespaces.c \
- ../test/pmem_namespaces.c
+ndctl_SOURCES += ../test/pmem_namespaces.c
ndctl_SOURCES += bat.c
endif
@@ -67,9 +66,6 @@ if ENABLE_TEST
ndctl_SOURCES += ../test/libndctl.c \
../test/dsm-fail.c \
../util/sysfs.c \
- ../test/dpa-alloc.c \
- ../test/parent-uuid.c \
- ../test/multi-pmem.c \
../test/core.c \
test.c
endif
diff --git a/ndctl/bat.c b/ndctl/bat.c
index ef00a3ba3d0b..13e964dc17cf 100644
--- a/ndctl/bat.c
+++ b/ndctl/bat.c
@@ -41,11 +41,6 @@ int cmd_bat(int argc, const char **argv, struct ndctl_ctx *ctx)
return EXIT_FAILURE;
}
- rc = test_blk_namespaces(loglevel, test, ctx);
- fprintf(stderr, "test_blk_namespaces: %s\n", rc ? "FAIL" : "PASS");
- if (rc && rc != 77)
- return rc;
-
rc = test_pmem_namespaces(loglevel, test, ctx);
fprintf(stderr, "test_pmem_namespaces: %s\n", rc ? "FAIL" : "PASS");
return ndctl_test_result(test, rc);
diff --git a/ndctl/test.c b/ndctl/test.c
index 6a05d8d62e46..a0f5bc95ae1d 100644
--- a/ndctl/test.c
+++ b/ndctl/test.c
@@ -58,16 +58,5 @@ int cmd_test(int argc, const char **argv, struct ndctl_ctx *ctx)
if (rc && rc != 77)
return rc;
- rc = test_dpa_alloc(loglevel, test, ctx);
- fprintf(stderr, "test-dpa-alloc: %s\n", result(rc));
- if (rc && rc != 77)
- return rc;
-
- rc = test_parent_uuid(loglevel, test, ctx);
- fprintf(stderr, "test-parent-uuid: %s\n", result(rc));
-
- rc = test_multi_pmem(loglevel, test, ctx);
- fprintf(stderr, "test-multi-pmem: %s\n", result(rc));
-
return ndctl_test_result(test, rc);
}
diff --git a/test.h b/test.h
index 7de13fe33ea3..b2267e669911 100644
--- a/test.h
+++ b/test.h
@@ -26,7 +26,6 @@ int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
struct ndctl_ctx;
int test_parent_uuid(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
-int test_multi_pmem(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
int test_dax_directio(int dax_fd, unsigned long align, void *dax_addr, off_t offset);
int test_dax_remap(struct ndctl_test *test, int dax_fd, unsigned long align, void *dax_addr,
off_t offset, bool fsdax);
@@ -40,9 +39,7 @@ static inline int test_dax_poison(struct ndctl_test *test, int dax_fd,
return 0;
}
#endif
-int test_dpa_alloc(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
int test_dsm_fail(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
int test_libndctl(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
-int test_blk_namespaces(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
int test_pmem_namespaces(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
#endif /* __TEST_H__ */
diff --git a/test/Makefile.am b/test/Makefile.am
index c5b8764389ea..a5a54df4f260 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -3,9 +3,6 @@ include $(top_srcdir)/Makefile.am.in
TESTS =\
libndctl \
dsm-fail \
- dpa-alloc \
- parent-uuid \
- multi-pmem \
create.sh \
clear.sh \
pmem-errors.sh \
@@ -13,7 +10,6 @@ TESTS =\
multi-dax.sh \
btt-check.sh \
label-compat.sh \
- blk-exhaust.sh \
sector-mode.sh \
inject-error.sh \
btt-errors.sh \
@@ -35,9 +31,6 @@ EXTRA_DIST += $(TESTS) common \
check_PROGRAMS =\
libndctl \
dsm-fail \
- dpa-alloc \
- parent-uuid \
- multi-pmem \
dax-errors \
smart-notify \
smart-listen \
@@ -48,7 +41,6 @@ check_PROGRAMS =\
if ENABLE_DESTRUCTIVE
TESTS +=\
- blk-ns \
pmem-ns \
sub-section.sh \
dax-dev \
@@ -68,7 +60,6 @@ TESTS += security.sh
endif
check_PROGRAMS +=\
- blk-ns \
pmem-ns \
dax-dev \
dax-pmd \
@@ -108,18 +99,9 @@ ack_shutdown_count_set_SOURCES =\
ack_shutdown_count_set_LDADD = $(LIBNDCTL_LIB) $(KMOD_LIBS)
-blk_ns_SOURCES = blk_namespaces.c $(testcore)
-blk_ns_LDADD = $(LIBNDCTL_LIB) $(KMOD_LIBS) $(UUID_LIBS)
-
pmem_ns_SOURCES = pmem_namespaces.c $(testcore)
pmem_ns_LDADD = $(LIBNDCTL_LIB) $(KMOD_LIBS) $(UUID_LIBS)
-dpa_alloc_SOURCES = dpa-alloc.c $(testcore)
-dpa_alloc_LDADD = $(LIBNDCTL_LIB) $(UUID_LIBS) $(KMOD_LIBS)
-
-parent_uuid_SOURCES = parent-uuid.c $(testcore)
-parent_uuid_LDADD = $(LIBNDCTL_LIB) $(UUID_LIBS) $(KMOD_LIBS)
-
dax_dev_SOURCES = dax-dev.c $(testcore)
dax_dev_LDADD = $(LIBNDCTL_LIB) $(KMOD_LIBS)
@@ -169,19 +151,6 @@ smart_notify_LDADD = $(LIBNDCTL_LIB)
smart_listen_SOURCES = smart-listen.c
smart_listen_LDADD = $(LIBNDCTL_LIB)
-multi_pmem_SOURCES = \
- multi-pmem.c \
- $(testcore) \
- ../ndctl/namespace.c \
- ../ndctl/check.c \
- ../util/json.c
-multi_pmem_LDADD = \
- $(LIBNDCTL_LIB) \
- $(JSON_LIBS) \
- $(UUID_LIBS) \
- $(KMOD_LIBS) \
- ../libutil.a
-
list_smart_dimm_SOURCES = \
list-smart-dimm.c \
../util/json.c
diff --git a/test/blk-exhaust.sh b/test/blk-exhaust.sh
deleted file mode 100755
index b6d3808969f1..000000000000
--- a/test/blk-exhaust.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash -x
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
-
-set -e
-
-rc=77
-
-. $(dirname $0)/common
-
-check_min_kver "4.11" || do_skip "may lack blk-exhaustion fix"
-
-trap 'err $LINENO' ERR
-
-# setup (reset nfit_test dimms)
-modprobe nfit_test
-reset
-
-# if the kernel accounting is correct we should be able to create two
-# pmem and two blk namespaces on nfit_test.0
-rc=1
-$NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem
-$NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem
-$NDCTL create-namespace -b $NFIT_TEST_BUS0 -t blk -m raw
-$NDCTL create-namespace -b $NFIT_TEST_BUS0 -t blk -m raw
-
-# clearnup and exit
-_cleanup
-
-exit 0
diff --git a/test/blk_namespaces.c b/test/blk_namespaces.c
deleted file mode 100644
index f076e853ddda..000000000000
--- a/test/blk_namespaces.c
+++ /dev/null
@@ -1,357 +0,0 @@
-// SPDX-License-Identifier: LGPL-2.1
-// Copyright (C) 2015-2020, Intel Corporation. All rights reserved.
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/fs.h>
-#include <ndctl/libndctl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <syslog.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <ndctl.h>
-#include <unistd.h>
-#include <uuid/uuid.h>
-#include <linux/version.h>
-#include <test.h>
-#include <libkmod.h>
-#include <ccan/array_size/array_size.h>
-
-/* The purpose of this test is to verify that we can successfully do I/O to
- * multiple nd_blk namespaces that have discontiguous segments. It first
- * sets up two namespaces, each 1/2 the total size of the NVDIMM and each with
- * two discontiguous segments, arranged like this:
- *
- * +-------+-------+-------+-------+
- * | nd0 | nd1 | nd0 | nd1 |
- * +-------+-------+-------+-------+
- *
- * It then runs some I/O to the beginning, middle and end of each of these
- * namespaces, checking data integrity. The I/O to the middle of the
- * namespace will hit two pages, one on either side of the segment boundary.
- */
-#define err(msg)\
- fprintf(stderr, "%s:%d: %s (%s)\n", __func__, __LINE__, msg, strerror(errno))
-
-static struct ndctl_namespace *create_blk_namespace(int region_fraction,
- struct ndctl_region *region)
-{
- struct ndctl_namespace *ndns, *seed_ns = NULL;
- unsigned long long size;
- uuid_t uuid;
-
- ndctl_region_set_align(region, sysconf(_SC_PAGESIZE));
- ndctl_namespace_foreach(region, ndns)
- if (ndctl_namespace_get_size(ndns) == 0) {
- seed_ns = ndns;
- break;
- }
-
- if (!seed_ns)
- return NULL;
-
- uuid_generate(uuid);
- size = ndctl_region_get_size(region)/region_fraction;
-
- if (ndctl_namespace_set_uuid(seed_ns, uuid) < 0)
- return NULL;
-
- if (ndctl_namespace_set_size(seed_ns, size) < 0)
- return NULL;
-
- if (ndctl_namespace_set_sector_size(seed_ns, 512) < 0)
- return NULL;
-
- if (ndctl_namespace_enable(seed_ns) < 0)
- return NULL;
-
- return seed_ns;
-}
-
-static int disable_blk_namespace(struct ndctl_namespace *ndns)
-{
- if (ndctl_namespace_disable_invalidate(ndns) < 0)
- return -ENODEV;
-
- if (ndctl_namespace_delete(ndns) < 0)
- return -ENODEV;
-
- return 0;
-}
-
-static int ns_do_io(const char *bdev)
-{
- int fd, i;
- int rc = 0;
- const int page_size = 4096;
- const int num_pages = 4;
- unsigned long num_dev_pages, num_blocks;
- off_t addr;
-
- void *random_page[num_pages];
- void *blk_page[num_pages];
-
- rc = posix_memalign(random_page, page_size, page_size * num_pages);
- if (rc) {
- fprintf(stderr, "posix_memalign failure\n");
- return rc;
- }
-
- rc = posix_memalign(blk_page, page_size, page_size * num_pages);
- if (rc) {
- fprintf(stderr, "posix_memalign failure\n");
- goto err_free_blk;
- }
-
- for (i = 1; i < num_pages; i++) {
- random_page[i] = (char*)random_page[0] + page_size * i;
- blk_page[i] = (char*)blk_page[0] + page_size * i;
- }
-
- /* read random data into random_page */
- if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
- err("open");
- rc = -ENODEV;
- goto err_free_all;
- }
-
- rc = read(fd, random_page[0], page_size * num_pages);
- if (rc < 0) {
- err("read");
- close(fd);
- goto err_free_all;
- }
-
- close(fd);
-
- if ((fd = open(bdev, O_RDWR|O_DIRECT)) < 0) {
- err("open");
- rc = -ENODEV;
- goto err_free_all;
- }
-
- ioctl(fd, BLKGETSIZE, &num_blocks);
- num_dev_pages = num_blocks / 8;
-
- /* write the random data out to each of the segments */
- rc = pwrite(fd, random_page[0], page_size, 0);
- if (rc < 0) {
- err("write");
- goto err_close;
- }
-
- /* two pages that span the region discontinuity */
- addr = page_size * (num_dev_pages/2 - 1);
- rc = pwrite(fd, random_page[1], page_size*2, addr);
- if (rc < 0) {
- err("write");
- goto err_close;
- }
-
- addr = page_size * (num_dev_pages - 1);
- rc = pwrite(fd, random_page[3], page_size, addr);
- if (rc < 0) {
- err("write");
- goto err_close;
- }
-
- /* read back the random data into blk_page */
- rc = pread(fd, blk_page[0], page_size, 0);
- if (rc < 0) {
- err("read");
- goto err_close;
- }
-
- /* two pages that span the region discontinuity */
- addr = page_size * (num_dev_pages/2 - 1);
- rc = pread(fd, blk_page[1], page_size*2, addr);
- if (rc < 0) {
- err("read");
- goto err_close;
- }
-
- addr = page_size * (num_dev_pages - 1);
- rc = pread(fd, blk_page[3], page_size, addr);
- if (rc < 0) {
- err("read");
- goto err_close;
- }
-
- /* verify the data */
- if (memcmp(random_page[0], blk_page[0], page_size * num_pages)) {
- fprintf(stderr, "Block data miscompare\n");
- rc = -EIO;
- goto err_close;
- }
-
- rc = 0;
- err_close:
- close(fd);
- err_free_all:
- free(random_page[0]);
- err_free_blk:
- free(blk_page[0]);
- return rc;
-}
-
-static const char *comm = "test-blk-namespaces";
-
-int test_blk_namespaces(int log_level, struct ndctl_test *test,
- struct ndctl_ctx *ctx)
-{
- char bdev[50];
- int rc = -ENXIO;
- struct ndctl_bus *bus;
- struct ndctl_dimm *dimm;
- struct kmod_module *mod = NULL;
- struct kmod_ctx *kmod_ctx = NULL;
- struct ndctl_namespace *ndns[2];
- struct ndctl_region *region, *blk_region = NULL;
-
- if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 2, 0)))
- return 77;
-
- ndctl_set_log_priority(ctx, log_level);
-
- bus = ndctl_bus_get_by_provider(ctx, "ACPI.NFIT");
- if (bus) {
- /* skip this bus if no BLK regions */
- ndctl_region_foreach(bus, region)
- if (ndctl_region_get_nstype(region)
- == ND_DEVICE_NAMESPACE_BLK)
- break;
- if (!region)
- bus = NULL;
- }
-
- if (!bus) {
- fprintf(stderr, "ACPI.NFIT unavailable falling back to nfit_test\n");
- rc = ndctl_test_init(&kmod_ctx, &mod, NULL, log_level, test);
- ndctl_invalidate(ctx);
- bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0");
- if (rc < 0 || !bus) {
- ndctl_test_skip(test);
- fprintf(stderr, "nfit_test unavailable skipping tests\n");
- return 77;
- }
- }
-
- fprintf(stderr, "%s: found provider: %s\n", comm,
- ndctl_bus_get_provider(bus));
-
- /* get the system to a clean state */
- ndctl_region_foreach(bus, region)
- ndctl_region_disable_invalidate(region);
-
- ndctl_dimm_foreach(bus, dimm) {
- rc = ndctl_dimm_zero_labels(dimm);
- if (rc < 0) {
- fprintf(stderr, "failed to zero %s\n",
- ndctl_dimm_get_devname(dimm));
- goto err_module;
- }
- }
-
- /* create our config */
- ndctl_region_foreach(bus, region)
- if (strcmp(ndctl_region_get_type_name(region), "blk") == 0) {
- blk_region = region;
- break;
- }
-
- if (!blk_region || ndctl_region_enable(blk_region) < 0) {
- fprintf(stderr, "%s: failed to find block region\n", comm);
- rc = -ENODEV;
- goto err_cleanup;
- }
-
- rc = -ENODEV;
- ndns[0] = create_blk_namespace(4, blk_region);
- if (!ndns[0]) {
- fprintf(stderr, "%s: failed to create block namespace\n", comm);
- goto err_cleanup;
- }
-
- ndns[1] = create_blk_namespace(4, blk_region);
- if (!ndns[1]) {
- fprintf(stderr, "%s: failed to create block namespace\n", comm);
- goto err_cleanup;
- }
-
- rc = disable_blk_namespace(ndns[0]);
- if (rc < 0) {
- fprintf(stderr, "%s: failed to disable block namespace\n", comm);
- goto err_cleanup;
- }
-
- ndns[0] = create_blk_namespace(2, blk_region);
- if (!ndns[0]) {
- fprintf(stderr, "%s: failed to create block namespace\n", comm);
- rc = -ENODEV;
- goto err_cleanup;
- }
-
- rc = disable_blk_namespace(ndns[1]);
- if (rc < 0) {
- fprintf(stderr, "%s: failed to disable block namespace\n", comm);
- goto err_cleanup;
- }
-
- rc = -ENODEV;
- ndns[1] = create_blk_namespace(2, blk_region);
- if (!ndns[1]) {
- fprintf(stderr, "%s: failed to create block namespace\n", comm);
- goto err_cleanup;
- }
-
- /* okay, all set up, do some I/O */
- rc = -EIO;
- sprintf(bdev, "/dev/%s", ndctl_namespace_get_block_device(ndns[0]));
- if (ns_do_io(bdev))
- goto err_cleanup;
- sprintf(bdev, "/dev/%s", ndctl_namespace_get_block_device(ndns[1]));
- if (ns_do_io(bdev))
- goto err_cleanup;
- rc = 0;
-
- err_cleanup:
- /* unload nfit_test */
- bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0");
- if (bus)
- ndctl_region_foreach(bus, region)
- ndctl_region_disable_invalidate(region);
- bus = ndctl_bus_get_by_provider(ctx, "nfit_test.1");
- if (bus)
- ndctl_region_foreach(bus, region)
- ndctl_region_disable_invalidate(region);
- if (mod)
- kmod_module_remove_module(mod, 0);
-
- err_module:
- if (kmod_ctx)
- kmod_unref(kmod_ctx);
- return rc;
-}
-
-int __attribute__((weak)) main(int argc, char *argv[])
-{
- struct ndctl_test *test = ndctl_test_new(0);
- struct ndctl_ctx *ctx;
- int rc;
-
- comm = argv[0];
- if (!test) {
- fprintf(stderr, "failed to initialize test\n");
- return EXIT_FAILURE;
- }
-
- rc = ndctl_new(&ctx);
- if (rc)
- return ndctl_test_result(test, rc);
-
- rc = test_blk_namespaces(LOG_DEBUG, test, ctx);
- ndctl_unref(ctx);
- return ndctl_test_result(test, rc);
-}
diff --git a/test/core.c b/test/core.c
index 93e1dae5a144..dc1405d75c49 100644
--- a/test/core.c
+++ b/test/core.c
@@ -123,7 +123,6 @@ int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
"dax_pmem_core",
"dax_pmem_compat",
"libnvdimm",
- "nd_blk",
"nd_btt",
"nd_e820",
"nd_pmem",
diff --git a/test/create.sh b/test/create.sh
index e9baaa075a28..9a6f3733939e 100755
--- a/test/create.sh
+++ b/test/create.sh
@@ -40,19 +40,6 @@ eval $(echo $json | json2var)
# free capacity for blk creation
$NDCTL destroy-namespace -f $dev
-# create blk
-dev="x"
-json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t blk -m raw -v)
-eval $(echo $json | json2var)
-[ $dev = "x" ] && echo "fail: $LINENO" && exit 1
-[ $mode != "raw" ] && echo "fail: $LINENO" && exit 1
-
-# convert blk to sector mode
-json=$($NDCTL create-namespace -m sector -l $SECTOR_SIZE -f -e $dev)
-eval $(echo $json | json2var)
-[ $sector_size != $SECTOR_SIZE ] && echo "fail: $LINENO" && exit 1
-[ $mode != "sector" ] && echo "fail: $LINENO" && exit 1
-
_cleanup
exit 0
diff --git a/test/dpa-alloc.c b/test/dpa-alloc.c
deleted file mode 100644
index 59185cf8cf3b..000000000000
--- a/test/dpa-alloc.c
+++ /dev/null
@@ -1,326 +0,0 @@
-// SPDX-License-Identifier: LGPL-2.1
-// Copyright (C) 2014-2020, Intel Corporation. All rights reserved.
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <errno.h>
-#include <unistd.h>
-#include <limits.h>
-#include <syslog.h>
-#include <libkmod.h>
-#include <uuid/uuid.h>
-
-#include <test.h>
-#include <ndctl.h>
-#include <util/size.h>
-#include <linux/version.h>
-#include <ndctl/libndctl.h>
-#include <ccan/array_size/array_size.h>
-
-static const char *NFIT_PROVIDER0 = "nfit_test.0";
-static const char *NFIT_PROVIDER1 = "nfit_test.1";
-#define NUM_NAMESPACES 4
-
-struct test_dpa_namespace {
- struct ndctl_namespace *ndns;
- unsigned long long size;
- uuid_t uuid;
-} namespaces[NUM_NAMESPACES];
-
-#define MIN_SIZE SZ_4M
-
-static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
-{
- unsigned int default_available_slots, available_slots, i;
- struct ndctl_region *region, *blk_region = NULL;
- struct ndctl_namespace *ndns;
- struct ndctl_dimm *dimm;
- unsigned long size, page_size;
- struct ndctl_bus *bus;
- char uuid_str[40];
- int round;
- int rc;
-
- page_size = sysconf(_SC_PAGESIZE);
- /* disable nfit_test.1, not used in this test */
- bus = ndctl_bus_get_by_provider(ctx, NFIT_PROVIDER1);
- if (!bus)
- return -ENXIO;
- ndctl_region_foreach(bus, region) {
- ndctl_region_disable_invalidate(region);
- ndctl_region_set_align(region, sysconf(_SC_PAGESIZE)
- * ndctl_region_get_interleave_ways(region));
- }
-
- /* init nfit_test.0 */
- bus = ndctl_bus_get_by_provider(ctx, NFIT_PROVIDER0);
- if (!bus)
- return -ENXIO;
- ndctl_region_foreach(bus, region) {
- ndctl_region_disable_invalidate(region);
- ndctl_region_set_align(region, sysconf(_SC_PAGESIZE)
- * ndctl_region_get_interleave_ways(region));
- }
-
- ndctl_dimm_foreach(bus, dimm) {
- rc = ndctl_dimm_zero_labels(dimm);
- if (rc < 0) {
- fprintf(stderr, "failed to zero %s\n",
- ndctl_dimm_get_devname(dimm));
- return rc;
- }
- }
-
- /*
- * Find a guineapig BLK region, we know that the dimm with
- * handle==0 from nfit_test.0 always allocates from highest DPA
- * to lowest with no excursions into BLK only ranges.
- */
- ndctl_region_foreach(bus, region) {
- if (ndctl_region_get_type(region) != ND_DEVICE_REGION_BLK)
- continue;
- dimm = ndctl_region_get_first_dimm(region);
- if (!dimm)
- continue;
- if (ndctl_dimm_get_handle(dimm) == 0) {
- blk_region = region;
- break;
- }
- }
- if (!blk_region || ndctl_region_enable(blk_region) < 0) {
- fprintf(stderr, "failed to find a usable BLK region\n");
- return -ENXIO;
- }
- region = blk_region;
-
- if (ndctl_region_get_available_size(region) / MIN_SIZE < NUM_NAMESPACES) {
- fprintf(stderr, "%s insufficient available_size\n",
- ndctl_region_get_devname(region));
- return -ENXIO;
- }
-
- default_available_slots = ndctl_dimm_get_available_labels(dimm);
-
- /* grow namespaces */
- for (i = 0; i < ARRAY_SIZE(namespaces); i++) {
- uuid_t uuid;
-
- ndns = ndctl_region_get_namespace_seed(region);
- if (!ndns) {
- fprintf(stderr, "%s: failed to get seed: %d\n",
- ndctl_region_get_devname(region), i);
- return -ENXIO;
- }
- uuid_generate_random(uuid);
- ndctl_namespace_set_uuid(ndns, uuid);
- ndctl_namespace_set_sector_size(ndns, 512);
- ndctl_namespace_set_size(ndns, MIN_SIZE);
- rc = ndctl_namespace_enable(ndns);
- if (rc) {
- fprintf(stderr, "failed to enable %s: %d\n",
- ndctl_namespace_get_devname(ndns), rc);
- return rc;
- }
- ndctl_namespace_disable_invalidate(ndns);
- rc = ndctl_namespace_set_size(ndns, page_size);
- if (rc) {
- fprintf(stderr, "failed to init %s to size: %lu\n",
- ndctl_namespace_get_devname(ndns),
- page_size);
- return rc;
- }
- namespaces[i].ndns = ndns;
- ndctl_namespace_get_uuid(ndns, namespaces[i].uuid);
- }
-
- available_slots = ndctl_dimm_get_available_labels(dimm);
- if (available_slots != default_available_slots
- - ARRAY_SIZE(namespaces)) {
- fprintf(stderr, "expected %ld slots available\n",
- default_available_slots
- - ARRAY_SIZE(namespaces));
- return -ENOSPC;
- }
-
- /* exhaust label space, by round-robin allocating 4K */
- round = 1;
- for (i = 0; i < available_slots; i++) {
- ndns = namespaces[i % ARRAY_SIZE(namespaces)].ndns;
- if (i % ARRAY_SIZE(namespaces) == 0)
- round++;
- size = page_size * round;
- rc = ndctl_namespace_set_size(ndns, size);
- if (rc) {
- fprintf(stderr, "%s: set_size: %lx failed: %d\n",
- ndctl_namespace_get_devname(ndns), size, rc);
- return rc;
- }
- }
-
- /*
- * The last namespace we updated should still be modifiable via
- * the kernel's reserve label
- */
- i--;
- round++;
- ndns = namespaces[i % ARRAY_SIZE(namespaces)].ndns;
- size = page_size * round;
- rc = ndctl_namespace_set_size(ndns, size);
- if (rc) {
- fprintf(stderr, "%s failed to update while labels full\n",
- ndctl_namespace_get_devname(ndns));
- return rc;
- }
-
- round--;
- size = page_size * round;
- rc = ndctl_namespace_set_size(ndns, size);
- if (rc) {
- fprintf(stderr, "%s failed to reduce size while labels full\n",
- ndctl_namespace_get_devname(ndns));
- return rc;
- }
-
- /* do the allocations survive a region cycle? */
- for (i = 0; i < ARRAY_SIZE(namespaces); i++) {
- ndns = namespaces[i].ndns;
- namespaces[i].size = ndctl_namespace_get_size(ndns);
- namespaces[i].ndns = NULL;
- }
-
- ndctl_region_disable_invalidate(region);
- rc = ndctl_region_enable(region);
- if (rc) {
- fprintf(stderr, "failed to re-enable %s: %d\n",
- ndctl_region_get_devname(region), rc);
- return rc;
- }
-
- ndctl_namespace_foreach(region, ndns) {
- uuid_t uuid;
-
- ndctl_namespace_get_uuid(ndns, uuid);
- for (i = 0; i < ARRAY_SIZE(namespaces); i++) {
- if (uuid_compare(uuid, namespaces[i].uuid) == 0) {
- namespaces[i].ndns = ndns;
- break;
- }
- }
- }
-
- /* validate that they all came back */
- for (i = 0; i < ARRAY_SIZE(namespaces); i++) {
- ndns = namespaces[i].ndns;
- size = ndns ? ndctl_namespace_get_size(ndns) : 0;
-
- if (ndns && size == namespaces[i].size)
- continue;
- uuid_unparse(namespaces[i].uuid, uuid_str);
- fprintf(stderr, "failed to recover %s\n", uuid_str);
- return -ENODEV;
- }
-
- /* test deletion and merging */
- ndns = namespaces[0].ndns;
- for (i = 1; i < ARRAY_SIZE(namespaces); i++) {
- struct ndctl_namespace *victim = namespaces[i].ndns;
-
- uuid_unparse(namespaces[i].uuid, uuid_str);
- size = ndctl_namespace_get_size(victim);
- rc = ndctl_namespace_disable(victim);
- if (rc) {
- fprintf(stderr, "failed to disable %s\n", uuid_str);
- return rc;
- }
- rc = ndctl_namespace_delete(victim);
- if (rc) {
- fprintf(stderr, "failed to delete %s\n", uuid_str);
- return rc;
- }
- size += ndctl_namespace_get_size(ndns);
- rc = ndctl_namespace_set_size(ndns, size);
- if (rc) {
- fprintf(stderr, "failed to merge %s\n", uuid_str);
- return rc;
- }
- }
-
- /* there can be only one */
- i = 0;
- ndctl_namespace_foreach(region, ndns) {
- unsigned long long sz = ndctl_namespace_get_size(ndns);
-
- if (sz) {
- i++;
- if (sz == size)
- continue;
- fprintf(stderr, "%s size: %llx expected %lx\n",
- ndctl_namespace_get_devname(ndns),
- sz, size);
- return -ENXIO;
- }
- }
- if (i != 1) {
- fprintf(stderr, "failed to delete namespaces\n");
- return -ENXIO;
- }
-
- available_slots = ndctl_dimm_get_available_labels(dimm);
- if (available_slots != default_available_slots - 1) {
- fprintf(stderr, "mishandled slot count\n");
- return -ENXIO;
- }
-
- ndctl_region_foreach(bus, region)
- ndctl_region_disable_invalidate(region);
-
- return 0;
-}
-
-int test_dpa_alloc(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
-{
- struct kmod_module *mod;
- struct kmod_ctx *kmod_ctx;
- int err, result = EXIT_FAILURE;
-
- if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 2, 0)))
- return 77;
-
- ndctl_set_log_priority(ctx, loglevel);
- err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
- if (err < 0) {
- ndctl_test_skip(test);
- fprintf(stderr, "nfit_test unavailable skipping tests\n");
- return 77;
- }
-
- err = do_test(ctx, test);
- if (err == 0)
- result = EXIT_SUCCESS;
- kmod_module_remove_module(mod, 0);
- kmod_unref(kmod_ctx);
- return result;
-}
-
-int __attribute__((weak)) main(int argc, char *argv[])
-{
- struct ndctl_test *test = ndctl_test_new(0);
- struct ndctl_ctx *ctx;
- int rc;
-
- if (!test) {
- fprintf(stderr, "failed to initialize test\n");
- return EXIT_FAILURE;
- }
-
- rc = ndctl_new(&ctx);
- if (rc)
- return ndctl_test_result(test, rc);
-
- rc = test_dpa_alloc(LOG_DEBUG, test, ctx);
- ndctl_unref(ctx);
- return ndctl_test_result(test, rc);
-}
diff --git a/test/libndctl.c b/test/libndctl.c
index aa624289c708..0bee06b93787 100644
--- a/test/libndctl.c
+++ b/test/libndctl.c
@@ -30,46 +30,35 @@
/*
* Kernel provider "nfit_test.0" produces an NFIT with the following attributes:
*
- * (a) (b) DIMM BLK-REGION
- * +-------------------+--------+--------+--------+
- * +------+ | pm0.0 | blk2.0 | pm1.0 | blk2.1 | 0 region2
- * | imc0 +--+- - - region0- - - +--------+ +--------+
- * +--+---+ | pm0.0 | blk3.0 | pm1.0 | blk3.1 | 1 region3
- * | +-------------------+--------v v--------+
- * +--+---+ | |
- * | cpu0 | region1
- * +--+---+ | |
- * | +----------------------------^ ^--------+
- * +--+---+ | blk4.0 | pm1.0 | blk4.0 | 2 region4
- * | imc1 +--+----------------------------| +--------+
- * +------+ | blk5.0 | pm1.0 | blk5.0 | 3 region5
- * +----------------------------+--------+--------+
+ * (a) (b) DIMM
+ * +-------------------+--------+--------+--------+
+ * +------+ | pm0.0 | free | pm1.0 | free | 0
+ * | imc0 +--+- - - region0- - - +--------+ +--------+
+ * +--+---+ | pm0.0 | free | pm1.0 | free | 1
+ * | +-------------------+--------v v--------+
+ * +--+---+ | |
+ * | cpu0 | region1
+ * +--+---+ | |
+ * | +----------------------------^ ^--------+
+ * +--+---+ | free | pm1.0 | free | 2
+ * | imc1 +--+----------------------------| +--------+
+ * +------+ | free | pm1.0 | free | 3
+ * +----------------------------+--------+--------+
*
- * *) In this layout we have four dimms and two memory controllers in one
- * socket. Each unique interface ("blk" or "pmem") to DPA space
- * is identified by a region device with a dynamically assigned id.
+ * In this platform we have four DIMMs and two memory controllers in one
+ * socket. Each PMEM interleave set is identified by a region device with
+ * a dynamically assigned id.
*
- * *) The first portion of dimm0 and dimm1 are interleaved as REGION0.
- * A single "pmem" namespace is created in the REGION0-"spa"-range
- * that spans dimm0 and dimm1 with a user-specified name of "pm0.0".
- * Some of that interleaved "spa" range is reclaimed as "bdw"
- * accessed space starting at offset (a) into each dimm. In that
- * reclaimed space we create two "bdw" "namespaces" from REGION2 and
- * REGION3 where "blk2.0" and "blk3.0" are just human readable names
- * that could be set to any user-desired name in the label.
+ * 1. The first portion of DIMM0 and DIMM1 are interleaved as REGION0. A
+ * single PMEM namespace is created in the REGION0-SPA-range that spans most
+ * of DIMM0 and DIMM1 with a user-specified name of "pm0.0". Some of that
+ * interleaved system-physical-address range is left free for
+ * another PMEM namespace to be defined.
*
- * *) In the last portion of dimm0 and dimm1 we have an interleaved
- * "spa" range, REGION1, that spans those two dimms as well as dimm2
- * and dimm3. Some of REGION1 allocated to a "pmem" namespace named
- * "pm1.0" the rest is reclaimed in 4 "bdw" namespaces (for each
- * dimm in the interleave set), "blk2.1", "blk3.1", "blk4.0", and
- * "blk5.0".
- *
- * *) The portion of dimm2 and dimm3 that do not participate in the
- * REGION1 interleaved "spa" range (i.e. the DPA address below
- * offset (b) are also included in the "blk4.0" and "blk5.0"
- * namespaces. Note, that this example shows that "bdw" namespaces
- * don't need to be contiguous in DPA-space.
+ * 2. In the last portion of DIMM0 and DIMM1 we have an interleaved
+ * system-physical-address range, REGION1, that spans those two DIMMs as
+ * well as DIMM2 and DIMM3. Some of REGION1 is allocated to a PMEM namespace
+ * named "pm1.0".
*
* Kernel provider "nfit_test.1" produces an NFIT with the following attributes:
*
@@ -127,10 +116,10 @@ struct dimm {
(((n & 0xfff) << 16) | ((s & 0xf) << 12) | ((i & 0xf) << 8) \
| ((c & 0xf) << 4) | (d & 0xf))
static struct dimm dimms0[] = {
- { DIMM_HANDLE(0, 0, 0, 0, 0), 0, 0, 2016, 10, 42, { 0 }, 2, { 0x201, 0x301, }, },
- { DIMM_HANDLE(0, 0, 0, 0, 1), 1, 0, 2016, 10, 42, { 0 }, 2, { 0x201, 0x301, }, },
- { DIMM_HANDLE(0, 0, 1, 0, 0), 2, 0, 2016, 10, 42, { 0 }, 2, { 0x201, 0x301, }, },
- { DIMM_HANDLE(0, 0, 1, 0, 1), 3, 0, 2016, 10, 42, { 0 }, 2, { 0x201, 0x301, }, },
+ { DIMM_HANDLE(0, 0, 0, 0, 0), 0, 0, 2016, 10, 42, { 0 }, 1, { 0x201, }, },
+ { DIMM_HANDLE(0, 0, 0, 0, 1), 1, 0, 2016, 10, 42, { 0 }, 1, { 0x201, }, },
+ { DIMM_HANDLE(0, 0, 1, 0, 0), 2, 0, 2016, 10, 42, { 0 }, 1, { 0x201, }, },
+ { DIMM_HANDLE(0, 0, 1, 0, 1), 3, 0, 2016, 10, 42, { 0 }, 1, { 0x201, }, },
};
static struct dimm dimms1[] = {
@@ -240,7 +229,6 @@ struct namespace {
};
static uuid_t null_uuid;
-static unsigned long blk_sector_sizes[] = { 512, 520, 528, 4096, 4104, 4160, 4224, };
static unsigned long pmem_sector_sizes[] = { 512, 4096 };
static unsigned long io_sector_sizes[] = { 0 };
@@ -262,60 +250,6 @@ static struct namespace namespace1_pmem0 = {
ARRAY_SIZE(pmem_sector_sizes), pmem_sector_sizes,
};
-static struct namespace namespace2_blk0 = {
- 0, "namespace_blk", NULL, NULL, NULL, SZ_7M,
- { 3, 3, 3, 3,
- 3, 3, 3, 3,
- 3, 3, 3, 3,
- 3, 3, 3, 3, }, 1, 1, 0,
- ARRAY_SIZE(blk_sector_sizes), blk_sector_sizes,
-};
-
-static struct namespace namespace2_blk1 = {
- 1, "namespace_blk", NULL, NULL, NULL, SZ_11M,
- { 4, 4, 4, 4,
- 4, 4, 4, 4,
- 4, 4, 4, 4,
- 4, 4, 4, 4, }, 1, 1, 0,
- ARRAY_SIZE(blk_sector_sizes), blk_sector_sizes,
-};
-
-static struct namespace namespace3_blk0 = {
- 0, "namespace_blk", NULL, NULL, NULL, SZ_7M,
- { 5, 5, 5, 5,
- 5, 5, 5, 5,
- 5, 5, 5, 5,
- 5, 5, 5, 5, }, 1, 1, 0,
- ARRAY_SIZE(blk_sector_sizes), blk_sector_sizes,
-};
-
-static struct namespace namespace3_blk1 = {
- 1, "namespace_blk", NULL, NULL, NULL, SZ_11M,
- { 6, 6, 6, 6,
- 6, 6, 6, 6,
- 6, 6, 6, 6,
- 6, 6, 6, 6, }, 1, 1, 0,
- ARRAY_SIZE(blk_sector_sizes), blk_sector_sizes,
-};
-
-static struct namespace namespace4_blk0 = {
- 0, "namespace_blk", &btt_settings, NULL, NULL, SZ_27M,
- { 7, 7, 7, 7,
- 7, 7, 7, 7,
- 7, 7, 7, 7,
- 7, 7, 7, 7, }, 1, 1, 0,
- ARRAY_SIZE(blk_sector_sizes), blk_sector_sizes,
-};
-
-static struct namespace namespace5_blk0 = {
- 0, "namespace_blk", &btt_settings, NULL, NULL, SZ_27M,
- { 8, 8, 8, 8,
- 8, 8, 8, 8,
- 8, 8, 8, 8,
- 8, 8, 8, 8, }, 1, 1, 0,
- ARRAY_SIZE(blk_sector_sizes), blk_sector_sizes,
-};
-
static struct region regions0[] = {
{ { 1 }, 2, 1, "pmem", SZ_32M, SZ_32M, { 1 },
.namespaces = {
@@ -339,40 +273,6 @@ static struct region regions0[] = {
[0] = &default_pfn,
},
},
- { { DIMM_HANDLE(0, 0, 0, 0, 0) }, 1, 1, "blk", SZ_18M, SZ_32M,
- .namespaces = {
- [0] = &namespace2_blk0,
- [1] = &namespace2_blk1,
- },
- .btts = {
- [0] = &default_btt,
- },
- },
- { { DIMM_HANDLE(0, 0, 0, 0, 1) }, 1, 1, "blk", SZ_18M, SZ_32M,
- .namespaces = {
- [0] = &namespace3_blk0,
- [1] = &namespace3_blk1,
- },
- .btts = {
- [0] = &default_btt,
- },
- },
- { { DIMM_HANDLE(0, 0, 1, 0, 0) }, 1, 1, "blk", SZ_27M, SZ_32M,
- .namespaces = {
- [0] = &namespace4_blk0,
- },
- .btts = {
- [0] = &default_btt,
- },
- },
- { { DIMM_HANDLE(0, 0, 1, 0, 1) }, 1, 1, "blk", SZ_27M, SZ_32M,
- .namespaces = {
- [0] = &namespace5_blk0,
- },
- .btts = {
- [0] = &default_btt,
- },
- },
};
static struct namespace namespace1 = {
@@ -485,26 +385,6 @@ static struct ndctl_region *get_pmem_region_by_range_index(struct ndctl_bus *bus
return NULL;
}
-static struct ndctl_region *get_blk_region_by_dimm_handle(struct ndctl_bus *bus,
- unsigned int handle)
-{
- struct ndctl_region *region;
-
- ndctl_region_foreach(bus, region) {
- struct ndctl_mapping *map;
-
- if (ndctl_region_get_type(region) != ND_DEVICE_REGION_BLK)
- continue;
- ndctl_mapping_foreach(region, map) {
- struct ndctl_dimm *dimm = ndctl_mapping_get_dimm(map);
-
- if (ndctl_dimm_get_handle(dimm) == handle)
- return region;
- }
- }
- return NULL;
-}
-
enum ns_mode {
BTT, PFN, DAX,
};
@@ -522,11 +402,8 @@ static int check_regions(struct ndctl_bus *bus, struct region *regions, int n,
struct ndctl_interleave_set *iset;
char devname[50];
- if (strcmp(regions[i].type, "pmem") == 0)
- region = get_pmem_region_by_range_index(bus, regions[i].range_index);
- else
- region = get_blk_region_by_dimm_handle(bus, regions[i].handle);
-
+ region = get_pmem_region_by_range_index(bus,
+ regions[i].range_index);
if (!region) {
fprintf(stderr, "failed to find region type: %s ident: %x\n",
regions[i].type, regions[i].handle);
@@ -1065,7 +942,6 @@ static int check_btt_create(struct ndctl_region *region, struct ndctl_namespace
return -ENXIO;
for (i = 0; i < btt_s->num_sector_sizes; i++) {
- struct ndctl_namespace *ns_seed = ndctl_region_get_namespace_seed(region);
struct ndctl_btt *btt_seed = ndctl_region_get_btt_seed(region);
enum ndctl_namespace_mode mode;
@@ -1115,16 +991,6 @@ static int check_btt_create(struct ndctl_region *region, struct ndctl_namespace
goto err;
}
- /* check new seed creation for BLK regions */
- if (ndctl_region_get_type(region) == ND_DEVICE_REGION_BLK) {
- if (ns_seed == ndctl_region_get_namespace_seed(region)
- && ndns == ns_seed) {
- fprintf(stderr, "%s: failed to advance namespace seed\n",
- ndctl_region_get_devname(region));
- goto err;
- }
- }
-
if (namespace->ro) {
ndctl_region_set_ro(region, 0);
rc = ndctl_btt_enable(btt);
diff --git a/test/multi-pmem.c b/test/multi-pmem.c
deleted file mode 100644
index 3ea08cc43f9a..000000000000
--- a/test/multi-pmem.c
+++ /dev/null
@@ -1,285 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <syslog.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <libkmod.h>
-#include <uuid/uuid.h>
-#include <sys/types.h>
-#include <util/size.h>
-#include <linux/falloc.h>
-#include <linux/version.h>
-#include <ndctl/libndctl.h>
-#include <ccan/array_size/array_size.h>
-
-#include <ndctl.h>
-#include <builtin.h>
-#include <test.h>
-
-#define NUM_NAMESPACES 4
-#define SZ_NAMESPACE SZ_16M
-
-static int setup_namespace(struct ndctl_region *region)
-{
- struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
- const char *argv[] = {
- "__func__", "-v", "-m", "raw", "-s", "16M", "-r", "",
- };
- int argc = ARRAY_SIZE(argv);
-
- argv[argc - 1] = ndctl_region_get_devname(region);
- builtin_xaction_namespace_reset();
- return cmd_create_namespace(argc, argv, ctx);
-}
-
-static void destroy_namespace(struct ndctl_namespace *ndns)
-{
- struct ndctl_ctx *ctx = ndctl_namespace_get_ctx(ndns);
- const char *argv[] = {
- "__func__", "-v", "-f", "",
- };
- int argc = ARRAY_SIZE(argv);
-
- argv[argc - 1] = ndctl_namespace_get_devname(ndns);
- builtin_xaction_namespace_reset();
- cmd_destroy_namespace(argc, argv, ctx);
-}
-
-/* Check that the namespace device is gone (if it wasn't the seed) */
-static int check_deleted(struct ndctl_region *region, const char *devname,
- struct ndctl_test *test)
-{
- struct ndctl_namespace *ndns;
-
- if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 10, 0)))
- return 0;
-
- ndctl_namespace_foreach(region, ndns) {
- if (strcmp(devname, ndctl_namespace_get_devname(ndns)))
- continue;
- if (ndns == ndctl_region_get_namespace_seed(region))
- continue;
- fprintf(stderr, "multi-pmem: expected %s to be deleted\n",
- devname);
- return -ENXIO;
- }
-
- return 0;
-}
-
-static int do_multi_pmem(struct ndctl_ctx *ctx, struct ndctl_test *test)
-{
- int i;
- char devname[100];
- struct ndctl_bus *bus;
- uuid_t uuid[NUM_NAMESPACES];
- struct ndctl_namespace *ndns;
- struct ndctl_dimm *dimm_target, *dimm;
- struct ndctl_region *region, *target = NULL;
- struct ndctl_namespace *namespaces[NUM_NAMESPACES];
- unsigned long long blk_avail, blk_avail_orig, expect;
-
- if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0))) {
- ndctl_test_skip(test);
- return 77;
- }
-
- bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0");
- if (!bus)
- return -ENXIO;
-
- /* disable all regions so that set_config_data commands are permitted */
- ndctl_region_foreach(bus, region)
- ndctl_region_disable_invalidate(region);
-
- ndctl_dimm_foreach(bus, dimm) {
- int rc = ndctl_dimm_zero_labels(dimm);
-
- if (rc < 0) {
- fprintf(stderr, "failed to zero %s\n",
- ndctl_dimm_get_devname(dimm));
- return rc;
- }
- }
-
- /*
- * Set regions back to their default state and find our target
- * region.
- */
- ndctl_region_foreach(bus, region) {
- ndctl_region_enable(region);
- if (ndctl_region_get_available_size(region)
- == SZ_NAMESPACE * NUM_NAMESPACES)
- target = region;
- }
-
- if (!target) {
- fprintf(stderr, "multi-pmem: failed to find target region\n");
- return -ENXIO;
- }
- region = target;
-
- for (i = 0; i < (int) ARRAY_SIZE(uuid); i++) {
- if (setup_namespace(region) != 0) {
- fprintf(stderr, "multi-pmem: failed to setup namespace: %d\n", i);
- return -ENXIO;
- }
- sprintf(devname, "namespace%d.%d",
- ndctl_region_get_id(region), i);
- ndctl_namespace_foreach(region, ndns)
- if (strcmp(ndctl_namespace_get_devname(ndns), devname) == 0
- && ndctl_namespace_is_enabled(ndns))
- break;
- if (!ndns) {
- fprintf(stderr, "multi-pmem: failed to find namespace: %s\n",
- devname);
- return -ENXIO;
- }
- ndctl_namespace_get_uuid(ndns, uuid[i]);
- }
-
- /* bounce the region and verify everything came back as expected */
- ndctl_region_disable_invalidate(region);
- ndctl_region_enable(region);
-
- for (i = 0; i < (int) ARRAY_SIZE(uuid); i++) {
- char uuid_str1[40], uuid_str2[40];
- uuid_t uuid_check;
-
- sprintf(devname, "namespace%d.%d",
- ndctl_region_get_id(region), i);
- ndctl_namespace_foreach(region, ndns)
- if (strcmp(ndctl_namespace_get_devname(ndns), devname) == 0
- && ndctl_namespace_is_enabled(ndns))
- break;
- if (!ndns) {
- fprintf(stderr, "multi-pmem: failed to restore namespace: %s\n",
- devname);
- return -ENXIO;
- }
-
- ndctl_namespace_get_uuid(ndns, uuid_check);
- uuid_unparse(uuid_check, uuid_str2);
- uuid_unparse(uuid[i], uuid_str1);
- if (uuid_compare(uuid_check, uuid[i]) != 0) {
- fprintf(stderr, "multi-pmem: expected uuid[%d]: %s, got %s\n",
- i, uuid_str1, uuid_str2);
- return -ENXIO;
- }
- namespaces[i] = ndns;
- }
-
- /*
- * Check that aliased blk capacity does not increase until the
- * highest dpa pmem-namespace is deleted.
- */
- dimm_target = ndctl_region_get_first_dimm(region);
- if (!dimm_target) {
- fprintf(stderr, "multi-pmem: failed to retrieve dimm from %s\n",
- ndctl_region_get_devname(region));
- return -ENXIO;
- }
-
- dimm = NULL;
- ndctl_region_foreach(bus, region) {
- if (ndctl_region_get_type(region) != ND_DEVICE_REGION_BLK)
- continue;
- ndctl_dimm_foreach_in_region(region, dimm)
- if (dimm == dimm_target)
- break;
- if (dimm)
- break;
- }
-
- blk_avail_orig = ndctl_region_get_available_size(region);
- for (i = 1; i < NUM_NAMESPACES - 1; i++) {
- ndns = namespaces[i];
- sprintf(devname, "%s", ndctl_namespace_get_devname(ndns));
- destroy_namespace(ndns);
- blk_avail = ndctl_region_get_available_size(region);
- if (blk_avail != blk_avail_orig) {
- fprintf(stderr, "multi-pmem: destroy %s %llx avail, expect %llx\n",
- devname, blk_avail, blk_avail_orig);
- return -ENXIO;
- }
-
- if (check_deleted(target, devname, test) != 0)
- return -ENXIO;
- }
-
- ndns = namespaces[NUM_NAMESPACES - 1];
- sprintf(devname, "%s", ndctl_namespace_get_devname(ndns));
- destroy_namespace(ndns);
- blk_avail = ndctl_region_get_available_size(region);
- expect = (SZ_NAMESPACE / ndctl_region_get_interleave_ways(target))
- * (NUM_NAMESPACES - 1) + blk_avail_orig;
- if (blk_avail != expect) {
- fprintf(stderr, "multi-pmem: destroy %s %llx avail, expect %llx\n",
- devname, blk_avail, expect);
- return -ENXIO;
- }
-
- if (check_deleted(target, devname, test) != 0)
- return -ENXIO;
-
- ndctl_bus_foreach(ctx, bus) {
- if (strncmp(ndctl_bus_get_provider(bus), "nfit_test", 9) != 0)
- continue;
- ndctl_region_foreach(bus, region)
- ndctl_region_disable_invalidate(region);
- }
-
- return 0;
-}
-
-int test_multi_pmem(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
-{
- struct kmod_module *mod;
- struct kmod_ctx *kmod_ctx;
- int err, result = EXIT_FAILURE;
-
- if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 2, 0)))
- return 77;
-
- ndctl_set_log_priority(ctx, loglevel);
-
- err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
- if (err < 0) {
- result = 77;
- ndctl_test_skip(test);
- fprintf(stderr, "%s unavailable skipping tests\n",
- "nfit_test");
- return result;
- }
-
- result = do_multi_pmem(ctx, test);
-
- kmod_module_remove_module(mod, 0);
- kmod_unref(kmod_ctx);
- return result;
-}
-
-int __attribute__((weak)) main(int argc, char *argv[])
-{
- struct ndctl_test *test = ndctl_test_new(0);
- struct ndctl_ctx *ctx;
- int rc;
-
- if (!test) {
- fprintf(stderr, "failed to initialize test\n");
- return EXIT_FAILURE;
- }
-
- rc = ndctl_new(&ctx);
- if (rc)
- return ndctl_test_result(test, rc);
- rc = test_multi_pmem(LOG_DEBUG, test, ctx);
- ndctl_unref(ctx);
- return ndctl_test_result(test, rc);
-}
diff --git a/test/parent-uuid.c b/test/parent-uuid.c
deleted file mode 100644
index bded33afbf23..000000000000
--- a/test/parent-uuid.c
+++ /dev/null
@@ -1,254 +0,0 @@
-// SPDX-License-Identifier: LGPL-2.1
-// Copyright (C) 2015-2020, Intel Corporation. All rights reserved.
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <errno.h>
-#include <unistd.h>
-#include <limits.h>
-#include <syslog.h>
-#include <libkmod.h>
-#include <uuid/uuid.h>
-#include <linux/version.h>
-#include <test.h>
-
-#include <ndctl/libndctl.h>
-
-static const char *PROVIDER = "nfit_test.0";
-
-static struct ndctl_bus *get_bus_by_provider(struct ndctl_ctx *ctx,
- const char *provider)
-{
- struct ndctl_bus *bus;
-
- ndctl_bus_foreach(ctx, bus)
- if (strcmp(provider, ndctl_bus_get_provider(bus)) == 0)
- return bus;
-
- return NULL;
-}
-
-static struct ndctl_btt *get_idle_btt(struct ndctl_region *region)
-{
- struct ndctl_btt *btt;
-
- ndctl_btt_foreach(region, btt)
- if (!ndctl_btt_is_enabled(btt)
- && !ndctl_btt_is_configured(btt))
- return btt;
- return NULL;
-}
-
-static struct ndctl_namespace *create_blk_namespace(int region_fraction,
- struct ndctl_region *region, unsigned long long req_size,
- uuid_t uuid)
-{
- struct ndctl_namespace *ndns, *seed_ns = NULL;
- unsigned long long size;
-
- ndctl_region_set_align(region, sysconf(_SC_PAGESIZE));
- ndctl_namespace_foreach(region, ndns)
- if (ndctl_namespace_get_size(ndns) == 0) {
- seed_ns = ndns;
- break;
- }
-
- if (!seed_ns)
- return NULL;
-
- size = ndctl_region_get_size(region)/region_fraction;
- if (req_size)
- size = req_size;
-
- if (ndctl_namespace_set_uuid(seed_ns, uuid) < 0)
- return NULL;
-
- if (ndctl_namespace_set_size(seed_ns, size) < 0)
- return NULL;
-
- if (ndctl_namespace_set_sector_size(seed_ns, 512) < 0)
- return NULL;
-
- if (ndctl_namespace_enable(seed_ns) < 0)
- return NULL;
-
- return seed_ns;
-}
-
-static int disable_blk_namespace(struct ndctl_namespace *ndns)
-{
- if (ndctl_namespace_disable_invalidate(ndns) < 0)
- return -ENODEV;
-
- if (ndctl_namespace_delete(ndns) < 0)
- return -ENODEV;
-
- return 0;
-}
-
-static struct ndctl_btt *check_valid_btt(struct ndctl_region *region,
- struct ndctl_namespace *ndns, uuid_t btt_uuid)
-{
- struct ndctl_btt *btt = NULL;
- ndctl_btt_foreach(region, btt) {
- struct ndctl_namespace *btt_ndns;
- uuid_t uu;
-
- ndctl_btt_get_uuid(btt, uu);
- if (uuid_compare(uu, btt_uuid) != 0)
- continue;
- if (!ndctl_btt_is_enabled(btt))
- continue;
- btt_ndns = ndctl_btt_get_namespace(btt);
- if (!btt_ndns || strcmp(ndctl_namespace_get_devname(btt_ndns),
- ndctl_namespace_get_devname(ndns)) != 0)
- continue;
- return btt;
- }
- return NULL;
-}
-
-static int do_test(struct ndctl_ctx *ctx)
-{
- int rc;
- struct ndctl_bus *bus;
- struct ndctl_btt *btt, *found = NULL, *_btt;
- struct ndctl_region *region, *blk_region = NULL;
- struct ndctl_namespace *ndns, *_ndns;
- unsigned long long ns_size = 18874368;
- uuid_t uuid = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16};
- uuid_t btt_uuid;
-
- bus = get_bus_by_provider(ctx, PROVIDER);
- if (!bus) {
- fprintf(stderr, "failed to find NFIT-provider: %s\n", PROVIDER);
- return -ENODEV;
- }
-
- ndctl_region_foreach(bus, region)
- if (strcmp(ndctl_region_get_type_name(region), "blk") == 0) {
- blk_region = region;
- break;
- }
-
- if (!blk_region) {
- fprintf(stderr, "failed to find block region\n");
- return -ENODEV;
- }
-
- /* create a blk namespace */
- ndns = create_blk_namespace(1, blk_region, ns_size, uuid);
- if (!ndns) {
- fprintf(stderr, "failed to create block namespace\n");
- return -ENXIO;
- }
-
- /* create a btt for this namespace */
- uuid_generate(btt_uuid);
- btt = get_idle_btt(region);
- if (!btt)
- return -ENXIO;
-
- ndctl_namespace_disable_invalidate(ndns);
- ndctl_btt_set_uuid(btt, btt_uuid);
- ndctl_btt_set_sector_size(btt, 512);
- ndctl_btt_set_namespace(btt, ndns);
- rc = ndctl_btt_enable(btt);
- if (rc) {
- fprintf(stderr, "failed to create btt 0\n");
- return rc;
- }
-
- /* re-create the namespace - this should auto-enable the btt */
- disable_blk_namespace(ndns);
- ndns = create_blk_namespace(1, blk_region, ns_size, uuid);
- if (!ndns) {
- fprintf(stderr, "failed to re-create block namespace\n");
- return -ENXIO;
- }
-
- /* Verify btt was auto-created */
- found = check_valid_btt(blk_region, ndns, btt_uuid);
- if (!found)
- return -ENXIO;
- btt = found;
-
- /*disable the btt and namespace again */
- ndctl_btt_delete(btt);
- disable_blk_namespace(ndns);
-
- /* recreate the namespace with a different uuid */
- uuid_generate(uuid);
- ndns = create_blk_namespace(1, blk_region, ns_size, uuid);
- if (!ndns) {
- fprintf(stderr, "failed to re-create block namespace\n");
- return -ENXIO;
- }
-
- /* make sure there is no btt on this namespace */
- found = check_valid_btt(blk_region, ndns, btt_uuid);
- if (found) {
- fprintf(stderr, "found a stale btt\n");
- return -ENXIO;
- }
-
- ndctl_btt_foreach_safe(blk_region, btt, _btt)
- ndctl_btt_delete(btt);
-
- ndctl_namespace_foreach_safe(blk_region, ndns, _ndns)
- if (ndctl_namespace_get_size(ndns) != 0)
- disable_blk_namespace(ndns);
-
- ndctl_region_foreach(bus, region)
- ndctl_region_disable_invalidate(region);
-
- return 0;
-}
-
-int test_parent_uuid(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
-{
- struct kmod_module *mod;
- struct kmod_ctx *kmod_ctx;
- int err, result = EXIT_FAILURE;
-
- if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 3, 0)))
- return 77;
-
- ndctl_set_log_priority(ctx, loglevel);
- err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
- if (err < 0) {
- ndctl_test_skip(test);
- fprintf(stderr, "nfit_test unavailable skipping tests\n");
- return 77;
- }
-
- err = do_test(ctx);
- if (err == 0)
- result = EXIT_SUCCESS;
- kmod_module_remove_module(mod, 0);
- kmod_unref(kmod_ctx);
- return result;
-}
-
-int __attribute__((weak)) main(int argc, char *argv[])
-{
- struct ndctl_test *test = ndctl_test_new(0);
- struct ndctl_ctx *ctx;
- int rc;
-
- if (!test) {
- fprintf(stderr, "failed to initialize test\n");
- return EXIT_FAILURE;
- }
-
- rc = ndctl_new(&ctx);
- if (rc)
- return ndctl_test_result(test, rc);
-
- rc = test_parent_uuid(LOG_DEBUG, test, ctx);
- ndctl_unref(ctx);
- return ndctl_test_result(test, rc);
-}
^ permalink raw reply related
* [ndctl PATCH v3 05/16] ndctl/test: Skip BLK flags checks
From: Dan Williams @ 2022-01-05 21:32 UTC (permalink / raw)
To: vishal.l.verma; +Cc: nvdimm, linux-cxl
In-Reply-To: <164141829899.3990253.17547886681174580434.stgit@dwillia2-desk3.amr.corp.intel.com>
With the removal of BLK-mode support, test/libndctl will fail to detect the
JEDEC format on the nfit_test bus. Report + skip that check rather than
fail the test when that happens.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
test/libndctl.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/libndctl.c b/test/libndctl.c
index 0d6b9dd5b04b..aa624289c708 100644
--- a/test/libndctl.c
+++ b/test/libndctl.c
@@ -2536,7 +2536,7 @@ static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,
fprintf(stderr, "dimm%d expected formats: %d got: %d\n",
i, dimms[i].formats,
ndctl_dimm_get_formats(dimm));
- return -ENXIO;
+ fprintf(stderr, "continuing...\n");
}
for (j = 0; j < dimms[i].formats; j++) {
if (ndctl_dimm_get_formatN(dimm, j) != dimms[i].format[j]) {
@@ -2544,7 +2544,7 @@ static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,
"dimm%d expected format[%d]: %d got: %d\n",
i, j, dimms[i].format[j],
ndctl_dimm_get_formatN(dimm, j));
- return -ENXIO;
+ fprintf(stderr, "continuing...\n");
}
}
}
^ permalink raw reply related
* [ndctl PATCH v3 09/16] util: Distribute 'filter' and 'json' helpers to per-tool objects
From: Dan Williams @ 2022-01-05 21:32 UTC (permalink / raw)
To: vishal.l.verma; +Cc: nvdimm, linux-cxl
In-Reply-To: <164141829899.3990253.17547886681174580434.stgit@dwillia2-desk3.amr.corp.intel.com>
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).
Signed-off-by: Dan Williams <dan.j.williams@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
ndctl/filter.c | 60 --
ndctl/filter.h | 12
ndctl/inject-error.c | 6
ndctl/inject-smart.c | 6
ndctl/json-smart.c | 5
ndctl/json.c | 1114 ++++++++++++++++++++++++++++++
ndctl/json.h | 24 +
ndctl/keys.c | 5
ndctl/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/filter.c => ndctl/filter.c (88%)
rename util/filter.h => ndctl/filter.h (89%)
rename ndctl/{util/json-smart.c => json-smart.c} (99%)
create mode 100644 ndctl/json.c
create mode 100644 ndctl/json.h
rename ndctl/{util/keys.c => keys.c} (99%)
rename ndctl/{util/keys.h => keys.h} (100%)
diff --git a/Makefile.am b/Makefile.am
index 269d891f7cd4..daea39f5d41e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -86,7 +86,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 --git a/Makefile.am.in b/Makefile.am.in
index 9c2c4dfbc021..d6b126986bb4 100644
--- a/Makefile.am.in
+++ b/Makefile.am.in
@@ -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 --git a/cxl/Makefile.am b/cxl/Makefile.am
index da9f91d8fd05..ee8488900a3b 100644
--- a/cxl/Makefile.am
+++ b/cxl/Makefile.am
@@ -12,6 +12,9 @@ cxl_SOURCES =\
list.c \
memdev.c \
../util/json.c \
+ json.c \
+ filter.c \
+ filter.h \
builtin.h
cxl_LDADD =\
diff --git a/cxl/filter.c b/cxl/filter.c
new file mode 100644
index 000000000000..21322ed4b4d0
--- /dev/null
+++ b/cxl/filter.c
@@ -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 --git a/cxl/filter.h b/cxl/filter.h
new file mode 100644
index 000000000000..da800336b528
--- /dev/null
+++ b/cxl/filter.h
@@ -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 --git a/cxl/json.c b/cxl/json.c
new file mode 100644
index 000000000000..e562502d9116
--- /dev/null
+++ b/cxl/json.c
@@ -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 --git a/cxl/json.h b/cxl/json.h
new file mode 100644
index 000000000000..3abcfe6661bf
--- /dev/null
+++ b/cxl/json.h
@@ -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 --git a/cxl/list.c b/cxl/list.c
index b1468b70f8c9..7f7a04d9a6e5 100644
--- a/cxl/list.c
+++ b/cxl/list.c
@@ -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 --git a/cxl/memdev.c b/cxl/memdev.c
index 5ee38e51f4ee..d063d51cc571 100644
--- a/cxl/memdev.c
+++ b/cxl/memdev.c
@@ -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 --git a/daxctl/Makefile.am b/daxctl/Makefile.am
index d1bf9fb25a7d..bbf764f8081f 100644
--- a/daxctl/Makefile.am
+++ b/daxctl/Makefile.am
@@ -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 --git a/daxctl/device.c b/daxctl/device.c
index c2ff0cc60b52..d202f02d07e7 100644
--- a/daxctl/device.c
+++ b/daxctl/device.c
@@ -11,7 +11,6 @@
#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 <ndctl/libndctl.h>
@@ -20,6 +19,9 @@
#include <util/parse-configs.h>
#include <ccan/array_size/array_size.h>
+#include "filter.h"
+#include "json.h"
+
static struct {
const char *dev;
const char *mode;
diff --git a/daxctl/filter.c b/daxctl/filter.c
new file mode 100644
index 000000000000..cecb808edade
--- /dev/null
+++ b/daxctl/filter.c
@@ -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 --git a/daxctl/filter.h b/daxctl/filter.h
new file mode 100644
index 000000000000..234f2216e57e
--- /dev/null
+++ b/daxctl/filter.h
@@ -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 --git a/daxctl/json.c b/daxctl/json.c
new file mode 100644
index 000000000000..66a795e2e544
--- /dev/null
+++ b/daxctl/json.c
@@ -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 --git a/daxctl/json.h b/daxctl/json.h
new file mode 100644
index 000000000000..fc82f06bd594
--- /dev/null
+++ b/daxctl/json.h
@@ -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 --git a/daxctl/list.c b/daxctl/list.c
index cf93c2f7e8ed..aeff1967116b 100644
--- a/daxctl/list.c
+++ b/daxctl/list.c
@@ -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 --git a/ndctl/Makefile.am b/ndctl/Makefile.am
index 93b682e8b202..5d5b1cacda9d 100644
--- a/ndctl/Makefile.am
+++ b/ndctl/Makefile.am
@@ -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 --git a/ndctl/bus.c b/ndctl/bus.c
index 9bc1797e50eb..4fbb6bb505d1 100644
--- a/ndctl/bus.c
+++ b/ndctl/bus.c
@@ -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 --git a/ndctl/check.c b/ndctl/check.c
index b4e20657e1dd..523923745a33 100644
--- a/ndctl/check.c
+++ b/ndctl/check.c
@@ -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 --git a/ndctl/dimm.c b/ndctl/dimm.c
index 1d2d9a2b51d7..0f052644a46e 100644
--- a/ndctl/dimm.c
+++ b/ndctl/dimm.c
@@ -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 --git a/util/filter.c b/ndctl/filter.c
similarity index 88%
rename from util/filter.c
rename to ndctl/filter.c
index d81dadebd0d8..64d00ce87dd5 100644
--- a/util/filter.c
+++ b/ndctl/filter.c
@@ -9,10 +9,9 @@
#include <util/util.h>
#include <sys/types.h>
#include <ndctl/ndctl.h>
-#include <util/filter.h>
#include <ndctl/libndctl.h>
-#include <daxctl/libdaxctl.h>
-#include <cxl/libcxl.h>
+
+#include "filter.h"
struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *__ident)
{
@@ -304,61 +303,6 @@ struct ndctl_region *util_region_filter_by_namespace(struct ndctl_region *region
return NULL;
}
-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;
-}
-
-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;
-}
-
enum ndctl_namespace_mode util_nsmode(const char *mode)
{
if (!mode)
diff --git a/util/filter.h b/ndctl/filter.h
similarity index 89%
rename from util/filter.h
rename to ndctl/filter.h
index 9a80d65e8b23..9800cc230865 100644
--- a/util/filter.h
+++ b/ndctl/filter.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */
-#ifndef _UTIL_FILTER_H_
-#define _UTIL_FILTER_H_
+#ifndef _NDCTL_UTIL_FILTER_H_
+#define _NDCTL_UTIL_FILTER_H_
#include <stdbool.h>
#include <ccan/list/list.h>
@@ -25,12 +25,6 @@ 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);
-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);
-struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
- const char *ident);
enum ndctl_namespace_mode util_nsmode(const char *mode);
const char *util_nsmode_name(enum ndctl_namespace_mode mode);
@@ -89,4 +83,4 @@ struct util_filter_params {
struct ndctl_ctx;
int util_filter_walk(struct ndctl_ctx *ctx, struct util_filter_ctx *fctx,
struct util_filter_params *param);
-#endif
+#endif /* _NDCTL_UTIL_FILTER_H_ */
diff --git a/ndctl/inject-error.c b/ndctl/inject-error.c
index 05c1a22fc36c..f595cec0033d 100644
--- a/ndctl/inject-error.c
+++ b/ndctl/inject-error.c
@@ -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 --git a/ndctl/inject-smart.c b/ndctl/inject-smart.c
index 9077bca256e4..2b9d7e85241c 100644
--- a/ndctl/inject-smart.c
+++ b/ndctl/inject-smart.c
@@ -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 --git a/ndctl/util/json-smart.c b/ndctl/json-smart.c
similarity index 99%
rename from ndctl/util/json-smart.c
rename to ndctl/json-smart.c
index e598e04420cd..400f60b0a710 100644
--- a/ndctl/util/json-smart.c
+++ b/ndctl/json-smart.c
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
#include <limits.h>
-#include <util/json.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 <ndctl.h>
+
+#include "json.h"
static void smart_threshold_to_json(struct ndctl_dimm *dimm,
struct json_object *jhealth)
diff --git a/ndctl/json.c b/ndctl/json.c
new file mode 100644
index 000000000000..c62e6cae01a9
--- /dev/null
+++ b/ndctl/json.c
@@ -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 --git a/ndctl/json.h b/ndctl/json.h
new file mode 100644
index 000000000000..f544b659ca1d
--- /dev/null
+++ b/ndctl/json.h
@@ -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 --git a/ndctl/util/keys.c b/ndctl/keys.c
similarity index 99%
rename from ndctl/util/keys.c
rename to ndctl/keys.c
index 30cb4c884b98..876b34714b7e 100644
--- a/ndctl/util/keys.c
+++ b/ndctl/keys.c
@@ -13,10 +13,11 @@
#include <keyutils.h>
#include <syslog.h>
-#include <ndctl.h>
#include <ndctl/config.h>
+#include <ndctl/ndctl.h>
#include <ndctl/libndctl.h>
-#include <util/keys.h>
+
+#include "keys.h"
static int get_key_path(struct ndctl_dimm *dimm, char *path,
enum ndctl_key_type key_type)
diff --git a/ndctl/util/keys.h b/ndctl/keys.h
similarity index 100%
rename from ndctl/util/keys.h
rename to ndctl/keys.h
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index b4939138ed47..47a234ccc8ce 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -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 --git a/ndctl/lib/papr.c b/ndctl/lib/papr.c
index 9c6f2f045fc2..43b8412b2073 100644
--- a/ndctl/lib/papr.c
+++ b/ndctl/lib/papr.c
@@ -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 --git a/ndctl/lib/private.h b/ndctl/lib/private.h
index d442e6c16e9a..4d8622978790 100644
--- a/ndctl/lib/private.h
+++ b/ndctl/lib/private.h
@@ -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 --git a/ndctl/list.c b/ndctl/list.c
index 0017f159c708..869edde4fc65 100644
--- a/ndctl/list.c
+++ b/ndctl/list.c
@@ -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 --git a/ndctl/load-keys.c b/ndctl/load-keys.c
index 26648fe90fe6..d60e7eeb985d 100644
--- a/ndctl/load-keys.c
+++ b/ndctl/load-keys.c
@@ -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 --git a/ndctl/monitor.c b/ndctl/monitor.c
index 0e9b65cb2bc4..8b600a4e762b 100644
--- a/ndctl/monitor.c
+++ b/ndctl/monitor.c
@@ -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/parse-configs.h>
@@ -27,6 +26,9 @@
#endif
#include <util/log.h>
+#include "filter.h"
+#include "json.h"
+
static struct monitor {
const char *log;
const char *configs;
diff --git a/ndctl/namespace.c b/ndctl/namespace.c
index c67c0861afac..257b58ce5917 100644
--- a/ndctl/namespace.c
+++ b/ndctl/namespace.c
@@ -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 --git a/ndctl/region.c b/ndctl/region.c
index 4552c4a33478..e49954660ebb 100644
--- a/ndctl/region.c
+++ b/ndctl/region.c
@@ -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 --git a/test/Makefile.am b/test/Makefile.am
index a5a54df4f260..a2a4ee4a4335 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -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 --git a/test/ack-shutdown-count-set.c b/test/ack-shutdown-count-set.c
index c561ff3416ea..a9e95c63b76c 100644
--- a/test/ack-shutdown-count-set.c
+++ b/test/ack-shutdown-count-set.c
@@ -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 --git a/test/daxdev-errors.c b/test/daxdev-errors.c
index fbbea21448d8..706670767b1a 100644
--- a/test/daxdev-errors.c
+++ b/test/daxdev-errors.c
@@ -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 --git a/test/device-dax.c b/test/device-dax.c
index aad8fa5f1cb1..49c9bc8b1748 100644
--- a/test/device-dax.c
+++ b/test/device-dax.c
@@ -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 --git a/test/dsm-fail.c b/test/dsm-fail.c
index 0a6383d49910..5b443dcd703d 100644
--- a/test/dsm-fail.c
+++ b/test/dsm-fail.c
@@ -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 --git a/test/libndctl.c b/test/libndctl.c
index 0bee06b93787..75c15303fad4 100644
--- a/test/libndctl.c
+++ b/test/libndctl.c
@@ -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 --git a/test/list-smart-dimm.c b/test/list-smart-dimm.c
index 00c24e11bf24..47b711e63670 100644
--- a/test/list-smart-dimm.c
+++ b/test/list-smart-dimm.c
@@ -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 --git a/test/pmem_namespaces.c b/test/pmem_namespaces.c
index a4db1ae3ecae..4bafff5164c8 100644
--- a/test/pmem_namespaces.c
+++ b/test/pmem_namespaces.c
@@ -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 --git a/test/revoke-devmem.c b/test/revoke-devmem.c
index bb8979e9a3d4..59d1a72df6ad 100644
--- a/test/revoke-devmem.c
+++ b/test/revoke-devmem.c
@@ -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 --git a/util/help.c b/util/help.c
index 6eebfe5143e1..da8408328771 100644
--- a/util/help.c
+++ b/util/help.c
@@ -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 --git a/util/json.c b/util/json.c
index f97cf070b840..9f0a8e137caa 100644
--- a/util/json.c
+++ b/util/json.c
@@ -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, struct json_object *jarray,
}
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 --git a/util/json.h b/util/json.h
index ce575e6358f3..4ca2c890fa5c 100644
--- a/util/json.h
+++ b/util/json.h
@@ -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__ */
^ permalink raw reply related
* [PATCH v2 18/18] pnv_phb4.c: change TYPE_PNV_PHB4_ROOT_BUS name
From: Daniel Henrique Barboza @ 2022-01-05 21:23 UTC (permalink / raw)
To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david
In-Reply-To: <20220105212338.49899-1-danielhb413@gmail.com>
Similar to what was happening with pnv-phb3 buses,
TYPE_PNV_PHB4_ROOT_BUS set to "pnv-phb4-root-bus" is a bit too long for
a default root bus name. The usual default name for theses buses in QEMU
are 'pcie', but we want to make a distinction between pnv-phb4 buses and
other PCIE buses, at least as far as default name goes, because not all
PCIE devices are attachable to a pnv-phb4 root-bus type.
Changing the default to 'pnv-phb4-root' allow us to have a shorter name
while making this bus distinct, and the user can always set its own bus
naming via the "id" attribute anyway.
This is the 'info qtree' output after this change, using a powernv9
domain with 2 sockets and default settings enabled:
qemu-system-ppc64 -m 4G -machine powernv9,accel=tcg \
-smp 2,sockets=2,cores=1,threads=1
dev: pnv-phb4, id ""
index = 5 (0x5)
chip-id = 1 (0x1)
version = 704374636546 (0xa400000002)
device-id = 1217 (0x4c1)
x-config-reg-migration-enabled = true
bypass-iommu = false
bus: pnv-phb4-root.11
type pnv-phb4-root
dev: pnv-phb4-root-port, id ""
(...)
dev: pnv-phb4, id ""
index = 0 (0x0)
chip-id = 1 (0x1)
version = 704374636546 (0xa400000002)
device-id = 1217 (0x4c1)
x-config-reg-migration-enabled = true
bypass-iommu = false
bus: pnv-phb4-root.6
type pnv-phb4-root
dev: pnv-phb4-root-port, id ""
(..)
dev: pnv-phb4, id ""
index = 5 (0x5)
chip-id = 0 (0x0)
version = 704374636546 (0xa400000002)
device-id = 1217 (0x4c1)
x-config-reg-migration-enabled = true
bypass-iommu = false
bus: pnv-phb4-root.5
type pnv-phb4-root
dev: pnv-phb4-root-port, id ""
(...)
dev: pnv-phb4, id ""
index = 0 (0x0)
chip-id = 0 (0x0)
version = 704374636546 (0xa400000002)
device-id = 1217 (0x4c1)
x-config-reg-migration-enabled = true
bypass-iommu = false
bus: pnv-phb4-root.0
type pnv-phb4-root
dev: pnv-phb4-root-port, id ""
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
include/hw/pci-host/pnv_phb4.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
index 610580a88f..0aec495cbf 100644
--- a/include/hw/pci-host/pnv_phb4.h
+++ b/include/hw/pci-host/pnv_phb4.h
@@ -47,7 +47,7 @@ typedef struct PnvPhb4DMASpace {
/*
* PHB4 PCIe Root port
*/
-#define TYPE_PNV_PHB4_ROOT_BUS "pnv-phb4-root-bus"
+#define TYPE_PNV_PHB4_ROOT_BUS "pnv-phb4-root"
#define TYPE_PNV_PHB4_ROOT_PORT "pnv-phb4-root-port"
typedef struct PnvPHB4RootPort {
--
2.33.1
^ permalink raw reply related
* [PATCH v2 08/18] ppc/pnv: Complete user created PHB3 devices
From: Daniel Henrique Barboza @ 2022-01-05 21:23 UTC (permalink / raw)
To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david
In-Reply-To: <20220105212338.49899-1-danielhb413@gmail.com>
From: Cédric Le Goater <clg@kaod.org>
PHB3s ared SysBus devices and should be allowed to be dynamically
created.
Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
hw/pci-host/pnv_phb3.c | 9 +++++++++
hw/ppc/pnv.c | 2 ++
2 files changed, 11 insertions(+)
diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c
index a52aedcad3..7fb35dc031 100644
--- a/hw/pci-host/pnv_phb3.c
+++ b/hw/pci-host/pnv_phb3.c
@@ -993,6 +993,9 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp)
/* User created devices */
if (!phb->chip) {
+ Error *local_err = NULL;
+ BusState *s;
+
phb->chip = pnv_get_chip(pnv, phb->chip_id);
if (!phb->chip) {
error_setg(errp, "invalid chip id: %d", phb->chip_id);
@@ -1004,6 +1007,12 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp)
* correctly the device tree.
*/
pnv_chip_parent_fixup(phb->chip, OBJECT(phb), phb->phb_id);
+
+ s = qdev_get_parent_bus(DEVICE(phb->chip));
+ if (!qdev_set_parent_bus(DEVICE(phb), s, &local_err)) {
+ error_propagate(errp, local_err);
+ return;
+ }
}
if (phb->phb_id >= PNV_CHIP_GET_CLASS(phb->chip)->num_phbs) {
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index fa5e7bc751..8dc6382357 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1941,6 +1941,8 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
+
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB3);
}
static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
--
2.33.1
^ permalink raw reply related
* [ndctl PATCH v3 02/16] ndctl/test: Prepare for BLK-aperture support removal
From: Dan Williams @ 2022-01-05 21:31 UTC (permalink / raw)
To: vishal.l.verma; +Cc: nvdimm, linux-cxl
In-Reply-To: <164141829899.3990253.17547886681174580434.stgit@dwillia2-desk3.amr.corp.intel.com>
The kernel is dropping its support for the BLK-aperture access method. The
primary side effect of this for nfit_test is that NVDIMM namespace labeling
will not be enabled by default. Update the unit tests to initialize the
label index area in this scenario.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
test/core.c | 31 ++++++++++++++++++++++++++++---
test/libndctl.c | 49 +++++++++++++++++++++++++++++++++++--------------
2 files changed, 63 insertions(+), 17 deletions(-)
diff --git a/test/core.c b/test/core.c
index 2b03aa9b3f2a..93e1dae5a144 100644
--- a/test/core.c
+++ b/test/core.c
@@ -261,8 +261,8 @@ retry:
ndctl_bus_foreach(nd_ctx, bus) {
struct ndctl_region *region;
- if (strncmp(ndctl_bus_get_provider(bus),
- "nfit_test", 9) != 0)
+ if (strcmp(ndctl_bus_get_provider(bus),
+ "nfit_test.0") != 0)
continue;
ndctl_region_foreach(bus, region)
ndctl_region_disable_invalidate(region);
@@ -280,5 +280,30 @@ retry:
NULL, NULL, NULL, NULL);
if (rc)
kmod_unref(*ctx);
- return rc;
+
+ if (!nd_ctx)
+ return rc;
+
+ ndctl_bus_foreach (nd_ctx, bus) {
+ struct ndctl_region *region;
+ struct ndctl_dimm *dimm;
+
+ if (strcmp(ndctl_bus_get_provider(bus), "nfit_test.0") != 0)
+ continue;
+
+ ndctl_region_foreach (bus, region)
+ ndctl_region_disable_invalidate(region);
+
+ ndctl_dimm_foreach (bus, dimm) {
+ ndctl_dimm_read_label_index(dimm);
+ ndctl_dimm_init_labels(dimm, NDCTL_NS_VERSION_1_2);
+ ndctl_dimm_disable(dimm);
+ ndctl_dimm_enable(dimm);
+ }
+
+ ndctl_region_foreach (bus, region)
+ ndctl_region_enable(region);
+ }
+
+ return 0;
}
diff --git a/test/libndctl.c b/test/libndctl.c
index 391b94086dae..0d6b9dd5b04b 100644
--- a/test/libndctl.c
+++ b/test/libndctl.c
@@ -2588,17 +2588,41 @@ static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,
return 0;
}
-static void reset_bus(struct ndctl_bus *bus)
+enum dimm_reset {
+ DIMM_INIT,
+ DIMM_ZERO,
+};
+
+static int reset_dimms(struct ndctl_bus *bus, enum dimm_reset reset)
{
- struct ndctl_region *region;
struct ndctl_dimm *dimm;
+ int rc = 0;
+
+ ndctl_dimm_foreach(bus, dimm) {
+ if (reset == DIMM_ZERO)
+ ndctl_dimm_zero_labels(dimm);
+ else {
+ ndctl_dimm_read_label_index(dimm);
+ ndctl_dimm_init_labels(dimm, NDCTL_NS_VERSION_1_2);
+ }
+ ndctl_dimm_disable(dimm);
+ rc = ndctl_dimm_enable(dimm);
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
+static void reset_bus(struct ndctl_bus *bus, enum dimm_reset reset)
+{
+ struct ndctl_region *region;
/* disable all regions so that set_config_data commands are permitted */
ndctl_region_foreach(bus, region)
ndctl_region_disable_invalidate(region);
- ndctl_dimm_foreach(bus, dimm)
- ndctl_dimm_zero_labels(dimm);
+ reset_dimms(bus, reset);
/* set regions back to their default state */
ndctl_region_foreach(bus, region)
@@ -2609,7 +2633,6 @@ static int do_test0(struct ndctl_ctx *ctx, struct ndctl_test *test)
{
struct ndctl_bus *bus = ndctl_bus_get_by_provider(ctx, NFIT_PROVIDER0);
struct ndctl_region *region;
- struct ndctl_dimm *dimm;
int rc;
if (!bus)
@@ -2626,13 +2649,10 @@ static int do_test0(struct ndctl_ctx *ctx, struct ndctl_test *test)
if (rc)
return rc;
- ndctl_dimm_foreach(bus, dimm) {
- rc = ndctl_dimm_zero_labels(dimm);
- if (rc < 0) {
- fprintf(stderr, "failed to zero %s\n",
- ndctl_dimm_get_devname(dimm));
- return rc;
- }
+ rc = reset_dimms(bus, DIMM_INIT);
+ if (rc < 0) {
+ fprintf(stderr, "failed to reset dimms\n");
+ return rc;
}
/*
@@ -2650,14 +2670,14 @@ static int do_test0(struct ndctl_ctx *ctx, struct ndctl_test *test)
rc = check_regions(bus, regions0, ARRAY_SIZE(regions0), DAX);
if (rc)
return rc;
- reset_bus(bus);
+ reset_bus(bus, DIMM_INIT);
}
if (ndctl_test_attempt(test, KERNEL_VERSION(4, 8, 0))) {
rc = check_regions(bus, regions0, ARRAY_SIZE(regions0), PFN);
if (rc)
return rc;
- reset_bus(bus);
+ reset_bus(bus, DIMM_INIT);
}
return check_regions(bus, regions0, ARRAY_SIZE(regions0), BTT);
@@ -2672,6 +2692,7 @@ static int do_test1(struct ndctl_ctx *ctx, struct ndctl_test *test)
return -ENXIO;
ndctl_bus_wait_probe(bus);
+ reset_bus(bus, DIMM_ZERO);
/*
* Starting with v4.10 the dimm on nfit_test.1 gets a unique
^ permalink raw reply related
* Re: [PATCH v5 00/11] Factorization of messages with similar meaning
From: Junio C Hamano @ 2022-01-05 21:31 UTC (permalink / raw)
To: Johannes Sixt
Cc: Jean-Noël Avila via GitGitGadget, git, Jeff King,
Ævar Arnfjörð Bjarmason, René Scharfe,
Jean-Noël Avila
In-Reply-To: <478ed4c7-467d-384d-b6d9-68956dc39c41@kdbg.org>
Johannes Sixt <j6t@kdbg.org> writes:
>> * Apply changes by René on tag.c
>> * cosmetic changes
>
> This round looks good to me, with one caveat: I am not a translator, nor
> do I use a translated version of Git. So, I haven't verified the claim
> that the number translatable strings was reduced greatly, nor whether
> there are any accidential duplicates due to typos. I infer the
> correctness only by looking at the changes.
Thanks, both. Will queue with a touch-up for that doubled SP.
^ permalink raw reply
* [ndctl PATCH v3 01/16] ndctl/docs: Clarify update-firwmware activation 'overflow' conditions
From: Dan Williams @ 2022-01-05 21:31 UTC (permalink / raw)
To: vishal.l.verma; +Cc: nvdimm, linux-cxl
In-Reply-To: <164141829899.3990253.17547886681174580434.stgit@dwillia2-desk3.amr.corp.intel.com>
Give examples and remediation for "overflow" events, i.e. where the
estimated time to complete activation exceeds the platform advertised
maximum. When that happens forced activation can lead to undefined results.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Documentation/ndctl/ndctl-update-firmware.txt | 64 +++++++++++++++++++++++++
1 file changed, 63 insertions(+), 1 deletion(-)
diff --git a/Documentation/ndctl/ndctl-update-firmware.txt b/Documentation/ndctl/ndctl-update-firmware.txt
index 1080d62a20b9..61664575f5b1 100644
--- a/Documentation/ndctl/ndctl-update-firmware.txt
+++ b/Documentation/ndctl/ndctl-update-firmware.txt
@@ -58,7 +58,69 @@ include::xable-bus-options.txt[]
Arm a device for firmware activation. This is enabled by default
when a firmware image is specified. Specify --no-arm to disable
this default. Otherwise, without a firmware image, this option can be
- used to manually arm a device for firmware activate.
+ used to manually arm a device for firmware activate. When a
+ device transitions from unarmed to armed the platform recalculates the
+ firmware activation time and compares it against the maximum platform
+ supported time. If the activation time would exceed the platform maximum the
+ arm attempt is aborted:
+
+[verse]
+ndctl update-firmware --arm --bus=nfit_test.0 all
+ Error: update firmware: nmem4: arm aborted, tripped overflow
+[
+ {
+ "dev":"nmem1",
+ "id":"cdab-0a-07e0-ffffffff",
+ "handle":"0",
+ "phys_id":"0",
+ "security":"disabled",
+ "firmware":{
+ "current_version":"0",
+ "can_update":true
+ }
+ },
+ {
+ "dev":"nmem3",
+ "id":"cdab-0a-07e0-fffeffff",
+ "handle":"0x100",
+ "phys_id":"0x2",
+ "security":"disabled",
+ "firmware":{
+ "current_version":"0",
+ "can_update":true
+ }
+ },
+ {
+ "dev":"nmem2",
+ "id":"cdab-0a-07e0-feffffff",
+ "handle":"0x1",
+ "phys_id":"0x1",
+ "security":"disabled",
+ "firmware":{
+ "current_version":"0",
+ "can_update":true
+ }
+ }
+]
+updated 3 nmems.
+
+ It is possible, but not recommended, to ignore timeout overflows
+ with the --force option. At any point to view the 'armed' state of the
+ bus do:
+
+[verse]
+ndctl list -BF -b nfit_test.0
+[
+ {
+ "provider":"nfit_test.0",
+ "dev":"ndbus2",
+ "scrub_state":"idle",
+ "firmware":{
+ "activate_method":"suspend",
+ "activate_state":"overflow"
+ }
+ }
+]
-D::
--disarm::
^ permalink raw reply related
* [ndctl PATCH v3 00/16] ndctl: Meson support
From: Dan Williams @ 2022-01-05 21:31 UTC (permalink / raw)
To: vishal.l.verma; +Cc: Vaibhav Jain, nvdimm, linux-cxl
Changes since v2 [1]:
- Rebase on v72
- Add Meson support for the new config file directory definitions.
- Add Meson support for landing the daxctl udev rule
daxdev-reconfigure service in the right directories
- Include the deprecation of BLK Aperture test infrastructure
- Include a miscellaneous doc clarification for 'ndctl update-firmware'
- Fix the tests support for moving the build directory out-of-line
- Include a fix for the deprectation of the dax_pmem_compat module
pending in the libnvdimm-for-next tree.
[1]: https://lore.kernel.org/r/163061537869.1943957.8491829881215255815.stgit@dwillia2-desk3.amr.corp.intel.com
---
As mentioned in patch 14 the motiviation for converting to Meson is
primarily driven by speed (an order of magnitude in some scenarios), but
Meson also includes better test and debug-build support. The build
language is easier to read, write, and debug. Meson is all around better
suited to the next phase of the ndctl project that will include all
things "device memory" related (ndctl, daxctl, and cxl).
In order to simplify the conversion the old BLK-aperture test
infrastructure is jettisoned and it will also be removed upstream. Some
other refactorings and fixups are included as well to better organize
the utilty infrastructure between truly common and sub-tool specific.
Vishal,
In preparation for ndctl-v73 please consider pulling in this series
early mainly for my own sanity of not needing to forward port more
updates to the autotools infrastructure.
---
Dan Williams (16):
ndctl/docs: Clarify update-firwmware activation 'overflow' conditions
ndctl/test: Prepare for BLK-aperture support removal
ndctl/test: Move 'reset()' to function in 'common'
ndctl/test: Initialize the label area by default
ndctl/test: Skip BLK flags checks
ndctl/test: Move sector-mode to a different region
ndctl: Deprecate BLK aperture support
ndctl/test: Fix support for missing dax_pmem_compat module
util: Distribute 'filter' and 'json' helpers to per-tool objects
Documentation: Drop attrs.adoc include
build: Drop unnecessary $tool/config.h includes
test: Prepare out of line builds
ndctl: Drop executable bit for bash-completion script
build: Add meson build infrastructure
build: Add meson rpmbuild support
ndctl: Jettison autotools
.gitignore | 64 -
Documentation/cxl/Makefile.am | 61 -
Documentation/cxl/lib/Makefile.am | 58 -
Documentation/cxl/lib/meson.build | 79 +
Documentation/cxl/meson.build | 84 +
Documentation/daxctl/Makefile.am | 75 -
Documentation/daxctl/daxctl-reconfigure-device.txt | 2
Documentation/daxctl/meson.build | 94 +
Documentation/ndctl/Makefile.am | 106 -
Documentation/ndctl/intel-nvdimm-security.txt | 2
Documentation/ndctl/labels-description.txt | 5
Documentation/ndctl/meson.build | 124 ++
Documentation/ndctl/ndctl-create-namespace.txt | 29
Documentation/ndctl/ndctl-init-labels.txt | 7
Documentation/ndctl/ndctl-list.txt | 4
Documentation/ndctl/ndctl-load-keys.txt | 2
Documentation/ndctl/ndctl-monitor.txt | 2
Documentation/ndctl/ndctl-sanitize-dimm.txt | 2
Documentation/ndctl/ndctl-setup-passphrase.txt | 2
Documentation/ndctl/ndctl-update-firmware.txt | 64 +
Documentation/ndctl/ndctl-update-passphrase.txt | 2
Documentation/ndctl/region-description.txt | 10
Makefile.am | 103 -
Makefile.am.in | 49 -
README.md | 1
autogen.sh | 28
clean_config.sh | 2
config.h.meson | 151 ++
configure.ac | 270 ----
contrib/meson.build | 28
contrib/ndctl | 0
contrib/nfit_test_depmod.conf | 1
cxl/Makefile.am | 22
cxl/filter.c | 25
cxl/filter.h | 7
cxl/json.c | 214 +++
cxl/json.h | 8
cxl/lib/Makefile.am | 32
cxl/lib/meson.build | 35
cxl/list.c | 4
cxl/memdev.c | 3
cxl/meson.build | 25
daxctl/Makefile.am | 40 -
daxctl/device.c | 5
daxctl/filter.c | 43 +
daxctl/filter.h | 12
daxctl/json.c | 245 +++
daxctl/json.h | 18
daxctl/lib/Makefile.am | 42 -
daxctl/lib/meson.build | 44 +
daxctl/list.c | 4
daxctl/meson.build | 35
daxctl/migrate.c | 1
meson.build | 286 ++++
meson_options.txt | 25
ndctl.spec.in | 15
ndctl/Makefile.am | 84 -
ndctl/bat.c | 5
ndctl/bus.c | 4
ndctl/check.c | 2
ndctl/dimm.c | 6
ndctl/filter.c | 60 -
ndctl/filter.h | 12
ndctl/inject-error.c | 6
ndctl/inject-smart.c | 6
ndctl/json-smart.c | 5
ndctl/json.c | 1114 ++++++++++++++
ndctl/json.h | 24
ndctl/keys.c | 6
ndctl/keys.h | 0
ndctl/lib/Makefile.am | 58 -
ndctl/lib/libndctl.c | 2
ndctl/lib/meson.build | 48 +
ndctl/lib/papr.c | 4
ndctl/lib/private.h | 4
ndctl/list.c | 5
ndctl/load-keys.c | 7
ndctl/meson.build | 82 +
ndctl/monitor.c | 5
ndctl/namespace.c | 6
ndctl/region.c | 3
ndctl/test.c | 11
rhel/meson.build | 22
rpmbuild.sh | 5
sles/meson.build | 35
test.h | 3
test/Makefile.am | 192 --
test/ack-shutdown-count-set.c | 2
test/blk-exhaust.sh | 32
test/blk_namespaces.c | 357 -----
test/btt-check.sh | 7
test/btt-errors.sh | 16
test/btt-pad-compat.sh | 9
test/clear.sh | 4
test/common | 59 +
test/core.c | 57 +
test/create.sh | 17
test/dax-pmd.c | 11
test/dax.sh | 6
test/daxctl-create.sh | 4
test/daxdev-errors.c | 2
test/daxdev-errors.sh | 8
test/device-dax-fio.sh | 2
test/device-dax.c | 2
test/dm.sh | 4
test/dpa-alloc.c | 326 ----
test/dsm-fail.c | 4
test/firmware-update.sh | 8
test/inject-error.sh | 7
test/inject-smart.sh | 2
test/label-compat.sh | 2
test/libndctl.c | 253 +--
test/list-smart-dimm.c | 6
test/max_available_extent_ns.sh | 9
test/meson.build | 237 +++
test/mmap.sh | 6
test/monitor.sh | 17
test/multi-dax.sh | 4
test/multi-pmem.c | 285 ----
test/parent-uuid.c | 254 ---
test/pfn-meta-errors.sh | 4
test/pmem-errors.sh | 12
test/pmem_namespaces.c | 2
test/rescan-partitions.sh | 7
test/revoke-devmem.c | 2
test/sector-mode.sh | 17
test/sub-section.sh | 4
test/track-uuid.sh | 6
tools/meson-vcs-tag.sh | 18
util/help.c | 2
util/json.c | 1542 --------------------
util/json.h | 39 -
util/meson.build | 16
version.h.in | 2
134 files changed, 3561 insertions(+), 4658 deletions(-)
delete mode 100644 Documentation/cxl/Makefile.am
delete mode 100644 Documentation/cxl/lib/Makefile.am
create mode 100644 Documentation/cxl/lib/meson.build
create mode 100644 Documentation/cxl/meson.build
delete mode 100644 Documentation/daxctl/Makefile.am
create mode 100644 Documentation/daxctl/meson.build
delete mode 100644 Documentation/ndctl/Makefile.am
create mode 100644 Documentation/ndctl/meson.build
delete mode 100644 Makefile.am
delete mode 100644 Makefile.am.in
delete mode 100755 autogen.sh
create mode 100755 clean_config.sh
create mode 100644 config.h.meson
delete mode 100644 configure.ac
create mode 100644 contrib/meson.build
mode change 100755 => 100644 contrib/ndctl
delete mode 100644 cxl/Makefile.am
create mode 100644 cxl/filter.c
create mode 100644 cxl/filter.h
create mode 100644 cxl/json.c
create mode 100644 cxl/json.h
delete mode 100644 cxl/lib/Makefile.am
create mode 100644 cxl/lib/meson.build
create mode 100644 cxl/meson.build
delete mode 100644 daxctl/Makefile.am
create mode 100644 daxctl/filter.c
create mode 100644 daxctl/filter.h
create mode 100644 daxctl/json.c
create mode 100644 daxctl/json.h
delete mode 100644 daxctl/lib/Makefile.am
create mode 100644 daxctl/lib/meson.build
create mode 100644 daxctl/meson.build
create mode 100644 meson.build
create mode 100644 meson_options.txt
delete mode 100644 ndctl/Makefile.am
rename util/filter.c => ndctl/filter.c (88%)
rename util/filter.h => ndctl/filter.h (89%)
rename ndctl/{util/json-smart.c => json-smart.c} (99%)
create mode 100644 ndctl/json.c
create mode 100644 ndctl/json.h
rename ndctl/{util/keys.c => keys.c} (99%)
rename ndctl/{util/keys.h => keys.h} (100%)
delete mode 100644 ndctl/lib/Makefile.am
create mode 100644 ndctl/lib/meson.build
create mode 100644 ndctl/meson.build
create mode 100644 rhel/meson.build
create mode 100644 sles/meson.build
delete mode 100644 test/Makefile.am
delete mode 100755 test/blk-exhaust.sh
delete mode 100644 test/blk_namespaces.c
delete mode 100644 test/dpa-alloc.c
create mode 100644 test/meson.build
delete mode 100644 test/multi-pmem.c
delete mode 100644 test/parent-uuid.c
create mode 100755 tools/meson-vcs-tag.sh
create mode 100644 util/meson.build
create mode 100644 version.h.in
base-commit: 25062cf34c70012f5d42ce1fef7e2dc129807c10
^ permalink raw reply
* [PATCH v2 3/3] prlimit: do not grab the tasklist_lock
From: Barret Rhoden @ 2022-01-05 21:28 UTC (permalink / raw)
To: ebiederm
Cc: Christian Brauner, Andrew Morton, Alexey Gladkov, William Cohen,
Viresh Kumar, Alexey Dobriyan, Chris Hyser, Peter Collingbourne,
Xiaofeng Cao, David Hildenbrand, Cyrill Gorcunov, linux-kernel
In-Reply-To: <20220105212828.197013-1-brho@google.com>
Unnecessarily grabbing the tasklist_lock can be a scalability bottleneck
for workloads that also must grab the tasklist_lock for waiting,
killing, and cloning.
The tasklist_lock was grabbed to protect tsk->sighand from disappearing
(becoming NULL). tsk->signal was already protected by holding a
reference to tsk.
update_rlimit_cpu() assumed tsk->sighand != NULL. With this commit, it
attempts to lock_task_sighand(). However, this means that
update_rlimit_cpu() can fail. This only happens when a task is exiting.
Note that during exec, sighand may *change*, but it will not be NULL.
Prior to this commit, the do_prlimit() ensured that update_rlimit_cpu()
would not fail by read locking the tasklist_lock and checking tsk->sighand
!= NULL.
If update_rlimit_cpu() fails, there may be other tasks that are not
exiting that share tsk->signal. We need to run update_rlimit_cpu() on
one of them. We can't "back out" the new rlim - once we unlocked
task_lock(group_leader), the rlim is essentially changed.
The only other caller of update_rlimit_cpu() is
selinux_bprm_committing_creds(). It has tsk == current, so
update_rlimit_cpu() cannot fail (current->sighand cannot disappear
until current exits).
This change resulted in a 14% speedup on a microbenchmark where parents
kill and wait on their children, and children getpriority, setpriority,
and getrlimit.
Signed-off-by: Barret Rhoden <brho@google.com>
---
include/linux/posix-timers.h | 2 +-
kernel/sys.c | 32 +++++++++++++++++++++-----------
kernel/time/posix-cpu-timers.c | 12 +++++++++---
3 files changed, 31 insertions(+), 15 deletions(-)
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
index 5bbcd280bfd2..9cf126c3b27f 100644
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -253,7 +253,7 @@ void posix_cpu_timers_exit_group(struct task_struct *task);
void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx,
u64 *newval, u64 *oldval);
-void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new);
+int update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new);
void posixtimer_rearm(struct kernel_siginfo *info);
#endif
diff --git a/kernel/sys.c b/kernel/sys.c
index fb2a5e7c0589..073ae9db192f 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1432,13 +1432,7 @@ static int do_prlimit(struct task_struct *tsk, unsigned int resource,
return -EPERM;
}
- /* protect tsk->signal and tsk->sighand from disappearing */
- read_lock(&tasklist_lock);
- if (!tsk->sighand) {
- retval = -ESRCH;
- goto out;
- }
-
+ /* Holding a refcount on tsk protects tsk->signal from disappearing. */
rlim = tsk->signal->rlim + resource;
task_lock(tsk->group_leader);
if (new_rlim) {
@@ -1467,10 +1461,26 @@ static int do_prlimit(struct task_struct *tsk, unsigned int resource,
*/
if (!retval && new_rlim && resource == RLIMIT_CPU &&
new_rlim->rlim_cur != RLIM_INFINITY &&
- IS_ENABLED(CONFIG_POSIX_TIMERS))
- update_rlimit_cpu(tsk, new_rlim->rlim_cur);
-out:
- read_unlock(&tasklist_lock);
+ IS_ENABLED(CONFIG_POSIX_TIMERS)) {
+ if (update_rlimit_cpu(tsk, new_rlim->rlim_cur)) {
+ /*
+ * update_rlimit_cpu can fail if the task is exiting.
+ * We already set the task group's rlim, so we need to
+ * update_rlimit_cpu for some other task in the process.
+ * If all of the tasks are exiting, then we don't need
+ * to update_rlimit_cpu.
+ */
+ struct task_struct *t_i;
+
+ rcu_read_lock();
+ for_each_thread(tsk, t_i) {
+ if (!update_rlimit_cpu(t_i, new_rlim->rlim_cur))
+ break;
+ }
+ rcu_read_unlock();
+ }
+ }
+
return retval;
}
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index 96b4e7810426..e13e628509fb 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -34,14 +34,20 @@ void posix_cputimers_group_init(struct posix_cputimers *pct, u64 cpu_limit)
* tsk->signal->posix_cputimers.bases[clock].nextevt expiration cache if
* necessary. Needs siglock protection since other code may update the
* expiration cache as well.
+ *
+ * Returns 0 on success, -ESRCH on failure. Can fail if the task is exiting and
+ * we cannot lock_task_sighand. Cannot fail if task is current.
*/
-void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new)
+int update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new)
{
u64 nsecs = rlim_new * NSEC_PER_SEC;
+ unsigned long irq_fl;
- spin_lock_irq(&task->sighand->siglock);
+ if (!lock_task_sighand(task, &irq_fl))
+ return -ESRCH;
set_process_cpu_timer(task, CPUCLOCK_PROF, &nsecs, NULL);
- spin_unlock_irq(&task->sighand->siglock);
+ unlock_task_sighand(task, &irq_fl);
+ return 0;
}
/*
--
2.34.1.448.ga2b2bfdf31-goog
^ permalink raw reply related
* [PATCH v2 2/3] prlimit: make do_prlimit() static
From: Barret Rhoden @ 2022-01-05 21:28 UTC (permalink / raw)
To: ebiederm
Cc: Christian Brauner, Andrew Morton, Alexey Gladkov, William Cohen,
Viresh Kumar, Alexey Dobriyan, Chris Hyser, Peter Collingbourne,
Xiaofeng Cao, David Hildenbrand, Cyrill Gorcunov, linux-kernel
In-Reply-To: <20220105212828.197013-1-brho@google.com>
There are no other callers in the kernel.
Fixed up a comment format and whitespace issue when moving do_prlimit()
higher in sys.c.
Signed-off-by: Barret Rhoden <brho@google.com>
---
include/linux/resource.h | 2 -
kernel/sys.c | 116 ++++++++++++++++++++-------------------
2 files changed, 59 insertions(+), 59 deletions(-)
diff --git a/include/linux/resource.h b/include/linux/resource.h
index bdf491cbcab7..4fdbc0c3f315 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -8,7 +8,5 @@
struct task_struct;
void getrusage(struct task_struct *p, int who, struct rusage *ru);
-int do_prlimit(struct task_struct *tsk, unsigned int resource,
- struct rlimit *new_rlim, struct rlimit *old_rlim);
#endif
diff --git a/kernel/sys.c b/kernel/sys.c
index 558e52fa5bbd..fb2a5e7c0589 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1415,6 +1415,65 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len)
return errno;
}
+/* make sure you are allowed to change @tsk limits before calling this */
+static int do_prlimit(struct task_struct *tsk, unsigned int resource,
+ struct rlimit *new_rlim, struct rlimit *old_rlim)
+{
+ struct rlimit *rlim;
+ int retval = 0;
+
+ if (resource >= RLIM_NLIMITS)
+ return -EINVAL;
+ if (new_rlim) {
+ if (new_rlim->rlim_cur > new_rlim->rlim_max)
+ return -EINVAL;
+ if (resource == RLIMIT_NOFILE &&
+ new_rlim->rlim_max > sysctl_nr_open)
+ return -EPERM;
+ }
+
+ /* protect tsk->signal and tsk->sighand from disappearing */
+ read_lock(&tasklist_lock);
+ if (!tsk->sighand) {
+ retval = -ESRCH;
+ goto out;
+ }
+
+ rlim = tsk->signal->rlim + resource;
+ task_lock(tsk->group_leader);
+ if (new_rlim) {
+ /*
+ * Keep the capable check against init_user_ns until cgroups can
+ * contain all limits.
+ */
+ if (new_rlim->rlim_max > rlim->rlim_max &&
+ !capable(CAP_SYS_RESOURCE))
+ retval = -EPERM;
+ if (!retval)
+ retval = security_task_setrlimit(tsk, resource, new_rlim);
+ }
+ if (!retval) {
+ if (old_rlim)
+ *old_rlim = *rlim;
+ if (new_rlim)
+ *rlim = *new_rlim;
+ }
+ task_unlock(tsk->group_leader);
+
+ /*
+ * RLIMIT_CPU handling. Arm the posix CPU timer if the limit is not
+ * infinite. In case of RLIM_INFINITY the posix CPU timer code
+ * ignores the rlimit.
+ */
+ if (!retval && new_rlim && resource == RLIMIT_CPU &&
+ new_rlim->rlim_cur != RLIM_INFINITY &&
+ IS_ENABLED(CONFIG_POSIX_TIMERS))
+ update_rlimit_cpu(tsk, new_rlim->rlim_cur);
+out:
+ read_unlock(&tasklist_lock);
+ return retval;
+}
+
SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim)
{
struct rlimit value;
@@ -1558,63 +1617,6 @@ static void rlim64_to_rlim(const struct rlimit64 *rlim64, struct rlimit *rlim)
rlim->rlim_max = (unsigned long)rlim64->rlim_max;
}
-/* make sure you are allowed to change @tsk limits before calling this */
-int do_prlimit(struct task_struct *tsk, unsigned int resource,
- struct rlimit *new_rlim, struct rlimit *old_rlim)
-{
- struct rlimit *rlim;
- int retval = 0;
-
- if (resource >= RLIM_NLIMITS)
- return -EINVAL;
- if (new_rlim) {
- if (new_rlim->rlim_cur > new_rlim->rlim_max)
- return -EINVAL;
- if (resource == RLIMIT_NOFILE &&
- new_rlim->rlim_max > sysctl_nr_open)
- return -EPERM;
- }
-
- /* protect tsk->signal and tsk->sighand from disappearing */
- read_lock(&tasklist_lock);
- if (!tsk->sighand) {
- retval = -ESRCH;
- goto out;
- }
-
- rlim = tsk->signal->rlim + resource;
- task_lock(tsk->group_leader);
- if (new_rlim) {
- /* Keep the capable check against init_user_ns until
- cgroups can contain all limits */
- if (new_rlim->rlim_max > rlim->rlim_max &&
- !capable(CAP_SYS_RESOURCE))
- retval = -EPERM;
- if (!retval)
- retval = security_task_setrlimit(tsk, resource, new_rlim);
- }
- if (!retval) {
- if (old_rlim)
- *old_rlim = *rlim;
- if (new_rlim)
- *rlim = *new_rlim;
- }
- task_unlock(tsk->group_leader);
-
- /*
- * RLIMIT_CPU handling. Arm the posix CPU timer if the limit is not
- * infinite. In case of RLIM_INFINITY the posix CPU timer code
- * ignores the rlimit.
- */
- if (!retval && new_rlim && resource == RLIMIT_CPU &&
- new_rlim->rlim_cur != RLIM_INFINITY &&
- IS_ENABLED(CONFIG_POSIX_TIMERS))
- update_rlimit_cpu(tsk, new_rlim->rlim_cur);
-out:
- read_unlock(&tasklist_lock);
- return retval;
-}
-
/* rcu lock must be held */
static int check_prlimit_permission(struct task_struct *task,
unsigned int flags)
--
2.34.1.448.ga2b2bfdf31-goog
^ permalink raw reply related
* [PATCH v2 1/3] setpriority: only grab the tasklist_lock for PRIO_PGRP
From: Barret Rhoden @ 2022-01-05 21:28 UTC (permalink / raw)
To: ebiederm
Cc: Christian Brauner, Andrew Morton, Alexey Gladkov, William Cohen,
Viresh Kumar, Alexey Dobriyan, Chris Hyser, Peter Collingbourne,
Xiaofeng Cao, David Hildenbrand, Cyrill Gorcunov, linux-kernel
In-Reply-To: <20220105212828.197013-1-brho@google.com>
The tasklist_lock is necessary only for PRIO_PGRP for both setpriority()
and getpriority().
Unnecessarily grabbing the tasklist_lock can be a scalability bottleneck
for workloads that also must grab the tasklist_lock for waiting,
killing, and cloning.
This change resulted in a 12% speedup on a microbenchmark where parents
kill and wait on their children, and children getpriority, setpriority,
and getrlimit.
Signed-off-by: Barret Rhoden <brho@google.com>
---
kernel/sys.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/kernel/sys.c b/kernel/sys.c
index 8fdac0d90504..558e52fa5bbd 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -220,7 +220,6 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
niceval = MAX_NICE;
rcu_read_lock();
- read_lock(&tasklist_lock);
switch (which) {
case PRIO_PROCESS:
if (who)
@@ -231,6 +230,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
error = set_one_prio(p, niceval, error);
break;
case PRIO_PGRP:
+ read_lock(&tasklist_lock);
if (who)
pgrp = find_vpid(who);
else
@@ -238,6 +238,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
error = set_one_prio(p, niceval, error);
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
+ read_unlock(&tasklist_lock);
break;
case PRIO_USER:
uid = make_kuid(cred->user_ns, who);
@@ -258,7 +259,6 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
break;
}
out_unlock:
- read_unlock(&tasklist_lock);
rcu_read_unlock();
out:
return error;
@@ -283,7 +283,6 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
return -EINVAL;
rcu_read_lock();
- read_lock(&tasklist_lock);
switch (which) {
case PRIO_PROCESS:
if (who)
@@ -297,6 +296,7 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
}
break;
case PRIO_PGRP:
+ read_lock(&tasklist_lock);
if (who)
pgrp = find_vpid(who);
else
@@ -306,6 +306,7 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
if (niceval > retval)
retval = niceval;
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
+ read_unlock(&tasklist_lock);
break;
case PRIO_USER:
uid = make_kuid(cred->user_ns, who);
@@ -329,7 +330,6 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
break;
}
out_unlock:
- read_unlock(&tasklist_lock);
rcu_read_unlock();
return retval;
--
2.34.1.448.ga2b2bfdf31-goog
^ permalink raw reply related
* [PATCH v2 0/3] prlimit and set/getpriority tasklist_lock optimizations
From: Barret Rhoden @ 2022-01-05 21:28 UTC (permalink / raw)
To: ebiederm
Cc: Christian Brauner, Andrew Morton, Alexey Gladkov, William Cohen,
Viresh Kumar, Alexey Dobriyan, Chris Hyser, Peter Collingbourne,
Xiaofeng Cao, David Hildenbrand, Cyrill Gorcunov, linux-kernel
The tasklist_lock popped up as a scalability bottleneck on some testing
workloads. The readlocks in do_prlimit and set/getpriority are not
necessary in all cases.
Based on a cycles profile, it looked like ~87% of the time was spent in
the kernel, ~42% of which was just trying to get *some* spinlock
(queued_spin_lock_slowpath, not necessarily the tasklist_lock).
The big offenders (with rough percentages in cycles of the overall trace):
- do_wait 11%
- setpriority 8% (this patchset)
- kill 8%
- do_exit 5%
- clone 3%
- prlimit64 2% (this patchset)
- getrlimit 1% (this patchset)
I can't easily test this patchset on the original workload for various
reasons. Instead, I used the microbenchmark below to at least verify
there was some improvement. This patchset had a 28% speedup (12% from
baseline to set/getprio, then another 14% for prlimmit).
One interesting thing is that my libc's getrlimit() was calling
prlimit64, so hoisting the read_lock(tasklist_lock) into sys_prlimit64
had no effect - it essentially optimized the older syscalls only. I
didn't do that in this patchset, but figured I'd mention it since it was
an option from the previous patch's discussion.
v1: https://lore.kernel.org/lkml/20211213220401.1039578-1-brho@google.com/
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
pid_t child;
struct rlimit rlim[1];
fork(); fork(); fork(); fork(); fork(); fork();
for (int i = 0; i < 5000; i++) {
child = fork();
if (child < 0)
exit(1);
if (child > 0) {
usleep(1000);
kill(child, SIGTERM);
waitpid(child, NULL, 0);
} else {
for (;;) {
setpriority(PRIO_PROCESS, 0,
getpriority(PRIO_PROCESS, 0));
getrlimit(RLIMIT_CPU, rlim);
}
}
}
return 0;
}
Barret Rhoden (3):
setpriority: only grab the tasklist_lock for PRIO_PGRP
prlimit: make do_prlimit() static
prlimit: do not grab the tasklist_lock
include/linux/posix-timers.h | 2 +-
include/linux/resource.h | 2 -
kernel/sys.c | 134 ++++++++++++++++++---------------
kernel/time/posix-cpu-timers.c | 12 ++-
4 files changed, 83 insertions(+), 67 deletions(-)
--
2.34.1.448.ga2b2bfdf31-goog
^ permalink raw reply
* Re: [lttng-dev] [RELEASE] LTTng-UST 2.12.3 and 2.11.5 (Linux user-space tracer)
From: Mathieu Desnoyers via lttng-dev @ 2022-01-05 21:31 UTC (permalink / raw)
To: lttng-dev, Diamon discuss, linux-trace-users
In-Reply-To: <697935027.5550.1641418043715.JavaMail.zimbra@efficios.com>
----- On Jan 5, 2022, at 4:27 PM, Mathieu Desnoyers mathieu.desnoyers@efficios.com wrote:
> Hi,
>
> This is a release announcement for the LTTng-UST 2.12.3 and 2.11.5
> tracer. Those are bug fix releases.
>
> The 2.11.5 release marks the end of life (EOL) of the stable-2.11 branch.
> Users experiencing issues with the 2.11 branch are expected to upgrade to
> either 2.12.3 or 2.13.1.
>
> Note that the latest stable branch is 2.13 (its most recent release
> is 2.13.1, released on December 10, 2021).
>
> * Notable changes in 2.12.3:
>
> Two notable fixes are "Fix: nestable pthread cancelstate" and
> "Fix: abort on decrement_sem_count during concurrent tracing start and
> teardown",
> which fix a rare deadlock scenario at application exit.
Just as a clarification, the second fix corrects a race scenario triggering an
assertion failure.
Thanks,
MAthieu
>
> Another notable fix is "fix: liblttng-ust-fd async-signal-safe close()", which
> ensures that the implementation of the symbol interposition for "close" is
> async-signal safe, as it should be.
>
> Please refer to the change logs below for the fixes contained in those
> two releases.
>
> Feedback is welcome,
>
> Thanks,
>
> Mathieu
>
> Project website: https://lttng.org
> Documentation: https://lttng.org/docs
> Download link: https://lttng.org/download
>
>
> 2022-01-05 (National Bird Day) lttng-ust 2.12.3
> * Fix: ust-cancelstate: include string.h for strerror
> * Fix: lttng-ust-fd: remove lttng_ust_common_ctor call
> * Fix: nestable pthread cancelstate
> * Fix: abort on decrement_sem_count during concurrent tracing start and teardown
> * fix: liblttng-ust-fd async-signal-safe close()
> * Set git-review branch to stable-2.12
> * fix: link benchmark with pthread
> * Fix: liblttng-ust-ctl have dependencies on liburcu
> * Fix: add extern "C" to two header files
>
> 2022-01-05 (National Bird Day) lttng-ust 2.11.5
> * Set git-review branch to stable-2.11
> * fix: allow building with userspace-rcu 0.13
>
> --
> Mathieu Desnoyers
> EfficiOS Inc.
> http://www.efficios.com
--
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
_______________________________________________
lttng-dev mailing list
lttng-dev@lists.lttng.org
https://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
^ permalink raw reply
* [PATCH v2 17/18] ppc/pnv: Introduce user creatable pnv-phb4 devices
From: Daniel Henrique Barboza @ 2022-01-05 21:23 UTC (permalink / raw)
To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david
In-Reply-To: <20220105212338.49899-1-danielhb413@gmail.com>
This patch introduces pnv-phb4 user creatable devices that are created
in a similar manner as pnv-phb3 devices, allowing the user to interact
with the PHBs directly instead of creating PCI Express Controllers that
will create a certain amount of PHBs per controller index.
First thing we need is to discover which stack will host the created
PHB, which is done by the new pnv_phb4_get_stack() function. During
pnv_phb4_realize() we'll inspect phb->stack to see if we're dealing with
an user creatable device or not. When using default settings, the
automatically created PHB4 devices will be realized with phb->stack
already assigned beforehand during PEC realize. In case we're dealing
with an user device, find its stack, set the PHB attributes based on the
stack it belongs and assign the PHB to the stack.
The xscom stack initialization takes place in pnv_pec_stk_realize() when
using default settings, but at that point we aren't aware of any user
PHB4 devices that will belong to the stack. In that case we'll postpone
xscom stack init until the the end of pnv_phb4_realize(), after all the
memory mappings of the PHB are done.
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
hw/pci-host/pnv_phb4.c | 84 +++++++++++++++++++++++++++++++++++++-
hw/pci-host/pnv_phb4_pec.c | 12 +++---
hw/ppc/pnv.c | 2 +
3 files changed, 90 insertions(+), 8 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 430a5c10f4..1c2334d491 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -1236,6 +1236,41 @@ static void pnv_phb4_instance_init(Object *obj)
object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE);
}
+static PnvPhb4PecStack *pnv_phb4_get_stack(PnvChip *chip, PnvPHB4 *phb,
+ Error **errp)
+{
+ Pnv9Chip *chip9 = NULL;
+ int chip_id = phb->chip_id;
+ int index = phb->phb_id;
+ int i, j;
+
+ if (chip->num_pecs == 0) {
+ /* Something weird happened. Bail out */
+ error_setg(errp, "chip id %d has no PCIE controllers", chip_id);
+ return NULL;
+ }
+
+ chip9 = PNV9_CHIP(chip);
+
+ for (i = 0; i < chip->num_pecs; i++) {
+ /*
+ * For each PEC, check the amount of stacks it supports
+ * and see if the given phb4 index matches a stack.
+ */
+ PnvPhb4PecState *pec = &chip9->pecs[i];
+
+ for (j = 0; j < pec->num_stacks; j++) {
+ if (index == pnv_phb4_pec_get_phb_id(pec, j)) {
+ return &pec->stacks[j];
+ }
+ }
+ }
+
+ error_setg(errp, "pnv-phb4 index %d didn't match any existing PEC",
+ chip_id);
+ return NULL;
+}
+
static void pnv_phb4_realize(DeviceState *dev, Error **errp)
{
PnvPHB4 *phb = PNV_PHB4(dev);
@@ -1243,8 +1278,49 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
XiveSource *xsrc = &phb->xsrc;
int nr_irqs;
char name[32];
+ PnvPhb4PecStack *stack = NULL;
+ bool stack_init_xscom = false;
+ Error *local_err = NULL;
- assert(phb->stack);
+ /* User created PHB */
+ if (!phb->stack) {
+ PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
+ PnvChip *chip = pnv_get_chip(pnv, phb->chip_id);
+ BusState *s;
+
+ if (!chip) {
+ error_setg(errp, "invalid chip id: %d", phb->chip_id);
+ return;
+ }
+
+ stack = pnv_phb4_get_stack(chip, phb, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ object_property_set_int(OBJECT(phb), "index",
+ phb->phb_id, &error_abort);
+
+ pnv_phb4_set_stack_phb_props(stack, phb);
+
+ /* Assign the phb to the stack */
+ stack->phb = phb;
+
+ /*
+ * Reparent user created devices to the chip to build
+ * correctly the device tree.
+ */
+ pnv_chip_parent_fixup(chip, OBJECT(phb), phb->phb_id);
+
+ s = qdev_get_parent_bus(DEVICE(chip));
+ if (!qdev_set_parent_bus(DEVICE(phb), s, &local_err)) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ stack_init_xscom = true;
+ }
/* Set the "big_phb" flag */
phb->big_phb = phb->phb_id == 0 || phb->phb_id == 3;
@@ -1298,6 +1374,10 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
pnv_phb4_update_xsrc(phb);
phb->qirqs = qemu_allocate_irqs(xive_source_set_irq, xsrc, xsrc->nr_irqs);
+
+ if (stack_init_xscom) {
+ pnv_pec_init_stack_xscom(stack);
+ }
}
static const char *pnv_phb4_root_bus_path(PCIHostState *host_bridge,
@@ -1347,7 +1427,7 @@ static void pnv_phb4_class_init(ObjectClass *klass, void *data)
dc->realize = pnv_phb4_realize;
device_class_set_props(dc, pnv_phb4_properties);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->user_creatable = false;
+ dc->user_creatable = true;
xfc->notify = pnv_phb4_xive_notify;
}
diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c
index 41c79d24c4..4417beb97d 100644
--- a/hw/pci-host/pnv_phb4_pec.c
+++ b/hw/pci-host/pnv_phb4_pec.c
@@ -573,13 +573,13 @@ static void pnv_pec_stk_realize(DeviceState *dev, Error **errp)
&pnv_pec_stk_pci_xscom_ops, stack, name,
PHB4_PEC_PCI_STK_REGS_COUNT);
- /* PHB pass-through */
- pnv_phb4_set_stack_phb_props(stack, stack->phb);
- if (!sysbus_realize(SYS_BUS_DEVICE(&stack->phb), errp)) {
- return;
+ /*
+ * There is no guarantee that stack->phb will be available
+ * at this point.
+ */
+ if (stack->phb) {
+ pnv_pec_init_stack_xscom(stack);
}
-
- pnv_pec_init_stack_xscom(stack);
}
static Property pnv_pec_stk_properties[] = {
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index fe7e67e73a..837146a2fb 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1960,6 +1960,8 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
pmc->dt_power_mgt = pnv_dt_power_mgt;
+
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB4);
}
static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
--
2.33.1
^ permalink raw reply related
* Re: [PATCH] rlimits: do not grab tasklist_lock for do_prlimit on current
From: Barret Rhoden @ 2022-01-05 21:31 UTC (permalink / raw)
To: Eric W. Biederman
Cc: Christian Brauner, Andrew Morton, Alexey Gladkov, William Cohen,
Viresh Kumar, Alexey Dobriyan, Chris Hyser, Peter Collingbourne,
Xiaofeng Cao, David Hildenbrand, Cyrill Gorcunov, linux-kernel
In-Reply-To: <87zgp1psd3.fsf@email.froward.int.ebiederm.org>
On 12/15/21 14:42, Eric W. Biederman wrote:
> In update_rlimit_cpu use lock_task_sighand instead of unconditionally
> grabbing sighand->siglock (because without tasklist_lock sighand might
> be NULL).
this ended up being a minor complication, since update_rlimit_cpu()
could fail if the task was exiting, but i think i sorted it out.
i'll send out revised patchset shortly with this change, including
making do_prlimit() static.
thanks,
barret
^ permalink raw reply
* Re: [RELEASE] LTTng-UST 2.12.3 and 2.11.5 (Linux user-space tracer)
From: Mathieu Desnoyers @ 2022-01-05 21:31 UTC (permalink / raw)
To: lttng-dev, Diamon discuss, linux-trace-users
In-Reply-To: <697935027.5550.1641418043715.JavaMail.zimbra@efficios.com>
----- On Jan 5, 2022, at 4:27 PM, Mathieu Desnoyers mathieu.desnoyers@efficios.com wrote:
> Hi,
>
> This is a release announcement for the LTTng-UST 2.12.3 and 2.11.5
> tracer. Those are bug fix releases.
>
> The 2.11.5 release marks the end of life (EOL) of the stable-2.11 branch.
> Users experiencing issues with the 2.11 branch are expected to upgrade to
> either 2.12.3 or 2.13.1.
>
> Note that the latest stable branch is 2.13 (its most recent release
> is 2.13.1, released on December 10, 2021).
>
> * Notable changes in 2.12.3:
>
> Two notable fixes are "Fix: nestable pthread cancelstate" and
> "Fix: abort on decrement_sem_count during concurrent tracing start and
> teardown",
> which fix a rare deadlock scenario at application exit.
Just as a clarification, the second fix corrects a race scenario triggering an
assertion failure.
Thanks,
MAthieu
>
> Another notable fix is "fix: liblttng-ust-fd async-signal-safe close()", which
> ensures that the implementation of the symbol interposition for "close" is
> async-signal safe, as it should be.
>
> Please refer to the change logs below for the fixes contained in those
> two releases.
>
> Feedback is welcome,
>
> Thanks,
>
> Mathieu
>
> Project website: https://lttng.org
> Documentation: https://lttng.org/docs
> Download link: https://lttng.org/download
>
>
> 2022-01-05 (National Bird Day) lttng-ust 2.12.3
> * Fix: ust-cancelstate: include string.h for strerror
> * Fix: lttng-ust-fd: remove lttng_ust_common_ctor call
> * Fix: nestable pthread cancelstate
> * Fix: abort on decrement_sem_count during concurrent tracing start and teardown
> * fix: liblttng-ust-fd async-signal-safe close()
> * Set git-review branch to stable-2.12
> * fix: link benchmark with pthread
> * Fix: liblttng-ust-ctl have dependencies on liburcu
> * Fix: add extern "C" to two header files
>
> 2022-01-05 (National Bird Day) lttng-ust 2.11.5
> * Set git-review branch to stable-2.11
> * fix: allow building with userspace-rcu 0.13
>
> --
> Mathieu Desnoyers
> EfficiOS Inc.
> http://www.efficios.com
--
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply
* Re: [diamon-discuss] [RELEASE] LTTng-UST 2.12.3 and 2.11.5 (Linux user-space tracer)
From: Mathieu Desnoyers @ 2022-01-05 21:31 UTC (permalink / raw)
To: lttng-dev, Diamon discuss, linux-trace-users
In-Reply-To: <697935027.5550.1641418043715.JavaMail.zimbra@efficios.com>
----- On Jan 5, 2022, at 4:27 PM, Mathieu Desnoyers mathieu.desnoyers@efficios.com wrote:
> Hi,
>
> This is a release announcement for the LTTng-UST 2.12.3 and 2.11.5
> tracer. Those are bug fix releases.
>
> The 2.11.5 release marks the end of life (EOL) of the stable-2.11 branch.
> Users experiencing issues with the 2.11 branch are expected to upgrade to
> either 2.12.3 or 2.13.1.
>
> Note that the latest stable branch is 2.13 (its most recent release
> is 2.13.1, released on December 10, 2021).
>
> * Notable changes in 2.12.3:
>
> Two notable fixes are "Fix: nestable pthread cancelstate" and
> "Fix: abort on decrement_sem_count during concurrent tracing start and
> teardown",
> which fix a rare deadlock scenario at application exit.
Just as a clarification, the second fix corrects a race scenario triggering an
assertion failure.
Thanks,
MAthieu
>
> Another notable fix is "fix: liblttng-ust-fd async-signal-safe close()", which
> ensures that the implementation of the symbol interposition for "close" is
> async-signal safe, as it should be.
>
> Please refer to the change logs below for the fixes contained in those
> two releases.
>
> Feedback is welcome,
>
> Thanks,
>
> Mathieu
>
> Project website: https://lttng.org
> Documentation: https://lttng.org/docs
> Download link: https://lttng.org/download
>
>
> 2022-01-05 (National Bird Day) lttng-ust 2.12.3
> * Fix: ust-cancelstate: include string.h for strerror
> * Fix: lttng-ust-fd: remove lttng_ust_common_ctor call
> * Fix: nestable pthread cancelstate
> * Fix: abort on decrement_sem_count during concurrent tracing start and teardown
> * fix: liblttng-ust-fd async-signal-safe close()
> * Set git-review branch to stable-2.12
> * fix: link benchmark with pthread
> * Fix: liblttng-ust-ctl have dependencies on liburcu
> * Fix: add extern "C" to two header files
>
> 2022-01-05 (National Bird Day) lttng-ust 2.11.5
> * Set git-review branch to stable-2.11
> * fix: allow building with userspace-rcu 0.13
>
> --
> Mathieu Desnoyers
> EfficiOS Inc.
> http://www.efficios.com
--
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply
* stable-rc/queue/4.9 baseline: 132 runs, 2 regressions (v4.9.295-13-g1d9484cc9e1a)
From: kernelci.org bot @ 2022-01-05 21:30 UTC (permalink / raw)
To: stable, kernel-build-reports, kernelci-results
stable-rc/queue/4.9 baseline: 132 runs, 2 regressions (v4.9.295-13-g1d9484cc9e1a)
Regressions Summary
-------------------
platform | arch | lab | compiler | defconfig | regressions
----------+------+---------------+----------+---------------------+------------
beagle-xm | arm | lab-baylibre | gcc-10 | omap2plus_defconfig | 1
panda | arm | lab-collabora | gcc-10 | omap2plus_defconfig | 1
Details: https://kernelci.org/test/job/stable-rc/branch/queue%2F4.9/kernel/v4.9.295-13-g1d9484cc9e1a/plan/baseline/
Test: baseline
Tree: stable-rc
Branch: queue/4.9
Describe: v4.9.295-13-g1d9484cc9e1a
URL: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git
SHA: 1d9484cc9e1a4df669a3985ac43ca6818c88cfc7
Test Regressions
----------------
platform | arch | lab | compiler | defconfig | regressions
----------+------+---------------+----------+---------------------+------------
beagle-xm | arm | lab-baylibre | gcc-10 | omap2plus_defconfig | 1
Details: https://kernelci.org/test/plan/id/61d5d9afec6a0c5e42ef675d
Results: 0 PASS, 1 FAIL, 0 SKIP
Full config: omap2plus_defconfig
Compiler: gcc-10 (arm-linux-gnueabihf-gcc (Debian 10.2.1-6) 10.2.1 20210110)
Plain log: https://storage.kernelci.org//stable-rc/queue-4.9/v4.9.295-13-g1d9484cc9e1a/arm/omap2plus_defconfig/gcc-10/lab-baylibre/baseline-beagle-xm.txt
HTML log: https://storage.kernelci.org//stable-rc/queue-4.9/v4.9.295-13-g1d9484cc9e1a/arm/omap2plus_defconfig/gcc-10/lab-baylibre/baseline-beagle-xm.html
Rootfs: http://storage.kernelci.org/images/rootfs/buildroot/buildroot-baseline/20211210.0/armel/rootfs.cpio.gz
* baseline.login: https://kernelci.org/test/case/id/61d5d9afec6a0c5e42ef675e
new failure (last pass: v4.9.295-13-gf65af3015b1d)
platform | arch | lab | compiler | defconfig | regressions
----------+------+---------------+----------+---------------------+------------
panda | arm | lab-collabora | gcc-10 | omap2plus_defconfig | 1
Details: https://kernelci.org/test/plan/id/61d5d8ea962da349e8ef6760
Results: 4 PASS, 1 FAIL, 1 SKIP
Full config: omap2plus_defconfig
Compiler: gcc-10 (arm-linux-gnueabihf-gcc (Debian 10.2.1-6) 10.2.1 20210110)
Plain log: https://storage.kernelci.org//stable-rc/queue-4.9/v4.9.295-13-g1d9484cc9e1a/arm/omap2plus_defconfig/gcc-10/lab-collabora/baseline-panda.txt
HTML log: https://storage.kernelci.org//stable-rc/queue-4.9/v4.9.295-13-g1d9484cc9e1a/arm/omap2plus_defconfig/gcc-10/lab-collabora/baseline-panda.html
Rootfs: http://storage.kernelci.org/images/rootfs/buildroot/buildroot-baseline/20211210.0/armel/rootfs.cpio.gz
* baseline.dmesg.emerg: https://kernelci.org/test/case/id/61d5d8eb962da349e8ef6763
failing since 8 days (last pass: v4.9.294-8-gdf4b9763cd1e, first fail: v4.9.294-18-gaa81ab4e03f9)
2 lines
2022-01-05T17:43:51.626740 kern :emerg : BUG: spinlock bad magic on CPU#0, mmcqd/0/83
2022-01-05T17:43:51.635966 kern :emerg : lock: emif_lock+0x0/0xfffff230 [emif], .magic: dead4ead, .owner: <none>/-1, .owner_cpu: -1
^ permalink raw reply
* [PATCH v2 04/18] pnv_phb4.c: make pnv-phb4-root-port user creatable
From: Daniel Henrique Barboza @ 2022-01-05 21:23 UTC (permalink / raw)
To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david
In-Reply-To: <20220105212338.49899-1-danielhb413@gmail.com>
We want to create only the absolutely minimal amount of devices when
running with -nodefaults. The root port is something that the machine
can boot up without. But, to do that, we need to provide a way for the
user to add them by hand.
This patch makes pnv-phb4-root-port user creatable and then uses the
pnv_phb_attach_root_port() helper to add a pnv_phb4_root_port only when
running with default settings.
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
hw/pci-host/pnv_phb4.c | 18 +++++++-----------
include/hw/pci-host/pnv_phb4.h | 2 --
2 files changed, 7 insertions(+), 13 deletions(-)
diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c
index 836b0c156c..14827f8464 100644
--- a/hw/pci-host/pnv_phb4.c
+++ b/hw/pci-host/pnv_phb4.c
@@ -22,6 +22,7 @@
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "qom/object.h"
+#include "sysemu/sysemu.h"
#include "trace.h"
#define phb_error(phb, fmt, ...) \
@@ -1159,12 +1160,6 @@ static void pnv_phb4_instance_init(Object *obj)
/* XIVE interrupt source object */
object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE);
-
- /* Root Port */
- object_initialize_child(obj, "root", &phb->root, TYPE_PNV_PHB4_ROOT_PORT);
-
- qdev_prop_set_int32(DEVICE(&phb->root), "addr", PCI_DEVFN(0, 0));
- qdev_prop_set_bit(DEVICE(&phb->root), "multifunction", false);
}
static void pnv_phb4_realize(DeviceState *dev, Error **errp)
@@ -1208,10 +1203,11 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
pci_setup_iommu(pci->bus, pnv_phb4_dma_iommu, phb);
pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE;
- /* Add a single Root port */
- qdev_prop_set_uint8(DEVICE(&phb->root), "chassis", phb->chip_id);
- qdev_prop_set_uint16(DEVICE(&phb->root), "slot", phb->phb_id);
- qdev_realize(DEVICE(&phb->root), BUS(pci->bus), &error_fatal);
+ /* Add a single Root port if running with defaults */
+ if (defaults_enabled()) {
+ pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb),
+ TYPE_PNV_PHB4_ROOT_PORT);
+ }
/* Setup XIVE Source */
if (phb->big_phb) {
@@ -1369,7 +1365,7 @@ static void pnv_phb4_root_port_class_init(ObjectClass *klass, void *data)
PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
dc->desc = "IBM PHB4 PCIE Root Port";
- dc->user_creatable = false;
+ dc->user_creatable = true;
device_class_set_parent_realize(dc, pnv_phb4_root_port_realize,
&rpc->parent_realize);
diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h
index 4a19338db3..ea63df9676 100644
--- a/include/hw/pci-host/pnv_phb4.h
+++ b/include/hw/pci-host/pnv_phb4.h
@@ -78,8 +78,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(PnvPHB4, PNV_PHB4)
struct PnvPHB4 {
PCIExpressHost parent_obj;
- PnvPHB4RootPort root;
-
uint32_t chip_id;
uint32_t phb_id;
--
2.33.1
^ permalink raw reply related
* Re: RFC: tsnep: ETF, AF_XDP, UIO or driver specific interface for real-time
From: Gerhard Engleder @ 2022-01-05 21:29 UTC (permalink / raw)
To: Magnus Karlsson
Cc: Vinicius Costa Gomes, David Miller, Jakub Kicinski,
Björn Töpel, Karlsson, Magnus, gregkh, Andrew Lunn,
netdev
In-Reply-To: <CAJ8uoz01whcZOOPafCzBeh7f_N=p4kxEYywv2K9D=gbwdEW9sw@mail.gmail.com>
On Wed, Jan 5, 2022 at 8:37 AM Magnus Karlsson
<magnus.karlsson@gmail.com> wrote:
>
> On Tue, Jan 4, 2022 at 11:12 PM Gerhard Engleder
> <gerhard@engleder-embedded.com> wrote:
> >
> > On Tue, Jan 4, 2022 at 9:26 AM Magnus Karlsson
> > <magnus.karlsson@gmail.com> wrote:
> > >
> > > On Fri, Dec 31, 2021 at 10:44 AM Gerhard Engleder
> > > <gerhard@engleder-embedded.com> wrote:
> > > >
> > > > On Mon, Dec 27, 2021 at 8:03 PM Vinicius Costa Gomes
> > > > <vinicius.gomes@intel.com> wrote:
> > > > >
> > > > > Hi Gerhard,
> > > > >
> > > > > Gerhard Engleder <gerhard@engleder-embedded.com> writes:
> > > > >
> > > > > > Hello,
> > > > > >
> > > > > > the driver for my FPGA based TSN endpoint Ethernet MAC is now in net-next. As
> > > > > > a first step, it supports a single TX/RX queue pair for normal Ethernet
> > > > > > communication. For TSN it supports hardware timestamps (PTP) and TAPRIO (gate
> > > > > > control). The next step is the user space interface for real-time communication
> > > > > > over additional TX/RX queue pairs.
> > > > > >
> > > > > > Multiple interfaces are used for real-time communication in user space:
> > > > > > A) ETF for timed transmit
> > > > > > B) AF_XDP for direct access omitting the network stack
> > > > > > C) UIO for mapping devices to user space
> > > > > > D) driver specific interfaces for direct access to DMA buffers and IO memory
> > > > > > (out of tree)
> > > > > >
> > > > > > The additional TX/RX queue pairs of my Ethernet MAC are optimized for real-time
> > > > > > communication. The mapping to ETF or AF_XDP is not straightforward. I know a
> > > > > > little about UIO and ETF and I have read Documentation/networking/af_xdp.rst,
> > > > > > but that does not qualify me as an expert. So I want to discuss if ETF, AF_XDP,
> > > > > > UIO or any other standard Linux user space interface is the right choice for my
> > > > > > driver?
> > > > > >
> > > > > > First I want to describe the main real-time feature of the device, the periodic
> > > > > > TX schedule:
> > > > > >
> > > > > > The data exchange between hardware and software is done similarly to other
> > > > > > Ethernet MACs. Descriptor rings are used and the ownership of descriptors
> > > > > > is transferred from software to hardware and vice versa during operation.
> > > > > >
> > > > > > Usually TX descriptor rings are queues, which transfer data from RAM to
> > > > > > Ethernet MAC as fast as possible. This is the case for the first TX/RX queue
> > > > > > pair, which is used by the Ethernet driver. For real-time communication
> > > > > > transmission at defined points in time is a requirement. Additionally, the
> > > > > > transmitted data shall be as up-to-data as possible. Therefore, the data shall
> > > > > > be transferred to the Ethernet MAC as late as possible. This enables minimal
> > > > > > reaction time for closed loop control. So there are actually two points in time.
> > > > > > First, the start of the DMA transfer of data from RAM to Ethernet MAC. Second,
> > > > > > the start of the transmission over Ethernet.
> > > > > >
> > > > > > Therefore, the TX descriptor ring of additional TX/RX queue pairs is enhanced
> > > > > > with timing information. This timing information defines both points in time.
> > > > > > As a result, the TX descriptor ring is processed at defined points in time and
> > > > > > not as fast as possible.
> > > > > >
> > > > > > Real-time communication is usually periodic. The timing pattern repeats after
> > > > > > the least common multiple of all cycle times. The relative timing information
> > > > > > of two consecutive TX descriptors is constant. So relative timing information
> > > > > > is used within the TX descriptor ring. There is no need to update this relative
> > > > > > timing information during operation. Only transmitted data and ownership must
> > > > > > be updated. The TAPRIO gate control list is good example for a periodic
> > > > > > schedule.
> > > > > >
> > > > > > The periodic nature of real-time communication has another side effect. The
> > > > > > timing is known in advance. So a TX descriptor is able to define the timing of
> > > > > > the next TX descriptor. As a result, the hardware knows the timing of the next
> > > > > > TX descriptor without fetching it from RAM. This prevents a chicken egg problem:
> > > > > > the TX descriptor cannot define its own DMA timing, because DMA would be needed
> > > > > > to read this timing.
> > > > > >
> > > > > > All these properties lead to a periodic TX schedule implemented with an
> > > > > > enhanced TX descriptor ring. Let's describe the details with an example:
> > > > > >
> > > > > > - two cycle times
> > > > > > - single Ethernet frame every 100us, first TX at absolute time 7000us
> > > > > > - TX times: 7000us, 7100us, 7200us, ...
> > > > > > - single Ethernet frame every 200us, first TX at absolute time 7050us
> > > > > > - TX times: 7050us, 7250us, 7450us, ...
> > > > > > - DMA shall be done as late as possible for 100us cycle time
> > > > > > - DMA of 200us cycle time shall be done directly after DMA of 100us cycle time
> > > > > >
> > > > > > The perdiodic TX schedule for this example looks like this:
> > > > > >
> > > > > > +-------------<-------------------------<-------------------------<------------+
> > > > > > | |
> > > > > > +-->+-------------------+---->+-------------------+---->+-------------------+->+
> > > > > > | TX desc 1 @0x1000 | | TX desc 2 @0x2000 | | TX desc 3 @0x3000 |
> > > > > > | | | | | |
> > > > > > | next_desc=0x2000 | | next_desc=0x3000 | | next_desc=0x1000 |
> > > > > > | dma_incr=10us | | dma_incr=90us | | dma_incr=100us |
> > > > > > | tx_incr=50us | | tx_incr=50us | | tx_incr=100us |
> > > > > > +-------------------+ +-------------------+ +-------------------+
> > > > > >
> > > > > > "next_desc" is the address of the next TX descriptor. "dma_incr" defines the
> > > > > > DMA start time of the next TX descriptor:
> > > > > >
> > > > > > "DMA start time" = "Current DMA start time" + dma_incr
> > > > > >
> > > > > > Similar "tx_incr" defines the Ethernet TX start time of the next TX descriptor:
> > > > > >
> > > > > > "Ethernet TX start time" = "Current Ethernet TX start time" + tx_incr
> > > > > >
> > > > > > The TX descriptor processing needs initial values for the address of the first
> > > > > > descriptor, the DMA start time of the first descriptor, and the Ethernet TX
> > > > > > start time of the first descriptor. These initial values are written to
> > > > > > registers:
> > > > > >
> > > > > > - "TX descriptor address" register = 0x1000
> > > > > > - "DMA start time" register = 6980us
> > > > > > - "Ethernet TX start time" register = 7000us
> > > > > >
> > > > > > These three registers always hold information about the next TX descriptor. The
> > > > > > location in the RAM, the point it time when it shall be read by DMA, the point
> > > > > > in time when it shall be transmitted.
> > > > > >
> > > > > > The least common multiple of the cycle times is 200us. Thus, the sum of all
> > > > > > "tx_incr" values must be 200us. Also the sum of all "dma_incr" values must be
> > > > > > 200us. Otherwise DMA and TX timing would drift away from each other.
> > > > > >
> > > > > > TX descriptors 1 and 3 belong to the 100us cycle time. TX descriptor 2
> > > > > > belongs to
> > > > > > the 200us cycle time. The TX schedule is processed in the following steps:
> > > > > >
> > > > > > cycle time | DMA read | Ethernet TX
> > > > > > 1) TX desc 1 100us | @6980us | @7000us
> > > > > > 2) TX desc 2 200us | @6990us | @7050us
> > > > > > 3) TX desc 3 100us | @7080us | @7100us
> > > > > > 4) TX desc 1 100us | @7180us | @7200us
> > > > > > 5) TX desc 2 200us | @7190us | @7250us
> > > > > > 6) TX desc 3 100us | @7280us | @7300us
> > > > > > 7) TX desc 1 100us | @7380us | @7400us
> > > > > > 8) TX desc 2 200us | @7390us | @7450us
> > > > > > 9) TX desc 3 100us | @7480us | @7500us
> > > > > > ...
> > > > > >
> > > > > > First DMA read is done at 6980us. This point in time is defined with the initial
> > > > > > value of the "DMA start time" register. The following DMA reads are
> > > > > > determined by
> > > > > > the "dma_incr" values of the TX descriptors. Every DMA read is started before
> > > > > > the Ethernet TX.
> > > > > >
> > > > > > First Ethernet TX is done at 7000us. This point in time is defined with the
> > > > > > initial value of the "Ethernet TX start time" register. The following Ethernet
> > > > > > TX times are determined by the "tx_incr" values of the TX descriptors.
> > > > > >
> > > > > > So the periodic TX schedule actually contains two schedules. One for DMA read
> > > > > > and another one for Ethernet TX. As a result, the timing of DMA and Ethernet TX
> > > > > > can be optimized independently from each other. The only restriction is that
> > > > > > DMA has to be done before the corresponding Ethernet TX.
> > > > >
> > > > > At the risk of repeating what you said, here's what I could gather that
> > > > > you would need.
> > > > >
> > > > > 1. Exclusive access of one application (or closely cooperating group of
> > > > > applications) to one TX ring;
> > > > > 2. Direct access to the device DMA mapped memory;
> > > > > 3. A way to configure the {DMA,TX} start times and the {DMA,TX}
> > > > > increments;
> > > >
> > > > Yes, that's a good summary.
> > > >
> > > > > > This periodic TX schedule has been used in a similar way for the
> > > > > > EtherCAT fieldbus
> > > > > > for nearly 10 years with positive experience. So for OPC UA Pub/Sub TSN it
> > > > > > shall be used again.
> > > > > >
> > > > > > This periodic TX schedule does not fit to ETF, because ETF uses absolute time
> > > > > > stamps and the timing is not known in advance. Additionally, the intention of
> > > > > > the periodic TX schedule is that the real-time application writes the data
> > > > > > directly to the TX descriptor ring. AF_XDP has a similar direction, but does
> > > > > > not support any TX timing.
> > > > >
> > > > > That's the magic of AF_XDP, as it is only a data path abstraction, you
> > > > > can move the control path somewhere else. One idea below.
> > > >
> > > > I assume you mean control path stuff like ethtool flow-type ether.
> > > >
> > > > > > I have no knowledge about any other Ethernet MAC which supports timed TX in
> > > > > > a similar way like this device.
> > > > > >
> > > > > > Currently a simple device/driver specific interface is used. Similar to UIO it
> > > > > > supports the mapping of registers of TX/RX queue pairs to user space. Every
> > > > > > additional TX/RX queue pair has its own register set within a separate 4kB
> > > > > > IO-memory. Thus, only the register sets of the additional TX/RX queue pairs are
> > > > > > mapped to user space. Every TX/RX queue pair is more less a separate device,
> > > > > > which can be operated independent of any other TX/RX queue pair. Additionally,
> > > > > > this device/driver specific interface supports the mapping of DMA buffers.
> > > > > >
> > > > > > A similar approach has been used for years for the periodic TX schedule in
> > > > > > combination with the EtherCAT fieldbus (out of tree driver). The main advantage
> > > > > > of this approach is that no hard or soft IRQs are needed for operation. There is
> > > > > > no need to increase to priority of soft IRQs, which can lead to real-time
> > > > > > problems.
> > > > > >
> > > > > > Which user space interface shall be used for this periodic TX schedule? Is
> > > > > > ETF or XDP an option? Shall UIO be used like for other real-time controllers?
> > > > > > Is a device/driver specific interface the way to go, because no other Ethernet
> > > > > > MAC has an interface like this?
> > > > >
> > > > > I think that AF_XDP (with zero copy) already has everything you need for
> > > > > the data plane, (1) and (2) above.
> > > >
> > > > I'm not sure. AF_XDP ring size is a power of 2, but in my case the
> > > > ring size is the
> > > > number of Ethernet frames within the least common multiple of all cycle times.
> > > > Also AF_XDP works like a FIFO, the Ethernet frames are transmitted one after the
> > > > other. In my case every Ethernet frame has to be placed at a certain
> > > > position in the
> > > > TX ring. This can be done at any time before the transmission and does
> > > > not need to
> > > > match the transmission order.
> > > > To be able to put the Ethernet frame at the right position in the TX
> > > > ring additional
> > > > information is required. Otherwise, the transmission time cannot be
> > > > determined. At
> > > > least some reference to the control plane (3) data is needed.
> > >
> > > Yes, the AF_XDP rings are strictly FIFO, so you would have to consume
> > > the descriptors in the driver in FIFO order and store them in some
> > > buffer there so you can put them onto your HW in arbitrary order.
> > > Would make your driver look very different from the other zero-copy
> > > drivers that have zero buffering in the data path.
> >
> > That doesn't sound like a good fit to me. Zero-copy is something I would
> > like to achieve. But hiding the periodic TX schedule behind the AF_XDP
> > FIFO interface seems to be a misuse.
>
> For me, the important aspect of zero-copy is that the packets
> themselves are not copied. This is still true with my suggestion. What
> is being copied and buffered are the descriptors only, not the
> buffers/packets themselves. Is copying descriptors too much? I do
> agree that it would be some kind of misuse of the FIFO. Better that it
> is not a FIFO at all in your case and that buffering is only done in
> that structure. Complicated to have to implement buffering in the
> driver.
Sorry, I misunderstood your first reply. Yes, copying descriptors should not
matter. I will try to add XDP and zero copy support to the driver to see what
is possible and gain more understanding of AF_XDP.
> > > One thing to note is that entries in the completion ring are reserved
> > > as a prerequisite for consuming a Tx ring entry. As you probably want
> > > to buffer packets in the driver, you would have to have a completion
> > > ring that is as least as large as the number of outstanding Tx packets
> > > plus the number of buffered packets in your driver. Otherwise, the
> > > application will not be able to send packets in all circumstances.
> > >
> > > > > So what's seems to be really missing is the control plane, (3).
> > > >
> > > > At least for static timing information moving the timing information
> > > > like {DMA,TX}
> > > > start times and the {DMA,TX} increments out of the data plane should
> > > > be possible.
> > > > For runtime changes, e.g. add/remove Ethernet frames to/from TX schedule during
> > > > operation, I'm not so sure, because data and control is tied together
> > > > in the TX descriptor.
> > >
> > > You probably want to stick this info in the metadata section before
> > > the packet as done in this RFC [1]. This would be the Tx analogue of
> > > the Rx part in [2]. Lot of work still remains here though.
> >
> > XDP hints are new to me. Interesting to read for me as I know only little
> > about BPF. Metadata like timestamps sounds reasonable to me. Not only
> > for PTP, but also for diagnosis of timing problems in real-time applications
> > (actual TX/RX time). Besides timestamps, my device supports additional
> > metadata for diagnosis: DMA timing measurement (time until first/last dword).
> >
> > > > > What I would do is something like this, I would add a few debugfs
> > > > > entries to the driver allowing me to configure the "extra" per ring
> > > > > parameters. This also gives some chance to see what is best format for
> > > > > communicating those parameters to the driver.
> > > > >
> > > > > With that I could see if something is not quite working from the AF_XDP
> > > > > side, fix those (I think the community will have some interest in having
> > > > > these cases fixed) while discussing where is the best place to put those
> > > > > configuration knobs. My first shot would be ethtool.
> > > >
> > > > Is it a possible future goal of AF_XDP to enable TX/RX of Ethernet
> > > > frames without
> > > > any kernel mode interactions? E.g. a hardware implementation of the AF_XDP
> > > > interface, or some VDSO code for descriptor ring handling?
> > >
> > > I have heard about people wanting to try to build a HW AF_XDP
> > > implementation using an FPGA. Do not know if anything came through in
> > > the end. Will dig around a bit.
> > >in user space
> > > As for the VDSO approach, what are you thinking there? To be able to
> > > have different flavors of rings (or other structures) for
> > > communication between user-space and kernel?
> >
> > I would say yes. Hide the actual flavor of rings (or other structures) behind
> > VDSO.
> >
> > Direct access to descriptor rings without kernel mode interaction is currently
> > done the following way: Descriptor rings of network devices are mapped to
> > user space. Device specific driver code is used to handle the descriptor ring
> > (transfer ownership to hardware, check ownership, write frame to TX descriptor,
> > read frame from RX descriptor, ...). This results in a device specific interface
> > and makes the application device specific. But the application should not be
> > tied to specific devices.
> >
> > Rough idea is, that device specific code is provided to user space over VDSO.
> > Descriptor rings are mapped to user space and handled with device specific
> > VDSO code. The VDSO functions are the interface, not the device specific
> > descriptor ring. The application could rely on this interface and wouldn't be
> > device specific.
> >
> > I assume that VDSO is not intended for that. But VDSO clock_gettime() is great.
> > So my idea is to copy its "do it in user space if possible, but let the kernel
> > determine how" approach.
>
> In the early RFC days of AF_XDP, we had code for being able to plug in
> different ring structures (or something else to be used to communicate
> between kernel and user-space), but we removed it as it complicated
> the code and had a negative performance impact. But the idea is
> interesting.
If we assume, that the implementation is possible: Would AF_XDP be the right
location for a feature, which allows direct mapping and handling of hardware
TX/RX descriptor rings for Ethernet frame TX/RX in user space in a hardware
independent way?
AF_XDP already supports exclusive usage of hardwareTX/RX descriptor rings
for user space applications. Interrupts and soft IRQs are involved, which make
the life for real-time developers complicated (real-time priority,
core assignment,
...) and degrade real-time performance. So it would be great to eliminate the
kernel space code and handle the hardware TX/RX descriptor rings directly in
user space.
> > >
> > > [1] https://lists.xdp-project.net/xdp-hints/20210803010331.39453-1-ederson.desouza@intel.com/
> > > [2] https://lore.kernel.org/bpf/20210526125848.1c7adbb0@carbon/
> > >
> > > /Magnus
> > >
> > > > > > I'm looking forward to your comments.
> > > > > >
> > > > > > Gerhard
> > > > >
> > > > > Cheers,
> > > > > --
> > > > > Vinicius
^ permalink raw reply
* [PATCH v2 03/18] ppc/pnv: Attach PHB3 root port device when defaults are enabled
From: Daniel Henrique Barboza @ 2022-01-05 21:23 UTC (permalink / raw)
To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david
In-Reply-To: <20220105212338.49899-1-danielhb413@gmail.com>
From: Cédric Le Goater <clg@kaod.org>
This cleanups the PHB3 model a bit more since the root port is an
independent device and it will ease our task when adding user created
PHB3s.
pnv_phb_attach_root_port() is made public in pnv.c so it can be reused
with the pnv_phb4 root port later.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
hw/pci-host/pnv_phb3.c | 15 ++++++---------
hw/ppc/pnv.c | 8 ++++++++
include/hw/pci-host/pnv_phb3.h | 2 --
include/hw/ppc/pnv.h | 1 +
4 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c
index 3467bbb5d9..fdc8d0b437 100644
--- a/hw/pci-host/pnv_phb3.c
+++ b/hw/pci-host/pnv_phb3.c
@@ -19,6 +19,7 @@
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "qom/object.h"
+#include "sysemu/sysemu.h"
#define phb3_error(phb, fmt, ...) \
qemu_log_mask(LOG_GUEST_ERROR, "phb3[%d:%d]: " fmt "\n", \
@@ -981,10 +982,6 @@ static void pnv_phb3_instance_init(Object *obj)
/* Power Bus Common Queue */
object_initialize_child(obj, "pbcq", &phb->pbcq, TYPE_PNV_PBCQ);
- /* Root Port */
- object_initialize_child(obj, "root", &phb->root, TYPE_PNV_PHB3_ROOT_PORT);
- qdev_prop_set_int32(DEVICE(&phb->root), "addr", PCI_DEVFN(0, 0));
- qdev_prop_set_bit(DEVICE(&phb->root), "multifunction", false);
}
static void pnv_phb3_realize(DeviceState *dev, Error **errp)
@@ -1053,10 +1050,10 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp)
pci_setup_iommu(pci->bus, pnv_phb3_dma_iommu, phb);
- /* Add a single Root port */
- qdev_prop_set_uint8(DEVICE(&phb->root), "chassis", phb->chip_id);
- qdev_prop_set_uint16(DEVICE(&phb->root), "slot", phb->phb_id);
- qdev_realize(DEVICE(&phb->root), BUS(pci->bus), &error_fatal);
+ if (defaults_enabled()) {
+ pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb),
+ TYPE_PNV_PHB3_ROOT_PORT);
+ }
}
void pnv_phb3_update_regions(PnvPHB3 *phb)
@@ -1177,7 +1174,7 @@ static void pnv_phb3_root_port_class_init(ObjectClass *klass, void *data)
device_class_set_parent_realize(dc, pnv_phb3_root_port_realize,
&rpc->parent_realize);
- dc->user_creatable = false;
+ dc->user_creatable = true;
k->vendor_id = PCI_VENDOR_ID_IBM;
k->device_id = 0x03dc;
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 9de8b83530..3a263f631a 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1156,6 +1156,14 @@ static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
}
}
+/* Attach a root port device */
+void pnv_phb_attach_root_port(PCIHostState *pci, const char *name)
+{
+ PCIDevice *root = pci_new(PCI_DEVFN(0, 0), name);
+
+ pci_realize_and_unref(root, pci->bus, &error_fatal);
+}
+
static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
{
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev);
diff --git a/include/hw/pci-host/pnv_phb3.h b/include/hw/pci-host/pnv_phb3.h
index e9c13e6bd8..2e423c3890 100644
--- a/include/hw/pci-host/pnv_phb3.h
+++ b/include/hw/pci-host/pnv_phb3.h
@@ -155,8 +155,6 @@ struct PnvPHB3 {
PnvPBCQState pbcq;
- PnvPHB3RootPort root;
-
QLIST_HEAD(, PnvPhb3DMASpace) dma_spaces;
PnvChip *chip;
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index c781525277..c726288e5e 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -177,6 +177,7 @@ DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER10,
TYPE_PNV_CHIP_POWER10)
PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir);
+void pnv_phb_attach_root_port(PCIHostState *pci, const char *name);
#define TYPE_PNV_MACHINE MACHINE_TYPE_NAME("powernv")
typedef struct PnvMachineClass PnvMachineClass;
--
2.33.1
^ permalink raw reply related
* [PATCH v2 15/18] pnv_phb4_pec.c: use 'default_enabled()' to init stack->phb
From: Daniel Henrique Barboza @ 2022-01-05 21:23 UTC (permalink / raw)
To: qemu-devel; +Cc: danielhb413, qemu-ppc, clg, david
In-Reply-To: <20220105212338.49899-1-danielhb413@gmail.com>
The next step before enabling user creatable pnv-phb4 devices is to
decople the init of the stack->phb object from
pnv_pec_stk_instance_init().
First, use 'defaults_enabled()' inside pnv_pec_realize() to create the
stack->phb object, while removing the equivalent object_initiate_child()
call from stk_instance_init(). Create a new "phb" stack property link so
we can assign stack->phb in an idiomatic manner.
Then we need to handle stack->phb->index assignment. The value is
retrieved with pnv_phb4_pec_get_phd_id() and, until this patch, this was
being assigned to a 'phb-id' stack link to phb->index. It is simpler to
assign this directly given that now we need to interact with the PnvPHB4
object directly to set its other attributes. Assign phb->index directly
with the value of pnv_phb4_pec_get_phb_id(), and remove the now unused
link.
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
hw/pci-host/pnv_phb4_pec.c | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c
index be6eefdbb1..638691783b 100644
--- a/hw/pci-host/pnv_phb4_pec.c
+++ b/hw/pci-host/pnv_phb4_pec.c
@@ -19,6 +19,7 @@
#include "hw/pci/pci_bus.h"
#include "hw/ppc/pnv.h"
#include "hw/qdev-properties.h"
+#include "sysemu/sysemu.h"
#include <libfdt.h>
@@ -392,11 +393,29 @@ static void pnv_pec_realize(DeviceState *dev, Error **errp)
for (i = 0; i < pec->num_stacks; i++) {
PnvPhb4PecStack *stack = &pec->stacks[i];
Object *stk_obj = OBJECT(stack);
- int phb_id = pnv_phb4_pec_get_phb_id(pec, i);
object_property_set_int(stk_obj, "stack-no", i, &error_abort);
- object_property_set_int(stk_obj, "phb-id", phb_id, &error_abort);
object_property_set_link(stk_obj, "pec", OBJECT(pec), &error_abort);
+
+ /* Create and realize the default stack->phb */
+ if (defaults_enabled()) {
+ PnvPHB4 *phb = PNV_PHB4(qdev_new(TYPE_PNV_PHB4));
+ int phb_id = pnv_phb4_pec_get_phb_id(pec, i);
+
+ object_property_set_int(OBJECT(phb), "index",
+ phb_id, &error_abort);
+ object_property_set_link(OBJECT(phb), "stack",
+ stk_obj, &error_abort);
+
+ pnv_phb4_set_stack_phb_props(stack, phb);
+ if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(phb), errp)) {
+ return;
+ }
+
+ object_property_set_link(stk_obj, "phb", OBJECT(phb),
+ &error_abort);
+ }
+
if (!qdev_realize(DEVICE(stk_obj), NULL, errp)) {
return;
}
@@ -531,10 +550,6 @@ static const TypeInfo pnv_pec_type_info = {
static void pnv_pec_stk_instance_init(Object *obj)
{
- PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(obj);
-
- object_initialize_child(obj, "phb", &stack->phb, TYPE_PNV_PHB4);
- object_property_add_alias(obj, "phb-id", OBJECT(&stack->phb), "index");
}
static void pnv_pec_stk_realize(DeviceState *dev, Error **errp)
@@ -588,6 +603,8 @@ static Property pnv_pec_stk_properties[] = {
DEFINE_PROP_UINT32("stack-no", PnvPhb4PecStack, stack_no, 0),
DEFINE_PROP_LINK("pec", PnvPhb4PecStack, pec, TYPE_PNV_PHB4_PEC,
PnvPhb4PecState *),
+ DEFINE_PROP_LINK("phb", PnvPhb4PecStack, phb, TYPE_PNV_PHB4,
+ PnvPHB4 *),
DEFINE_PROP_END_OF_LIST(),
};
--
2.33.1
^ permalink raw reply related
* Re: [PATCH] parisc: io: Improve the outb(), outw() and outl() macros
From: Bart Van Assche @ 2022-01-05 21:29 UTC (permalink / raw)
To: James E . J . Bottomley; +Cc: deller, linux-parisc
In-Reply-To: <20211012222936.3810578-1-bvanassche@acm.org>
On 10/12/21 15:29, Bart Van Assche wrote:
> This patch fixes the following build error for source file
> drivers/scsi/pcmcia/sym53c500_cs.c:
>
> In file included from ./include/linux/bug.h:5,
> from ./include/linux/cpumask.h:14,
> from ./include/linux/mm_types_task.h:14,
> from ./include/linux/mm_types.h:5,
> from ./include/linux/buildid.h:5,
> from ./include/linux/module.h:14,
> from drivers/scsi/pcmcia/sym53c500_cs.c:42:
> drivers/scsi/pcmcia/sym53c500_cs.c: In function ‘SYM53C500_intr’:
> ./arch/parisc/include/asm/bug.h:28:2: error: expected expression before ‘do’
> 28 | do { \
> | ^~
> ./arch/parisc/include/asm/io.h:276:20: note: in expansion of macro ‘BUG’
> 276 | #define outb(x, y) BUG()
> | ^~~
> drivers/scsi/pcmcia/sym53c500_cs.c:124:19: note: in expansion of macro ‘outb’
> 124 | #define REG0(x) (outb(C4_IMG, (x) + CONFIG4))
> | ^~~~
> drivers/scsi/pcmcia/sym53c500_cs.c:362:2: note: in expansion of macro ‘REG0’
> 362 | REG0(port_base);
> | ^~~~
>
> Signed-off-by: Bart Van Assche <bvanassche@acm.org>
> ---
> arch/parisc/include/asm/io.h | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/parisc/include/asm/io.h b/arch/parisc/include/asm/io.h
> index 0b5259102319..837ddddbac6a 100644
> --- a/arch/parisc/include/asm/io.h
> +++ b/arch/parisc/include/asm/io.h
> @@ -273,9 +273,9 @@ static inline int inl(unsigned long addr)
> return -1;
> }
>
> -#define outb(x, y) BUG()
> -#define outw(x, y) BUG()
> -#define outl(x, y) BUG()
> +#define outb(x, y) ({(void)(x); (void)(y); BUG(); 0;})
> +#define outw(x, y) ({(void)(x); (void)(y); BUG(); 0;})
> +#define outl(x, y) ({(void)(x); (void)(y); BUG(); 0;})
> #endif
>
> /*
>
(+Helge Deller and linux-parisc)
Ping?
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.