Compare commits

...

No commits in common. "c8" and "c9-beta" have entirely different histories.
c8 ... c9-beta

200 changed files with 43096 additions and 718 deletions

View File

@ -0,0 +1,51 @@
From ee7fabed859d07809dc3cfe6b23b7ad3b0c6cd73 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Tue, 12 Jan 2021 23:14:58 -0800
Subject: [PATCH 003/217] ndctl/test: Fix btt expect table compile warning
../test/libndctl.c:989:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
989 | unsigned long long expect_table[][2] = {
| ^~~~~~~~
...just move the declaration a few lines up.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/r/161052209839.1804207.11951679046842122849.stgit@dwillia2-desk3.amr.corp.intel.com
---
test/libndctl.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/test/libndctl.c b/test/libndctl.c
index 24d72b3..fc65149 100644
--- a/test/libndctl.c
+++ b/test/libndctl.c
@@ -980,12 +980,6 @@ static int check_btt_size(struct ndctl_btt *btt)
struct ndctl_ctx *ctx = ndctl_btt_get_ctx(btt);
struct ndctl_test *test = ndctl_get_private_data(ctx);
struct ndctl_namespace *ndns = ndctl_btt_get_namespace(btt);
-
- if (!ndns)
- return -ENXIO;
-
- ns_size = ndctl_namespace_get_size(ndns);
- sect_size = ndctl_btt_get_sector_size(btt);
unsigned long long expect_table[][2] = {
[0] = {
[0] = 0x11b5400,
@@ -1001,6 +995,12 @@ static int check_btt_size(struct ndctl_btt *btt)
},
};
+ if (!ndns)
+ return -ENXIO;
+
+ ns_size = ndctl_namespace_get_size(ndns);
+ sect_size = ndctl_btt_get_sector_size(btt);
+
if (sect_size >= SZ_4K)
sect_select = 1;
else if (sect_size >= 512)
--
2.27.0

View File

@ -0,0 +1,57 @@
From ff4030e88da2cdcaf52c0d7457cd30264ea8915b Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Tue, 12 Jan 2021 23:15:03 -0800
Subject: [PATCH 004/217] ndctl/test: Cleanup unnecessary out label
There are no cleanup actions to take in test_dax_remap(), and it is already
inconsistent for having a single return point, so remove the out label.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/r/161052210395.1804207.7318263492906073721.stgit@dwillia2-desk3.amr.corp.intel.com
---
test/dax-pmd.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/test/dax-pmd.c b/test/dax-pmd.c
index 401826d..b1251db 100644
--- a/test/dax-pmd.c
+++ b/test/dax-pmd.c
@@ -83,20 +83,18 @@ int test_dax_remap(struct ndctl_test *test, int dax_fd, unsigned long align, voi
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGBUS, &act, 0)) {
perror("sigaction");
- rc = EXIT_FAILURE;
- goto out;
+ return EXIT_FAILURE;
}
/* test fault after device-dax instance disabled */
if (sigsetjmp(sj_env, 1)) {
if (!fsdax && align > SZ_4K) {
fprintf(stderr, "got expected SIGBUS after mremap() of device-dax\n");
- rc = 0;
+ return 0;
} else {
fprintf(stderr, "unpexpected SIGBUS after mremap()\n");
- rc = -EIO;
+ return -EIO;
}
- goto out;
}
*(int *) anon = 0xAA;
@@ -107,9 +105,7 @@ int test_dax_remap(struct ndctl_test *test, int dax_fd, unsigned long align, voi
return -ENXIO;
}
- rc = 0;
-out:
- return rc;
+ return 0;
}
int test_dax_directio(int dax_fd, unsigned long align, void *dax_addr, off_t offset)
--
2.27.0

View File

@ -0,0 +1,40 @@
From 6694afe31dd67d186199a58d2252be5ea3472692 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Tue, 12 Jan 2021 23:15:09 -0800
Subject: [PATCH 005/217] ndctl/test: Fix device-dax mremap() test
The test_dax_remap() test is a regression check for mishandling of mremap()
in the presence of pmd_devmap(). My understanding is that it was a fuzzing
condition not something an application would want to do in practice.
On recent kernels with commit 73d5e0629919 ("mremap: check if it's possible
to split original vma"), the test fails for device-dax. That seems an
equally acceptable result of attempting this remap, so update the test
rather than ask the kernel to preserve the old behaviour.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/r/161052210936.1804207.17896246772670985157.stgit@dwillia2-desk3.amr.corp.intel.com
---
test/dax-pmd.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/test/dax-pmd.c b/test/dax-pmd.c
index b1251db..7648e34 100644
--- a/test/dax-pmd.c
+++ b/test/dax-pmd.c
@@ -69,6 +69,11 @@ int test_dax_remap(struct ndctl_test *test, int dax_fd, unsigned long align, voi
remap = mremap(addr, REMAP_SIZE, REMAP_SIZE, MREMAP_MAYMOVE|MREMAP_FIXED, anon);
+ if (remap == MAP_FAILED) {
+ fprintf(stderr, "%s: mremap failed, that's ok too\n", __func__);
+ return 0;
+ }
+
if (remap != anon) {
rc = -ENXIO;
perror("mremap");
--
2.27.0

View File

@ -0,0 +1,134 @@
From 940acf65a61595e8c0db3aebe1c74307acbbef68 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Tue, 12 Jan 2021 23:15:14 -0800
Subject: [PATCH 006/217] ndctl/test: Exercise soft_offline_page() corner cases
Test soft-offline injection into PMEM namespace metadata and user mapped
space. Both attempts should fail on kernels with a pfn_to_online_page()
implementation that considers subsection ZONE_DEVICE ranges.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/r/161052211455.1804207.13884321454837200896.stgit@dwillia2-desk3.amr.corp.intel.com
---
test/dax-poison.c | 19 +++++++++++++++++++
test/device-dax.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 64 insertions(+)
diff --git a/test/dax-poison.c b/test/dax-poison.c
index a4ef12e..4e09761 100644
--- a/test/dax-poison.c
+++ b/test/dax-poison.c
@@ -5,6 +5,7 @@
#include <signal.h>
#include <setjmp.h>
#include <sys/mman.h>
+#include <linux/mman.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
@@ -49,6 +50,7 @@ int test_dax_poison(struct ndctl_test *test, int dax_fd, unsigned long align,
unsigned char *addr = MAP_FAILED;
struct sigaction act;
unsigned x = x;
+ FILE *smaps;
void *buf;
int rc;
@@ -94,6 +96,9 @@ int test_dax_poison(struct ndctl_test *test, int dax_fd, unsigned long align,
goto out;
}
+ fprintf(stderr, "%s: mmap got %p align: %ld offset: %zd\n",
+ __func__, addr, align, offset);
+
if (sigsetjmp(sj_env, 1)) {
if (sig_mcerr_ar) {
fprintf(stderr, "madvise triggered 'action required' sigbus\n");
@@ -104,6 +109,20 @@ int test_dax_poison(struct ndctl_test *test, int dax_fd, unsigned long align,
}
}
+ rc = madvise(addr + align / 2, 4096, MADV_SOFT_OFFLINE);
+ if (rc == 0) {
+ fprintf(stderr, "softoffline should always fail for dax\n");
+ smaps = fopen("/proc/self/smaps", "r");
+ do {
+ rc = fread(buf, 1, 4096, smaps);
+ fwrite(buf, 1, rc, stderr);
+ } while (rc);
+ fclose(smaps);
+ fail();
+ rc = -ENXIO;
+ goto out;
+ }
+
rc = madvise(addr + align / 2, 4096, MADV_HWPOISON);
if (rc) {
fail();
diff --git a/test/device-dax.c b/test/device-dax.c
index 5f0da29..aad8fa5 100644
--- a/test/device-dax.c
+++ b/test/device-dax.c
@@ -128,6 +128,44 @@ static int verify_data(struct daxctl_dev *dev, char *dax_buf,
return 0;
}
+static int test_dax_soft_offline(struct ndctl_test *test, struct ndctl_namespace *ndns)
+{
+ unsigned long long resource = ndctl_namespace_get_resource(ndns);
+ int fd, rc;
+ char *buf;
+
+ if (resource == ULLONG_MAX) {
+ fprintf(stderr, "failed to get resource: %s\n",
+ ndctl_namespace_get_devname(ndns));
+ return -ENXIO;
+ }
+
+ fd = open("/sys/devices/system/memory/soft_offline_page", O_WRONLY);
+ if (fd < 0) {
+ fprintf(stderr, "failed to open soft_offline_page\n");
+ return -ENOENT;
+ }
+
+ rc = asprintf(&buf, "%#llx\n", resource);
+ if (rc < 0) {
+ fprintf(stderr, "failed to alloc resource\n");
+ close(fd);
+ return -ENOMEM;
+ }
+
+ fprintf(stderr, "%s: try to offline page @%#llx\n", __func__, resource);
+ rc = write(fd, buf, rc);
+ free(buf);
+ close(fd);
+
+ if (rc >= 0) {
+ fprintf(stderr, "%s: should have failed\n", __func__);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
static int __test_device_dax(unsigned long align, int loglevel,
struct ndctl_test *test, struct ndctl_ctx *ctx)
{
@@ -278,6 +316,13 @@ static int __test_device_dax(unsigned long align, int loglevel,
goto out;
}
+ rc = test_dax_soft_offline(test, ndns);
+ if (rc) {
+ fprintf(stderr, "%s: failed dax soft offline\n",
+ ndctl_namespace_get_devname(ndns));
+ goto out;
+ }
+
rc = test_dax_poison(test, fd, align, NULL, 0, devdax);
if (rc) {
fprintf(stderr, "%s: failed dax poison\n",
--
2.27.0

View File

@ -0,0 +1,73 @@
From 11357d68b77392e4360ae2824e75bf8397a84885 Mon Sep 17 00:00:00 2001
From: Redhairer Li <redhairer.li@intel.com>
Date: Sat, 9 Jan 2021 23:36:33 +0800
Subject: [PATCH 007/217] msft: Add xlat_firmware_status for JEDEC Byte
Addressable Energy Backed DSM
Translate the status codes of the result of JEDEC Byte Addressable Energy Backed
DSM to generic errno style error codes.
Signed-off-by: Li Redhairer <redhairer.li@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/r/20210109153633.8493-1-redhairer.li@intel.com
---
ndctl/lib/msft.c | 22 ++++++++++++++++++++++
ndctl/lib/msft.h | 6 ++++++
2 files changed, 28 insertions(+)
diff --git a/ndctl/lib/msft.c b/ndctl/lib/msft.c
index 145872c..3112799 100644
--- a/ndctl/lib/msft.c
+++ b/ndctl/lib/msft.c
@@ -149,10 +149,32 @@ static unsigned int msft_cmd_smart_get_life_used(struct ndctl_cmd *cmd)
return 100 - CMD_MSFT_SMART(cmd)->nvm_lifetime;
}
+static int msft_cmd_xlat_firmware_status(struct ndctl_cmd *cmd)
+{
+ unsigned int status;
+
+ status = cmd->get_firmware_status(cmd) & NDN_MSFT_STATUS_MASK;
+
+ /* Common statuses */
+ switch (status) {
+ case NDN_MSFT_STATUS_SUCCESS:
+ return 0;
+ case NDN_MSFT_STATUS_NOTSUPP:
+ return -EOPNOTSUPP;
+ case NDN_MSFT_STATUS_INVALPARM:
+ return -EINVAL;
+ case NDN_MSFT_STATUS_I2CERR:
+ return -EIO;
+ }
+
+ return -ENOMSG;
+}
+
struct ndctl_dimm_ops * const msft_dimm_ops = &(struct ndctl_dimm_ops) {
.new_smart = msft_dimm_cmd_new_smart,
.smart_get_flags = msft_cmd_smart_get_flags,
.smart_get_health = msft_cmd_smart_get_health,
.smart_get_media_temperature = msft_cmd_smart_get_media_temperature,
.smart_get_life_used = msft_cmd_smart_get_life_used,
+ .xlat_firmware_status = msft_cmd_xlat_firmware_status,
};
diff --git a/ndctl/lib/msft.h b/ndctl/lib/msft.h
index 7cfd26f..978cc11 100644
--- a/ndctl/lib/msft.h
+++ b/ndctl/lib/msft.h
@@ -50,4 +50,10 @@ struct ndn_pkg_msft {
union ndn_msft_cmd u;
} __attribute__((packed));
+#define NDN_MSFT_STATUS_MASK 0xffff
+#define NDN_MSFT_STATUS_SUCCESS 0
+#define NDN_MSFT_STATUS_NOTSUPP 1
+#define NDN_MSFT_STATUS_INVALPARM 2
+#define NDN_MSFT_STATUS_I2CERR 3
+
#endif /* __NDCTL_MSFT_H__ */
--
2.27.0

View File

@ -0,0 +1,140 @@
From fe626a8a8a1b1bc94ea95c693ec672109909e3dc Mon Sep 17 00:00:00 2001
From: Redhairer Li <redhairer.li@intel.com>
Date: Thu, 28 Jan 2021 22:03:39 +0800
Subject: [PATCH 008/217] ndctl/namespace: Fix disable-namespace accounting
relative to seed devices
Seed namespaces are included in "ndctl disable-namespace all". However
since the user never "creates" them it is surprising to see
"disable-namespace" report 1 more namespace relative to the number that
have been created. Catch attempts to disable a zero-sized namespace:
Before:
{
"dev":"namespace1.0",
"size":"492.00 MiB (515.90 MB)",
"blockdev":"pmem1"
}
{
"dev":"namespace1.1",
"size":"492.00 MiB (515.90 MB)",
"blockdev":"pmem1.1"
}
{
"dev":"namespace1.2",
"size":"492.00 MiB (515.90 MB)",
"blockdev":"pmem1.2"
}
disabled 4 namespaces
After:
{
"dev":"namespace1.0",
"size":"492.00 MiB (515.90 MB)",
"blockdev":"pmem1"
}
{
"dev":"namespace1.3",
"size":"492.00 MiB (515.90 MB)",
"blockdev":"pmem1.3"
}
{
"dev":"namespace1.1",
"size":"492.00 MiB (515.90 MB)",
"blockdev":"pmem1.1"
}
disabled 3 namespaces
Signed-off-by: Redhairer Li <redhairer.li@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/linux-nvdimm/20210128140339.3080-1-redhairer.li@intel.com/
---
ndctl/lib/libndctl.c | 10 ++++++++--
ndctl/namespace.c | 8 ++++----
ndctl/region.c | 2 +-
3 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 36fb6fe..2f6d806 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -4602,6 +4602,7 @@ NDCTL_EXPORT int ndctl_namespace_disable_safe(struct ndctl_namespace *ndns)
const char *bdev = NULL;
char path[50];
int fd;
+ unsigned long long size = ndctl_namespace_get_size(ndns);
if (pfn && ndctl_pfn_is_enabled(pfn))
bdev = ndctl_pfn_get_block_device(pfn);
@@ -4631,8 +4632,13 @@ NDCTL_EXPORT int ndctl_namespace_disable_safe(struct ndctl_namespace *ndns)
devname, bdev, strerror(errno));
return -errno;
}
- } else
- ndctl_namespace_disable_invalidate(ndns);
+ } else {
+ if (size == 0)
+ /* No disable necessary due to no capacity allocated */
+ return 1;
+ else
+ ndctl_namespace_disable_invalidate(ndns);
+ }
return 0;
}
diff --git a/ndctl/namespace.c b/ndctl/namespace.c
index 0c8df9f..1feb74d 100644
--- a/ndctl/namespace.c
+++ b/ndctl/namespace.c
@@ -1125,7 +1125,7 @@ static int namespace_prep_reconfig(struct ndctl_region *region,
}
rc = ndctl_namespace_disable_safe(ndns);
- if (rc)
+ if (rc < 0)
return rc;
ndctl_namespace_set_enforce_mode(ndns, NDCTL_NS_MODE_RAW);
@@ -1431,7 +1431,7 @@ static int dax_clear_badblocks(struct ndctl_dax *dax)
return -ENXIO;
rc = ndctl_namespace_disable_safe(ndns);
- if (rc) {
+ if (rc < 0) {
error("%s: unable to disable namespace: %s\n", devname,
strerror(-rc));
return rc;
@@ -1455,7 +1455,7 @@ static int pfn_clear_badblocks(struct ndctl_pfn *pfn)
return -ENXIO;
rc = ndctl_namespace_disable_safe(ndns);
- if (rc) {
+ if (rc < 0) {
error("%s: unable to disable namespace: %s\n", devname,
strerror(-rc));
return rc;
@@ -1478,7 +1478,7 @@ static int raw_clear_badblocks(struct ndctl_namespace *ndns)
return -ENXIO;
rc = ndctl_namespace_disable_safe(ndns);
- if (rc) {
+ if (rc < 0) {
error("%s: unable to disable namespace: %s\n", devname,
strerror(-rc));
return rc;
diff --git a/ndctl/region.c b/ndctl/region.c
index 3edb9b3..4552c4a 100644
--- a/ndctl/region.c
+++ b/ndctl/region.c
@@ -70,7 +70,7 @@ static int region_action(struct ndctl_region *region, enum device_action mode)
case ACTION_DISABLE:
ndctl_namespace_foreach(region, ndns) {
rc = ndctl_namespace_disable_safe(ndns);
- if (rc)
+ if (rc < 0)
return rc;
}
rc = ndctl_region_disable_invalidate(region);
--
2.27.0

View File

@ -0,0 +1,50 @@
From fb13dfb8d84c4f0a749665c8f07179450b199f3e Mon Sep 17 00:00:00 2001
From: Jeff Moyer <jmoyer@redhat.com>
Date: Tue, 9 Feb 2021 16:51:53 -0500
Subject: [PATCH 009/217] zero_info_block: skip seed devices
Currently, ndctl destroy-namespace -f all will output errors of the
form:
Error: destroy namespace: namespace0.0 failed to enable for zeroing, continuing
for any zero-sized namespace. That particular namespace looks like this:
{
"dev":"namespace0.0",
"mode":"raw",
"size":0,
"uuid":"00000000-0000-0000-0000-000000000000",
"sector_size":512,
"state":"disabled"
}
This patch skips over namespaces with size=0 when zeroing out info
blocks.
Fixes: 46654c2d60b70 ("ndctl/namespace: Always zero info-blocks")
Reported-by: Zhang Yi <yizhan@redhat.com>
Signed-off-by: Jeff Moyer <jmoyer@redhat.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/r/x49r1lohpty.fsf@segfault.boston.devel.redhat.com
---
ndctl/namespace.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/ndctl/namespace.c b/ndctl/namespace.c
index 1feb74d..1e8a2cd 100644
--- a/ndctl/namespace.c
+++ b/ndctl/namespace.c
@@ -1052,6 +1052,9 @@ static int zero_info_block(struct ndctl_namespace *ndns)
void *buf = NULL, *read_buf = NULL;
char path[50];
+ if (ndctl_namespace_get_size(ndns) == 0)
+ return 1;
+
ndctl_namespace_set_raw_mode(ndns, 1);
rc = ndctl_namespace_enable(ndns);
if (rc < 0) {
--
2.27.0

View File

@ -0,0 +1,51 @@
From 5d0d4dc5ae1de82de92212c98297b24fbba09227 Mon Sep 17 00:00:00 2001
From: QI Fuli <qi.fuli@fujitsu.com>
Date: Tue, 2 Feb 2021 22:02:06 +0900
Subject: [PATCH 010/217] ndctl: update .gitignore
Add Documentation/ndctl/attrs.adoc and *.lo to .gitignore.
Signed-off-by: QI Fuli <qi.fuli@fujitsu.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/r/20210202130206.3761-1-qi.fuli@fujitsu.com
---
.gitignore | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/.gitignore b/.gitignore
index 3ef9ff7..53512b2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
*.o
+*.lo
*.xml
.deps/
.libs/
@@ -15,13 +16,13 @@ Makefile.in
*.1
Documentation/daxctl/asciidoc.conf
Documentation/ndctl/asciidoc.conf
+Documentation/ndctl/attrs.adoc
Documentation/daxctl/asciidoctor-extensions.rb
Documentation/ndctl/asciidoctor-extensions.rb
.dirstamp
daxctl/config.h
daxctl/daxctl
daxctl/lib/libdaxctl.la
-daxctl/lib/libdaxctl.lo
daxctl/lib/libdaxctl.pc
*.a
ndctl/config.h
@@ -29,8 +30,6 @@ ndctl/lib/libndctl.pc
ndctl/ndctl
rhel/
sles/ndctl.spec
-util/log.lo
-util/sysfs.lo
version.m4
*.swp
cscope.files
--
2.27.0

View File

@ -0,0 +1,127 @@
From 7ce2fddfa3f108036a2d81de4d2e66ac29e4631e Mon Sep 17 00:00:00 2001
From: QI Fuli <qi.fuli@fujitsu.com>
Date: Wed, 3 Feb 2021 22:21:08 +0900
Subject: [PATCH 011/217] ndctl/test: add checking the presence of jq command
ahead
Due to the lack of jq command, the result of the test will be 'fail'.
This patch adds checking the presence of jq commmand ahead.
If there is no jq command in the system, the test will be marked as 'skip'.
Signed-off-by: QI Fuli <qi.fuli@fujitsu.com>
Link: https://github.com/pmem/ndctl/issues/141
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/r/20210203132108.6246-1-qi.fuli@fujitsu.com
---
test/daxdev-errors.sh | 1 +
test/inject-error.sh | 2 ++
test/inject-smart.sh | 1 +
test/label-compat.sh | 1 +
test/max_available_extent_ns.sh | 1 +
test/monitor.sh | 2 ++
test/multi-dax.sh | 1 +
test/sector-mode.sh | 2 ++
8 files changed, 11 insertions(+)
diff --git a/test/daxdev-errors.sh b/test/daxdev-errors.sh
index 6281f32..9547d78 100755
--- a/test/daxdev-errors.sh
+++ b/test/daxdev-errors.sh
@@ -9,6 +9,7 @@ rc=77
. $(dirname $0)/common
check_min_kver "4.12" || do_skip "lacks dax dev error handling"
+check_prereq "jq"
trap 'err $LINENO' ERR
diff --git a/test/inject-error.sh b/test/inject-error.sh
index c636033..7d0b826 100755
--- a/test/inject-error.sh
+++ b/test/inject-error.sh
@@ -11,6 +11,8 @@ err_count=8
. $(dirname $0)/common
+check_prereq "jq"
+
trap 'err $LINENO' ERR
# sample json:
diff --git a/test/inject-smart.sh b/test/inject-smart.sh
index 94705df..4ca83b8 100755
--- a/test/inject-smart.sh
+++ b/test/inject-smart.sh
@@ -166,6 +166,7 @@ do_tests()
}
check_min_kver "4.19" || do_skip "kernel $KVER may not support smart (un)injection"
+check_prereq "jq"
modprobe nfit_test
rc=1
diff --git a/test/label-compat.sh b/test/label-compat.sh
index 340b93d..8ab2858 100755
--- a/test/label-compat.sh
+++ b/test/label-compat.sh
@@ -10,6 +10,7 @@ BASE=$(dirname $0)
. $BASE/common
check_min_kver "4.11" || do_skip "may not provide reliable isetcookie values"
+check_prereq "jq"
trap 'err $LINENO' ERR
diff --git a/test/max_available_extent_ns.sh b/test/max_available_extent_ns.sh
index 14d741d..343f3c9 100755
--- a/test/max_available_extent_ns.sh
+++ b/test/max_available_extent_ns.sh
@@ -9,6 +9,7 @@ rc=77
trap 'err $LINENO' ERR
check_min_kver "4.19" || do_skip "kernel $KVER may not support max_available_size"
+check_prereq "jq"
init()
{
diff --git a/test/monitor.sh b/test/monitor.sh
index cdab5e1..28c5541 100755
--- a/test/monitor.sh
+++ b/test/monitor.sh
@@ -13,6 +13,8 @@ smart_supported_bus=""
. $(dirname $0)/common
+check_prereq "jq"
+
trap 'err $LINENO' ERR
check_min_kver "4.15" || do_skip "kernel $KVER may not support monitor service"
diff --git a/test/multi-dax.sh b/test/multi-dax.sh
index e932569..8496619 100755
--- a/test/multi-dax.sh
+++ b/test/multi-dax.sh
@@ -9,6 +9,7 @@ rc=77
. $(dirname $0)/common
check_min_kver "4.13" || do_skip "may lack multi-dax support"
+check_prereq "jq"
trap 'err $LINENO' ERR
diff --git a/test/sector-mode.sh b/test/sector-mode.sh
index dd7013e..54fa806 100755
--- a/test/sector-mode.sh
+++ b/test/sector-mode.sh
@@ -6,6 +6,8 @@ rc=77
. $(dirname $0)/common
+check_prereq "jq"
+
set -e
trap 'err $LINENO' ERR
--
2.27.0

View File

@ -0,0 +1,78 @@
From c81fa15bafb1295aaa7d7f09500c3fbdd68b0011 Mon Sep 17 00:00:00 2001
From: "Tsaur, Erwin" <erwin.tsaur@intel.com>
Date: Thu, 4 Mar 2021 17:18:04 -0800
Subject: [PATCH 012/217] Expose ndctl_bus_nfit_translate_spa as a public
function.
The motivation is to allow access to ACPI defined NVDIMM Root Device
_DSM Function Index 5(Translate SPA). The rest of the _DSM functions,
which are mostly ARS related, are already public.
Basically move ndctl_bus_nfit_translate_spa declaration from private.h
to libndctl.h.
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: "Tsaur, Erwin" <erwin.tsaur@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/r/20210305011804.3573-1-erwin.tsaur@intel.com
---
ndctl/lib/libndctl.sym | 4 ++++
ndctl/lib/nfit.c | 2 +-
ndctl/lib/private.h | 2 --
ndctl/libndctl.h | 2 ++
4 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index 0a82616..58afb74 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -451,3 +451,7 @@ LIBNDCTL_25 {
ndctl_bus_clear_fw_activate_nosuspend;
ndctl_bus_activate_firmware;
} LIBNDCTL_24;
+
+LIBNDCTL_26 {
+ ndctl_bus_nfit_translate_spa;
+} LIBNDCTL_25;
diff --git a/ndctl/lib/nfit.c b/ndctl/lib/nfit.c
index 6f68fcf..d85682f 100644
--- a/ndctl/lib/nfit.c
+++ b/ndctl/lib/nfit.c
@@ -114,7 +114,7 @@ static int is_valid_spa(struct ndctl_bus *bus, unsigned long long spa)
*
* If success, returns zero, store dimm's @handle, and @dpa.
*/
-int ndctl_bus_nfit_translate_spa(struct ndctl_bus *bus,
+NDCTL_EXPORT int ndctl_bus_nfit_translate_spa(struct ndctl_bus *bus,
unsigned long long address, unsigned int *handle, unsigned long long *dpa)
{
diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h
index ede1300..8f4510e 100644
--- a/ndctl/lib/private.h
+++ b/ndctl/lib/private.h
@@ -370,8 +370,6 @@ static inline int check_kmod(struct kmod_ctx *kmod_ctx)
return kmod_ctx ? 0 : -ENXIO;
}
-int ndctl_bus_nfit_translate_spa(struct ndctl_bus *bus, unsigned long long addr,
- unsigned int *handle, unsigned long long *dpa);
struct ndctl_cmd *ndctl_bus_cmd_new_err_inj(struct ndctl_bus *bus);
struct ndctl_cmd *ndctl_bus_cmd_new_err_inj_clr(struct ndctl_bus *bus);
struct ndctl_cmd *ndctl_bus_cmd_new_err_inj_stat(struct ndctl_bus *bus,
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index 60e1288..87d07b7 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -152,6 +152,8 @@ int ndctl_bus_clear_fw_activate_noidle(struct ndctl_bus *bus);
int ndctl_bus_set_fw_activate_nosuspend(struct ndctl_bus *bus);
int ndctl_bus_clear_fw_activate_nosuspend(struct ndctl_bus *bus);
int ndctl_bus_activate_firmware(struct ndctl_bus *bus, enum ndctl_fwa_method method);
+int ndctl_bus_nfit_translate_spa(struct ndctl_bus *bus, unsigned long long addr,
+ unsigned int *handle, unsigned long long *dpa);
struct ndctl_dimm;
struct ndctl_dimm *ndctl_dimm_get_first(struct ndctl_bus *bus);
--
2.27.0

View File

@ -0,0 +1,72 @@
From 43e48c0d2f271cba4237f6eefc3e4912a74c102b Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Tue, 9 Mar 2021 22:09:49 -0800
Subject: [PATCH 013/217] test/libndctl: Use ndctl_region_set_ro() to change
disk read-only state
Kernel commit 52f019d43c22 ("block: add a hard-readonly flag to struct
gendisk") broke the read-only management test, by fixing the broken
behavior that BLKROSET could make a block device read-write even when the
disk is read-only. The fix [1] propagates changes of the region
read-only state to the underlying disk. Add ndctl_region_set_ro() ahead of
BLKROSET so that BLKROSET does not conflict the block_device state with the
disk state.
[1]: http://lore.kernel.org/r/161534060720.528671.2341213328968989192.stgit@dwillia2-desk3.amr.corp.intel.com
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/r/161535658913.530219.12194565167385663385.stgit@dwillia2-desk3.amr.corp.intel.com
---
test/libndctl.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/test/libndctl.c b/test/libndctl.c
index fc65149..c42f785 100644
--- a/test/libndctl.c
+++ b/test/libndctl.c
@@ -1541,6 +1541,7 @@ static int validate_bdev(const char *devname, struct ndctl_btt *btt,
struct ndctl_pfn *pfn, struct ndctl_namespace *ndns,
struct namespace *namespace, void *buf)
{
+ struct ndctl_region *region = ndctl_namespace_get_region(ndns);
char bdevpath[50];
int fd, rc, ro;
@@ -1578,6 +1579,13 @@ static int validate_bdev(const char *devname, struct ndctl_btt *btt,
}
ro = 0;
+ rc = ndctl_region_set_ro(region, ro);
+ if (rc < 0) {
+ fprintf(stderr, "%s: ndctl_region_set_ro failed\n", devname);
+ rc = -errno;
+ goto out;
+ }
+
rc = ioctl(fd, BLKROSET, &ro);
if (rc < 0) {
fprintf(stderr, "%s: BLKROSET failed\n",
@@ -1605,8 +1613,16 @@ static int validate_bdev(const char *devname, struct ndctl_btt *btt,
rc = -ENXIO;
goto out;
}
+
+ rc = ndctl_region_set_ro(region, namespace->ro);
+ if (rc < 0) {
+ fprintf(stderr, "%s: ndctl_region_set_ro reset failed\n", devname);
+ rc = -errno;
+ goto out;
+ }
+
rc = 0;
- out:
+out:
close(fd);
return rc;
}
--
2.27.0

View File

@ -0,0 +1,221 @@
From 99415dfc7c5167c49a5732f577836f68872645b2 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Wed, 24 Mar 2021 12:09:29 -0700
Subject: [PATCH 014/217] daxctl: fail reconfigure-device based on kernel
onlining policy
If the kernel has a policy set to auto-online any new memory blocks, we
know that an attempt to reconfigure a device either in ZONE_MOVABLE, or
with the --no-online is going to fail. While we detect this race after
the fact, and print a warning, that is often insufficient as the user
may be forced to reboot to get out of the situation, resulting in an
unpleasant experience.
Detect whether the kernel policy is set to auto-online. If so, fail
device reconfigure operations that we know can't be satisfied. Allow
for overriding this safety check via the -f (--force) option. Update the
man page to talk about this, and the unit test to test for an expected
failure by enabling auto-onlining.
Cc: Dave Hansen <dave.hansen@intel.com>
Reported-by: Chunye Xu <chunye.xu@intel.com>
Reported-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
.../daxctl/daxctl-reconfigure-device.txt | 12 ++++++-
daxctl/device.c | 10 ++++++
daxctl/lib/libdaxctl-private.h | 1 +
daxctl/lib/libdaxctl.c | 21 +++++++++++
daxctl/lib/libdaxctl.sym | 5 +++
daxctl/libdaxctl.h | 1 +
test/daxctl-devices.sh | 36 +++++++++++++++++++
7 files changed, 85 insertions(+), 1 deletion(-)
diff --git a/Documentation/daxctl/daxctl-reconfigure-device.txt b/Documentation/daxctl/daxctl-reconfigure-device.txt
index ad33eda..f112b3c 100644
--- a/Documentation/daxctl/daxctl-reconfigure-device.txt
+++ b/Documentation/daxctl/daxctl-reconfigure-device.txt
@@ -119,6 +119,10 @@ recommended to use the --no-online option described below. This will abridge
the device reconfiguration operation to just hotplugging the memory, and
refrain from then onlining it.
+In case daxctl detects that there is a kernel policy to auto-online blocks
+(via /sys/devices/system/memory/auto_online_blocks), then reconfiguring to
+system-ram will result in a failure. This can be overridden with '--force'.
+
OPTIONS
-------
include::region-option.txt[]
@@ -162,12 +166,18 @@ include::movable-options.txt[]
-f::
--force::
- When converting from "system-ram" mode to "devdax", it is expected
+ - When converting from "system-ram" mode to "devdax", it is expected
that all the memory sections are first made offline. By default,
daxctl won't touch online memory. However with this option, attempt
to offline the memory on the NUMA node associated with the dax device
before converting it back to "devdax" mode.
+ - Additionally, if a kernel policy to auto-online blocks is detected,
+ reconfiguration to system-ram fails. With this option, the failure can
+ be overridden to allow reconfiguration regardless of kernel policy.
+ Doing this may result in a successful reconfiguration, but it may
+ not be possible to subsequently offline the memory without a reboot.
+
include::human-option.txt[]
diff --git a/daxctl/device.c b/daxctl/device.c
index 0721a57..a427b7d 100644
--- a/daxctl/device.c
+++ b/daxctl/device.c
@@ -541,8 +541,18 @@ static int disable_devdax_device(struct daxctl_dev *dev)
static int reconfig_mode_system_ram(struct daxctl_dev *dev)
{
+ const char *devname = daxctl_dev_get_devname(dev);
int rc, skip_enable = 0;
+ if (param.no_online || !param.no_movable) {
+ if (!param.force && daxctl_dev_will_auto_online_memory(dev)) {
+ fprintf(stderr,
+ "%s: error: kernel policy will auto-online memory, aborting\n",
+ devname);
+ return -EBUSY;
+ }
+ }
+
if (daxctl_dev_is_enabled(dev)) {
rc = disable_devdax_device(dev);
if (rc < 0)
diff --git a/daxctl/lib/libdaxctl-private.h b/daxctl/lib/libdaxctl-private.h
index af257fd..ae45311 100644
--- a/daxctl/lib/libdaxctl-private.h
+++ b/daxctl/lib/libdaxctl-private.h
@@ -111,6 +111,7 @@ struct daxctl_memory {
char *node_path;
unsigned long block_size;
enum memory_zones zone;
+ bool auto_online;
};
diff --git a/daxctl/lib/libdaxctl.c b/daxctl/lib/libdaxctl.c
index 479e8f6..879f7e6 100644
--- a/daxctl/lib/libdaxctl.c
+++ b/daxctl/lib/libdaxctl.c
@@ -1644,3 +1644,24 @@ DAXCTL_EXPORT int daxctl_memory_is_movable(struct daxctl_memory *mem)
return rc;
return (mem->zone == MEM_ZONE_MOVABLE) ? 1 : 0;
}
+
+DAXCTL_EXPORT int daxctl_dev_will_auto_online_memory(struct daxctl_dev *dev)
+{
+ const char *auto_path = "/sys/devices/system/memory/auto_online_blocks";
+ const char *devname = daxctl_dev_get_devname(dev);
+ struct daxctl_ctx *ctx = daxctl_dev_get_ctx(dev);
+ char buf[SYSFS_ATTR_SIZE];
+
+ /*
+ * If we can't read the policy for some reason, don't fail yet. Assume
+ * the auto-onlining policy is absent, and carry on. If onlining blocks
+ * does result in the memory being in an inconsistent state, we have a
+ * check and warning for it after the fact
+ */
+ if (sysfs_read_attr(ctx, auto_path, buf) != 0)
+ err(ctx, "%s: Unable to determine auto-online policy: %s\n",
+ devname, strerror(errno));
+
+ /* match both "online" and "online_movable" */
+ return !strncmp(buf, "online", 6);
+}
diff --git a/daxctl/lib/libdaxctl.sym b/daxctl/lib/libdaxctl.sym
index a4e1684..892e393 100644
--- a/daxctl/lib/libdaxctl.sym
+++ b/daxctl/lib/libdaxctl.sym
@@ -91,3 +91,8 @@ global:
daxctl_mapping_get_size;
daxctl_dev_set_mapping;
} LIBDAXCTL_7;
+
+LIBDAXCTL_9 {
+global:
+ daxctl_dev_will_auto_online_memory;
+} LIBDAXCTL_8;
diff --git a/daxctl/libdaxctl.h b/daxctl/libdaxctl.h
index e82b274..30ab51a 100644
--- a/daxctl/libdaxctl.h
+++ b/daxctl/libdaxctl.h
@@ -71,6 +71,7 @@ int daxctl_dev_disable(struct daxctl_dev *dev);
int daxctl_dev_enable_devdax(struct daxctl_dev *dev);
int daxctl_dev_enable_ram(struct daxctl_dev *dev);
int daxctl_dev_get_target_node(struct daxctl_dev *dev);
+int daxctl_dev_will_auto_online_memory(struct daxctl_dev *dev);
struct daxctl_memory;
struct daxctl_memory *daxctl_dev_get_memory(struct daxctl_dev *dev);
diff --git a/test/daxctl-devices.sh b/test/daxctl-devices.sh
index 496e4f2..eed5906 100755
--- a/test/daxctl-devices.sh
+++ b/test/daxctl-devices.sh
@@ -64,6 +64,26 @@ daxctl_get_mode()
"$DAXCTL" list -d "$1" | jq -er '.[].mode'
}
+set_online_policy()
+{
+ echo "online" > /sys/devices/system/memory/auto_online_blocks
+}
+
+unset_online_policy()
+{
+ echo "offline" > /sys/devices/system/memory/auto_online_blocks
+}
+
+save_online_policy()
+{
+ saved_policy="$(cat /sys/devices/system/memory/auto_online_blocks)"
+}
+
+restore_online_policy()
+{
+ echo "$saved_policy" > /sys/devices/system/memory/auto_online_blocks
+}
+
daxctl_test()
{
local daxdev
@@ -71,6 +91,9 @@ daxctl_test()
daxdev=$(daxctl_get_dev "$testdev")
test -n "$daxdev"
+ # these tests need to run with kernel onlining policy turned off
+ save_online_policy
+ unset_online_policy
"$DAXCTL" reconfigure-device -N -m system-ram "$daxdev"
[[ $(daxctl_get_mode "$daxdev") == "system-ram" ]]
"$DAXCTL" online-memory "$daxdev"
@@ -81,6 +104,19 @@ daxctl_test()
[[ $(daxctl_get_mode "$daxdev") == "system-ram" ]]
"$DAXCTL" reconfigure-device -f -m devdax "$daxdev"
[[ $(daxctl_get_mode "$daxdev") == "devdax" ]]
+
+ # this tests for reconfiguration failure if an online-policy is set
+ set_online_policy
+ : "This command is expected to fail:"
+ if ! "$DAXCTL" reconfigure-device -N -m system-ram "$daxdev"; then
+ echo "reconfigure failed as expected"
+ else
+ echo "reconfigure succeded, expected failure"
+ restore_online_policy
+ return 1
+ fi
+
+ restore_online_policy
}
find_testdev
--
2.27.0

View File

@ -0,0 +1,63 @@
From e563e6a7c55e65c554e07db6215f8bcb2d411d3b Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Tue, 30 Mar 2021 20:50:37 -0600
Subject: [PATCH 015/217] libdaxctl: add an API to check if a device is active
Add an API to check whether a daxctl device is active in system-ram
mode. This would be used from libndctl during
ndctl_namespace_disable_safe(), so that we don't disable/destroy an
underlying namespace while the memory is active and online.
Reported-by: Chunye Xu <chunye.xu@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
daxctl/lib/libdaxctl.c | 10 ++++++++++
daxctl/lib/libdaxctl.sym | 1 +
daxctl/libdaxctl.h | 1 +
3 files changed, 12 insertions(+)
diff --git a/daxctl/lib/libdaxctl.c b/daxctl/lib/libdaxctl.c
index 879f7e6..860bd9c 100644
--- a/daxctl/lib/libdaxctl.c
+++ b/daxctl/lib/libdaxctl.c
@@ -1665,3 +1665,13 @@ DAXCTL_EXPORT int daxctl_dev_will_auto_online_memory(struct daxctl_dev *dev)
/* match both "online" and "online_movable" */
return !strncmp(buf, "online", 6);
}
+
+DAXCTL_EXPORT int daxctl_dev_has_online_memory(struct daxctl_dev *dev)
+{
+ struct daxctl_memory *mem = daxctl_dev_get_memory(dev);
+
+ if (mem)
+ return daxctl_memory_is_online(mem);
+ else
+ return 0;
+}
diff --git a/daxctl/lib/libdaxctl.sym b/daxctl/lib/libdaxctl.sym
index 892e393..a13e93d 100644
--- a/daxctl/lib/libdaxctl.sym
+++ b/daxctl/lib/libdaxctl.sym
@@ -95,4 +95,5 @@ global:
LIBDAXCTL_9 {
global:
daxctl_dev_will_auto_online_memory;
+ daxctl_dev_has_online_memory;
} LIBDAXCTL_8;
diff --git a/daxctl/libdaxctl.h b/daxctl/libdaxctl.h
index 30ab51a..683ae9c 100644
--- a/daxctl/libdaxctl.h
+++ b/daxctl/libdaxctl.h
@@ -72,6 +72,7 @@ int daxctl_dev_enable_devdax(struct daxctl_dev *dev);
int daxctl_dev_enable_ram(struct daxctl_dev *dev);
int daxctl_dev_get_target_node(struct daxctl_dev *dev);
int daxctl_dev_will_auto_online_memory(struct daxctl_dev *dev);
+int daxctl_dev_has_online_memory(struct daxctl_dev *dev);
struct daxctl_memory;
struct daxctl_memory *daxctl_dev_get_memory(struct daxctl_dev *dev);
--
2.27.0

View File

@ -0,0 +1,113 @@
From 573f0d46cff15fff2804b3fb444d1e34f482e788 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Tue, 30 Mar 2021 20:54:55 -0600
Subject: [PATCH 016/217] libndctl: check for active system-ram before
disabling daxctl devices
Teach ndctl_namespace_disable_safe() to look at the state of a
daxctl_dev with respect to whether it is active in 'system-ram' mode
before disabling it. This is similar to checking whether a filesystem is
actively mounted on a namespace before disabling it.
Without this, libndctl would happily disable a devdax namespace while the
device was active in system-ram mode. If the namespace was subsequently
also destroyed, this would leave the memory without any sort of a
'handle' to perform any subsequent operation on it, and the system would
have to be rebooted to get out of this situation.
Reported-by: Chunye Xu <chunye.xu@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
ndctl/lib/libndctl.c | 25 ++++++++++++++++++++++++-
test/daxctl-devices.sh | 16 ++++++++++++++++
2 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 2f6d806..2eda56c 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -4593,21 +4593,40 @@ NDCTL_EXPORT int ndctl_namespace_disable_invalidate(struct ndctl_namespace *ndns
return ndctl_namespace_disable(ndns);
}
+static int ndctl_dax_has_active_memory(struct ndctl_dax *dax)
+{
+ struct daxctl_region *dax_region;
+ struct daxctl_dev *dax_dev;
+
+ dax_region = ndctl_dax_get_daxctl_region(dax);
+ if (!dax_region)
+ return 0;
+
+ daxctl_dev_foreach(dax_region, dax_dev)
+ if (daxctl_dev_has_online_memory(dax_dev))
+ return 1;
+
+ return 0;
+}
+
NDCTL_EXPORT int ndctl_namespace_disable_safe(struct ndctl_namespace *ndns)
{
const char *devname = ndctl_namespace_get_devname(ndns);
struct ndctl_ctx *ctx = ndctl_namespace_get_ctx(ndns);
struct ndctl_pfn *pfn = ndctl_namespace_get_pfn(ndns);
struct ndctl_btt *btt = ndctl_namespace_get_btt(ndns);
+ struct ndctl_dax *dax = ndctl_namespace_get_dax(ndns);
const char *bdev = NULL;
+ int fd, active = 0;
char path[50];
- int fd;
unsigned long long size = ndctl_namespace_get_size(ndns);
if (pfn && ndctl_pfn_is_enabled(pfn))
bdev = ndctl_pfn_get_block_device(pfn);
else if (btt && ndctl_btt_is_enabled(btt))
bdev = ndctl_btt_get_block_device(btt);
+ else if (dax && ndctl_dax_is_enabled(dax))
+ active = ndctl_dax_has_active_memory(dax);
else if (ndctl_namespace_is_enabled(ndns))
bdev = ndctl_namespace_get_block_device(ndns);
@@ -4632,6 +4651,10 @@ NDCTL_EXPORT int ndctl_namespace_disable_safe(struct ndctl_namespace *ndns)
devname, bdev, strerror(errno));
return -errno;
}
+ } else if (active) {
+ dbg(ctx, "%s: active as system-ram, refusing to disable\n",
+ devname);
+ return -EBUSY;
} else {
if (size == 0)
/* No disable necessary due to no capacity allocated */
diff --git a/test/daxctl-devices.sh b/test/daxctl-devices.sh
index eed5906..56c9691 100755
--- a/test/daxctl-devices.sh
+++ b/test/daxctl-devices.sh
@@ -105,6 +105,22 @@ daxctl_test()
"$DAXCTL" reconfigure-device -f -m devdax "$daxdev"
[[ $(daxctl_get_mode "$daxdev") == "devdax" ]]
+ # fail 'ndctl-disable-namespace' while the devdax namespace is active
+ # as system-ram. If this test fails, a reboot will be required to
+ # recover from the resulting state.
+ test -n "$testdev"
+ "$DAXCTL" reconfigure-device -m system-ram "$daxdev"
+ [[ $(daxctl_get_mode "$daxdev") == "system-ram" ]]
+ if ! "$NDCTL" disable-namespace "$testdev"; then
+ echo "disable-namespace failed as expected"
+ else
+ echo "disable-namespace succeded, expected failure"
+ echo "reboot required to recover from this state"
+ return 1
+ fi
+ "$DAXCTL" reconfigure-device -f -m devdax "$daxdev"
+ [[ $(daxctl_get_mode "$daxdev") == "devdax" ]]
+
# this tests for reconfiguration failure if an online-policy is set
set_online_policy
: "This command is expected to fail:"
--
2.27.0

View File

@ -0,0 +1,49 @@
From e81f890c7ae1c940c7f52b8984e8728706489728 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Wed, 31 Mar 2021 13:51:35 -0600
Subject: [PATCH 017/217] daxctl: emit counts of total and online memblocks
Fir daxctl device listings, if in 'system-ram' mode, it is useful to
know whether the memory associated with the device is online or not.
Since the memory is comprised of a number of 'memblocks', and it is
possible (albeit rare) to have a subset of them online, and the rest
offline, we can't just use a boolean online-or-offline flag for the
state.
Add a couple of counts, one for the total number of memblocks associated
with the device, and another for the ones that are online.
Link: https://github.com/pmem/ndctl/issues/139
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Reported-by: Steve Scargall <steve.scargall@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
util/json.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/util/json.c b/util/json.c
index ca0167b..a8d2412 100644
--- a/util/json.c
+++ b/util/json.c
@@ -482,6 +482,17 @@ struct json_object *util_daxctl_dev_to_json(struct daxctl_dev *dev,
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);
--
2.27.0

View File

@ -1,24 +1,22 @@
libndctl: Unify adding dimms for papr and nfit families
From daef3a386a9c45105a2c045ddee46600e265939f Mon Sep 17 00:00:00 2001
From: Santosh Sivaraj <santosh@fossix.org>
Date: Thu, 13 May 2021 11:42:15 +0530
Subject: [PATCH 018/217] libndctl: Unify adding dimms for papr and nfit
families
BZ:
Brew:
In preparation for enabling tests on non-nfit devices, unify both, already very
similar, functions into one. This will help in adding all attributes needed for
the unit tests. Since the function doesn't fail if some of the dimm attributes
are missing, this will work fine on PAPR platforms though only part of the DIMM
attributes are provided (This doesn't mean that all of the DIMM attributes can
be missing).
commit daef3a386a9c45105a2c045ddee46600e265939f
Author: Santosh Sivaraj <santosh@fossix.org>
Date: Thu May 13 11:42:15 2021 +0530
libndctl: Unify adding dimms for papr and nfit families
In preparation for enabling tests on non-nfit devices, unify both, already very
similar, functions into one. This will help in adding all attributes needed for
the unit tests. Since the function doesn't fail if some of the dimm attributes
are missing, this will work fine on PAPR platforms though only part of the DIMM
attributes are provided (This doesn't mean that all of the DIMM attributes can
be missing).
Link: https://lore.kernel.org/r/20210513061218.760322-1-santosh@fossix.org
Signed-off-by: Santosh Sivaraj <santosh@fossix.org>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/r/20210513061218.760322-1-santosh@fossix.org
Signed-off-by: Santosh Sivaraj <santosh@fossix.org>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
ndctl/lib/libndctl.c | 103 ++++++++++++++++---------------------------
1 file changed, 38 insertions(+), 65 deletions(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 2f6d806..e45353f 100644
@ -217,3 +215,6 @@ index 2f6d806..e45353f 100644
sprintf(path, "%s/read_only", region_base);
if (sysfs_read_attr(ctx, path, buf) < 0)
--
2.27.0

View File

@ -0,0 +1,211 @@
From 1649ad9c3e2c6e9c47870c8d3b54f10b24177bc7 Mon Sep 17 00:00:00 2001
From: Santosh Sivaraj <santosh@fossix.org>
Date: Thu, 13 May 2021 11:42:16 +0530
Subject: [PATCH 019/217] test: Don't skip tests if nfit modules are missing
For NFIT to be available ACPI is a must, so don't fail when nfit modules
are missing on a platform that doesn't support ACPI.
Link: https://lore.kernel.org/r/20210513061218.760322-2-santosh@fossix.org
Signed-off-by: Santosh Sivaraj <santosh@fossix.org>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
test.h | 2 +-
test/ack-shutdown-count-set.c | 2 +-
test/blk_namespaces.c | 2 +-
test/core.c | 28 ++++++++++++++++++++++++++--
test/dpa-alloc.c | 2 +-
test/dsm-fail.c | 2 +-
test/libndctl.c | 2 +-
test/multi-pmem.c | 2 +-
test/parent-uuid.c | 2 +-
test/pmem_namespaces.c | 2 +-
10 files changed, 35 insertions(+), 11 deletions(-)
diff --git a/test.h b/test.h
index cba8d41..7de13fe 100644
--- a/test.h
+++ b/test.h
@@ -20,7 +20,7 @@ void builtin_xaction_namespace_reset(void);
struct kmod_ctx;
struct kmod_module;
-int nfit_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
+int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
struct ndctl_ctx *nd_ctx, int log_level,
struct ndctl_test *test);
diff --git a/test/ack-shutdown-count-set.c b/test/ack-shutdown-count-set.c
index fb1d82b..c561ff3 100644
--- a/test/ack-shutdown-count-set.c
+++ b/test/ack-shutdown-count-set.c
@@ -99,7 +99,7 @@ static int test_ack_shutdown_count_set(int loglevel, struct ndctl_test *test,
int result = EXIT_FAILURE, err;
ndctl_set_log_priority(ctx, loglevel);
- err = nfit_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
+ err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
if (err < 0) {
result = 77;
ndctl_test_skip(test);
diff --git a/test/blk_namespaces.c b/test/blk_namespaces.c
index d7f00cb..f076e85 100644
--- a/test/blk_namespaces.c
+++ b/test/blk_namespaces.c
@@ -228,7 +228,7 @@ int test_blk_namespaces(int log_level, struct ndctl_test *test,
if (!bus) {
fprintf(stderr, "ACPI.NFIT unavailable falling back to nfit_test\n");
- rc = nfit_test_init(&kmod_ctx, &mod, NULL, log_level, test);
+ 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) {
diff --git a/test/core.c b/test/core.c
index cc7d8d9..2b03aa9 100644
--- a/test/core.c
+++ b/test/core.c
@@ -11,6 +11,7 @@
#include <util/log.h>
#include <util/sysfs.h>
#include <ndctl/libndctl.h>
+#include <ndctl/ndctl.h>
#include <ccan/array_size/array_size.h>
#define KVER_STRLEN 20
@@ -106,11 +107,11 @@ int ndctl_test_get_skipped(struct ndctl_test *test)
return test->skip;
}
-int nfit_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
+int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
struct ndctl_ctx *nd_ctx, int log_level,
struct ndctl_test *test)
{
- int rc;
+ int rc, family = -1;
unsigned int i;
const char *name;
struct ndctl_bus *bus;
@@ -127,10 +128,28 @@ int nfit_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
"nd_e820",
"nd_pmem",
};
+ char *test_env;
log_init(&log_ctx, "test/init", "NDCTL_TEST");
log_ctx.log_priority = log_level;
+ /*
+ * The following two checks determine the platform family. For
+ * Intel/platforms which support ACPI, check sysfs; for other platforms
+ * determine from the environment variable NVDIMM_TEST_FAMILY
+ */
+ if (access("/sys/bus/acpi", F_OK) == 0)
+ family = NVDIMM_FAMILY_INTEL;
+
+ test_env = getenv("NDCTL_TEST_FAMILY");
+ if (test_env && strcmp(test_env, "PAPR") == 0)
+ family = NVDIMM_FAMILY_PAPR;
+
+ if (family == -1) {
+ log_err(&log_ctx, "Cannot determine NVDIMM family\n");
+ return -ENOTSUP;
+ }
+
*ctx = kmod_new(NULL, NULL);
if (!*ctx)
return -ENXIO;
@@ -185,6 +204,11 @@ retry:
path = kmod_module_get_path(*mod);
if (!path) {
+ if (family != NVDIMM_FAMILY_INTEL &&
+ (strcmp(name, "nfit") == 0 ||
+ strcmp(name, "nd_e820") == 0))
+ continue;
+
log_err(&log_ctx, "%s.ko: failed to get path\n", name);
break;
}
diff --git a/test/dpa-alloc.c b/test/dpa-alloc.c
index e922009..0b3bb7a 100644
--- a/test/dpa-alloc.c
+++ b/test/dpa-alloc.c
@@ -289,7 +289,7 @@ int test_dpa_alloc(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
return 77;
ndctl_set_log_priority(ctx, loglevel);
- err = nfit_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
+ 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");
diff --git a/test/dsm-fail.c b/test/dsm-fail.c
index 9dfd8b0..0a6383d 100644
--- a/test/dsm-fail.c
+++ b/test/dsm-fail.c
@@ -346,7 +346,7 @@ int test_dsm_fail(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
int result = EXIT_FAILURE, err;
ndctl_set_log_priority(ctx, loglevel);
- err = nfit_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
+ err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
if (err < 0) {
result = 77;
ndctl_test_skip(test);
diff --git a/test/libndctl.c b/test/libndctl.c
index c42f785..d9b50f4 100644
--- a/test/libndctl.c
+++ b/test/libndctl.c
@@ -2708,7 +2708,7 @@ int test_libndctl(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
daxctl_set_log_priority(daxctl_ctx, loglevel);
ndctl_set_private_data(ctx, test);
- err = nfit_test_init(&kmod_ctx, &mod, ctx, loglevel, test);
+ err = ndctl_test_init(&kmod_ctx, &mod, ctx, loglevel, test);
if (err < 0) {
ndctl_test_skip(test);
fprintf(stderr, "nfit_test unavailable skipping tests\n");
diff --git a/test/multi-pmem.c b/test/multi-pmem.c
index 3d10952..3ea08cc 100644
--- a/test/multi-pmem.c
+++ b/test/multi-pmem.c
@@ -249,7 +249,7 @@ int test_multi_pmem(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx
ndctl_set_log_priority(ctx, loglevel);
- err = nfit_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
+ err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
if (err < 0) {
result = 77;
ndctl_test_skip(test);
diff --git a/test/parent-uuid.c b/test/parent-uuid.c
index 6424e9f..bded33a 100644
--- a/test/parent-uuid.c
+++ b/test/parent-uuid.c
@@ -218,7 +218,7 @@ int test_parent_uuid(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ct
return 77;
ndctl_set_log_priority(ctx, loglevel);
- err = nfit_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
+ 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");
diff --git a/test/pmem_namespaces.c b/test/pmem_namespaces.c
index f0f2edd..a4db1ae 100644
--- a/test/pmem_namespaces.c
+++ b/test/pmem_namespaces.c
@@ -191,7 +191,7 @@ int test_pmem_namespaces(int log_level, struct ndctl_test *test,
if (!bus) {
fprintf(stderr, "ACPI.NFIT unavailable falling back to nfit_test\n");
- rc = nfit_test_init(&kmod_ctx, &mod, NULL, log_level, test);
+ 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) {
--
2.27.0

View File

@ -1,20 +1,17 @@
papr: Add support to parse save_fail flag for dimm
From f081f302505209430df46908775a3cffb875a5c7 Mon Sep 17 00:00:00 2001
From: Santosh Sivaraj <santosh@fossix.org>
Date: Thu, 13 May 2021 11:42:17 +0530
Subject: [PATCH 020/217] papr: Add support to parse save_fail flag for dimm
BZ:
Brew:
This will help in getting the dimm fail tests to run on papr family too.
Also add nvdimm_test compatibility string for recognizing the test module.
commit f081f302505209430df46908775a3cffb875a5c7
Author: Santosh Sivaraj <santosh@fossix.org>
Date: Thu May 13 11:42:17 2021 +0530
papr: Add support to parse save_fail flag for dimm
This will help in getting the dimm fail tests to run on papr family too.
Also add nvdimm_test compatibility string for recognizing the test module.
Link: https://lore.kernel.org/r/20210513061218.760322-3-santosh@fossix.org
Signed-off-by: Santosh Sivaraj <santosh@fossix.org>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://lore.kernel.org/r/20210513061218.760322-3-santosh@fossix.org
Signed-off-by: Santosh Sivaraj <santosh@fossix.org>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
ndctl/lib/libndctl.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index e45353f..a8b99ea 100644
@ -39,3 +36,6 @@ index e45353f..a8b99ea 100644
}
/**
--
2.27.0

View File

@ -1,26 +1,26 @@
Use page size as alignment value
From fe831b526b88f6ca7a27fdb149b8a7d2ecddbc55 Mon Sep 17 00:00:00 2001
From: Santosh Sivaraj <santosh@fossix.org>
Date: Thu, 13 May 2021 11:42:18 +0530
Subject: [PATCH 021/217] Use page size as alignment value
BZ:
Brew:
The alignment sizes passed to ndctl in the tests are all hardcoded to 4k,
the default page size on x86. Change those to the default page size on that
architecture (sysconf/getconf). No functional changes otherwise.
commit fe831b526b88f6ca7a27fdb149b8a7d2ecddbc55
Author: Santosh Sivaraj <santosh@fossix.org>
Date: Thu May 13 11:42:18 2021 +0530
Link: https://lore.kernel.org/r/20210513061218.760322-4-santosh@fossix.org
Signed-off-by: Santosh Sivaraj <santosh@fossix.org>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
test/dpa-alloc.c | 15 ++++++++-------
test/multi-dax.sh | 6 ++++--
test/sector-mode.sh | 4 +++-
3 files changed, 15 insertions(+), 10 deletions(-)
Use page size as alignment value
The alignment sizes passed to ndctl in the tests are all hardcoded to 4k,
the default page size on x86. Change those to the default page size on that
architecture (sysconf/getconf). No functional changes otherwise.
Link: https://lore.kernel.org/r/20210513061218.760322-4-santosh@fossix.org
Signed-off-by: Santosh Sivaraj <santosh@fossix.org>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
diff -up ndctl-71.1/test/dpa-alloc.c.orig ndctl-71.1/test/dpa-alloc.c
--- ndctl-71.1/test/dpa-alloc.c.orig 2020-12-22 16:44:57.000000000 -0500
+++ ndctl-71.1/test/dpa-alloc.c 2022-06-06 17:13:12.045108349 -0400
@@ -38,12 +38,13 @@ static int do_test(struct ndctl_ctx *ctx
diff --git a/test/dpa-alloc.c b/test/dpa-alloc.c
index 0b3bb7a..59185cf 100644
--- a/test/dpa-alloc.c
+++ b/test/dpa-alloc.c
@@ -38,12 +38,13 @@ static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
struct ndctl_region *region, *blk_region = NULL;
struct ndctl_namespace *ndns;
struct ndctl_dimm *dimm;
@ -35,7 +35,7 @@ diff -up ndctl-71.1/test/dpa-alloc.c.orig ndctl-71.1/test/dpa-alloc.c
/* disable nfit_test.1, not used in this test */
bus = ndctl_bus_get_by_provider(ctx, NFIT_PROVIDER1);
if (!bus)
@@ -124,11 +125,11 @@ static int do_test(struct ndctl_ctx *ctx
@@ -124,11 +125,11 @@ static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
return rc;
}
ndctl_namespace_disable_invalidate(ndns);
@ -50,7 +50,7 @@ diff -up ndctl-71.1/test/dpa-alloc.c.orig ndctl-71.1/test/dpa-alloc.c
return rc;
}
namespaces[i].ndns = ndns;
@@ -150,7 +151,7 @@ static int do_test(struct ndctl_ctx *ctx
@@ -150,7 +151,7 @@ static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
ndns = namespaces[i % ARRAY_SIZE(namespaces)].ndns;
if (i % ARRAY_SIZE(namespaces) == 0)
round++;
@ -59,7 +59,7 @@ diff -up ndctl-71.1/test/dpa-alloc.c.orig ndctl-71.1/test/dpa-alloc.c
rc = ndctl_namespace_set_size(ndns, size);
if (rc) {
fprintf(stderr, "%s: set_size: %lx failed: %d\n",
@@ -166,7 +167,7 @@ static int do_test(struct ndctl_ctx *ctx
@@ -166,7 +167,7 @@ static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
i--;
round++;
ndns = namespaces[i % ARRAY_SIZE(namespaces)].ndns;
@ -68,7 +68,7 @@ diff -up ndctl-71.1/test/dpa-alloc.c.orig ndctl-71.1/test/dpa-alloc.c
rc = ndctl_namespace_set_size(ndns, size);
if (rc) {
fprintf(stderr, "%s failed to update while labels full\n",
@@ -175,7 +176,7 @@ static int do_test(struct ndctl_ctx *ctx
@@ -175,7 +176,7 @@ static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
}
round--;
@ -77,10 +77,11 @@ diff -up ndctl-71.1/test/dpa-alloc.c.orig ndctl-71.1/test/dpa-alloc.c
rc = ndctl_namespace_set_size(ndns, size);
if (rc) {
fprintf(stderr, "%s failed to reduce size while labels full\n",
diff -up ndctl-71.1/test/multi-dax.sh.orig ndctl-71.1/test/multi-dax.sh
--- ndctl-71.1/test/multi-dax.sh.orig 2020-12-22 16:44:57.000000000 -0500
+++ ndctl-71.1/test/multi-dax.sh 2022-06-06 17:13:12.046108353 -0400
@@ -12,6 +12,8 @@ check_min_kver "4.13" || do_skip "may la
diff --git a/test/multi-dax.sh b/test/multi-dax.sh
index 8496619..b343a38 100755
--- a/test/multi-dax.sh
+++ b/test/multi-dax.sh
@@ -13,6 +13,8 @@ check_prereq "jq"
trap 'err $LINENO' ERR
@ -89,7 +90,7 @@ diff -up ndctl-71.1/test/multi-dax.sh.orig ndctl-71.1/test/multi-dax.sh
# setup (reset nfit_test dimms)
modprobe nfit_test
$NDCTL disable-region -b $NFIT_TEST_BUS0 all
@@ -22,9 +24,9 @@ rc=1
@@ -23,9 +25,9 @@ rc=1
query=". | sort_by(.available_size) | reverse | .[0].dev"
region=$($NDCTL list -b $NFIT_TEST_BUS0 -t pmem -Ri | jq -r "$query")
@ -101,10 +102,11 @@ diff -up ndctl-71.1/test/multi-dax.sh.orig ndctl-71.1/test/multi-dax.sh
chardev2=$(echo $json | jq ". | select(.mode == \"devdax\") | .daxregion.devices[0].chardev")
_cleanup
diff -up ndctl-71.1/test/sector-mode.sh.orig ndctl-71.1/test/sector-mode.sh
--- ndctl-71.1/test/sector-mode.sh.orig 2020-12-22 16:44:57.000000000 -0500
+++ ndctl-71.1/test/sector-mode.sh 2022-06-06 17:13:12.046108353 -0400
@@ -9,6 +9,8 @@ rc=77
diff --git a/test/sector-mode.sh b/test/sector-mode.sh
index 54fa806..7a2faea 100755
--- a/test/sector-mode.sh
+++ b/test/sector-mode.sh
@@ -11,6 +11,8 @@ check_prereq "jq"
set -e
trap 'err $LINENO' ERR
@ -113,7 +115,7 @@ diff -up ndctl-71.1/test/sector-mode.sh.orig ndctl-71.1/test/sector-mode.sh
# setup (reset nfit_test dimms)
modprobe nfit_test
$NDCTL disable-region -b $NFIT_TEST_BUS0 all
@@ -25,7 +27,7 @@ NAMESPACE=$($NDCTL list -b $NFIT_TEST_BU
@@ -27,7 +29,7 @@ NAMESPACE=$($NDCTL list -b $NFIT_TEST_BUS1 -N | jq -r "$query")
REGION=$($NDCTL list -R --namespace=$NAMESPACE | jq -r "(.[]) | .dev")
echo 0 > /sys/bus/nd/devices/$REGION/read_only
$NDCTL create-namespace --no-autolabel -e $NAMESPACE -m sector -f -l 4K
@ -122,3 +124,6 @@ diff -up ndctl-71.1/test/sector-mode.sh.orig ndctl-71.1/test/sector-mode.sh
$NDCTL create-namespace --no-autolabel -e $NAMESPACE -m sector -f -l 4K
_cleanup
--
2.27.0

View File

@ -0,0 +1,38 @@
From 561af4f919b3f1b3d1a213137f1d024420996d56 Mon Sep 17 00:00:00 2001
From: Santosh Sivaraj <santosh@fossix.org>
Date: Sun, 28 Mar 2021 05:43:51 +0530
Subject: [PATCH 022/217] libndctl: Remove redundant checks and assignments
check_udev already checks for udev allocation failure, remove the redundant
check.
Link: https://lore.kernel.org/r/20210328001351.2245032-1-santosh@fossix.org
Signed-off-by: Santosh Sivaraj <santosh@fossix.org>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
ndctl/lib/libndctl.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index bf0968c..3a496ed 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -323,12 +323,9 @@ NDCTL_EXPORT int ndctl_new(struct ndctl_ctx **ctx)
dbg(c, "timeout = %ld\n", tmo);
}
- if (udev) {
- c->udev = udev;
- c->udev_queue = udev_queue_new(udev);
- if (!c->udev_queue)
- err(c, "failed to retrieve udev queue\n");
- }
+ c->udev_queue = udev_queue_new(udev);
+ if (!c->udev_queue)
+ err(c, "failed to retrieve udev queue\n");
c->kmod_ctx = kmod_ctx;
c->daxctl_ctx = daxctl_ctx;
--
2.27.0

View File

@ -0,0 +1,56 @@
From 063af7c447d257397a925df81897da2c71e31653 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Tue, 18 May 2021 16:25:27 -0600
Subject: [PATCH 023/217] ndctl: Update nvdimm mailing list address
The 'nvdimm' mailing list has moved from lists.01.org to
lists.linux.dev. Update CONTRIBUTING.md and configure.ac to reflect
this.
Link: https://lore.kernel.org/r/20210518222527.550730-1-vishal.l.verma@intel.com
Cc: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
CONTRIBUTING.md | 7 ++++---
configure.ac | 2 +-
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4c29d31..4f4865d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -6,13 +6,14 @@ The following is a set of guidelines that we adhere to, and request that
contributors follow.
1. The libnvdimm (kernel subsystem) and ndctl developers primarily use
- the [linux-nvdimm](https://lists.01.org/postorius/lists/linux-nvdimm.lists.01.org/)
+ the [nvdimm](https://subspace.kernel.org/lists.linux.dev.html)
mailing list for everything. It is recommended to send patches to
- **```linux-nvdimm@lists.01.org```**
+ **```nvdimm@lists.linux.dev```**
+ An archive is available on [lore](https://lore.kernel.org/nvdimm/)
1. Github [issues](https://github.com/pmem/ndctl/issues) are an acceptable
way to report a problem, but if you just have a question,
- [email](mailto:linux-nvdimm@lists.01.org) the above list.
+ [email](mailto:nvdimm@lists.linux.dev) the above list.
1. We follow the Linux Kernel [Coding Style Guide][cs] as applicable.
diff --git a/configure.ac b/configure.ac
index 5ec8d2f..dc39dbe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ AC_PREREQ(2.60)
m4_include([version.m4])
AC_INIT([ndctl],
GIT_VERSION,
- [linux-nvdimm@lists.01.org],
+ [nvdimm@lists.linux.dev],
[ndctl],
[https://github.com/pmem/ndctl])
AC_CONFIG_SRCDIR([ndctl/lib/libndctl.c])
--
2.27.0

View File

@ -0,0 +1,122 @@
From e086106b4d81a2079141c848db7695451c04e877 Mon Sep 17 00:00:00 2001
From: Vaibhav Jain <vaibhav@linux.ibm.com>
Date: Mon, 17 May 2021 21:18:24 +0530
Subject: [PATCH 024/217] libndctl/papr: Fix probe for papr-scm compatible
nvdimms
With recent changes introduced for unification of PAPR and NFIT
families the probe for papr-scm nvdimms is broken since they don't
expose 'handle' or 'phys_id' sysfs attributes. These attributes are
only exposed by NFIT and 'nvdimm_test' nvdimms. Since 'unable to read'
these sysfs attributes is a non-recoverable error hence this prevents
probing of 'PAPR-SCM' nvdimms and ndctl reports following error:
$ sudo NDCTL_LOG=debug ndctl list -DH
libndctl: ndctl_new: ctx 0x10015342c70 created
libndctl: add_dimm: nmem1: probe failed: Operation not permitted
libndctl: __sysfs_device_parse: nmem1: add_dev() failed
libndctl: add_dimm: nmem0: probe failed: Operation not permitted
libndctl: __sysfs_device_parse: nmem0: add_dev() failed
Fixing this bug is complicated by the fact these attributes are needed
for by the 'nvdimm_test' nvdimms which also uses the
NVDIMM_FAMILY_PAPR. Adding a two way comparison for these two
attributes in populate_dimm_attributes() to distinguish between
'nvdimm_test' and papr-scm nvdimms will be clunky and make future
updates to populate_dimm_attributes() error prone.
So, this patch proposes to fix the issue by re-introducing
add_papr_dimm() to probe both papr-scm and 'nvdimm_test' nvdimms. The
'compatible' sysfs attribute associated with the PAPR device is used
to distinguish between the two nvdimm types and in case an
'nvdimm_test' device is detected then forward its probe to
populate_dimm_attributes().
families")
Link: https://lore.kernel.org/r/20210517154824.142237-1-vaibhav@linux.ibm.com
Fixes: daef3a386a9c("libndctl: Unify adding dimms for papr and nfit
Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
ndctl/lib/libndctl.c | 57 ++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 3a496ed..aa36a3c 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -1754,6 +1754,58 @@ static int populate_dimm_attributes(struct ndctl_dimm *dimm,
return rc;
}
+static int add_papr_dimm(struct ndctl_dimm *dimm, const char *dimm_base)
+{
+ int rc = -ENODEV;
+ char buf[SYSFS_ATTR_SIZE];
+ struct ndctl_ctx *ctx = dimm->bus->ctx;
+ char *path = calloc(1, strlen(dimm_base) + 100);
+ const char * const devname = ndctl_dimm_get_devname(dimm);
+
+ dbg(ctx, "%s: Probing of_pmem dimm at %s\n", devname, dimm_base);
+
+ if (!path)
+ return -ENOMEM;
+
+ /* Check the compatibility of the probed nvdimm */
+ sprintf(path, "%s/../of_node/compatible", dimm_base);
+ if (sysfs_read_attr(ctx, path, buf) < 0) {
+ dbg(ctx, "%s: Unable to read compatible field\n", devname);
+ rc = -ENODEV;
+ goto out;
+ }
+
+ dbg(ctx, "%s:Compatible of_pmem = '%s'\n", devname, buf);
+
+ /* Probe for papr-scm memory */
+ if (strcmp(buf, "ibm,pmemory") == 0) {
+ /* Read the dimm flags file */
+ sprintf(path, "%s/papr/flags", dimm_base);
+ if (sysfs_read_attr(ctx, path, buf) < 0) {
+ rc = -errno;
+ err(ctx, "%s: Unable to read dimm-flags\n", devname);
+ goto out;
+ }
+
+ dbg(ctx, "%s: Adding papr-scm dimm flags:\"%s\"\n", devname, buf);
+ dimm->cmd_family = NVDIMM_FAMILY_PAPR;
+
+ /* Parse dimm flags */
+ parse_papr_flags(dimm, buf);
+
+ /* Allocate monitor mode fd */
+ dimm->health_eventfd = open(path, O_RDONLY|O_CLOEXEC);
+ rc = 0;
+
+ } else if (strcmp(buf, "nvdimm_test") == 0) {
+ /* probe via common populate_dimm_attributes() */
+ rc = populate_dimm_attributes(dimm, dimm_base, "papr");
+ }
+out:
+ free(path);
+ return rc;
+}
+
static void *add_dimm(void *parent, int id, const char *dimm_base)
{
int formats, i, rc = -ENODEV;
@@ -1845,8 +1897,9 @@ static void *add_dimm(void *parent, int id, const char *dimm_base)
/* Check if the given dimm supports nfit */
if (ndctl_bus_has_nfit(bus)) {
rc = populate_dimm_attributes(dimm, dimm_base, "nfit");
- } else if (ndctl_bus_has_of_node(bus))
- rc = populate_dimm_attributes(dimm, dimm_base, "papr");
+ } else if (ndctl_bus_has_of_node(bus)) {
+ rc = add_papr_dimm(dimm, dimm_base);
+ }
if (rc == -ENODEV) {
/* Unprobed dimm with no family */
--
2.27.0

View File

@ -0,0 +1,38 @@
From c52109355b715bbe21e284090435bee7563863cc Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 26 May 2021 16:33:04 -0700
Subject: [PATCH 025/217] ndctl/scrub: Stop translating return values
In preparation for triggering a poll loop within ndctl_bus_start_scrub(),
stop translating return values into -EOPNOTSUPP.
Link: https://lore.kernel.org/r/162207198482.3715490.5994844104395495686.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
ndctl/lib/libndctl.c | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index aa36a3c..e5641fe 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -1354,14 +1354,8 @@ static int __ndctl_bus_get_scrub_state(struct ndctl_bus *bus,
NDCTL_EXPORT int ndctl_bus_start_scrub(struct ndctl_bus *bus)
{
struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
- int rc;
- rc = sysfs_write_attr(ctx, bus->scrub_path, "1\n");
- if (rc == -EBUSY)
- return rc;
- else if (rc < 0)
- return -EOPNOTSUPP;
- return 0;
+ return sysfs_write_attr(ctx, bus->scrub_path, "1\n");
}
NDCTL_EXPORT int ndctl_bus_get_scrub_state(struct ndctl_bus *bus)
--
2.27.0

View File

@ -0,0 +1,48 @@
From 4e646fa490ba4b782afa188dd8818b94c419924e Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 26 May 2021 16:33:10 -0700
Subject: [PATCH 026/217] ndctl/scrub: Reread scrub-engine status at start
Given that the kernel has exponential backoff to cover the lack of
interrupts for scrub completion status there is a reasonable likelihood
that 'ndctl start-scrub' is issued while the hardware/platform scrub-state
is idle, but the kernel engine poll timer has not fired.
Trigger at least one poll cycle for the kernel to re-read the scrub-state
before reporting that ARS is busy.
Link: https://lore.kernel.org/r/162207199057.3715490.2469820075085914776.stgit@dwillia2-desk3.amr.corp.intel.com
Reported-by: Krzysztof Rusocki <krzysztof.rusocki@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
ndctl/lib/libndctl.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index e5641fe..536e142 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -1354,8 +1354,18 @@ static int __ndctl_bus_get_scrub_state(struct ndctl_bus *bus,
NDCTL_EXPORT int ndctl_bus_start_scrub(struct ndctl_bus *bus)
{
struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
+ int rc;
+
+ rc = sysfs_write_attr(ctx, bus->scrub_path, "1\n");
- return sysfs_write_attr(ctx, bus->scrub_path, "1\n");
+ /*
+ * Try at least 1 poll cycle before reporting busy in case this
+ * request hits the kernel's exponential backoff while the
+ * hardware/platform scrub state is idle.
+ */
+ if (rc == -EBUSY && ndctl_bus_poll_scrub_completion(bus, 1, 1) == 0)
+ return sysfs_write_attr(ctx, bus->scrub_path, "1\n");
+ return rc;
}
NDCTL_EXPORT int ndctl_bus_get_scrub_state(struct ndctl_bus *bus)
--
2.27.0

View File

@ -0,0 +1,167 @@
From 7e98977c10ad5f4baf5e3bc4d5b4b2fd733a8b7e Mon Sep 17 00:00:00 2001
From: Jingqi Liu <jingqi.liu@intel.com>
Date: Thu, 8 Jul 2021 16:14:46 +0800
Subject: [PATCH 027/217] ndctl/dimm: Fix label index block calculations
The following bug is caused by setting the size of Label Index Block
to a fixed 256 bytes.
Use the following Qemu command to start a Guest with 2MB label-size:
-object memory-backend-file,id=mem1,share=on,mem-path=/dev/dax1.1,size=14G,align=2M
-device nvdimm,memdev=mem1,id=nv1,label-size=2M
There is a namespace in the Guest as follows:
$ ndctl list
[
{
"dev":"namespace0.0",
"mode":"devdax",
"map":"dev",
"size":14780727296,
"uuid":"58ad5282-5a16-404f-b8ee-e28b4c784eb8",
"chardev":"dax0.0",
"align":2097152,
"name":"namespace0.0"
}
]
Fail to read labels. The result is as follows:
$ ndctl read-labels -u nmem0
[
]
read 0 nmem
If using the following Qemu command to start the Guest with 128K
label-size, this label can be read correctly.
-object memory-backend-file,id=mem1,share=on,mem-path=/dev/dax1.1,size=14G,align=2M
-device nvdimm,memdev=mem1,id=nv1,label-size=128K
The size of a Label Index Block depends on how many label slots fit into
the label storage area. The minimum size of an index block is 256 bytes
and the size must be a multiple of 256 bytes. For a storage area of 128KB,
the corresponding Label Index Block size is 256 bytes. But if the label
storage area is not 128KB, the Label Index Block size should not be 256 bytes.
Namespace Label Index Block appears twice at the top of the label storage area.
Following the two index blocks, an array for storing labels takes up the
remainder of the label storage area.
For obtaining the size of Namespace Index Block, we also cannot rely on
the field of 'mysize' in this index block since it might be corrupted.
Similar to the linux kernel, we use sizeof_namespace_index() to get the size
of Namespace Index Block. Then we can also correctly calculate the starting
offset of the following namespace labels.
Link: https://lore.kernel.org/r/20210708081446.14323-1-jingqi.liu@intel.com
Suggested-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Jingqi Liu <jingqi.liu@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
ndctl/dimm.c | 19 +++++++++++++++----
ndctl/lib/dimm.c | 5 +++++
ndctl/lib/libndctl.sym | 1 +
ndctl/libndctl.h | 1 +
4 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/ndctl/dimm.c b/ndctl/dimm.c
index 09ce49e..1d2d9a2 100644
--- a/ndctl/dimm.c
+++ b/ndctl/dimm.c
@@ -94,13 +94,18 @@ static struct json_object *dump_label_json(struct ndctl_dimm *dimm,
struct json_object *jarray = json_object_new_array();
struct json_object *jlabel = NULL;
struct namespace_label nslabel;
+ unsigned int nsindex_size;
unsigned int slot = -1;
ssize_t offset;
if (!jarray)
return NULL;
- for (offset = NSINDEX_ALIGN * 2; offset < size;
+ nsindex_size = ndctl_dimm_sizeof_namespace_index(dimm);
+ if (nsindex_size == 0)
+ return NULL;
+
+ for (offset = nsindex_size * 2; offset < size;
offset += ndctl_dimm_sizeof_namespace_label(dimm)) {
ssize_t len = min_t(ssize_t,
ndctl_dimm_sizeof_namespace_label(dimm),
@@ -204,17 +209,23 @@ static struct json_object *dump_label_json(struct ndctl_dimm *dimm,
return jarray;
}
-static struct json_object *dump_index_json(struct ndctl_cmd *cmd_read, ssize_t size)
+static struct json_object *dump_index_json(struct ndctl_dimm *dimm,
+ struct ndctl_cmd *cmd_read, ssize_t size)
{
struct json_object *jarray = json_object_new_array();
struct json_object *jindex = NULL;
struct namespace_index nsindex;
+ unsigned int nsindex_size;
ssize_t offset;
if (!jarray)
return NULL;
- for (offset = 0; offset < NSINDEX_ALIGN * 2; offset += NSINDEX_ALIGN) {
+ nsindex_size = ndctl_dimm_sizeof_namespace_index(dimm);
+ if (nsindex_size == 0)
+ return NULL;
+
+ for (offset = 0; offset < nsindex_size * 2; offset += nsindex_size) {
ssize_t len = min_t(ssize_t, sizeof(nsindex), size - offset);
struct json_object *jobj;
@@ -288,7 +299,7 @@ static struct json_object *dump_json(struct ndctl_dimm *dimm,
goto err;
json_object_object_add(jdimm, "dev", jobj);
- jindex = dump_index_json(cmd_read, size);
+ jindex = dump_index_json(dimm, cmd_read, size);
if (!jindex)
goto err;
json_object_object_add(jdimm, "index", jindex);
diff --git a/ndctl/lib/dimm.c b/ndctl/lib/dimm.c
index c045cbe..9e36e28 100644
--- a/ndctl/lib/dimm.c
+++ b/ndctl/lib/dimm.c
@@ -256,6 +256,11 @@ static int __label_validate(struct nvdimm_data *ndd)
return -EINVAL;
}
+NDCTL_EXPORT unsigned int ndctl_dimm_sizeof_namespace_index(struct ndctl_dimm *dimm)
+{
+ return sizeof_namespace_index(&dimm->ndd);
+}
+
/*
* If the dimm labels have not been previously validated this routine
* will make up a default size. Otherwise, it will pick the size based
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index 58afb74..5ee73b7 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -454,4 +454,5 @@ LIBNDCTL_25 {
LIBNDCTL_26 {
ndctl_bus_nfit_translate_spa;
+ ndctl_dimm_sizeof_namespace_index;
} LIBNDCTL_25;
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index 87d07b7..df109bb 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -337,6 +337,7 @@ int ndctl_dimm_init_labels(struct ndctl_dimm *dimm,
enum ndctl_namespace_version v);
unsigned long ndctl_dimm_get_available_labels(struct ndctl_dimm *dimm);
unsigned int ndctl_dimm_sizeof_namespace_label(struct ndctl_dimm *dimm);
+unsigned int ndctl_dimm_sizeof_namespace_index(struct ndctl_dimm *dimm);
unsigned int ndctl_cmd_cfg_size_get_size(struct ndctl_cmd *cfg_size);
ssize_t ndctl_cmd_cfg_read_get_data(struct ndctl_cmd *cfg_read, void *buf,
unsigned int len, unsigned int offset);
--
2.27.0

View File

@ -0,0 +1,58 @@
From 9bd2994f91bb77604521cbe09a76a51d092c2cfd Mon Sep 17 00:00:00 2001
From: Michal Suchanek <msuchanek@suse.de>
Date: Wed, 6 Jan 2021 14:17:40 +0100
Subject: [PATCH 028/217] ndctl/namespace: Skip seed namespaces when processing
all namespaces.
The seed namespaces are exposed by the kernel but most operations are
not valid on seed namespaces.
When processing all namespaces the user gets confusing errors from ndctl
trying to process seed namespaces. The kernel does not provide any way
to tell that a namspace is seed namespace but skipping namespaces with
zero size and UUID is a good heuristic.
The user can still specify the namespace by name directly in case
processing it is desirable.
Link: https://patchwork.kernel.org/patch/11473645/
Link: https://lore.kernel.org/r/e55ae2c17b8b9c3288491efe6214338118e8c5ae.1609938610.git.msuchanek@suse.de
Fixes: #41
Tested-by: Harish Sriram <harish@linux.ibm.com>
Reviewed-by: Santosh S <santosh@fossix.org>
Signed-off-by: Michal Suchanek <msuchanek@suse.de>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
ndctl/namespace.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/ndctl/namespace.c b/ndctl/namespace.c
index 1e8a2cd..5e65ed5 100644
--- a/ndctl/namespace.c
+++ b/ndctl/namespace.c
@@ -2210,9 +2210,19 @@ static int do_xaction_namespace(const char *namespace,
ndctl_namespace_foreach_safe(region, ndns, _n) {
ndns_name = ndctl_namespace_get_devname(ndns);
- if (strcmp(namespace, "all") != 0
- && strcmp(namespace, ndns_name) != 0)
- continue;
+ if (strcmp(namespace, "all") == 0) {
+ static const uuid_t zero_uuid;
+ uuid_t uuid;
+
+ ndctl_namespace_get_uuid(ndns, uuid);
+ if (!ndctl_namespace_get_size(ndns) &&
+ !memcmp(uuid, zero_uuid, sizeof(uuid_t)))
+ continue;
+ } else {
+ if (strcmp(namespace, ndns_name) != 0)
+ continue;
+ }
+
switch (action) {
case ACTION_DISABLE:
rc = ndctl_namespace_disable_safe(ndns);
--
2.27.0

View File

@ -0,0 +1,82 @@
From 07011a334fd1e4b641cdbfaf5de7500f7bdc941d Mon Sep 17 00:00:00 2001
From: Michal Suchanek <msuchanek@suse.de>
Date: Wed, 6 Jan 2021 14:17:41 +0100
Subject: [PATCH 029/217] ndctl/namespace: Suppress -ENXIO when processing all
namespaces.
When processing all namespaces and no namespaces exist user gets the
default -ENXIO. Set default rc to 0 when processing all namespaces.
This avoids confusing error message printed in addition to the message
saying 0 namespaces were affected.
Before:
# ndctl check-namespace all
namespace0.0: namespace_check: namespace0.0: check aborted, namespace online
error checking namespaces: Device or resource busy
checked 0 namespaces
# ndctl disable-namespace all
disabled 1 namespace
# ndctl check-namespace all
namespace0.0: namespace_check: Unable to recover any BTT info blocks
error checking namespaces: No such device or address
checked 0 namespaces
# ndctl destroy-namespace all
destroyed 1 namespace
# ndctl check-namespace all
error checking namespaces: No such device or address
checked 0 namespaces
# ndctl destroy-namespace all
error destroying namespaces: No such device or address
destroyed 0 namespaces
After:
# ndctl check-namespace all
namespace0.0: namespace_check: namespace0.0: check aborted, namespace online
error checking namespaces: Device or resource busy
checked 0 namespaces
# ndctl disable-namespace namespace0.0
disabled 1 namespace
# ndctl check-namespace all
namespace0.0: namespace_check: Unable to recover any BTT info blocks
error checking namespaces: No such device or address
checked 0 namespaces
# ndctl destroy-namespace all
destroyed 1 namespace
# ndctl check-namespace all
checked 0 namespaces
# ndctl destroy-namespace all
destroyed 0 namespaces
# ndctl destroy-namespace all
destroyed 0 namespaces
Note: this does change the return value from -ENXIO to 0 in the cases
when no namespaces exist and processing all namespaces was requested.
Link: https://patchwork.kernel.org/patch/11681431/
Link: https://lore.kernel.org/r/32c8cd8d2716f5e52aebea4e4d303eeb4e0550f9.1609938610.git.msuchanek@suse.de
Reviewed-by: Santosh S <santosh@fossix.org>
Signed-off-by: Michal Suchanek <msuchanek@suse.de>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
ndctl/namespace.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/ndctl/namespace.c b/ndctl/namespace.c
index 5e65ed5..cd822b3 100644
--- a/ndctl/namespace.c
+++ b/ndctl/namespace.c
@@ -2151,6 +2151,9 @@ static int do_xaction_namespace(const char *namespace,
if (!namespace && action != ACTION_CREATE)
return rc;
+ if (namespace && (strcmp(namespace, "all") == 0))
+ rc = 0;
+
if (verbose)
ndctl_set_log_priority(ctx, LOG_DEBUG);
--
2.27.0

View File

@ -1,31 +1,29 @@
namespace-action: Drop zero namespace checks.
From 80e0d88c3098bd419e26146a8cb3b693fdd06417 Mon Sep 17 00:00:00 2001
From: Santosh Sivaraj <santosh@fossix.org>
Date: Wed, 6 Jan 2021 14:17:42 +0100
Subject: [PATCH 030/217] namespace-action: Drop zero namespace checks.
BZ:
Brew:
With seed namespaces catched early on these checks for sizes in enable
and destroy namespace code path are not needed.
commit 80e0d88c3098bd419e26146a8cb3b693fdd06417
Author: Santosh Sivaraj <santosh@fossix.org>
Date: Wed Jan 6 14:17:42 2021 +0100
Reverts commit b9cb03f6d5a8 ("ndctl/namespace: Fix enable-namespace
error for seed namespaces")
namespace-action: Drop zero namespace checks.
With seed namespaces catched early on these checks for sizes in enable
and destroy namespace code path are not needed.
Reverts commit b9cb03f6d5a8 ("ndctl/namespace: Fix enable-namespace
error for seed namespaces")
Reverts commit e01045e58ad5 ("ndctl/namespace: Fix destroy-namespace
accounting relative to seed devices")
Link: https://patchwork.kernel.org/patch/11739975/
Link: https://lore.kernel.org/r/eb4bc7885708fa13e3d37286bc4a4219b1e4e5b6.1609938610.git.msuchanek@suse.de
Fixes: b9cb03f6d5a8 ("ndctl/namespace: Fix enable-namespace error for seed namespaces")
Fixes: e01045e58ad5 ("ndctl/namespace: Fix destroy-namespace accounting relative to seed devices")
Signed-off-by: Santosh Sivaraj <santosh@fossix.org>
[rebased on top of the previous patches]
Signed-off-by: Michal Suchanek <msuchanek@suse.de>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Reverts commit e01045e58ad5 ("ndctl/namespace: Fix destroy-namespace
accounting relative to seed devices")
Link: https://patchwork.kernel.org/patch/11739975/
Link: https://lore.kernel.org/r/eb4bc7885708fa13e3d37286bc4a4219b1e4e5b6.1609938610.git.msuchanek@suse.de
Fixes: b9cb03f6d5a8 ("ndctl/namespace: Fix enable-namespace error for seed namespaces")
Fixes: e01045e58ad5 ("ndctl/namespace: Fix destroy-namespace accounting relative to seed devices")
Signed-off-by: Santosh Sivaraj <santosh@fossix.org>
[rebased on top of the previous patches]
Signed-off-by: Michal Suchanek <msuchanek@suse.de>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
ndctl/lib/libndctl.c | 5 -----
ndctl/namespace.c | 10 ----------
2 files changed, 15 deletions(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 536e142..87f60b9 100644
@ -82,3 +80,6 @@ index cd822b3..c67c086 100644
return rc;
}
--
2.27.0

View File

@ -0,0 +1,187 @@
From dc712e47c39f4dbc5f089831fd50dd1a2752c8fc Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Thu, 7 Oct 2021 02:21:23 -0600
Subject: [PATCH 031/217] ndctl: add .clang-format
Copy the Linux kernel's .clang-format and modify it for ndctl. Only the
'ForEachMacros' section has been modified from the original kernel copy.
Cc: Dan Williams <dan.j.williams@intel.com>
Reported-by: Ben Widawsky <ben.widawsky@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
.clang-format | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 161 insertions(+)
create mode 100644 .clang-format
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..4e00fff
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,161 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# clang-format configuration file. Intended for clang-format >= 4.
+# Copied from Linux's .clang-format
+#
+# For more information, see:
+#
+# https://clang.llvm.org/docs/ClangFormat.html
+# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
+#
+---
+AccessModifierOffset: -4
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
+AlignOperands: true
+AlignTrailingComments: false
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: false
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: false
+ AfterControlStatement: false
+ AfterEnum: false
+ AfterFunction: true
+ AfterNamespace: true
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ #AfterExternBlock: false # Unknown to clang-format-5.0
+ BeforeCatch: false
+ BeforeElse: false
+ IndentBraces: false
+ #SplitEmptyFunction: true # Unknown to clang-format-4.0
+ #SplitEmptyRecord: true # Unknown to clang-format-4.0
+ #SplitEmptyNamespace: true # Unknown to clang-format-4.0
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
+BreakBeforeTernaryOperators: false
+BreakConstructorInitializersBeforeComma: false
+#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: false
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+#CompactNamespaces: false # Unknown to clang-format-4.0
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 8
+ContinuationIndentWidth: 8
+Cpp11BracedListStyle: false
+DerivePointerAlignment: false
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+#FixNamespaceComments: false # Unknown to clang-format-4.0
+
+# Taken from:
+# while read -r sym; do
+# printf " - '%s'\n" "$sym";
+# done < \
+# <(cscope -dL6 "foreach|for_each" \
+# | awk '{ print $4 $5 }' | grep -E 'foreach|for_each' \
+# | sed -e 's/#define//' \
+# -e 's/*//' \
+# -e 's/://' \
+# -e 's/\(.*for_each.*\)(.*/\1/' \
+# -e 's/\(.*foreach.*\)(.*/\1/' \
+# | sort -u)
+ForEachMacros:
+ - 'daxctl_dev_foreach'
+ - 'daxctl_mapping_foreach'
+ - 'daxctl_region_foreach'
+ - 'kmod_list_foreach'
+ - 'kmod_list_foreach_reverse'
+ - 'list_for_each'
+ - 'list_for_each_off'
+ - 'list_for_each_rev'
+ - 'list_for_each_safe'
+ - 'list_for_each_safe_off'
+ - 'ndctl_btt_foreach'
+ - 'ndctl_btt_foreach_safe'
+ - 'ndctl_bus_foreach'
+ - 'ndctl_dax_foreach'
+ - 'ndctl_dax_foreach_safe'
+ - 'ndctl_dimm_foreach'
+ - 'ndctl_dimm_foreach_in_interleave_set'
+ - 'ndctl_dimm_foreach_in_region'
+ - 'ndctl_interleave_set_foreach'
+ - 'ndctl_mapping_foreach'
+ - 'ndctl_namespace_badblock_foreach'
+ - 'ndctl_namespace_bb_foreach'
+ - 'ndctl_namespace_foreach'
+ - 'ndctl_namespace_foreach_safe'
+ - 'ndctl_pfn_foreach'
+ - 'ndctl_pfn_foreach_safe'
+ - 'ndctl_region_badblock_foreach'
+ - 'ndctl_region_foreach'
+ - 'udev_list_entry_foreach'
+
+#IncludeBlocks: Preserve # Unknown to clang-format-5.0
+IncludeCategories:
+ - Regex: '.*'
+ Priority: 1
+IncludeIsMainRegex: '(Test)?$'
+IndentCaseLabels: false
+#IndentPPDirectives: None # Unknown to clang-format-5.0
+IndentWidth: 8
+IndentWrappedFunctionNames: false
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
+ObjCBlockIndentWidth: 8
+ObjCSpaceAfterProperty: true
+ObjCSpaceBeforeProtocolList: true
+
+# Taken from git's rules
+#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
+PenaltyBreakBeforeFirstCallParameter: 30
+PenaltyBreakComment: 10
+PenaltyBreakFirstLessLess: 0
+PenaltyBreakString: 10
+PenaltyExcessCharacter: 100
+PenaltyReturnTypeOnItsOwnLine: 60
+
+PointerAlignment: Right
+ReflowComments: false
+SortIncludes: false
+#SortUsingDeclarations: false # Unknown to clang-format-4.0
+SpaceAfterCStyleCast: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
+#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
+SpaceBeforeParens: ControlStatements
+#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: false
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp03
+TabWidth: 8
+UseTab: Always
+...
--
2.27.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,256 @@
From 894fb9b2b59364f7f5683ea68c8bd765223a4ca8 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Thu, 7 Oct 2021 02:21:25 -0600
Subject: [PATCH 033/217] cxl: add a local copy of the cxl_mem UAPI header
While CXL functionality is under development, it is useful to have a
local copy of the UAPI header for cxl_mem definitions. This allows
building cxl and libcxl on systems where the appropriate kernel headers
are not installed in the usual locations.
Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Makefile.am | 3 +-
Makefile.am.in | 1 +
cxl/cxl_mem.h | 189 ++++++++++++++++++++++++++++++++++++++++++++
cxl/lib/Makefile.am | 2 +-
4 files changed, 193 insertions(+), 2 deletions(-)
create mode 100644 cxl/cxl_mem.h
diff --git a/Makefile.am b/Makefile.am
index 428fd40..4904ee7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -89,4 +89,5 @@ libutil_a_SOURCES = \
nobase_include_HEADERS = \
daxctl/libdaxctl.h \
- cxl/libcxl.h
+ cxl/libcxl.h \
+ cxl/cxl_mem.h
diff --git a/Makefile.am.in b/Makefile.am.in
index aaeee53..a748128 100644
--- a/Makefile.am.in
+++ b/Makefile.am.in
@@ -11,6 +11,7 @@ AM_CPPFLAGS = \
-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/cxl_mem.h b/cxl/cxl_mem.h
new file mode 100644
index 0000000..d38cc9c
--- /dev/null
+++ b/cxl/cxl_mem.h
@@ -0,0 +1,189 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+/* Copyright (C) 2020-2021, Intel Corporation. All rights reserved. */
+/*
+ * CXL IOCTLs for Memory Devices
+ */
+
+#ifndef _UAPI_CXL_MEM_H_
+#define _UAPI_CXL_MEM_H_
+
+#include <linux/types.h>
+#include <sys/user.h>
+#include <unistd.h>
+
+#define __user
+
+/**
+ * DOC: UAPI
+ *
+ * Not all of all commands that the driver supports are always available for use
+ * by userspace. Userspace must check the results from the QUERY command in
+ * order to determine the live set of commands.
+ */
+
+#define CXL_MEM_QUERY_COMMANDS _IOR(0xCE, 1, struct cxl_mem_query_commands)
+#define CXL_MEM_SEND_COMMAND _IOWR(0xCE, 2, struct cxl_send_command)
+
+#define CXL_CMDS \
+ ___C(INVALID, "Invalid Command"), \
+ ___C(IDENTIFY, "Identify Command"), \
+ ___C(RAW, "Raw device command"), \
+ ___C(GET_SUPPORTED_LOGS, "Get Supported Logs"), \
+ ___C(GET_FW_INFO, "Get FW Info"), \
+ ___C(GET_PARTITION_INFO, "Get Partition Information"), \
+ ___C(GET_LSA, "Get Label Storage Area"), \
+ ___C(GET_HEALTH_INFO, "Get Health Info"), \
+ ___C(GET_LOG, "Get Log"), \
+ ___C(SET_PARTITION_INFO, "Set Partition Information"), \
+ ___C(SET_LSA, "Set Label Storage Area"), \
+ ___C(GET_ALERT_CONFIG, "Get Alert Configuration"), \
+ ___C(SET_ALERT_CONFIG, "Set Alert Configuration"), \
+ ___C(GET_SHUTDOWN_STATE, "Get Shutdown State"), \
+ ___C(SET_SHUTDOWN_STATE, "Set Shutdown State"), \
+ ___C(GET_POISON, "Get Poison List"), \
+ ___C(INJECT_POISON, "Inject Poison"), \
+ ___C(CLEAR_POISON, "Clear Poison"), \
+ ___C(GET_SCAN_MEDIA_CAPS, "Get Scan Media Capabilities"), \
+ ___C(SCAN_MEDIA, "Scan Media"), \
+ ___C(GET_SCAN_MEDIA, "Get Scan Media Results"), \
+ ___C(MAX, "invalid / last command")
+
+#define ___C(a, b) CXL_MEM_COMMAND_ID_##a
+enum { CXL_CMDS };
+
+#undef ___C
+#define ___C(a, b) { b }
+static const struct {
+ const char *name;
+} cxl_command_names[] = { CXL_CMDS };
+
+/*
+ * Here's how this actually breaks out:
+ * cxl_command_names[] = {
+ * [CXL_MEM_COMMAND_ID_INVALID] = { "Invalid Command" },
+ * [CXL_MEM_COMMAND_ID_IDENTIFY] = { "Identify Command" },
+ * ...
+ * [CXL_MEM_COMMAND_ID_MAX] = { "invalid / last command" },
+ * };
+ */
+
+#undef ___C
+
+/**
+ * struct cxl_command_info - Command information returned from a query.
+ * @id: ID number for the command.
+ * @flags: Flags that specify command behavior.
+ * @size_in: Expected input size, or -1 if variable length.
+ * @size_out: Expected output size, or -1 if variable length.
+ *
+ * Represents a single command that is supported by both the driver and the
+ * hardware. This is returned as part of an array from the query ioctl. The
+ * following would be a command that takes a variable length input and returns 0
+ * bytes of output.
+ *
+ * - @id = 10
+ * - @flags = 0
+ * - @size_in = -1
+ * - @size_out = 0
+ *
+ * See struct cxl_mem_query_commands.
+ */
+struct cxl_command_info {
+ __u32 id;
+
+ __u32 flags;
+#define CXL_MEM_COMMAND_FLAG_MASK GENMASK(0, 0)
+
+ __s32 size_in;
+ __s32 size_out;
+};
+
+/**
+ * struct cxl_mem_query_commands - Query supported commands.
+ * @n_commands: In/out parameter. When @n_commands is > 0, the driver will
+ * return min(num_support_commands, n_commands). When @n_commands
+ * is 0, driver will return the number of total supported commands.
+ * @rsvd: Reserved for future use.
+ * @commands: Output array of supported commands. This array must be allocated
+ * by userspace to be at least min(num_support_commands, @n_commands)
+ *
+ * Allow userspace to query the available commands supported by both the driver,
+ * and the hardware. Commands that aren't supported by either the driver, or the
+ * hardware are not returned in the query.
+ *
+ * Examples:
+ *
+ * - { .n_commands = 0 } // Get number of supported commands
+ * - { .n_commands = 15, .commands = buf } // Return first 15 (or less)
+ * supported commands
+ *
+ * See struct cxl_command_info.
+ */
+struct cxl_mem_query_commands {
+ /*
+ * Input: Number of commands to return (space allocated by user)
+ * Output: Number of commands supported by the driver/hardware
+ *
+ * If n_commands is 0, kernel will only return number of commands and
+ * not try to populate commands[], thus allowing userspace to know how
+ * much space to allocate
+ */
+ __u32 n_commands;
+ __u32 rsvd;
+
+ struct cxl_command_info __user commands[]; /* out: supported commands */
+};
+
+/**
+ * struct cxl_send_command - Send a command to a memory device.
+ * @id: The command to send to the memory device. This must be one of the
+ * commands returned by the query command.
+ * @flags: Flags for the command (input).
+ * @raw: Special fields for raw commands
+ * @raw.opcode: Opcode passed to hardware when using the RAW command.
+ * @raw.rsvd: Must be zero.
+ * @rsvd: Must be zero.
+ * @retval: Return value from the memory device (output).
+ * @in: Parameters associated with input payload.
+ * @in.size: Size of the payload to provide to the device (input).
+ * @in.rsvd: Must be zero.
+ * @in.payload: Pointer to memory for payload input, payload is little endian.
+ * @out: Parameters associated with output payload.
+ * @out.size: Size of the payload received from the device (input/output). This
+ * field is filled in by userspace to let the driver know how much
+ * space was allocated for output. It is populated by the driver to
+ * let userspace know how large the output payload actually was.
+ * @out.rsvd: Must be zero.
+ * @out.payload: Pointer to memory for payload output, payload is little endian.
+ *
+ * Mechanism for userspace to send a command to the hardware for processing. The
+ * driver will do basic validation on the command sizes. In some cases even the
+ * payload may be introspected. Userspace is required to allocate large enough
+ * buffers for size_out which can be variable length in certain situations.
+ */
+struct cxl_send_command {
+ __u32 id;
+ __u32 flags;
+ union {
+ struct {
+ __u16 opcode;
+ __u16 rsvd;
+ } raw;
+ __u32 rsvd;
+ };
+ __u32 retval;
+
+ struct {
+ __s32 size;
+ __u32 rsvd;
+ __u64 payload;
+ } in;
+
+ struct {
+ __s32 size;
+ __u32 rsvd;
+ __u64 payload;
+ } out;
+};
+
+#endif
diff --git a/cxl/lib/Makefile.am b/cxl/lib/Makefile.am
index 277f0cd..72c9ccd 100644
--- a/cxl/lib/Makefile.am
+++ b/cxl/lib/Makefile.am
@@ -3,7 +3,7 @@ include $(top_srcdir)/Makefile.am.in
%.pc: %.pc.in Makefile
$(SED_PROCESS)
-pkginclude_HEADERS = ../libcxl.h
+pkginclude_HEADERS = ../libcxl.h ../cxl_mem.h
lib_LTLIBRARIES = libcxl.la
libcxl_la_SOURCES =\
--
2.27.0

View File

@ -0,0 +1,114 @@
From 7aa7c7be6e803de267a165237e23577ab496e792 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Thu, 7 Oct 2021 02:21:26 -0600
Subject: [PATCH 034/217] util: add the struct_size() helper from the kernel
Add struct_size() from include/linux/overflow.h which calculates the
size of a struct with a trailing variable length array.
Suggested-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
util/size.h | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++
util/util.h | 6 ++++++
2 files changed, 68 insertions(+)
diff --git a/util/size.h b/util/size.h
index 646edae..a0f3593 100644
--- a/util/size.h
+++ b/util/size.h
@@ -4,6 +4,8 @@
#ifndef _NDCTL_SIZE_H_
#define _NDCTL_SIZE_H_
#include <stdbool.h>
+#include <stdint.h>
+#include <util/util.h>
#define SZ_1K 0x00000400
#define SZ_4K 0x00001000
@@ -30,4 +32,64 @@ static inline bool is_power_of_2(unsigned long long v)
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
#define HPAGE_SIZE (2 << 20)
+/*
+ * Helpers for struct_size() copied from include/linux/overflow.h (GPL-2.0)
+ *
+ * For simplicity and code hygiene, the fallback code below insists on
+ * a, b and *d having the same type (similar to the min() and max()
+ * macros), whereas gcc's type-generic overflow checkers accept
+ * different types. Hence we don't just make check_add_overflow an
+ * alias for __builtin_add_overflow, but add type checks similar to
+ * below.
+ */
+#define check_add_overflow(a, b, d) (({ \
+ typeof(a) __a = (a); \
+ typeof(b) __b = (b); \
+ typeof(d) __d = (d); \
+ (void) (&__a == &__b); \
+ (void) (&__a == __d); \
+ __builtin_add_overflow(__a, __b, __d); \
+}))
+
+#define check_mul_overflow(a, b, d) (({ \
+ typeof(a) __a = (a); \
+ typeof(b) __b = (b); \
+ typeof(d) __d = (d); \
+ (void) (&__a == &__b); \
+ (void) (&__a == __d); \
+ __builtin_mul_overflow(__a, __b, __d); \
+}))
+
+/*
+ * Compute a*b+c, returning SIZE_MAX on overflow. Internal helper for
+ * struct_size() below.
+ */
+static inline size_t __ab_c_size(size_t a, size_t b, size_t c)
+{
+ size_t bytes;
+
+ if (check_mul_overflow(a, b, &bytes))
+ return SIZE_MAX;
+ if (check_add_overflow(bytes, c, &bytes))
+ return SIZE_MAX;
+
+ return bytes;
+}
+
+/**
+ * struct_size() - Calculate size of structure with trailing array.
+ * @p: Pointer to the structure.
+ * @member: Name of the array member.
+ * @count: Number of elements in the array.
+ *
+ * Calculates size of memory needed for structure @p followed by an
+ * array of @count number of @member elements.
+ *
+ * Return: number of bytes needed or SIZE_MAX on overflow.
+ */
+#define struct_size(p, member, count) \
+ __ab_c_size(count, \
+ sizeof(*(p)->member) + __must_be_array((p)->member),\
+ sizeof(*(p)))
+
#endif /* _NDCTL_SIZE_H_ */
diff --git a/util/util.h b/util/util.h
index ae0e4e1..b2b4ae6 100644
--- a/util/util.h
+++ b/util/util.h
@@ -63,6 +63,12 @@
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+/* Are two types/vars the same type (ignoring qualifiers)? */
+#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
+
+/* &a[0] degrades to a pointer: a different type from an array */
+#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
+
enum {
READ, WRITE,
};
--
2.27.0

View File

@ -0,0 +1,535 @@
From 96afebd1b32ff839129f3bc0ba323ab5f04674ea Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Thu, 7 Oct 2021 02:21:27 -0600
Subject: [PATCH 035/217] libcxl: add support for command query and submission
Add a set of APIs around 'cxl_cmd' for querying the kernel for supported
commands, allocating and validating command structures against the
supported set, and submitting the commands.
'Query Commands' and 'Send Command' are implemented as IOCTLs in the
kernel. 'Query Commands' returns information about each supported
command, such as flags governing its use, or input and output payload
sizes. This information is used to validate command support, as well as
set up input and output buffers for command submission.
Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
cxl/lib/libcxl.c | 390 +++++++++++++++++++++++++++++++++++++++++++++
cxl/lib/libcxl.sym | 9 ++
cxl/lib/private.h | 33 ++++
cxl/libcxl.h | 11 ++
4 files changed, 443 insertions(+)
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index c15e987..727d599 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -9,14 +9,17 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/ioctl.h>
#include <sys/sysmacros.h>
#include <uuid/uuid.h>
#include <ccan/list/list.h>
#include <ccan/array_size/array_size.h>
#include <util/log.h>
+#include <util/size.h>
#include <util/sysfs.h>
#include <util/bitmap.h>
+#include <cxl/cxl_mem.h>
#include <cxl/libcxl.h>
#include "private.h"
@@ -343,3 +346,390 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev
{
return memdev->firmware_version;
}
+
+CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd)
+{
+ if (!cmd)
+ return;
+ if (--cmd->refcount == 0) {
+ free(cmd->query_cmd);
+ free(cmd->send_cmd);
+ free(cmd->input_payload);
+ free(cmd->output_payload);
+ free(cmd);
+ }
+}
+
+CXL_EXPORT void cxl_cmd_ref(struct cxl_cmd *cmd)
+{
+ cmd->refcount++;
+}
+
+static int cxl_cmd_alloc_query(struct cxl_cmd *cmd, int num_cmds)
+{
+ size_t size;
+
+ if (!cmd)
+ return -EINVAL;
+
+ if (cmd->query_cmd != NULL)
+ free(cmd->query_cmd);
+
+ size = struct_size(cmd->query_cmd, commands, num_cmds);
+ if (size == SIZE_MAX)
+ return -EOVERFLOW;
+
+ cmd->query_cmd = calloc(1, size);
+ if (!cmd->query_cmd)
+ return -ENOMEM;
+
+ cmd->query_cmd->n_commands = num_cmds;
+
+ return 0;
+}
+
+static struct cxl_cmd *cxl_cmd_new(struct cxl_memdev *memdev)
+{
+ struct cxl_cmd *cmd;
+ size_t size;
+
+ size = sizeof(*cmd);
+ cmd = calloc(1, size);
+ if (!cmd)
+ return NULL;
+
+ cxl_cmd_ref(cmd);
+ cmd->memdev = memdev;
+
+ return cmd;
+}
+
+static int __do_cmd(struct cxl_cmd *cmd, int ioctl_cmd, int fd)
+{
+ void *cmd_buf;
+ int rc;
+
+ switch (ioctl_cmd) {
+ case CXL_MEM_QUERY_COMMANDS:
+ cmd_buf = cmd->query_cmd;
+ break;
+ case CXL_MEM_SEND_COMMAND:
+ cmd_buf = cmd->send_cmd;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = ioctl(fd, ioctl_cmd, cmd_buf);
+ if (rc < 0)
+ rc = -errno;
+
+ return rc;
+}
+
+static int do_cmd(struct cxl_cmd *cmd, int ioctl_cmd)
+{
+ char *path;
+ struct stat st;
+ unsigned int major, minor;
+ int rc = 0, fd;
+ struct cxl_memdev *memdev = cmd->memdev;
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ const char *devname = cxl_memdev_get_devname(memdev);
+
+ major = cxl_memdev_get_major(memdev);
+ minor = cxl_memdev_get_minor(memdev);
+
+ if (asprintf(&path, "/dev/cxl/%s", devname) < 0)
+ return -ENOMEM;
+
+ fd = open(path, O_RDWR);
+ if (fd < 0) {
+ err(ctx, "failed to open %s: %s\n", path, strerror(errno));
+ rc = -errno;
+ goto out;
+ }
+
+ if (fstat(fd, &st) >= 0 && S_ISCHR(st.st_mode)
+ && major(st.st_rdev) == major
+ && minor(st.st_rdev) == minor) {
+ rc = __do_cmd(cmd, ioctl_cmd, fd);
+ } else {
+ err(ctx, "failed to validate %s as a CXL memdev node\n", path);
+ rc = -ENXIO;
+ }
+ close(fd);
+out:
+ free(path);
+ return rc;
+}
+
+static int alloc_do_query(struct cxl_cmd *cmd, int num_cmds)
+{
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(cmd->memdev);
+ int rc;
+
+ rc = cxl_cmd_alloc_query(cmd, num_cmds);
+ if (rc)
+ return rc;
+
+ rc = do_cmd(cmd, CXL_MEM_QUERY_COMMANDS);
+ if (rc < 0)
+ err(ctx, "%s: query commands failed: %s\n",
+ cxl_memdev_get_devname(cmd->memdev),
+ strerror(-rc));
+ return rc;
+}
+
+static int cxl_cmd_do_query(struct cxl_cmd *cmd)
+{
+ struct cxl_memdev *memdev = cmd->memdev;
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ const char *devname = cxl_memdev_get_devname(memdev);
+ int rc, n_commands;
+
+ switch (cmd->query_status) {
+ case CXL_CMD_QUERY_OK:
+ return 0;
+ case CXL_CMD_QUERY_UNSUPPORTED:
+ return -EOPNOTSUPP;
+ case CXL_CMD_QUERY_NOT_RUN:
+ break;
+ default:
+ err(ctx, "%s: Unknown query_status %d\n",
+ devname, cmd->query_status);
+ return -EINVAL;
+ }
+
+ rc = alloc_do_query(cmd, 0);
+ if (rc)
+ return rc;
+
+ n_commands = cmd->query_cmd->n_commands;
+ dbg(ctx, "%s: supports %d commands\n", devname, n_commands);
+
+ return alloc_do_query(cmd, n_commands);
+}
+
+static int cxl_cmd_validate(struct cxl_cmd *cmd, u32 cmd_id)
+{
+ struct cxl_memdev *memdev = cmd->memdev;
+ struct cxl_mem_query_commands *query = cmd->query_cmd;
+ const char *devname = cxl_memdev_get_devname(memdev);
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ u32 i;
+
+ for (i = 0; i < query->n_commands; i++) {
+ struct cxl_command_info *cinfo = &query->commands[i];
+ const char *cmd_name = cxl_command_names[cinfo->id].name;
+
+ if (cinfo->id != cmd_id)
+ continue;
+
+ dbg(ctx, "%s: %s: in: %d, out %d, flags: %#08x\n",
+ devname, cmd_name, cinfo->size_in,
+ cinfo->size_out, cinfo->flags);
+
+ cmd->query_idx = i;
+ cmd->query_status = CXL_CMD_QUERY_OK;
+ return 0;
+ }
+ cmd->query_status = CXL_CMD_QUERY_UNSUPPORTED;
+ return -EOPNOTSUPP;
+}
+
+CXL_EXPORT int cxl_cmd_set_input_payload(struct cxl_cmd *cmd, void *buf,
+ int size)
+{
+ struct cxl_memdev *memdev = cmd->memdev;
+
+ if (size > memdev->payload_max || size < 0)
+ return -EINVAL;
+
+ if (!buf) {
+
+ /* If the user didn't supply a buffer, allocate it */
+ cmd->input_payload = calloc(1, size);
+ if (!cmd->input_payload)
+ return -ENOMEM;
+ cmd->send_cmd->in.payload = (u64)cmd->input_payload;
+ } else {
+ /*
+ * Use user-buffer as is. If an automatic allocation was
+ * previously made (based on a fixed size from query),
+ * it will get freed during unref.
+ */
+ cmd->send_cmd->in.payload = (u64)buf;
+ }
+ cmd->send_cmd->in.size = size;
+
+ return 0;
+}
+
+CXL_EXPORT int cxl_cmd_set_output_payload(struct cxl_cmd *cmd, void *buf,
+ int size)
+{
+ struct cxl_memdev *memdev = cmd->memdev;
+
+ if (size > memdev->payload_max || size < 0)
+ return -EINVAL;
+
+ if (!buf) {
+
+ /* If the user didn't supply a buffer, allocate it */
+ cmd->output_payload = calloc(1, size);
+ if (!cmd->output_payload)
+ return -ENOMEM;
+ cmd->send_cmd->out.payload = (u64)cmd->output_payload;
+ } else {
+ /*
+ * Use user-buffer as is. If an automatic allocation was
+ * previously made (based on a fixed size from query),
+ * it will get freed during unref.
+ */
+ cmd->send_cmd->out.payload = (u64)buf;
+ }
+ cmd->send_cmd->out.size = size;
+
+ return 0;
+}
+
+static int cxl_cmd_alloc_send(struct cxl_cmd *cmd, u32 cmd_id)
+{
+ struct cxl_mem_query_commands *query = cmd->query_cmd;
+ struct cxl_command_info *cinfo = &query->commands[cmd->query_idx];
+ size_t size;
+
+ if (!query)
+ return -EINVAL;
+
+ size = sizeof(struct cxl_send_command);
+ cmd->send_cmd = calloc(1, size);
+ if (!cmd->send_cmd)
+ return -ENOMEM;
+
+ if (cinfo->id != cmd_id)
+ return -EINVAL;
+
+ cmd->send_cmd->id = cmd_id;
+
+ if (cinfo->size_in > 0) {
+ cmd->input_payload = calloc(1, cinfo->size_in);
+ if (!cmd->input_payload)
+ return -ENOMEM;
+ cmd->send_cmd->in.payload = (u64)cmd->input_payload;
+ cmd->send_cmd->in.size = cinfo->size_in;
+ }
+ if (cinfo->size_out > 0) {
+ cmd->output_payload = calloc(1, cinfo->size_out);
+ if (!cmd->output_payload)
+ return -ENOMEM;
+ cmd->send_cmd->out.payload = (u64)cmd->output_payload;
+ cmd->send_cmd->out.size = cinfo->size_out;
+ }
+
+ return 0;
+}
+
+static struct cxl_cmd *cxl_cmd_new_generic(struct cxl_memdev *memdev,
+ u32 cmd_id)
+{
+ const char *devname = cxl_memdev_get_devname(memdev);
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ struct cxl_cmd *cmd;
+ int rc;
+
+ cmd = cxl_cmd_new(memdev);
+ if (!cmd)
+ return NULL;
+
+ rc = cxl_cmd_do_query(cmd);
+ if (rc) {
+ err(ctx, "%s: query returned: %s\n", devname, strerror(-rc));
+ goto fail;
+ }
+
+ rc = cxl_cmd_validate(cmd, cmd_id);
+ if (rc) {
+ errno = -rc;
+ goto fail;
+ }
+
+ rc = cxl_cmd_alloc_send(cmd, cmd_id);
+ if (rc) {
+ errno = -rc;
+ goto fail;
+ }
+
+ cmd->status = 1;
+ return cmd;
+
+fail:
+ cxl_cmd_unref(cmd);
+ return NULL;
+}
+
+CXL_EXPORT const char *cxl_cmd_get_devname(struct cxl_cmd *cmd)
+{
+ return cxl_memdev_get_devname(cmd->memdev);
+}
+
+CXL_EXPORT struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev,
+ int opcode)
+{
+ struct cxl_cmd *cmd;
+
+ /* opcode '0' is reserved */
+ if (opcode <= 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ cmd = cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_RAW);
+ if (!cmd)
+ return NULL;
+
+ cmd->send_cmd->raw.opcode = opcode;
+ return cmd;
+}
+
+CXL_EXPORT int cxl_cmd_submit(struct cxl_cmd *cmd)
+{
+ struct cxl_memdev *memdev = cmd->memdev;
+ const char *devname = cxl_memdev_get_devname(memdev);
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ int rc;
+
+ switch (cmd->query_status) {
+ case CXL_CMD_QUERY_OK:
+ break;
+ case CXL_CMD_QUERY_UNSUPPORTED:
+ return -EOPNOTSUPP;
+ case CXL_CMD_QUERY_NOT_RUN:
+ return -EINVAL;
+ default:
+ err(ctx, "%s: Unknown query_status %d\n",
+ devname, cmd->query_status);
+ return -EINVAL;
+ }
+
+ dbg(ctx, "%s: submitting SEND cmd: in: %d, out: %d\n", devname,
+ cmd->send_cmd->in.size, cmd->send_cmd->out.size);
+ rc = do_cmd(cmd, CXL_MEM_SEND_COMMAND);
+ cmd->status = cmd->send_cmd->retval;
+ dbg(ctx, "%s: got SEND cmd: in: %d, out: %d, retval: %d, status: %d\n",
+ devname, cmd->send_cmd->in.size, cmd->send_cmd->out.size,
+ rc, cmd->status);
+
+ return rc;
+}
+
+CXL_EXPORT int cxl_cmd_get_mbox_status(struct cxl_cmd *cmd)
+{
+ return cmd->status;
+}
+
+CXL_EXPORT int cxl_cmd_get_out_size(struct cxl_cmd *cmd)
+{
+ return cmd->send_cmd->out.size;
+}
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 2616e5c..3900f90 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -20,6 +20,15 @@ global:
cxl_memdev_get_pmem_size;
cxl_memdev_get_ram_size;
cxl_memdev_get_firmware_verison;
+ cxl_cmd_get_devname;
+ cxl_cmd_new_raw;
+ cxl_cmd_set_input_payload;
+ cxl_cmd_set_output_payload;
+ cxl_cmd_ref;
+ cxl_cmd_unref;
+ cxl_cmd_submit;
+ cxl_cmd_get_mbox_status;
+ cxl_cmd_get_out_size;
local:
*;
};
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index fc88fa1..87ca17e 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -4,6 +4,9 @@
#define _LIBCXL_PRIVATE_H_
#include <libkmod.h>
+#include <cxl/cxl_mem.h>
+#include <ccan/endian/endian.h>
+#include <ccan/short_types/short_types.h>
#define CXL_EXPORT __attribute__ ((visibility("default")))
@@ -21,6 +24,36 @@ struct cxl_memdev {
struct kmod_module *module;
};
+enum cxl_cmd_query_status {
+ CXL_CMD_QUERY_NOT_RUN = 0,
+ CXL_CMD_QUERY_OK,
+ CXL_CMD_QUERY_UNSUPPORTED,
+};
+
+/**
+ * struct cxl_cmd - CXL memdev command
+ * @memdev: the memory device to which the command is being sent
+ * @query_cmd: structure for the Linux 'Query commands' ioctl
+ * @send_cmd: structure for the Linux 'Send command' ioctl
+ * @input_payload: buffer for input payload managed by libcxl
+ * @output_payload: buffer for output payload managed by libcxl
+ * @refcount: reference for passing command buffer around
+ * @query_status: status from query_commands
+ * @query_idx: index of 'this' command in the query_commands array
+ * @status: command return status from the device
+ */
+struct cxl_cmd {
+ struct cxl_memdev *memdev;
+ struct cxl_mem_query_commands *query_cmd;
+ struct cxl_send_command *send_cmd;
+ void *input_payload;
+ void *output_payload;
+ int refcount;
+ int query_status;
+ int query_idx;
+ int status;
+};
+
static inline int check_kmod(struct kmod_ctx *kmod_ctx)
{
return kmod_ctx ? 0 : -ENXIO;
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index fd06790..6e87b80 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -48,6 +48,17 @@ const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);
memdev != NULL; \
memdev = cxl_memdev_get_next(memdev))
+struct cxl_cmd;
+const char *cxl_cmd_get_devname(struct cxl_cmd *cmd);
+struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);
+int cxl_cmd_set_input_payload(struct cxl_cmd *cmd, void *in, int size);
+int cxl_cmd_set_output_payload(struct cxl_cmd *cmd, void *out, int size);
+void cxl_cmd_ref(struct cxl_cmd *cmd);
+void cxl_cmd_unref(struct cxl_cmd *cmd);
+int cxl_cmd_submit(struct cxl_cmd *cmd);
+int cxl_cmd_get_mbox_status(struct cxl_cmd *cmd);
+int cxl_cmd_get_out_size(struct cxl_cmd *cmd);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
--
2.27.0

View File

@ -0,0 +1,157 @@
From 244862cbbfecda9b6b638eccaca526f4daba2795 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Thu, 7 Oct 2021 02:21:28 -0600
Subject: [PATCH 036/217] libcxl: add support for the 'Identify Device' command
Add APIs to allocate and send an 'Identify Device' command, and
accessors to retrieve some of the fields from the resulting data.
Only add a handful accessor functions; more can be added as the need
arises. The fields added are fw_revision, partition_align, and
lsa_size.
Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
cxl/lib/libcxl.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++
cxl/lib/libcxl.sym | 4 ++++
cxl/lib/private.h | 19 +++++++++++++++++
cxl/libcxl.h | 4 ++++
4 files changed, 79 insertions(+)
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 727d599..ed21670 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -13,7 +13,10 @@
#include <sys/sysmacros.h>
#include <uuid/uuid.h>
#include <ccan/list/list.h>
+#include <ccan/endian/endian.h>
+#include <ccan/minmax/minmax.h>
#include <ccan/array_size/array_size.h>
+#include <ccan/short_types/short_types.h>
#include <util/log.h>
#include <util/size.h>
@@ -674,6 +677,55 @@ CXL_EXPORT const char *cxl_cmd_get_devname(struct cxl_cmd *cmd)
return cxl_memdev_get_devname(cmd->memdev);
}
+CXL_EXPORT struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev)
+{
+ return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_IDENTIFY);
+}
+
+CXL_EXPORT int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev,
+ int fw_len)
+{
+ struct cxl_cmd_identify *id =
+ (struct cxl_cmd_identify *)cmd->send_cmd->out.payload;
+
+ if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_IDENTIFY)
+ return -EINVAL;
+ if (cmd->status < 0)
+ return cmd->status;
+
+ if (fw_len > 0)
+ memcpy(fw_rev, id->fw_revision,
+ min(fw_len, CXL_CMD_IDENTIFY_FW_REV_LENGTH));
+ return 0;
+}
+
+CXL_EXPORT unsigned long long cxl_cmd_identify_get_partition_align(
+ struct cxl_cmd *cmd)
+{
+ struct cxl_cmd_identify *id =
+ (struct cxl_cmd_identify *)cmd->send_cmd->out.payload;
+
+ if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_IDENTIFY)
+ return -EINVAL;
+ if (cmd->status < 0)
+ return cmd->status;
+
+ return le64_to_cpu(id->partition_align);
+}
+
+CXL_EXPORT unsigned int cxl_cmd_identify_get_label_size(struct cxl_cmd *cmd)
+{
+ struct cxl_cmd_identify *id =
+ (struct cxl_cmd_identify *)cmd->send_cmd->out.payload;
+
+ if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_IDENTIFY)
+ return -EINVAL;
+ if (cmd->status < 0)
+ return cmd->status;
+
+ return le32_to_cpu(id->lsa_size);
+}
+
CXL_EXPORT struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev,
int opcode)
{
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 3900f90..1dc45f4 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -29,6 +29,10 @@ global:
cxl_cmd_submit;
cxl_cmd_get_mbox_status;
cxl_cmd_get_out_size;
+ cxl_cmd_new_identify;
+ cxl_cmd_identify_get_fw_rev;
+ cxl_cmd_identify_get_partition_align;
+ cxl_cmd_identify_get_label_size;
local:
*;
};
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index 87ca17e..3273f21 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -54,6 +54,25 @@ struct cxl_cmd {
int status;
};
+#define CXL_CMD_IDENTIFY_FW_REV_LENGTH 0x10
+
+struct cxl_cmd_identify {
+ char fw_revision[CXL_CMD_IDENTIFY_FW_REV_LENGTH];
+ le64 total_capacity;
+ le64 volatile_capacity;
+ le64 persistent_capacity;
+ le64 partition_align;
+ le16 info_event_log_size;
+ le16 warning_event_log_size;
+ le16 failure_event_log_size;
+ le16 fatal_event_log_size;
+ le32 lsa_size;
+ u8 poison_list_max_mer[3];
+ le16 inject_poison_limit;
+ u8 poison_caps;
+ u8 qos_telemetry_caps;
+} __attribute__((packed));
+
static inline int check_kmod(struct kmod_ctx *kmod_ctx)
{
return kmod_ctx ? 0 : -ENXIO;
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index 6e87b80..0f2d5e9 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -58,6 +58,10 @@ void cxl_cmd_unref(struct cxl_cmd *cmd);
int cxl_cmd_submit(struct cxl_cmd *cmd);
int cxl_cmd_get_mbox_status(struct cxl_cmd *cmd);
int cxl_cmd_get_out_size(struct cxl_cmd *cmd);
+struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev);
+int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev, int fw_len);
+unsigned long long cxl_cmd_identify_get_partition_align(struct cxl_cmd *cmd);
+unsigned int cxl_cmd_identify_get_label_size(struct cxl_cmd *cmd);
#ifdef __cplusplus
} /* extern "C" */
--
2.27.0

View File

@ -0,0 +1,575 @@
From 55ada0eab92d52826c9be0186db664ba9eeba749 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Thu, 7 Oct 2021 02:21:29 -0600
Subject: [PATCH 037/217] libcxl: add GET_HEALTH_INFO mailbox command and
accessors
Add libcxl APIs to create a new GET_HEALTH_INFO mailbox command, the
command output data structure (privately), and accessor APIs to return
the different fields in the health info output.
Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
cxl/lib/libcxl.c | 291 +++++++++++++++++++++++++++++++++++++++++++++
cxl/lib/libcxl.sym | 29 +++++
cxl/lib/private.h | 47 ++++++++
cxl/libcxl.h | 33 +++++
util/bitmap.h | 85 +++++++++++++
5 files changed, 485 insertions(+)
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index ed21670..065824d 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -677,6 +677,297 @@ CXL_EXPORT const char *cxl_cmd_get_devname(struct cxl_cmd *cmd)
return cxl_memdev_get_devname(cmd->memdev);
}
+static int cxl_cmd_validate_status(struct cxl_cmd *cmd, u32 id)
+{
+ if (cmd->send_cmd->id != id)
+ return -EINVAL;
+ if (cmd->status < 0)
+ return cmd->status;
+ return 0;
+}
+
+/* Helpers for health_info fields (no endian conversion) */
+#define cmd_get_field_u8(cmd, n, N, field) \
+do { \
+ struct cxl_cmd_##n *c = \
+ (struct cxl_cmd_##n *)cmd->send_cmd->out.payload; \
+ int rc = cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_##N); \
+ if (rc) \
+ return rc; \
+ return c->field; \
+} while(0)
+
+#define cmd_get_field_u16(cmd, n, N, field) \
+do { \
+ struct cxl_cmd_##n *c = \
+ (struct cxl_cmd_##n *)cmd->send_cmd->out.payload; \
+ int rc = cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_##N); \
+ if (rc) \
+ return rc; \
+ return le16_to_cpu(c->field); \
+} while(0)
+
+
+#define cmd_get_field_u32(cmd, n, N, field) \
+do { \
+ struct cxl_cmd_##n *c = \
+ (struct cxl_cmd_##n *)cmd->send_cmd->out.payload; \
+ int rc = cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_##N); \
+ if (rc) \
+ return rc; \
+ return le32_to_cpu(c->field); \
+} while(0)
+
+
+#define cmd_get_field_u8_mask(cmd, n, N, field, mask) \
+do { \
+ struct cxl_cmd_##n *c = \
+ (struct cxl_cmd_##n *)cmd->send_cmd->out.payload; \
+ int rc = cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_##N); \
+ if (rc) \
+ return rc; \
+ return !!(c->field & mask); \
+} while(0)
+
+CXL_EXPORT struct cxl_cmd *cxl_cmd_new_get_health_info(
+ struct cxl_memdev *memdev)
+{
+ return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_GET_HEALTH_INFO);
+}
+
+#define cmd_health_get_status_field(c, m) \
+ cmd_get_field_u8_mask(c, get_health_info, GET_HEALTH_INFO, health_status, m)
+
+CXL_EXPORT int cxl_cmd_health_info_get_maintenance_needed(struct cxl_cmd *cmd)
+{
+ cmd_health_get_status_field(cmd,
+ CXL_CMD_HEALTH_INFO_STATUS_MAINTENANCE_NEEDED_MASK);
+}
+
+CXL_EXPORT int cxl_cmd_health_info_get_performance_degraded(struct cxl_cmd *cmd)
+{
+ cmd_health_get_status_field(cmd,
+ CXL_CMD_HEALTH_INFO_STATUS_PERFORMANCE_DEGRADED_MASK);
+}
+
+CXL_EXPORT int cxl_cmd_health_info_get_hw_replacement_needed(struct cxl_cmd *cmd)
+{
+ cmd_health_get_status_field(cmd,
+ CXL_CMD_HEALTH_INFO_STATUS_HW_REPLACEMENT_NEEDED_MASK);
+}
+
+#define cmd_health_check_media_field(cmd, f) \
+do { \
+ struct cxl_cmd_get_health_info *c = \
+ (struct cxl_cmd_get_health_info *)cmd->send_cmd->out.payload; \
+ int rc = cxl_cmd_validate_status(cmd, \
+ CXL_MEM_COMMAND_ID_GET_HEALTH_INFO); \
+ if (rc) \
+ return rc; \
+ return (c->media_status == f); \
+} while(0)
+
+CXL_EXPORT int cxl_cmd_health_info_get_media_normal(struct cxl_cmd *cmd)
+{
+ cmd_health_check_media_field(cmd,
+ CXL_CMD_HEALTH_INFO_MEDIA_STATUS_NORMAL);
+}
+
+CXL_EXPORT int cxl_cmd_health_info_get_media_not_ready(struct cxl_cmd *cmd)
+{
+ cmd_health_check_media_field(cmd,
+ CXL_CMD_HEALTH_INFO_MEDIA_STATUS_NOT_READY);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_media_persistence_lost(struct cxl_cmd *cmd)
+{
+ cmd_health_check_media_field(cmd,
+ CXL_CMD_HEALTH_INFO_MEDIA_STATUS_PERSISTENCE_LOST);
+}
+
+CXL_EXPORT int cxl_cmd_health_info_get_media_data_lost(struct cxl_cmd *cmd)
+{
+ cmd_health_check_media_field(cmd,
+ CXL_CMD_HEALTH_INFO_MEDIA_STATUS_DATA_LOST);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_media_powerloss_persistence_loss(struct cxl_cmd *cmd)
+{
+ cmd_health_check_media_field(cmd,
+ CXL_CMD_HEALTH_INFO_MEDIA_STATUS_POWERLOSS_PERSISTENCE_LOSS);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_media_shutdown_persistence_loss(struct cxl_cmd *cmd)
+{
+ cmd_health_check_media_field(cmd,
+ CXL_CMD_HEALTH_INFO_MEDIA_STATUS_SHUTDOWN_PERSISTENCE_LOSS);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_media_persistence_loss_imminent(struct cxl_cmd *cmd)
+{
+ cmd_health_check_media_field(cmd,
+ CXL_CMD_HEALTH_INFO_MEDIA_STATUS_PERSISTENCE_LOSS_IMMINENT);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_media_powerloss_data_loss(struct cxl_cmd *cmd)
+{
+ cmd_health_check_media_field(cmd,
+ CXL_CMD_HEALTH_INFO_MEDIA_STATUS_POWERLOSS_DATA_LOSS);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_media_shutdown_data_loss(struct cxl_cmd *cmd)
+{
+ cmd_health_check_media_field(cmd,
+ CXL_CMD_HEALTH_INFO_MEDIA_STATUS_SHUTDOWN_DATA_LOSS);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_media_data_loss_imminent(struct cxl_cmd *cmd)
+{
+ cmd_health_check_media_field(cmd,
+ CXL_CMD_HEALTH_INFO_MEDIA_STATUS_DATA_LOSS_IMMINENT);
+}
+
+#define cmd_health_check_ext_field(cmd, fname, type) \
+do { \
+ struct cxl_cmd_get_health_info *c = \
+ (struct cxl_cmd_get_health_info *)cmd->send_cmd->out.payload; \
+ int rc = cxl_cmd_validate_status(cmd, \
+ CXL_MEM_COMMAND_ID_GET_HEALTH_INFO); \
+ if (rc) \
+ return rc; \
+ return (FIELD_GET(fname##_MASK, c->ext_status) == \
+ fname##_##type); \
+} while(0)
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_ext_life_used_normal(struct cxl_cmd *cmd)
+{
+ cmd_health_check_ext_field(cmd,
+ CXL_CMD_HEALTH_INFO_EXT_LIFE_USED, NORMAL);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_ext_life_used_warning(struct cxl_cmd *cmd)
+{
+ cmd_health_check_ext_field(cmd,
+ CXL_CMD_HEALTH_INFO_EXT_LIFE_USED, WARNING);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_ext_life_used_critical(struct cxl_cmd *cmd)
+{
+ cmd_health_check_ext_field(cmd,
+ CXL_CMD_HEALTH_INFO_EXT_LIFE_USED, CRITICAL);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_ext_temperature_normal(struct cxl_cmd *cmd)
+{
+ cmd_health_check_ext_field(cmd,
+ CXL_CMD_HEALTH_INFO_EXT_TEMPERATURE, NORMAL);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_ext_temperature_warning(struct cxl_cmd *cmd)
+{
+ cmd_health_check_ext_field(cmd,
+ CXL_CMD_HEALTH_INFO_EXT_TEMPERATURE, WARNING);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_ext_temperature_critical(struct cxl_cmd *cmd)
+{
+ cmd_health_check_ext_field(cmd,
+ CXL_CMD_HEALTH_INFO_EXT_TEMPERATURE, CRITICAL);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_ext_corrected_volatile_normal(struct cxl_cmd *cmd)
+{
+ cmd_health_check_ext_field(cmd,
+ CXL_CMD_HEALTH_INFO_EXT_CORRECTED_VOLATILE, NORMAL);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_ext_corrected_volatile_warning(struct cxl_cmd *cmd)
+{
+ cmd_health_check_ext_field(cmd,
+ CXL_CMD_HEALTH_INFO_EXT_CORRECTED_VOLATILE, WARNING);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_ext_corrected_persistent_normal(struct cxl_cmd *cmd)
+{
+ cmd_health_check_ext_field(cmd,
+ CXL_CMD_HEALTH_INFO_EXT_CORRECTED_PERSISTENT, NORMAL);
+}
+
+CXL_EXPORT int
+cxl_cmd_health_info_get_ext_corrected_persistent_warning(struct cxl_cmd *cmd)
+{
+ cmd_health_check_ext_field(cmd,
+ CXL_CMD_HEALTH_INFO_EXT_CORRECTED_PERSISTENT, WARNING);
+}
+
+static int health_info_get_life_used_raw(struct cxl_cmd *cmd)
+{
+ cmd_get_field_u8(cmd, get_health_info, GET_HEALTH_INFO,
+ life_used);
+}
+
+CXL_EXPORT int cxl_cmd_health_info_get_life_used(struct cxl_cmd *cmd)
+{
+ int rc = health_info_get_life_used_raw(cmd);
+
+ if (rc < 0)
+ return rc;
+ if (rc == CXL_CMD_HEALTH_INFO_LIFE_USED_NOT_IMPL)
+ return -EOPNOTSUPP;
+ return rc;
+}
+
+static int health_info_get_temperature_raw(struct cxl_cmd *cmd)
+{
+ cmd_get_field_u16(cmd, get_health_info, GET_HEALTH_INFO,
+ temperature);
+}
+
+CXL_EXPORT int cxl_cmd_health_info_get_temperature(struct cxl_cmd *cmd)
+{
+ int rc = health_info_get_temperature_raw(cmd);
+
+ if (rc < 0)
+ return rc;
+ if (rc == CXL_CMD_HEALTH_INFO_TEMPERATURE_NOT_IMPL)
+ return -EOPNOTSUPP;
+ return rc;
+}
+
+CXL_EXPORT int cxl_cmd_health_info_get_dirty_shutdowns(struct cxl_cmd *cmd)
+{
+ cmd_get_field_u32(cmd, get_health_info, GET_HEALTH_INFO,
+ dirty_shutdowns);
+}
+
+CXL_EXPORT int cxl_cmd_health_info_get_volatile_errors(struct cxl_cmd *cmd)
+{
+ cmd_get_field_u32(cmd, get_health_info, GET_HEALTH_INFO,
+ volatile_errors);
+}
+
+CXL_EXPORT int cxl_cmd_health_info_get_pmem_errors(struct cxl_cmd *cmd)
+{
+ cmd_get_field_u32(cmd, get_health_info, GET_HEALTH_INFO,
+ pmem_errors);
+}
+
CXL_EXPORT struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev)
{
return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_IDENTIFY);
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 1dc45f4..c83bc28 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -33,6 +33,35 @@ global:
cxl_cmd_identify_get_fw_rev;
cxl_cmd_identify_get_partition_align;
cxl_cmd_identify_get_label_size;
+ cxl_cmd_new_get_health_info;
+ cxl_cmd_health_info_get_maintenance_needed;
+ cxl_cmd_health_info_get_performance_degraded;
+ cxl_cmd_health_info_get_hw_replacement_needed;
+ cxl_cmd_health_info_get_media_normal;
+ cxl_cmd_health_info_get_media_not_ready;
+ cxl_cmd_health_info_get_media_persistence_lost;
+ cxl_cmd_health_info_get_media_data_lost;
+ cxl_cmd_health_info_get_media_powerloss_persistence_loss;
+ cxl_cmd_health_info_get_media_shutdown_persistence_loss;
+ cxl_cmd_health_info_get_media_persistence_loss_imminent;
+ cxl_cmd_health_info_get_media_powerloss_data_loss;
+ cxl_cmd_health_info_get_media_shutdown_data_loss;
+ cxl_cmd_health_info_get_media_data_loss_imminent;
+ cxl_cmd_health_info_get_ext_life_used_normal;
+ cxl_cmd_health_info_get_ext_life_used_warning;
+ cxl_cmd_health_info_get_ext_life_used_critical;
+ cxl_cmd_health_info_get_ext_temperature_normal;
+ cxl_cmd_health_info_get_ext_temperature_warning;
+ cxl_cmd_health_info_get_ext_temperature_critical;
+ cxl_cmd_health_info_get_ext_corrected_volatile_normal;
+ cxl_cmd_health_info_get_ext_corrected_volatile_warning;
+ cxl_cmd_health_info_get_ext_corrected_persistent_normal;
+ cxl_cmd_health_info_get_ext_corrected_persistent_warning;
+ cxl_cmd_health_info_get_life_used;
+ cxl_cmd_health_info_get_temperature;
+ cxl_cmd_health_info_get_dirty_shutdowns;
+ cxl_cmd_health_info_get_volatile_errors;
+ cxl_cmd_health_info_get_pmem_errors;
local:
*;
};
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index 3273f21..885553a 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -73,6 +73,53 @@ struct cxl_cmd_identify {
u8 qos_telemetry_caps;
} __attribute__((packed));
+struct cxl_cmd_get_health_info {
+ u8 health_status;
+ u8 media_status;
+ u8 ext_status;
+ u8 life_used;
+ le16 temperature;
+ le32 dirty_shutdowns;
+ le32 volatile_errors;
+ le32 pmem_errors;
+} __attribute__((packed));
+
+/* CXL 2.0 8.2.9.5.3 Byte 0 Health Status */
+#define CXL_CMD_HEALTH_INFO_STATUS_MAINTENANCE_NEEDED_MASK BIT(0)
+#define CXL_CMD_HEALTH_INFO_STATUS_PERFORMANCE_DEGRADED_MASK BIT(1)
+#define CXL_CMD_HEALTH_INFO_STATUS_HW_REPLACEMENT_NEEDED_MASK BIT(2)
+
+/* CXL 2.0 8.2.9.5.3 Byte 1 Media Status */
+#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_NORMAL 0x0
+#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_NOT_READY 0x1
+#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_PERSISTENCE_LOST 0x2
+#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_DATA_LOST 0x3
+#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_POWERLOSS_PERSISTENCE_LOSS 0x4
+#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_SHUTDOWN_PERSISTENCE_LOSS 0x5
+#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_PERSISTENCE_LOSS_IMMINENT 0x6
+#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_POWERLOSS_DATA_LOSS 0x7
+#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_SHUTDOWN_DATA_LOSS 0x8
+#define CXL_CMD_HEALTH_INFO_MEDIA_STATUS_DATA_LOSS_IMMINENT 0x9
+
+/* CXL 2.0 8.2.9.5.3 Byte 2 Additional Status */
+#define CXL_CMD_HEALTH_INFO_EXT_LIFE_USED_MASK GENMASK(1, 0)
+#define CXL_CMD_HEALTH_INFO_EXT_LIFE_USED_NORMAL (0)
+#define CXL_CMD_HEALTH_INFO_EXT_LIFE_USED_WARNING (1)
+#define CXL_CMD_HEALTH_INFO_EXT_LIFE_USED_CRITICAL (2)
+#define CXL_CMD_HEALTH_INFO_EXT_TEMPERATURE_MASK GENMASK(3, 2)
+#define CXL_CMD_HEALTH_INFO_EXT_TEMPERATURE_NORMAL (0)
+#define CXL_CMD_HEALTH_INFO_EXT_TEMPERATURE_WARNING (1)
+#define CXL_CMD_HEALTH_INFO_EXT_TEMPERATURE_CRITICAL (2)
+#define CXL_CMD_HEALTH_INFO_EXT_CORRECTED_VOLATILE_MASK BIT(4)
+#define CXL_CMD_HEALTH_INFO_EXT_CORRECTED_VOLATILE_NORMAL (0)
+#define CXL_CMD_HEALTH_INFO_EXT_CORRECTED_VOLATILE_WARNING (1)
+#define CXL_CMD_HEALTH_INFO_EXT_CORRECTED_PERSISTENT_MASK BIT(5)
+#define CXL_CMD_HEALTH_INFO_EXT_CORRECTED_PERSISTENT_NORMAL (0)
+#define CXL_CMD_HEALTH_INFO_EXT_CORRECTED_PERSISTENT_WARNING (1)
+
+#define CXL_CMD_HEALTH_INFO_LIFE_USED_NOT_IMPL 0xff
+#define CXL_CMD_HEALTH_INFO_TEMPERATURE_NOT_IMPL 0xffff
+
static inline int check_kmod(struct kmod_ctx *kmod_ctx)
{
return kmod_ctx ? 0 : -ENXIO;
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index 0f2d5e9..eae2db8 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -62,6 +62,39 @@ struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev);
int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev, int fw_len);
unsigned long long cxl_cmd_identify_get_partition_align(struct cxl_cmd *cmd);
unsigned int cxl_cmd_identify_get_label_size(struct cxl_cmd *cmd);
+struct cxl_cmd *cxl_cmd_new_get_health_info(struct cxl_memdev *memdev);
+int cxl_cmd_health_info_get_maintenance_needed(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_performance_degraded(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_hw_replacement_needed(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_media_normal(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_media_not_ready(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_media_persistence_lost(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_media_data_lost(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_media_normal(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_media_not_ready(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_media_persistence_lost(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_media_data_lost(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_media_powerloss_persistence_loss(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_media_shutdown_persistence_loss(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_media_persistence_loss_imminent(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_media_powerloss_data_loss(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_media_shutdown_data_loss(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_media_data_loss_imminent(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_ext_life_used_normal(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_ext_life_used_warning(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_ext_life_used_critical(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_ext_temperature_normal(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_ext_temperature_warning(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_ext_temperature_critical(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_ext_corrected_volatile_normal(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_ext_corrected_volatile_warning(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_ext_corrected_persistent_normal(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_ext_corrected_persistent_warning(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_life_used(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_temperature(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_dirty_shutdowns(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_volatile_errors(struct cxl_cmd *cmd);
+int cxl_cmd_health_info_get_pmem_errors(struct cxl_cmd *cmd);
#ifdef __cplusplus
} /* extern "C" */
diff --git a/util/bitmap.h b/util/bitmap.h
index 490f3f0..04b3429 100644
--- a/util/bitmap.h
+++ b/util/bitmap.h
@@ -3,10 +3,33 @@
#ifndef _NDCTL_BITMAP_H_
#define _NDCTL_BITMAP_H_
+#include <linux/const.h>
#include <util/size.h>
+#include <util/util.h>
#include <ccan/short_types/short_types.h>
+#ifndef _UL
+#define _UL(x) (_AC(x, UL))
+#endif
+#ifndef _ULL
+#define _ULL(x) (_AC(x, ULL))
+#endif
+
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+#define UL(x) (_UL(x))
+#define ULL(x) (_ULL(x))
+
+/* GENMASK() and its dependencies copied from include/linux/{bits.h, const.h} */
+#define __is_constexpr(x) \
+ (sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))
+#define GENMASK_INPUT_CHECK(h, l) \
+ (BUILD_BUG_ON_ZERO(__builtin_choose_expr( \
+ __is_constexpr((l) > (h)), (l) > (h), 0)))
+#define __GENMASK(h, l) \
+ (((~UL(0)) - (UL(1) << (l)) + 1) & \
+ (~UL(0) >> (BITS_PER_LONG - 1 - (h))))
+#define GENMASK(h, l) \
+ (GENMASK_INPUT_CHECK(h, l) + __GENMASK(h, l))
#define BIT(nr) (1UL << (nr))
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
@@ -30,5 +53,67 @@ unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
unsigned long offset);
int bitmap_full(const unsigned long *src, unsigned int nbits);
+/*
+ * Bitfield access macros
+ * (Copied from Linux's include/linux/bitfield.h)
+ *
+ * FIELD_{GET,PREP} macros take as first parameter shifted mask
+ * from which they extract the base mask and shift amount.
+ * Mask must be a compilation time constant.
+ *
+ * Example:
+ *
+ * #define REG_FIELD_A GENMASK(6, 0)
+ * #define REG_FIELD_B BIT(7)
+ * #define REG_FIELD_C GENMASK(15, 8)
+ * #define REG_FIELD_D GENMASK(31, 16)
+ *
+ * Get:
+ * a = FIELD_GET(REG_FIELD_A, reg);
+ * b = FIELD_GET(REG_FIELD_B, reg);
+ *
+ * Set:
+ * reg = FIELD_PREP(REG_FIELD_A, 1) |
+ * FIELD_PREP(REG_FIELD_B, 0) |
+ * FIELD_PREP(REG_FIELD_C, c) |
+ * FIELD_PREP(REG_FIELD_D, 0x40);
+ *
+ * Modify:
+ * reg &= ~REG_FIELD_C;
+ * reg |= FIELD_PREP(REG_FIELD_C, c);
+ */
+
+/* Force a compilation error if a constant expression is not a power of 2 */
+#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) \
+ BUILD_BUG_ON(((n) & ((n) - 1)) != 0)
+#define BUILD_BUG_ON_NOT_POWER_OF_2(n) \
+ BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
+
+#define __bf_shf(x) (__builtin_ffsll(x) - 1)
+
+#define __BF_FIELD_CHECK(_mask, _reg, _val) \
+ ({ \
+ BUILD_BUG_ON(!__builtin_constant_p(_mask)); \
+ BUILD_BUG_ON((_mask) == 0); \
+ BUILD_BUG_ON(__builtin_constant_p(_val) ? \
+ ~((_mask) >> __bf_shf(_mask)) & (_val) : 0); \
+ BUILD_BUG_ON((_mask) > (typeof(_reg))~0ull); \
+ __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \
+ (1ULL << __bf_shf(_mask))); \
+ })
+
+/**
+ * FIELD_GET() - extract a bitfield element
+ * @_mask: shifted mask defining the field's length and position
+ * @_reg: value of entire bitfield
+ *
+ * FIELD_GET() extracts the field specified by @_mask from the
+ * bitfield passed in as @_reg by masking and shifting it down.
+ */
+#define FIELD_GET(_mask, _reg) \
+ ({ \
+ __BF_FIELD_CHECK(_mask, _reg, 0U); \
+ (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \
+ })
#endif /* _NDCTL_BITMAP_H_ */
--
2.27.0

View File

@ -0,0 +1,113 @@
From c7ae078f1050ed54e254377404af2ae0879f2a39 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Thu, 7 Oct 2021 02:21:30 -0600
Subject: [PATCH 038/217] libcxl: add support for the 'GET_LSA' command
Add a command allocator and accessor APIs for the 'GET_LSA' mailbox
command.
Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
cxl/lib/libcxl.c | 36 ++++++++++++++++++++++++++++++++++++
cxl/lib/libcxl.sym | 2 ++
cxl/lib/private.h | 5 +++++
cxl/libcxl.h | 4 ++++
4 files changed, 47 insertions(+)
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 065824d..76913a2 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -1036,6 +1036,42 @@ CXL_EXPORT struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev,
return cmd;
}
+CXL_EXPORT struct cxl_cmd *cxl_cmd_new_read_label(struct cxl_memdev *memdev,
+ unsigned int offset, unsigned int length)
+{
+ struct cxl_cmd_get_lsa_in *get_lsa;
+ struct cxl_cmd *cmd;
+
+ cmd = cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_GET_LSA);
+ if (!cmd)
+ return NULL;
+
+ get_lsa = (struct cxl_cmd_get_lsa_in *)cmd->send_cmd->in.payload;
+ get_lsa->offset = cpu_to_le32(offset);
+ get_lsa->length = cpu_to_le32(length);
+ return cmd;
+}
+
+CXL_EXPORT ssize_t cxl_cmd_read_label_get_payload(struct cxl_cmd *cmd,
+ void *buf, unsigned int length)
+{
+ struct cxl_cmd_get_lsa_in *get_lsa;
+ void *payload;
+ int rc;
+
+ rc = cxl_cmd_validate_status(cmd, CXL_MEM_COMMAND_ID_GET_LSA);
+ if (rc)
+ return rc;
+
+ get_lsa = (struct cxl_cmd_get_lsa_in *)cmd->send_cmd->in.payload;
+ if (length > le32_to_cpu(get_lsa->length))
+ return -EINVAL;
+
+ payload = (void *)cmd->send_cmd->out.payload;
+ memcpy(buf, payload, length);
+ return length;
+}
+
CXL_EXPORT int cxl_cmd_submit(struct cxl_cmd *cmd)
{
struct cxl_memdev *memdev = cmd->memdev;
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index c83bc28..629322c 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -62,6 +62,8 @@ global:
cxl_cmd_health_info_get_dirty_shutdowns;
cxl_cmd_health_info_get_volatile_errors;
cxl_cmd_health_info_get_pmem_errors;
+ cxl_cmd_new_read_label;
+ cxl_cmd_read_label_get_payload;
local:
*;
};
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index 885553a..bf3a897 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -73,6 +73,11 @@ struct cxl_cmd_identify {
u8 qos_telemetry_caps;
} __attribute__((packed));
+struct cxl_cmd_get_lsa_in {
+ le32 offset;
+ le32 length;
+} __attribute__((packed));
+
struct cxl_cmd_get_health_info {
u8 health_status;
u8 media_status;
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index eae2db8..7408745 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -95,6 +95,10 @@ int cxl_cmd_health_info_get_temperature(struct cxl_cmd *cmd);
int cxl_cmd_health_info_get_dirty_shutdowns(struct cxl_cmd *cmd);
int cxl_cmd_health_info_get_volatile_errors(struct cxl_cmd *cmd);
int cxl_cmd_health_info_get_pmem_errors(struct cxl_cmd *cmd);
+struct cxl_cmd *cxl_cmd_new_read_label(struct cxl_memdev *memdev,
+ unsigned int offset, unsigned int length);
+ssize_t cxl_cmd_read_label_get_payload(struct cxl_cmd *cmd, void *buf,
+ unsigned int length);
#ifdef __cplusplus
} /* extern "C" */
--
2.27.0

View File

@ -0,0 +1,89 @@
From 101966ed3e4a73a6e0e1c269306e976040e068a9 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Thu, 7 Oct 2021 02:21:32 -0600
Subject: [PATCH 039/217] libcxl: add label_size to cxl_memdev, and an API to
retrieve it
Size of the Label Storage Area (LSA) is available as a sysfs attribute
called 'label_storage_size'. Add that to libcxl's memdev so that it is available
for label related commands.
Cc: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
cxl/lib/libcxl.c | 12 ++++++++++++
cxl/lib/libcxl.sym | 1 +
cxl/lib/private.h | 1 +
cxl/libcxl.h | 1 +
4 files changed, 15 insertions(+)
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 76913a2..def3a97 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -247,6 +247,13 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)
if (memdev->payload_max < 0)
goto err_read;
+ sprintf(path, "%s/label_storage_size", cxlmem_base);
+ if (sysfs_read_attr(ctx, path, buf) < 0)
+ goto err_read;
+ memdev->lsa_size = strtoull(buf, NULL, 0);
+ if (memdev->lsa_size == ULLONG_MAX)
+ goto err_read;
+
memdev->dev_path = strdup(cxlmem_base);
if (!memdev->dev_path)
goto err_read;
@@ -350,6 +357,11 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev
return memdev->firmware_version;
}
+CXL_EXPORT size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev)
+{
+ return memdev->lsa_size;
+}
+
CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd)
{
if (!cmd)
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 629322c..858e953 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -64,6 +64,7 @@ global:
cxl_cmd_health_info_get_pmem_errors;
cxl_cmd_new_read_label;
cxl_cmd_read_label_get_payload;
+ cxl_memdev_get_label_size;
local:
*;
};
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index bf3a897..c4ed741 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -21,6 +21,7 @@ struct cxl_memdev {
unsigned long long pmem_size;
unsigned long long ram_size;
int payload_max;
+ size_t lsa_size;
struct kmod_module *module;
};
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index 7408745..d3b97a1 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -42,6 +42,7 @@ struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev);
unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev);
unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev);
const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);
+size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev);
#define cxl_memdev_foreach(ctx, memdev) \
for (memdev = cxl_memdev_get_first(ctx); \
--
2.27.0

View File

@ -0,0 +1,184 @@
From cd1aed6cefe8f4f2043349e1a614876f67743439 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Thu, 7 Oct 2021 02:21:33 -0600
Subject: [PATCH 040/217] libcxl: add representation for an nvdimm bridge
object
Add an nvdimm bridge object representation internal to libcxl. A bridge
object is tied to its parent memdev object, and this patch adds its
first interface, which checks whether a bridge is 'active' - i.e.
implying the label space on the memdev is owned by the kernel.
Cc: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
cxl/lib/libcxl.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++
cxl/lib/libcxl.sym | 1 +
cxl/lib/private.h | 8 +++++
cxl/libcxl.h | 1 +
4 files changed, 83 insertions(+)
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index def3a97..60ed646 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -45,11 +45,19 @@ struct cxl_ctx {
void *private_data;
};
+static void free_bridge(struct cxl_nvdimm_bridge *bridge)
+{
+ free(bridge->dev_buf);
+ free(bridge->dev_path);
+ free(bridge);
+}
+
static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)
{
if (head)
list_del_from(head, &memdev->list);
kmod_module_unref(memdev->module);
+ free_bridge(memdev->bridge);
free(memdev->firmware_version);
free(memdev->dev_buf);
free(memdev->dev_path);
@@ -205,6 +213,40 @@ CXL_EXPORT void cxl_set_log_priority(struct cxl_ctx *ctx, int priority)
ctx->ctx.log_priority = priority;
}
+static void *add_cxl_bridge(void *parent, int id, const char *br_base)
+{
+ const char *devname = devpath_to_devname(br_base);
+ struct cxl_memdev *memdev = parent;
+ struct cxl_ctx *ctx = memdev->ctx;
+ struct cxl_nvdimm_bridge *bridge;
+
+ dbg(ctx, "%s: bridge_base: \'%s\'\n", devname, br_base);
+
+ bridge = calloc(1, sizeof(*bridge));
+ if (!bridge)
+ goto err_dev;
+ bridge->id = id;
+
+ bridge->dev_path = strdup(br_base);
+ if (!bridge->dev_path)
+ goto err_read;
+
+ bridge->dev_buf = calloc(1, strlen(br_base) + 50);
+ if (!bridge->dev_buf)
+ goto err_read;
+ bridge->buf_len = strlen(br_base) + 50;
+
+ memdev->bridge = bridge;
+ return bridge;
+
+ err_read:
+ free(bridge->dev_buf);
+ free(bridge->dev_path);
+ free(bridge);
+ err_dev:
+ return NULL;
+}
+
static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)
{
const char *devname = devpath_to_devname(cxlmem_base);
@@ -271,6 +313,8 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)
goto err_read;
memdev->buf_len = strlen(cxlmem_base) + 50;
+ sysfs_device_parse(ctx, cxlmem_base, "pmem", memdev, add_cxl_bridge);
+
cxl_memdev_foreach(ctx, memdev_dup)
if (memdev_dup->id == memdev->id) {
free_memdev(memdev, NULL);
@@ -362,6 +406,35 @@ CXL_EXPORT size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev)
return memdev->lsa_size;
}
+static int is_enabled(const char *drvpath)
+{
+ struct stat st;
+
+ if (lstat(drvpath, &st) < 0 || !S_ISLNK(st.st_mode))
+ return 0;
+ else
+ return 1;
+}
+
+CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev)
+{
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ struct cxl_nvdimm_bridge *bridge = memdev->bridge;
+ char *path = bridge->dev_buf;
+ int len = bridge->buf_len;
+
+ if (!bridge)
+ return 0;
+
+ if (snprintf(path, len, "%s/driver", bridge->dev_path) >= len) {
+ err(ctx, "%s: nvdimm bridge buffer too small!\n",
+ cxl_memdev_get_devname(memdev));
+ return 0;
+ }
+
+ return is_enabled(path);
+}
+
CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd)
{
if (!cmd)
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 858e953..f3b0c63 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -65,6 +65,7 @@ global:
cxl_cmd_new_read_label;
cxl_cmd_read_label_get_payload;
cxl_memdev_get_label_size;
+ cxl_memdev_nvdimm_bridge_active;
local:
*;
};
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index c4ed741..525c41e 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -10,6 +10,13 @@
#define CXL_EXPORT __attribute__ ((visibility("default")))
+struct cxl_nvdimm_bridge {
+ int id;
+ void *dev_buf;
+ size_t buf_len;
+ char *dev_path;
+};
+
struct cxl_memdev {
int id, major, minor;
void *dev_buf;
@@ -23,6 +30,7 @@ struct cxl_memdev {
int payload_max;
size_t lsa_size;
struct kmod_module *module;
+ struct cxl_nvdimm_bridge *bridge;
};
enum cxl_cmd_query_status {
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index d3b97a1..535e349 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -43,6 +43,7 @@ unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev);
unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev);
const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);
size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev);
+int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev);
#define cxl_memdev_foreach(ctx, memdev) \
for (memdev = cxl_memdev_get_first(ctx); \
--
2.27.0

View File

@ -0,0 +1,247 @@
From 6255d23452809ddc6d48083c35fc935e4fa420d8 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Thu, 7 Oct 2021 02:21:34 -0600
Subject: [PATCH 041/217] libcxl: add interfaces for label operations
Add libcxl interfaces to allow performinfg label (LSA) manipulations.
Add a 'cxl_cmd_new_set_lsa' interface to create a 'Set LSA' mailbox
command payload, and interfaces to read, write, and zero the LSA area on
a memdev.
Cc: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
cxl/lib/libcxl.c | 158 +++++++++++++++++++++++++++++++++++++++++++++
cxl/lib/libcxl.sym | 4 ++
cxl/lib/private.h | 6 ++
cxl/libcxl.h | 8 +++
4 files changed, 176 insertions(+)
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 60ed646..f0664be 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -1197,3 +1197,161 @@ CXL_EXPORT int cxl_cmd_get_out_size(struct cxl_cmd *cmd)
{
return cmd->send_cmd->out.size;
}
+
+CXL_EXPORT struct cxl_cmd *cxl_cmd_new_write_label(struct cxl_memdev *memdev,
+ void *lsa_buf, unsigned int offset, unsigned int length)
+{
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ struct cxl_cmd_set_lsa *set_lsa;
+ struct cxl_cmd *cmd;
+ int rc;
+
+ cmd = cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_SET_LSA);
+ if (!cmd)
+ return NULL;
+
+ /* this will allocate 'in.payload' */
+ rc = cxl_cmd_set_input_payload(cmd, NULL, sizeof(*set_lsa) + length);
+ if (rc) {
+ err(ctx, "%s: cmd setup failed: %s\n",
+ cxl_memdev_get_devname(memdev), strerror(-rc));
+ goto out_fail;
+ }
+ set_lsa = (struct cxl_cmd_set_lsa *)cmd->send_cmd->in.payload;
+ set_lsa->offset = cpu_to_le32(offset);
+ memcpy(set_lsa->lsa_data, lsa_buf, length);
+
+ return cmd;
+
+out_fail:
+ cxl_cmd_unref(cmd);
+ return NULL;
+}
+
+enum lsa_op {
+ LSA_OP_GET,
+ LSA_OP_SET,
+ LSA_OP_ZERO,
+};
+
+static int __lsa_op(struct cxl_memdev *memdev, int op, void *buf,
+ size_t length, size_t offset)
+{
+ const char *devname = cxl_memdev_get_devname(memdev);
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ void *zero_buf = NULL;
+ struct cxl_cmd *cmd;
+ ssize_t ret_len;
+ int rc = 0;
+
+ switch (op) {
+ case LSA_OP_GET:
+ cmd = cxl_cmd_new_read_label(memdev, offset, length);
+ if (!cmd)
+ return -ENOMEM;
+ rc = cxl_cmd_set_output_payload(cmd, buf, length);
+ if (rc) {
+ err(ctx, "%s: cmd setup failed: %s\n",
+ cxl_memdev_get_devname(memdev), strerror(-rc));
+ goto out;
+ }
+ break;
+ case LSA_OP_ZERO:
+ zero_buf = calloc(1, length);
+ if (!zero_buf)
+ return -ENOMEM;
+ buf = zero_buf;
+ /* fall through */
+ case LSA_OP_SET:
+ cmd = cxl_cmd_new_write_label(memdev, buf, offset, length);
+ if (!cmd) {
+ rc = -ENOMEM;
+ goto out_free;
+ }
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ rc = cxl_cmd_submit(cmd);
+ if (rc < 0) {
+ err(ctx, "%s: cmd submission failed: %s\n",
+ devname, strerror(-rc));
+ goto out;
+ }
+
+ rc = cxl_cmd_get_mbox_status(cmd);
+ if (rc != 0) {
+ err(ctx, "%s: firmware status: %d\n",
+ devname, rc);
+ rc = -ENXIO;
+ goto out;
+ }
+
+ if (op == LSA_OP_GET) {
+ ret_len = cxl_cmd_read_label_get_payload(cmd, buf, length);
+ if (ret_len < 0) {
+ rc = ret_len;
+ goto out;
+ }
+ }
+
+out:
+ cxl_cmd_unref(cmd);
+out_free:
+ free(zero_buf);
+ return rc;
+
+}
+
+static int lsa_op(struct cxl_memdev *memdev, int op, void *buf,
+ size_t length, size_t offset)
+{
+ const char *devname = cxl_memdev_get_devname(memdev);
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ size_t remaining = length, cur_len, cur_off = 0;
+ int label_iter_max, rc = 0;
+
+ if (op != LSA_OP_ZERO && buf == NULL) {
+ err(ctx, "%s: LSA buffer cannot be NULL\n", devname);
+ return -EINVAL;
+ }
+
+ if (length == 0)
+ return 0;
+
+ label_iter_max = memdev->payload_max - sizeof(struct cxl_cmd_set_lsa);
+ while (remaining) {
+ cur_len = min((size_t)label_iter_max, remaining);
+ rc = __lsa_op(memdev, op, buf + cur_off,
+ cur_len, offset + cur_off);
+ if (rc)
+ break;
+
+ remaining -= cur_len;
+ cur_off += cur_len;
+ }
+
+ if (rc && (op == LSA_OP_SET))
+ err(ctx, "%s: labels may be in an inconsistent state\n",
+ devname);
+ return rc;
+}
+
+CXL_EXPORT int cxl_memdev_zero_label(struct cxl_memdev *memdev, size_t length,
+ size_t offset)
+{
+ return lsa_op(memdev, LSA_OP_ZERO, NULL, length, offset);
+}
+
+CXL_EXPORT int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf,
+ size_t length, size_t offset)
+{
+ return lsa_op(memdev, LSA_OP_SET, buf, length, offset);
+}
+
+CXL_EXPORT int cxl_memdev_read_label(struct cxl_memdev *memdev, void *buf,
+ size_t length, size_t offset)
+{
+ return lsa_op(memdev, LSA_OP_GET, buf, length, offset);
+}
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index f3b0c63..077d104 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -66,6 +66,10 @@ global:
cxl_cmd_read_label_get_payload;
cxl_memdev_get_label_size;
cxl_memdev_nvdimm_bridge_active;
+ cxl_cmd_new_write_label;
+ cxl_memdev_zero_label;
+ cxl_memdev_write_label;
+ cxl_memdev_read_label;
local:
*;
};
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index 525c41e..a1b8b50 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -87,6 +87,12 @@ struct cxl_cmd_get_lsa_in {
le32 length;
} __attribute__((packed));
+struct cxl_cmd_set_lsa {
+ le32 offset;
+ le32 rsvd;
+ unsigned char lsa_data[0];
+} __attribute__ ((packed));
+
struct cxl_cmd_get_health_info {
u8 health_status;
u8 media_status;
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index 535e349..89d35ba 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -44,6 +44,12 @@ unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev);
const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);
size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev);
int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev);
+int cxl_memdev_zero_label(struct cxl_memdev *memdev, size_t length,
+ size_t offset);
+int cxl_memdev_read_label(struct cxl_memdev *memdev, void *buf, size_t length,
+ size_t offset);
+int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf, size_t length,
+ size_t offset);
#define cxl_memdev_foreach(ctx, memdev) \
for (memdev = cxl_memdev_get_first(ctx); \
@@ -101,6 +107,8 @@ struct cxl_cmd *cxl_cmd_new_read_label(struct cxl_memdev *memdev,
unsigned int offset, unsigned int length);
ssize_t cxl_cmd_read_label_get_payload(struct cxl_cmd *cmd, void *buf,
unsigned int length);
+struct cxl_cmd *cxl_cmd_new_write_label(struct cxl_memdev *memdev,
+ void *buf, unsigned int offset, unsigned int length);
#ifdef __cplusplus
} /* extern "C" */
--
2.27.0

View File

@ -0,0 +1,583 @@
From c415cebe4b5ca50e06db78a4719f312e33106936 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Thu, 7 Oct 2021 02:21:35 -0600
Subject: [PATCH 042/217] cxl: add commands to read, write, and zero labels
Add the following cxl-cli commands: read-labels, write-labels,
zero-labels. They operate on a CXL memdev, or a set of memdevs, and
allow interacting with the label storage area (LSA) on the device.
Add man pages for the above cxl-cli commands.
Cc: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/cxl/Makefile.am | 5 +-
Documentation/cxl/cxl-read-labels.txt | 33 +++
Documentation/cxl/cxl-write-labels.txt | 32 +++
Documentation/cxl/cxl-zero-labels.txt | 29 ++
Documentation/cxl/labels-description.txt | 8 +
Documentation/cxl/labels-options.txt | 17 ++
Documentation/cxl/memdev-option.txt | 4 +
cxl/Makefile.am | 1 +
cxl/builtin.h | 5 +
cxl/cxl.c | 3 +
cxl/memdev.c | 324 +++++++++++++++++++++++
11 files changed, 460 insertions(+), 1 deletion(-)
create mode 100644 Documentation/cxl/cxl-read-labels.txt
create mode 100644 Documentation/cxl/cxl-write-labels.txt
create mode 100644 Documentation/cxl/cxl-zero-labels.txt
create mode 100644 Documentation/cxl/labels-description.txt
create mode 100644 Documentation/cxl/labels-options.txt
create mode 100644 Documentation/cxl/memdev-option.txt
create mode 100644 cxl/memdev.c
diff --git a/Documentation/cxl/Makefile.am b/Documentation/cxl/Makefile.am
index db98dd7..efabaa3 100644
--- a/Documentation/cxl/Makefile.am
+++ b/Documentation/cxl/Makefile.am
@@ -19,7 +19,10 @@ endif
man1_MANS = \
cxl.1 \
- cxl-list.1
+ cxl-list.1 \
+ cxl-read-labels.1 \
+ cxl-write-labels.1 \
+ cxl-zero-labels.1
EXTRA_DIST = $(man1_MANS)
diff --git a/Documentation/cxl/cxl-read-labels.txt b/Documentation/cxl/cxl-read-labels.txt
new file mode 100644
index 0000000..143f296
--- /dev/null
+++ b/Documentation/cxl/cxl-read-labels.txt
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0
+
+cxl-read-labels(1)
+==================
+
+NAME
+----
+cxl-read-labels - read out the label area on a CXL memdev
+
+SYNOPSIS
+--------
+[verse]
+'cxl read-labels' <mem0> [<mem1>..<memN>] [<options>]
+
+include::labels-description.txt[]
+This command dumps the raw binary data in a memdev's label area to stdout or a
+file. In the multi-memdev case the data is concatenated.
+
+OPTIONS
+-------
+include::labels-options.txt[]
+
+-o::
+--output::
+ output file
+
+include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkcxl:cxl-write-labels[1],
+linkcxl:cxl-zero-labels[1],
+CXL-2.0 9.13.2
diff --git a/Documentation/cxl/cxl-write-labels.txt b/Documentation/cxl/cxl-write-labels.txt
new file mode 100644
index 0000000..75f42a5
--- /dev/null
+++ b/Documentation/cxl/cxl-write-labels.txt
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+
+cxl-write-labels(1)
+===================
+
+NAME
+----
+cxl-write-labels - write data to the label area on a memdev
+
+SYNOPSIS
+--------
+[verse]
+'cxl write-labels <mem> [-i <filename>]'
+
+include::labels-description.txt[]
+Read data from the input filename, or stdin, and write it to the given
+<mem> device. Note that the device must not be active in any region, or
+actively registered with the nvdimm subsystem. If it is, the kernel will
+not allow write access to the device's label data area.
+
+OPTIONS
+-------
+include::labels-options.txt[]
+-i::
+--input::
+ input file
+
+SEE ALSO
+--------
+linkcxl:cxl-read-labels[1],
+linkcxl:cxl-zero-labels[1],
+CXL-2.0 9.13.2
diff --git a/Documentation/cxl/cxl-zero-labels.txt b/Documentation/cxl/cxl-zero-labels.txt
new file mode 100644
index 0000000..bf95b24
--- /dev/null
+++ b/Documentation/cxl/cxl-zero-labels.txt
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+
+cxl-zero-labels(1)
+==================
+
+NAME
+----
+cxl-zero-labels - zero out the label area on a set of memdevs
+
+SYNOPSIS
+--------
+[verse]
+'cxl zero-labels' <mem0> [<mem1>..<memN>] [<options>]
+
+include::labels-description.txt[]
+This command resets the device to its default state by
+deleting all labels.
+
+OPTIONS
+-------
+include::labels-options.txt[]
+
+include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkcxl:cxl-read-labels[1],
+linkcxl:cxl-write-labels[1],
+CXL-2.0 9.13.2
diff --git a/Documentation/cxl/labels-description.txt b/Documentation/cxl/labels-description.txt
new file mode 100644
index 0000000..f60bd5d
--- /dev/null
+++ b/Documentation/cxl/labels-description.txt
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+
+DESCRIPTION
+-----------
+The region label area is a small persistent partition of capacity
+available on some CXL memory devices. The label area is used to
+and configure or determine the set of memory devices participating
+in different interleave sets.
diff --git a/Documentation/cxl/labels-options.txt b/Documentation/cxl/labels-options.txt
new file mode 100644
index 0000000..06fbac3
--- /dev/null
+++ b/Documentation/cxl/labels-options.txt
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
+
+<memory device(s)>::
+include::memdev-option.txt[]
+
+-s::
+--size=::
+ Limit the operation to the given number of bytes. A size of 0
+ indicates to operate over the entire label capacity.
+
+-O::
+--offset=::
+ Begin the operation at the given offset into the label area.
+
+-v::
+ Turn on verbose debug messages in the library (if libcxl was built with
+ logging and debug enabled).
diff --git a/Documentation/cxl/memdev-option.txt b/Documentation/cxl/memdev-option.txt
new file mode 100644
index 0000000..e778582
--- /dev/null
+++ b/Documentation/cxl/memdev-option.txt
@@ -0,0 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
+A 'memX' device name, or a memdev id number. Restrict the operation to
+the specified memdev(s). The keyword 'all' can be specified to indicate
+the lack of any restriction.
diff --git a/cxl/Makefile.am b/cxl/Makefile.am
index 98606b9..da9f91d 100644
--- a/cxl/Makefile.am
+++ b/cxl/Makefile.am
@@ -10,6 +10,7 @@ config.h: $(srcdir)/Makefile.am
cxl_SOURCES =\
cxl.c \
list.c \
+ memdev.c \
../util/json.c \
builtin.h
diff --git a/cxl/builtin.h b/cxl/builtin.h
index 3797f98..78eca6e 100644
--- a/cxl/builtin.h
+++ b/cxl/builtin.h
@@ -5,4 +5,9 @@
struct cxl_ctx;
int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx);
+int cmd_write_labels(int argc, const char **argv, struct cxl_ctx *ctx);
+int cmd_read_labels(int argc, const char **argv, struct cxl_ctx *ctx);
+int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx);
+int cmd_init_labels(int argc, const char **argv, struct cxl_ctx *ctx);
+int cmd_check_labels(int argc, const char **argv, struct cxl_ctx *ctx);
#endif /* _CXL_BUILTIN_H_ */
diff --git a/cxl/cxl.c b/cxl/cxl.c
index a7725f8..4b1661d 100644
--- a/cxl/cxl.c
+++ b/cxl/cxl.c
@@ -61,6 +61,9 @@ static struct cmd_struct commands[] = {
{ "version", .c_fn = cmd_version },
{ "list", .c_fn = cmd_list },
{ "help", .c_fn = cmd_help },
+ { "zero-labels", .c_fn = cmd_zero_labels },
+ { "read-labels", .c_fn = cmd_read_labels },
+ { "write-labels", .c_fn = cmd_write_labels },
};
int main(int argc, const char **argv)
diff --git a/cxl/memdev.c b/cxl/memdev.c
new file mode 100644
index 0000000..5ee38e5
--- /dev/null
+++ b/cxl/memdev.c
@@ -0,0 +1,324 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2020-2021 Intel Corporation. All rights reserved. */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#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>
+
+struct action_context {
+ FILE *f_out;
+ FILE *f_in;
+};
+
+static struct parameters {
+ const char *outfile;
+ const char *infile;
+ unsigned len;
+ unsigned offset;
+ bool verbose;
+} param;
+
+#define fail(fmt, ...) \
+do { \
+ fprintf(stderr, "cxl-%s:%s:%d: " fmt, \
+ VERSION, __func__, __LINE__, ##__VA_ARGS__); \
+} while (0)
+
+#define BASE_OPTIONS() \
+OPT_BOOLEAN('v',"verbose", &param.verbose, "turn on debug")
+
+#define READ_OPTIONS() \
+OPT_STRING('o', "output", &param.outfile, "output-file", \
+ "filename to write label area contents")
+
+#define WRITE_OPTIONS() \
+OPT_STRING('i', "input", &param.infile, "input-file", \
+ "filename to read label area data")
+
+#define LABEL_OPTIONS() \
+OPT_UINTEGER('s', "size", &param.len, "number of label bytes to operate"), \
+OPT_UINTEGER('O', "offset", &param.offset, \
+ "offset into the label area to start operation")
+
+static const struct option read_options[] = {
+ BASE_OPTIONS(),
+ LABEL_OPTIONS(),
+ READ_OPTIONS(),
+ OPT_END(),
+};
+
+static const struct option write_options[] = {
+ BASE_OPTIONS(),
+ LABEL_OPTIONS(),
+ WRITE_OPTIONS(),
+ OPT_END(),
+};
+
+static const struct option zero_options[] = {
+ BASE_OPTIONS(),
+ LABEL_OPTIONS(),
+ OPT_END(),
+};
+
+static int action_zero(struct cxl_memdev *memdev, struct action_context *actx)
+{
+ size_t size;
+ int rc;
+
+ if (param.len)
+ size = param.len;
+ else
+ size = cxl_memdev_get_label_size(memdev);
+
+ if (cxl_memdev_nvdimm_bridge_active(memdev)) {
+ fprintf(stderr,
+ "%s: has active nvdimm bridge, abort label write\n",
+ cxl_memdev_get_devname(memdev));
+ return -EBUSY;
+ }
+
+ rc = cxl_memdev_zero_label(memdev, size, param.offset);
+ if (rc < 0)
+ fprintf(stderr, "%s: label zeroing failed: %s\n",
+ cxl_memdev_get_devname(memdev), strerror(-rc));
+
+ return rc;
+}
+
+static int action_write(struct cxl_memdev *memdev, struct action_context *actx)
+{
+ size_t size = param.len, read_len;
+ unsigned char *buf;
+ int rc;
+
+ if (cxl_memdev_nvdimm_bridge_active(memdev)) {
+ fprintf(stderr,
+ "%s: has active nvdimm bridge, abort label write\n",
+ cxl_memdev_get_devname(memdev));
+ return -EBUSY;
+ }
+
+ if (!size) {
+ size_t label_size = cxl_memdev_get_label_size(memdev);
+
+ fseek(actx->f_in, 0L, SEEK_END);
+ size = ftell(actx->f_in);
+ fseek(actx->f_in, 0L, SEEK_SET);
+
+ if (size > label_size) {
+ fprintf(stderr,
+ "File size (%zu) greater than label area size (%zu), aborting\n",
+ size, label_size);
+ return -EINVAL;
+ }
+ }
+
+ buf = calloc(1, size);
+ if (!buf)
+ return -ENOMEM;
+
+ read_len = fread(buf, 1, size, actx->f_in);
+ if (read_len != size) {
+ rc = -ENXIO;
+ goto out;
+ }
+
+ rc = cxl_memdev_write_label(memdev, buf, size, param.offset);
+ if (rc < 0)
+ fprintf(stderr, "%s: label write failed: %s\n",
+ cxl_memdev_get_devname(memdev), strerror(-rc));
+
+out:
+ free(buf);
+ return rc;
+}
+
+static int action_read(struct cxl_memdev *memdev, struct action_context *actx)
+{
+ size_t size, write_len;
+ char *buf;
+ int rc;
+
+ if (param.len)
+ size = param.len;
+ else
+ size = cxl_memdev_get_label_size(memdev);
+
+ buf = calloc(1, size);
+ if (!buf)
+ return -ENOMEM;
+
+ rc = cxl_memdev_read_label(memdev, buf, size, param.offset);
+ if (rc < 0) {
+ fprintf(stderr, "%s: label read failed: %s\n",
+ cxl_memdev_get_devname(memdev), strerror(-rc));
+ goto out;
+ }
+
+ write_len = fwrite(buf, 1, size, actx->f_out);
+ if (write_len != size) {
+ rc = -ENXIO;
+ goto out;
+ }
+ fflush(actx->f_out);
+
+out:
+ free(buf);
+ return rc;
+}
+
+static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,
+ int (*action)(struct cxl_memdev *memdev, struct action_context *actx),
+ const struct option *options, const char *usage)
+{
+ struct cxl_memdev *memdev, *single = NULL;
+ struct action_context actx = { 0 };
+ int i, rc = 0, count = 0, err = 0;
+ const char * const u[] = {
+ usage,
+ NULL
+ };
+ unsigned long id;
+
+ argc = parse_options(argc, argv, options, u, 0);
+
+ if (argc == 0)
+ usage_with_options(u, options);
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "all") == 0) {
+ argv[0] = "all";
+ argc = 1;
+ break;
+ }
+
+ if (sscanf(argv[i], "mem%lu", &id) != 1) {
+ fprintf(stderr, "'%s' is not a valid memdev name\n",
+ argv[i]);
+ err++;
+ }
+ }
+
+ if (err == argc) {
+ usage_with_options(u, options);
+ return -EINVAL;
+ }
+
+ if (!param.outfile)
+ actx.f_out = stdout;
+ else {
+ actx.f_out = fopen(param.outfile, "w+");
+ if (!actx.f_out) {
+ fprintf(stderr, "failed to open: %s: (%s)\n",
+ param.outfile, strerror(errno));
+ rc = -errno;
+ goto out;
+ }
+ }
+
+ if (!param.infile) {
+ actx.f_in = stdin;
+ } else {
+ actx.f_in = fopen(param.infile, "r");
+ if (!actx.f_in) {
+ fprintf(stderr, "failed to open: %s: (%s)\n",
+ param.infile, strerror(errno));
+ rc = -errno;
+ goto out_close_fout;
+ }
+ }
+
+ if (param.verbose)
+ cxl_set_log_priority(ctx, LOG_DEBUG);
+
+ rc = 0;
+ err = 0;
+ count = 0;
+
+ for (i = 0; i < argc; i++) {
+ if (sscanf(argv[i], "mem%lu", &id) != 1
+ && strcmp(argv[i], "all") != 0)
+ continue;
+
+ cxl_memdev_foreach (ctx, memdev) {
+ if (!util_cxl_memdev_filter(memdev, argv[i]))
+ continue;
+
+ if (action == action_write) {
+ single = memdev;
+ rc = 0;
+ } else
+ rc = action(memdev, &actx);
+
+ if (rc == 0)
+ count++;
+ else if (rc && !err)
+ err = rc;
+ }
+ }
+ rc = err;
+
+ if (action == action_write) {
+ if (count > 1) {
+ error("write-labels only supports writing a single memdev\n");
+ usage_with_options(u, options);
+ return -EINVAL;
+ } else if (single) {
+ rc = action(single, &actx);
+ if (rc)
+ count = 0;
+ }
+ }
+
+ if (actx.f_in != stdin)
+ fclose(actx.f_in);
+
+ out_close_fout:
+ if (actx.f_out != stdout)
+ fclose(actx.f_out);
+
+ out:
+ /*
+ * count if some actions succeeded, 0 if none were attempted,
+ * negative error code otherwise.
+ */
+ if (count > 0)
+ return count;
+ return rc;
+}
+
+int cmd_write_labels(int argc, const char **argv, struct cxl_ctx *ctx)
+{
+ int count = memdev_action(argc, argv, ctx, action_write, write_options,
+ "cxl write-labels <memdev> [-i <filename>]");
+
+ fprintf(stderr, "wrote %d mem%s\n", count >= 0 ? count : 0,
+ count > 1 ? "s" : "");
+ return count >= 0 ? 0 : EXIT_FAILURE;
+}
+
+int cmd_read_labels(int argc, const char **argv, struct cxl_ctx *ctx)
+{
+ int count = memdev_action(argc, argv, ctx, action_read, read_options,
+ "cxl read-labels <mem0> [<mem1>..<memN>] [-o <filename>]");
+
+ fprintf(stderr, "read %d mem%s\n", count >= 0 ? count : 0,
+ count > 1 ? "s" : "");
+ return count >= 0 ? 0 : EXIT_FAILURE;
+}
+
+int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx)
+{
+ int count = memdev_action(argc, argv, ctx, action_zero, zero_options,
+ "cxl zero-labels <mem0> [<mem1>..<memN>] [<options>]");
+
+ fprintf(stderr, "zeroed %d mem%s\n", count >= 0 ? count : 0,
+ count > 1 ? "s" : "");
+ return count >= 0 ? 0 : EXIT_FAILURE;
+}
--
2.27.0

View File

@ -0,0 +1,248 @@
From 62fe17528d362110e258d56d8a2f44f2798f3f45 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Thu, 7 Oct 2021 02:21:36 -0600
Subject: [PATCH 043/217] Documentation/cxl: add library API documentation
Add library API documentation for libcxl(3) using the existing
asciidoc(tor) build system. Add a section 3 man page for 'libcxl' that
provides an overview of the library and its usage, and a man page for
the 'cxl_new()' API.
Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
.gitignore | 3 ++
Documentation/cxl/lib/Makefile.am | 58 +++++++++++++++++++++++++++++++
Documentation/cxl/lib/cxl_new.txt | 43 +++++++++++++++++++++++
Documentation/cxl/lib/libcxl.txt | 56 +++++++++++++++++++++++++++++
Makefile.am | 1 +
configure.ac | 1 +
6 files changed, 162 insertions(+)
create mode 100644 Documentation/cxl/lib/Makefile.am
create mode 100644 Documentation/cxl/lib/cxl_new.txt
create mode 100644 Documentation/cxl/lib/libcxl.txt
diff --git a/.gitignore b/.gitignore
index 6a97b92..6468c7a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,12 +14,15 @@ Makefile.in
/libtool
/stamp-h1
*.1
+*.3
Documentation/daxctl/asciidoc.conf
Documentation/ndctl/asciidoc.conf
Documentation/cxl/asciidoc.conf
+Documentation/cxl/lib/asciidoc.conf
Documentation/daxctl/asciidoctor-extensions.rb
Documentation/ndctl/asciidoctor-extensions.rb
Documentation/cxl/asciidoctor-extensions.rb
+Documentation/cxl/lib/asciidoctor-extensions.rb
Documentation/ndctl/attrs.adoc
.dirstamp
daxctl/config.h
diff --git a/Documentation/cxl/lib/Makefile.am b/Documentation/cxl/lib/Makefile.am
new file mode 100644
index 0000000..41e3a5f
--- /dev/null
+++ b/Documentation/cxl/lib/Makefile.am
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2020-2021 Intel Corporation. All rights reserved.
+
+if USE_ASCIIDOCTOR
+
+do_subst = sed -e 's,@Utility@,Libcxl,g' -e's,@utility@,libcxl,g'
+CONFFILE = asciidoctor-extensions.rb
+asciidoctor-extensions.rb: ../../asciidoctor-extensions.rb.in
+ $(AM_V_GEN) $(do_subst) < $< > $@
+
+else
+
+do_subst = sed -e 's,UTILITY,libcxl,g'
+CONFFILE = asciidoc.conf
+asciidoc.conf: ../../asciidoc.conf.in
+ $(AM_V_GEN) $(do_subst) < $< > $@
+
+endif
+
+man3_MANS = \
+ libcxl.3 \
+ cxl_new.3
+
+EXTRA_DIST = $(man3_MANS)
+
+CLEANFILES = $(man3_MANS)
+
+XML_DEPS = \
+ ../../../version.m4 \
+ ../../copyright.txt \
+ Makefile \
+ $(CONFFILE)
+
+RM ?= rm -f
+
+if USE_ASCIIDOCTOR
+
+%.3: %.txt $(XML_DEPS)
+ $(AM_V_GEN)$(RM) $@+ $@ && \
+ $(ASCIIDOC) -b manpage -d manpage -acompat-mode \
+ -I. -rasciidoctor-extensions \
+ -amansource=libcxl -amanmanual="libcxl Manual" \
+ -andctl_version=$(VERSION) -o $@+ $< && \
+ mv $@+ $@
+
+else
+
+%.xml: %.txt $(XML_DEPS)
+ $(AM_V_GEN)$(RM) $@+ $@ && \
+ $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
+ --unsafe -alibcxl_version=$(VERSION) -o $@+ $< && \
+ mv $@+ $@
+
+%.3: %.xml $(XML_DEPS)
+ $(AM_V_GEN)$(RM) $@ && \
+ $(XMLTO) -o . -m ../../manpage-normal.xsl man $<
+
+endif
diff --git a/Documentation/cxl/lib/cxl_new.txt b/Documentation/cxl/lib/cxl_new.txt
new file mode 100644
index 0000000..147d4e0
--- /dev/null
+++ b/Documentation/cxl/lib/cxl_new.txt
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: LGPL-2.0
+
+cxl_new(3)
+==========
+
+NAME
+----
+cxl_new - Create a new library context object that acts as a handle for all
+library operations
+
+SYNOPSIS
+--------
+[verse]
+----
+#include <cxl/libcxl.h>
+
+int cxl_new(struct cxl_ctx **ctx);
+----
+
+DESCRIPTION
+-----------
+Instantiates a new library context, and stores an opaque pointer in ctx. The
+context is freed by linklibcxl:cxl_unref[3], i.e. cxl_new(3) implies an
+internal linklibcxl:cxl_ref[3].
+
+
+RETURN VALUE
+------------
+Returns 0 on success, and a negative errno on failure.
+Possible error codes are:
+
+ * -ENOMEM
+ * -ENXIO
+
+EXAMPLE
+-------
+See example usage in test/libcxl.c
+
+include::../../copyright.txt[]
+
+SEE ALSO
+--------
+linklibcxl:cxl_ref[3], linklibcxl:cxl_unref[3]
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
new file mode 100644
index 0000000..2539369
--- /dev/null
+++ b/Documentation/cxl/lib/libcxl.txt
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: LGPL-2.0
+
+libcxl(3)
+=========
+
+NAME
+----
+libcxl - A library to interact with CXL devices through sysfs(5)
+and ioctl(2) interfaces
+
+SYNOPSIS
+--------
+[verse]
+#include <cxl/libcxl.h>
+cc ... -lcxl
+
+DESCRIPTION
+-----------
+libcxl provides interfaces to interact with CXL devices in Linux, using sysfs
+interfaces for most kernel interactions, and the ioctl() interface for command
+submission.
+
+The starting point for all library interfaces is a 'cxl_ctx' object, returned
+by linklibcxl:cxl_new[3]. CXL 'Type 3' memory devices are children of the
+cxl_ctx object, and can be iterated through using an iterator API.
+
+Library level interfaces that are agnostic to any device, or a specific
+subclass of operations have the prefix 'cxl_'
+
+The object representing a CXL Type 3 device is 'cxl_memdev'. Library interfaces
+related to these devices have the prefix 'cxl_memdev_'. These interfaces are
+mostly associated with sysfs interactions (unless otherwise noted in their
+respective documentation pages). They are typically used to retrieve data
+published by the kernel, or to send data or trigger kernel operations for a
+given device.
+
+A 'cxl_cmd' is a reference counted object which is used to perform 'Mailbox'
+commands as described in the CXL Specification. A 'cxl_cmd' object is tied to a
+'cxl_memdev'. Associated library interfaces have the prefix 'cxl_cmd_'. Within
+this sub-class of interfaces, there are:
+
+ * 'cxl_cmd_new_*' interfaces that allocate a new cxl_cmd object for a given
+ command type.
+
+ * 'cxl_cmd_submit' which submits the command via ioctl()
+
+ * 'cxl_cmd_<name>_get_<field>' interfaces that get specific fields out of the
+ command response
+
+ * 'cxl_cmd_get_*' interfaces to get general command related information.
+
+include::../../copyright.txt[]
+
+SEE ALSO
+--------
+linklibcxl:cxl[1]
diff --git a/Makefile.am b/Makefile.am
index 4904ee7..e2f6bef 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,6 +4,7 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
SUBDIRS = . cxl/lib daxctl/lib ndctl/lib cxl ndctl daxctl
if ENABLE_DOCS
SUBDIRS += Documentation/ndctl Documentation/daxctl Documentation/cxl
+SUBDIRS += Documentation/cxl/lib
endif
SUBDIRS += test
diff --git a/configure.ac b/configure.ac
index dadae0a..00497ae 100644
--- a/configure.ac
+++ b/configure.ac
@@ -231,6 +231,7 @@ AC_CONFIG_FILES([
Documentation/ndctl/Makefile
Documentation/daxctl/Makefile
Documentation/cxl/Makefile
+ Documentation/cxl/lib/Makefile
])
AC_OUTPUT
--
2.27.0

View File

@ -0,0 +1,147 @@
From 57b1484fa427228afd52cdfa4fa3916a7a5878bf Mon Sep 17 00:00:00 2001
From: Ira Weiny <ira.weiny@intel.com>
Date: Thu, 7 Oct 2021 02:21:37 -0600
Subject: [PATCH 044/217] ndctl: Add CXL packages to the RPM spec
Add CXL related packages - the cxl-cli utility, the libcxl library, and
development headers to respective RPM packages in the main spec file.
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Makefile.am | 4 ++++
ndctl.spec.in | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+)
diff --git a/Makefile.am b/Makefile.am
index e2f6bef..fa2010a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -23,17 +23,21 @@ CLEANFILES += $(noinst_SCRIPTS)
do_rhel_subst = sed -e 's,VERSION,$(VERSION),g' \
-e 's,DAX_DNAME,daxctl-devel,g' \
+ -e 's,CXL_DNAME,cxl-devel,g' \
-e 's,DNAME,ndctl-devel,g' \
-e '/^%defattr.*/d' \
-e 's,DAX_LNAME,daxctl-libs,g' \
+ -e 's,CXL_LNAME,cxl-libs,g' \
-e 's,LNAME,ndctl-libs,g'
do_sles_subst = sed -e 's,VERSION,$(VERSION),g' \
-e 's,DAX_DNAME,libdaxctl-devel,g' \
+ -e 's,CXL_DNAME,libcxl-devel,g' \
-e 's,DNAME,libndctl-devel,g' \
-e 's,%license,%doc,g' \
-e 's,\(^License:.*GPL\)v2,\1-2.0,g' \
-e "s,DAX_LNAME,libdaxctl$$(($(LIBDAXCTL_CURRENT) - $(LIBDAXCTL_AGE))),g" \
+ -e "s,CXL_LNAME,libcxl$$(($(LIBCXL_CURRENT) - $(LIBCXL_AGE))),g" \
-e "s,LNAME,libndctl$$(($(LIBNDCTL_CURRENT) - $(LIBNDCTL_AGE))),g"
rhel/ndctl.spec: ndctl.spec.in Makefile.am version.m4
diff --git a/ndctl.spec.in b/ndctl.spec.in
index 0563b2d..4b08c05 100644
--- a/ndctl.spec.in
+++ b/ndctl.spec.in
@@ -8,6 +8,7 @@ Source0: https://github.com/pmem/%{name}/archive/v%{version}.tar.gz#/%{name}-%{v
Requires: LNAME%{?_isa} = %{version}-%{release}
Requires: DAX_LNAME%{?_isa} = %{version}-%{release}
+Requires: CXL_LNAME%{?_isa} = %{version}-%{release}
BuildRequires: autoconf
%if 0%{?rhel} < 9
BuildRequires: asciidoc
@@ -54,6 +55,24 @@ the Linux kernel Device-DAX facility. This facility enables DAX mappings
of performance / feature differentiated memory without need of a
filesystem.
+%package -n cxl-cli
+Summary: Manage CXL devices
+License: GPLv2
+Requires: CXL_LNAME%{?_isa} = %{version}-%{release}
+
+%description -n cxl-cli
+The cxl utility provides enumeration and provisioning commands for
+the Linux kernel CXL devices.
+
+%package -n CXL_DNAME
+Summary: Development files for libcxl
+License: LGPLv2
+Requires: CXL_LNAME%{?_isa} = %{version}-%{release}
+
+%description -n CXL_DNAME
+This package contains libraries and header files for developing applications
+that use libcxl, a library for enumerating and communicating with CXL devices.
+
%package -n DAX_DNAME
Summary: Development files for libdaxctl
License: LGPLv2
@@ -84,6 +103,13 @@ Device DAX is a facility for establishing DAX mappings of performance /
feature-differentiated memory. DAX_LNAME provides an enumeration /
control API for these devices.
+%package -n CXL_LNAME
+Summary: Management library for CXL devices
+License: LGPLv2
+
+%description -n CXL_LNAME
+libcxl is a library for enumerating and communicating with CXL devices.
+
%prep
%setup -q ndctl-%{version}
@@ -105,6 +131,8 @@ make check
%ldconfig_scriptlets -n DAX_LNAME
+%ldconfig_scriptlets -n CXL_LNAME
+
%define bashcompdir %(pkg-config --variable=completionsdir bash-completion)
%files
@@ -126,6 +154,12 @@ make check
%{_mandir}/man1/daxctl*
%{_datadir}/daxctl/daxctl.conf
+%files -n cxl-cli
+%defattr(-,root,root)
+%license LICENSES/preferred/GPL-2.0 LICENSES/other/MIT LICENSES/other/CC0-1.0
+%{_bindir}/cxl
+%{_mandir}/man1/cxl*
+
%files -n LNAME
%defattr(-,root,root)
%doc README.md
@@ -138,6 +172,12 @@ make check
%license LICENSES/preferred/LGPL-2.1 LICENSES/other/MIT LICENSES/other/CC0-1.0
%{_libdir}/libdaxctl.so.*
+%files -n CXL_LNAME
+%defattr(-,root,root)
+%doc README.md
+%license LICENSES/preferred/LGPL-2.1 LICENSES/other/MIT LICENSES/other/CC0-1.0
+%{_libdir}/libcxl.so.*
+
%files -n DNAME
%defattr(-,root,root)
%license LICENSES/preferred/LGPL-2.1
@@ -152,6 +192,15 @@ make check
%{_libdir}/libdaxctl.so
%{_libdir}/pkgconfig/libdaxctl.pc
+%files -n CXL_DNAME
+%defattr(-,root,root)
+%license LICENSES/preferred/LGPL-2.1
+%{_includedir}/cxl/
+%{_libdir}/libcxl.so
+%{_libdir}/pkgconfig/libcxl.pc
+%{_mandir}/man3/cxl*
+%{_mandir}/man3/libcxl.3.gz
+
%changelog
* Fri May 27 2016 Dan Williams <dan.j.williams@intel.com> - 53-1
--
2.27.0

View File

@ -0,0 +1,139 @@
From 02c40b971bd4d092b3612fcb5e9ddd57548e6dbb Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Thu, 7 Oct 2021 02:21:38 -0600
Subject: [PATCH 045/217] cxl-cli: add bash completion
Add bash completion for the cxl-cli commands implemented so far:
cxl-list
cxl-read-labels
cxl-write-labels
cxl-zero-labels
Acked-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
contrib/ndctl | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 109 insertions(+)
diff --git a/contrib/ndctl b/contrib/ndctl
index 680fe6a..cae4b1b 100755
--- a/contrib/ndctl
+++ b/contrib/ndctl
@@ -647,5 +647,114 @@ _daxctl()
__daxctl_main
}
+### cxl-cli ###
+
+__cxl_get_devs()
+{
+ local opts=("--memdevs" "$*")
+ cxl list "${opts[@]}" | grep -E "^\s*\"memdev\":" | cut -d'"' -f4
+}
+
+__cxlcomp()
+{
+ local i=0
+
+ COMPREPLY=( $( compgen -W "$1" -- "$2" ) )
+ for cword in "${COMPREPLY[@]}"; do
+ if [[ "$cword" == @(--memdev|--offset|--size|--input|--output) ]]; then
+ COMPREPLY[$i]="${cword}="
+ else
+ COMPREPLY[$i]="${cword} "
+ fi
+ ((i++))
+ done
+}
+
+__cxl_comp_options()
+{
+
+ local cur=$1
+ local opts
+
+ if [[ "$cur" == *=* ]]; then
+ local cur_subopt=${cur%%=*}
+ local cur_arg=${cur##*=}
+ case $cur_subopt in
+ --memdev)
+ opts="$(__cxl_get_devs -i)"
+ ;;
+ *)
+ return
+ ;;
+ esac
+ __cxlcomp "$opts" "$cur_arg"
+ fi
+}
+
+__cxl_comp_non_option_args()
+{
+ local subcmd=$1
+ local cur=$2
+ local opts
+
+ case $subcmd in
+ read-labels)
+ ;&
+ write-labels)
+ ;&
+ zero-labels)
+ opts="$(__cxl_get_devs -i) all"
+ ;;
+ *)
+ return
+ ;;
+ esac
+ __cxlcomp "$opts" "$cur"
+}
+
+__cxl_main()
+{
+ local cmd subcmd
+
+ cmd=${words[0]}
+ COMPREPLY=()
+
+ # Skip options backward and find the last cxl command
+ __nd_common_prev_skip_opts
+ subcmd=$prev_skip_opts
+ # List cxl subcommands or long options
+ if [ -z $subcmd ]; then
+ if [[ $cur == --* ]]; then
+ cmds="--version --help --list-cmds"
+ else
+ cmds=$($cmd --list-cmds)
+ fi
+ __cxlcomp "$cmds" "$cur"
+ else
+ # List long option names
+ if [[ $cur == --* ]]; then
+ opts=$($cmd $subcmd --list-opts)
+ __cxlcomp "$opts" "$cur"
+ __cxl_comp_options "$cur"
+ else
+ [ -z "$subcmd" ] && return
+ __cxl_comp_non_option_args "$subcmd" "$cur"
+ fi
+ fi
+}
+
+type cxl &>/dev/null &&
+_cxl()
+{
+ local cur words cword prev
+ if [ $preload_get_comp_words_by_ref = "true" ]; then
+ _get_comp_words_by_ref -n =: cur words cword prev
+ else
+ __nd_common_get_comp_words_by_ref -n =: cur words cword prev
+ fi
+ __cxl_main
+}
+
complete -o nospace -F _ndctl ndctl
complete -o nospace -F _daxctl daxctl
+complete -o nospace -F _cxl cxl
--
2.27.0

View File

@ -0,0 +1,308 @@
From f5d1e2133c54c1f420a0c3cf45fa633f097823be Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Thu, 7 Oct 2021 02:21:39 -0600
Subject: [PATCH 046/217] cxl: add health information to cxl-list
Add JSON output for fields from the 'GET_HEALTH_INFO' mailbox command
to memory device listings.
Cc: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/cxl/cxl-list.txt | 38 +++++++
cxl/list.c | 5 +
util/json.c | 179 +++++++++++++++++++++++++++++++++
util/json.h | 1 +
4 files changed, 223 insertions(+)
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
index 370d5b8..c8d10fb 100644
--- a/Documentation/cxl/cxl-list.txt
+++ b/Documentation/cxl/cxl-list.txt
@@ -48,6 +48,44 @@ OPTIONS
--idle::
Include idle (not enabled / zero-sized) devices in the listing
+-H::
+--health::
+ Include health information in the memdev listing. Example listing:
+----
+# cxl list -m mem0 -H
+[
+ {
+ "memdev":"mem0",
+ "pmem_size":268435456,
+ "ram_size":268435456,
+ "health":{
+ "maintenance_needed":true,
+ "performance_degraded":true,
+ "hw_replacement_needed":true,
+ "media_normal":false,
+ "media_not_ready":false,
+ "media_persistence_lost":false,
+ "media_data_lost":true,
+ "media_powerloss_persistence_loss":false,
+ "media_shutdown_persistence_loss":false,
+ "media_persistence_loss_imminent":false,
+ "media_powerloss_data_loss":false,
+ "media_shutdown_data_loss":false,
+ "media_data_loss_imminent":false,
+ "ext_life_used":"normal",
+ "ext_temperature":"critical",
+ "ext_corrected_volatile":"warning",
+ "ext_corrected_persistent":"normal",
+ "life_used_percent":15,
+ "temperature":25,
+ "dirty_shutdowns":10,
+ "volatile_errors":20,
+ "pmem_errors":30
+ }
+ }
+]
+----
+
include::human-option.txt[]
include::verbose-option.txt[]
diff --git a/cxl/list.c b/cxl/list.c
index 043d20c..b1468b7 100644
--- a/cxl/list.c
+++ b/cxl/list.c
@@ -16,6 +16,7 @@ static struct {
bool memdevs;
bool idle;
bool human;
+ bool health;
} list;
static unsigned long listopts_to_flags(void)
@@ -26,6 +27,8 @@ static unsigned long listopts_to_flags(void)
flags |= UTIL_JSON_IDLE;
if (list.human)
flags |= UTIL_JSON_HUMAN;
+ if (list.health)
+ flags |= UTIL_JSON_HEALTH;
return flags;
}
@@ -57,6 +60,8 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
OPT_BOOLEAN('i', "idle", &list.idle, "include idle devices"),
OPT_BOOLEAN('u', "human", &list.human,
"use human friendly number formats "),
+ OPT_BOOLEAN('H', "health", &list.health,
+ "include memory device health information "),
OPT_END(),
};
const char * const u[] = {
diff --git a/util/json.c b/util/json.c
index 3be3a92..f97cf07 100644
--- a/util/json.c
+++ b/util/json.c
@@ -1442,6 +1442,180 @@ struct json_object *util_badblock_rec_to_json(u64 block, u64 count,
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)
{
@@ -1464,5 +1638,10 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
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 91918c8..ce575e6 100644
--- a/util/json.h
+++ b/util/json.h
@@ -19,6 +19,7 @@ enum util_json_flags {
UTIL_JSON_CONFIGURED = (1 << 7),
UTIL_JSON_FIRMWARE = (1 << 8),
UTIL_JSON_DAX_MAPPINGS = (1 << 9),
+ UTIL_JSON_HEALTH = (1 << 10),
};
struct json_object;
--
2.27.0

View File

@ -0,0 +1,75 @@
From ac46d00d7d4d555a238bb898e2ff4af0c444bebe Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Tue, 16 Nov 2021 17:51:31 -0700
Subject: [PATCH 047/217] ndctl: install bash-completion symlinks
Install symlinks for other utilities (daxctl, cxl-cli) in the
completions directory so that the dynamic completion loader can pick up
their respective names. Without this, completions for daxctl and cxl
would only work after a prior invocation of ndctl's completion.
Reported-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Makefile.am | 3 +++
configure.ac | 1 +
ndctl.spec.in | 4 +++-
3 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/Makefile.am b/Makefile.am
index fa2010a..bd0037e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -49,6 +49,9 @@ sles/ndctl.spec: sles/header ndctl.spec.in Makefile.am version.m4
if ENABLE_BASH_COMPLETION
bashcompletiondir = $(BASH_COMPLETION_DIR)
dist_bashcompletion_DATA = contrib/ndctl
+install-data-hook:
+ $(LN_S) -f $(BASH_COMPLETION_DIR)/ndctl $(DESTDIR)/$(BASH_COMPLETION_DIR)/daxctl
+ $(LN_S) -f $(BASH_COMPLETION_DIR)/ndctl $(DESTDIR)/$(BASH_COMPLETION_DIR)/cxl
endif
modprobe_file = contrib/nvdimm-security.conf
diff --git a/configure.ac b/configure.ac
index 00497ae..9ac785f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -31,6 +31,7 @@ AC_PREFIX_DEFAULT([/usr])
AC_PROG_SED
AC_PROG_MKDIR_P
+AC_PROG_LN_S
AC_ARG_ENABLE([docs],
AS_HELP_STRING([--disable-docs],
diff --git a/ndctl.spec.in b/ndctl.spec.in
index 4b08c05..27ca097 100644
--- a/ndctl.spec.in
+++ b/ndctl.spec.in
@@ -140,7 +140,7 @@ make check
%license LICENSES/preferred/GPL-2.0 LICENSES/other/MIT LICENSES/other/CC0-1.0
%{_bindir}/ndctl
%{_mandir}/man1/ndctl*
-%{bashcompdir}/
+%{bashcompdir}/ndctl
%{_unitdir}/ndctl-monitor.service
%{_sysconfdir}/ndctl/keys/keys.readme
%{_sysconfdir}/modprobe.d/nvdimm-security.conf
@@ -153,12 +153,14 @@ make check
%{_bindir}/daxctl
%{_mandir}/man1/daxctl*
%{_datadir}/daxctl/daxctl.conf
+%{bashcompdir}/daxctl
%files -n cxl-cli
%defattr(-,root,root)
%license LICENSES/preferred/GPL-2.0 LICENSES/other/MIT LICENSES/other/CC0-1.0
%{_bindir}/cxl
%{_mandir}/man1/cxl*
+%{bashcompdir}/cxl
%files -n LNAME
%defattr(-,root,root)
--
2.27.0

View File

@ -0,0 +1,400 @@
From 706a418798633ccb550b114eca7cc11038ab2695 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Tue, 14 Dec 2021 19:01:02 -0700
Subject: [PATCH 048/217] scripts: Add a man page template generator
Add a script to generate man page templates for the utils and libraries
under ndctl - including cxl, libcxl, ndctl, and daxctl.
The script can control certain include options depending on the options
supplied, and either dump the templates to stdout, or write the actual
files in their eventual directories, and open up an editor to further
edit them (unless --no-edit is used).
Link: https://lore.kernel.org/r/20211215020102.97880-1-vishal.l.verma@intel.com
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
scripts/docsurgeon | 339 +++++++++++++++++++++++++
scripts/docsurgeon_parser_generator.m4 | 23 ++
2 files changed, 362 insertions(+)
create mode 100755 scripts/docsurgeon
create mode 100644 scripts/docsurgeon_parser_generator.m4
diff --git a/scripts/docsurgeon b/scripts/docsurgeon
new file mode 100755
index 0000000..ca0ad78
--- /dev/null
+++ b/scripts/docsurgeon
@@ -0,0 +1,339 @@
+#!/bin/bash -eE
+
+this_script="docsurgeon"
+script_dir="$(cd "$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")" && pwd)"
+env_file="${script_dir}/.env"
+if [ -e "$env_file" ]; then
+ # shellcheck source=.env
+ . "$env_file"
+fi
+
+sources_file="${script_dir}/.sources"
+
+parser_generator="${script_dir}/${this_script}_parser_generator.m4"
+parser_lib="${script_dir}/${this_script}_parser.sh"
+if [ ! -e "$parser_lib" ] || [ "$parser_generator" -nt "$parser_lib" ]; then
+ if command -V argbash > /dev/null; then
+ argbash --strip user-content "$parser_generator" -o "$parser_lib"
+ else
+ echo "error: please install argbash" >&2
+ exit 1
+ fi
+fi
+
+if [[ $1 != "bin" ]]; then
+ # shellcheck source=docsurgeon_parser.sh
+ . "${script_dir}/${this_script}_parser.sh" || { echo "Couldn't find $parser_lib" >&2; exit 1; }
+fi
+
+# some script defaults - override using '.env'
+docbase="Documentation"
+copyright_cli="// SPDX-License-Identifier: GPL-2.0"
+copyright_footer_cli="include::../copyright.txt[]"
+copyright_lib="// SPDX-License-Identifier: LGPL-2.0"
+copyright_footer_lib="include::../../copyright.txt[]"
+
+# List of files we're creating, to be edited/renamed later
+# This starts out blank, and is filled in as we go by gen_*() functions
+declare -a outfiles
+
+cleanup()
+{
+ if [ ${#outfiles[@]} -gt 0 ]; then
+ rm -f "${outfiles[@]}"
+ fi
+ set +x
+}
+
+trap cleanup EXIT
+
+auto_detect_params()
+{
+ fs=""
+ module=""
+ section=""
+
+ # if module and section were explicitly specified, respect them
+ if [[ $_arg_module ]] && [[ $_arg_section ]]; then
+ return
+ fi
+
+ # check if names are self-consistent, and determine 'fs'
+ for name in ${_arg_name[@]}; do
+ if [[ ! $fs ]]; then
+ if [[ $name == *-* ]]; then
+ fs="-"
+ elif [[ $name == *_* ]]; then
+ fs="_"
+ else
+ # can't autodetect section
+ return
+ fi
+ fi
+ if [[ $fs == "-" ]] && [[ $name == *_* ]]; then
+ die "can't auto-detect params with mixed-style names"
+ fi
+ if [[ $fs == "_" ]] && [[ $name == *-* ]]; then
+ die "can't auto-detect params with mixed-style names"
+ fi
+ done
+
+ # try to detect module name
+ for name in ${_arg_name[@]}; do
+ str=${name%%$fs*}
+ if [[ $module ]]; then
+ if [[ $str != $module ]]; then
+ die "Can't autodetect module because of mixed names ($str and $module)"
+ fi
+ else
+ module="$str"
+ fi
+ done
+
+ # try to detect section number
+ case "$fs" in
+ -)
+ section=1
+ ;;
+ _)
+ section=3
+ ;;
+ *)
+ die "Unknown fs, can't autodetect section number"
+ ;;
+ esac
+
+ if [[ $module ]]; then
+ _arg_module="$module"
+ fi
+ if [[ $section ]]; then
+ _arg_section="$section"
+ fi
+}
+
+process_options_logic()
+{
+ if [[ $_arg_debug == "on" ]]; then
+ set -x
+ fi
+
+ auto_detect_params
+}
+
+gen_underline()
+{
+ name="$1"
+ char="$2"
+ num="${#name}"
+
+ printf -v tmpstring "%-${num}s" " "
+ echo "${tmpstring// /$char}"
+}
+
+gen_header()
+{
+ printf "\n%s\n%s\n" "$1" "$(gen_underline "$1" "=")"
+}
+
+gen_section()
+{
+ printf "\n%s\n%s\n" "$1" "$(gen_underline "$1" "-")"
+}
+
+gen_section_name()
+{
+ name="$1"
+
+ gen_section "NAME"
+ cat <<- EOF
+ $name -
+ EOF
+}
+
+gen_section_synopsis_1()
+{
+ name="$1"
+
+ gen_section "SYNOPSIS"
+ cat <<- EOF
+ [verse]
+ '$_arg_module ${name#*-} [<options>]'
+ EOF
+}
+
+gen_section_synopsis_3()
+{
+ name="$1"
+
+ gen_section "SYNOPSIS"
+ cat <<- EOF
+ [verse]
+ ----
+ #include <$_arg_module/lib$_arg_module.h>
+
+ <type> $name();
+ ----
+ EOF
+}
+
+gen_section_example_1()
+{
+ name="$1"
+
+ gen_section "EXAMPLE"
+ cat <<- EOF
+ ----
+ # $_arg_module ${name#*-}
+ ----
+ EOF
+}
+
+gen_section_example_3()
+{
+ name="$1"
+
+ gen_section "EXAMPLE"
+ cat <<- EOF
+ See example usage in test/lib$_arg_module.c
+ EOF
+}
+
+gen_section_options_1()
+{
+ gen_section "OPTIONS"
+cat << EOF
+-o::
+--option::
+ Description
+EOF
+
+ if [[ $_arg_human_option == "on" ]]; then
+ printf "\n%s\n" "include::human-option.txt[]"
+ fi
+ if [[ $_arg_verbose_option == "on" ]]; then
+ printf "\n%s\n" "include::verbose-option.txt[]"
+ fi
+}
+
+gen_section_seealso_1()
+{
+ gen_section "SEE ALSO"
+ cat <<- EOF
+ link$_arg_module:$_arg_module-list[$_arg_section],
+ EOF
+}
+
+gen_section_seealso_3()
+{
+ gen_section "SEE ALSO"
+ cat <<- EOF
+ linklib$_arg_module:${_arg_module}_other_API[$_arg_section],
+ EOF
+}
+
+gen_cli()
+{
+ name="$1"
+ path="$docbase/$_arg_module"
+ if [ ! -d "$path" ]; then
+ die "Not found: $path"
+ fi
+
+ tmp="$(mktemp -p "$path" "$name.txt.XXXX")"
+ outfiles+=("$tmp")
+
+ # Start template generation
+ printf "%s\n" "$copyright_cli" > "$tmp"
+ gen_header "$name" >> "$tmp"
+ gen_section_name "$name" >> "$tmp"
+ gen_section_synopsis_1 "$name" >> "$tmp"
+ gen_section "DESCRIPTION" >> "$tmp"
+ gen_section_example_1 "$name" >> "$tmp"
+ gen_section_options_1 >> "$tmp"
+ printf "\n%s\n" "$copyright_footer_cli" >> "$tmp"
+ gen_section_seealso_1 >> "$tmp"
+}
+
+gen_lib()
+{
+ name="$1"
+ path="$docbase/$_arg_module/lib"
+ if [ ! -d "$path" ]; then
+ die "Not found: $path"
+ fi
+
+ tmp="$(mktemp -p "$path" "$name.txt.XXXX")"
+ outfiles+=("$tmp")
+
+ # Start template generation
+ printf "%s\n" "$copyright_lib" > "$tmp"
+ gen_header "$name($_arg_section)" >> "$tmp"
+ gen_section_name "$name" >> "$tmp"
+ gen_section_synopsis_3 "$name" >> "$tmp"
+ gen_section "DESCRIPTION" >> "$tmp"
+ gen_section "RETURN VALUE" >> "$tmp"
+ gen_section_example_3 "$name" >> "$tmp"
+ printf "\n%s\n" "$copyright_footer_lib" >> "$tmp"
+ gen_section_seealso_3 >> "$tmp"
+}
+
+gen_man()
+{
+ name="$1"
+ case "$_arg_section" in
+ 1)
+ gen_cli "$name"
+ ;;
+ 3)
+ gen_lib "$name"
+ ;;
+ *)
+ die "Unknown section: $_arg_section"
+ ;;
+ esac
+}
+
+gen_include()
+{
+ echo "in gen_include"
+}
+
+main()
+{
+ process_options_logic
+
+ cmd="$_arg_command"
+ case "$cmd" in
+ gen-man)
+ for name in ${_arg_name[@]}; do
+ gen_man "$name"
+ done
+ ;;
+ gen-include)
+ for name in ${_arg_name[@]}; do
+ gen_include
+ done
+ ;;
+ *)
+ die "Unknown command: $cmd"
+ ;;
+ esac
+
+ if [[ $_arg_dump == "on" ]]; then
+ for file in ${outfiles[@]}; do
+ echo "${file##*/}"
+ cat "$file"
+ rm "$file"
+ done
+ elif [ ${#outfiles[@]} -gt 0 ]; then
+ if [[ $_arg_edit = "on" ]]; then
+ vim -p "${outfiles[@]}"
+ fi
+
+ for file in ${outfiles[@]}; do
+ mv "$file" "${file%.*}"
+ done
+ fi
+}
+
+main "$@"
diff --git a/scripts/docsurgeon_parser_generator.m4 b/scripts/docsurgeon_parser_generator.m4
new file mode 100644
index 0000000..9283c7c
--- /dev/null
+++ b/scripts/docsurgeon_parser_generator.m4
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+# m4_ignore(
+echo "This is just a parsing library template, not the library - pass this file to 'argbash' to fix this." >&2
+exit 11 #)Created by argbash-init v2.9.0
+# Rearrange the order of options below according to what you would like to see in the help message.
+# ARG_OPTIONAL_REPEATED([name], [n], [Command or function name to generate a template for.\n Can be repeated for multiple names. ], [])
+# ARG_OPTIONAL_BOOLEAN([edit], [e], [Edit template files after creation], [on])
+# ARG_OPTIONAL_BOOLEAN([debug], [], [Debug script problems (enables set -x)], )
+# ARG_OPTIONAL_BOOLEAN([dump], [], [Write generated file to stdout instead of a file], )
+# ARG_OPTIONAL_SINGLE([module], [m], [Module (Docs subdir) in which to create the template], [])
+# ARG_OPTIONAL_SINGLE([section], [s], [man section for which to create the template], [])
+# ARG_OPTIONAL_BOOLEAN([human-option], [u], [Include the human option in 'OPTIONS'], )
+# ARG_OPTIONAL_BOOLEAN([verbose-option], [V], [Include the verbose option in 'OPTIONS'], )
+# ARG_POSITIONAL_DOUBLEDASH()
+# ARG_POSITIONAL_SINGLE([command], [Operation to perform:\n gen-man\n gen-include], [])
+# ARGBASH_SET_DELIM([ =])
+# ARG_OPTION_STACKING([getopt])
+# ARG_RESTRICT_VALUES([no-local-options])
+# ARG_DEFAULTS_POS
+# ARG_HELP([Tool to aid in creating and managing man page templates])
+# ARG_VERSION([echo "docsurgeon 0.1"])
+# ARGBASH_GO
--
2.27.0

View File

@ -0,0 +1,167 @@
From 8f4e42c0c526e85b045fd0329df7cb904f511c98 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Thu, 7 Oct 2021 14:59:53 -0700
Subject: [PATCH 049/217] daxctl: Add "Soft Reservation" theory of operation
As systems are starting to ship memory with the EFI "Special Purpose"
attribute that Linux optionally turns into "Soft Reserved" ranges one of
the immediate first questions is "where is my special memory, and how do
access it". Add some documentation to explain the default behaviour of
"Soft Reserved".
Link: https://lore.kernel.org/r/163364399303.201290.6835215953983673447.stgit@dwillia2-desk3.amr.corp.intel.com
Reported-by: John Groves <john@jagalactic.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
.../daxctl/daxctl-reconfigure-device.txt | 127 ++++++++++++------
1 file changed, 88 insertions(+), 39 deletions(-)
diff --git a/Documentation/daxctl/daxctl-reconfigure-device.txt b/Documentation/daxctl/daxctl-reconfigure-device.txt
index f112b3c..132684c 100644
--- a/Documentation/daxctl/daxctl-reconfigure-device.txt
+++ b/Documentation/daxctl/daxctl-reconfigure-device.txt
@@ -12,6 +12,94 @@ SYNOPSIS
[verse]
'daxctl reconfigure-device' <dax0.0> [<dax1.0>...<daxY.Z>] [<options>]
+DESCRIPTION
+-----------
+
+Reconfigure the operational mode of a dax device. This can be used to convert
+a regular 'devdax' mode device to the 'system-ram' mode which arranges for the
+dax range to be hot-plugged into the system as regular memory.
+
+NOTE: This is a destructive operation. Any data on the dax device *will* be
+lost.
+
+NOTE: Device reconfiguration depends on the dax-bus device model. See
+linkdaxctl:daxctl-migrate-device-model[1] for more information. If dax-class is
+in use (via the dax_pmem_compat driver), the reconfiguration will fail with an
+error such as the following:
+----
+# daxctl reconfigure-device --mode=system-ram --region=0 all
+libdaxctl: daxctl_dev_disable: dax3.0: error: device model is dax-class
+dax3.0: disable failed: Operation not supported
+error reconfiguring devices: Operation not supported
+reconfigured 0 devices
+----
+
+'daxctl-reconfigure-device' nominally expects that it will online new memory
+blocks as 'movable', so that kernel data doesn't make it into this memory.
+However, there are other potential agents that may be configured to
+automatically online new hot-plugged memory as it appears. Most notably,
+these are the '/sys/devices/system/memory/auto_online_blocks' configuration,
+or system udev rules. If such an agent races to online memory sections, daxctl
+checks if the blocks were onlined as 'movable' memory. If this was not the
+case, and the memory blocks are found to be in a different zone, then a
+warning is displayed. If it is desired that a different agent control the
+onlining of memory blocks, and the associated memory zone, then it is
+recommended to use the --no-online option described below. This will abridge
+the device reconfiguration operation to just hotplugging the memory, and
+refrain from then onlining it.
+
+In case daxctl detects that there is a kernel policy to auto-online blocks
+(via /sys/devices/system/memory/auto_online_blocks), then reconfiguring to
+system-ram will result in a failure. This can be overridden with '--force'.
+
+
+THEORY OF OPERATION
+-------------------
+The kernel device-dax subsystem surfaces character devices
+that provide DAX-access (direct mappings sans page-cache buffering) to a
+given memory region. The devices are named /dev/daxX.Y where X is a
+region-id and Y is an instance-id within that region. There are 2
+mechanisms that trigger device-dax instances to appear:
+
+1. Persistent Memory (PMEM) namespace configured in "devdax" mode. See
+"ndctl create-namspace --help" and
+https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/dax/Kconfig[CONFIG_DEV_DAX_PMEM].
+In this case the device-dax instance is statically sized to its host
+memory region which is bounded to the physical address range of the host
+namespace.
+
+2. Soft Reserved memory enumerated by platform firmware. On EFI systems
+this is communicated via the so called EFI_MEMORY_SP "Special Purpose"
+attribute. See
+https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/dax/Kconfig[CONFIG_DEV_DAX_HMEM].
+In this case the device-dax instance(s) associated with the given memory
+region can be resized and divided into multiple devices.
+
+In the Soft Reservation case the expectation for EFI + ACPI based
+platforms is that in addition to the EFI_MEMORY_SP attribute the
+firmware also creates distinct ACPI proximity domains for any address
+range that has different performance characteristics than default
+"System RAM". So, the SRAT will define the proximity domain, the SLIT
+communicates relative distance to other proximity domains, and the HMAT
+is populated with nominal read/write latency and read/write bandwidth
+data. That HMAT data is emitted to the kernel log on bootup, and also
+exported to sysfs. See
+https://www.kernel.org/doc/html/latest/admin-guide/mm/numaperf.html[NUMAPERF],
+for the runtime representation of CPU to Memory node performance
+details.
+
+Outside of the NUMA performance details linked above the other method to
+detect the presence of "Soft Reserved" memory is to dump /proc/iomem and
+look for "Soft Reserved" ranges. If the kernel was not built with
+CONFIG_EFI_SOFTRESERVE, predates the introduction of
+CONFIG_EFI_SOFTRESERVE (v5.5), or was booted with the efi=nosoftreserve
+command line then device-dax will not attach and the expectation is that
+the memory shows up as a memory-only NUMA node. Otherwise the memory
+shows up as a device-dax instance and DAXCTL(1) can be used to
+optionally partition it and assign the memory back to the kernel as
+"System RAM", or the device can be mapped directly as the back end of a
+userspace memory allocator like https://pmem.io/vmem/libvmem/[LIBVMEM].
+
EXAMPLES
--------
@@ -83,45 +171,6 @@ reconfigured 1 device
reconfigured 1 device
----
-DESCRIPTION
------------
-
-Reconfigure the operational mode of a dax device. This can be used to convert
-a regular 'devdax' mode device to the 'system-ram' mode which arranges for the
-dax range to be hot-plugged into the system as regular memory.
-
-NOTE: This is a destructive operation. Any data on the dax device *will* be
-lost.
-
-NOTE: Device reconfiguration depends on the dax-bus device model. See
-linkdaxctl:daxctl-migrate-device-model[1] for more information. If dax-class is
-in use (via the dax_pmem_compat driver), the reconfiguration will fail with an
-error such as the following:
-----
-# daxctl reconfigure-device --mode=system-ram --region=0 all
-libdaxctl: daxctl_dev_disable: dax3.0: error: device model is dax-class
-dax3.0: disable failed: Operation not supported
-error reconfiguring devices: Operation not supported
-reconfigured 0 devices
-----
-
-'daxctl-reconfigure-device' nominally expects that it will online new memory
-blocks as 'movable', so that kernel data doesn't make it into this memory.
-However, there are other potential agents that may be configured to
-automatically online new hot-plugged memory as it appears. Most notably,
-these are the '/sys/devices/system/memory/auto_online_blocks' configuration,
-or system udev rules. If such an agent races to online memory sections, daxctl
-checks if the blocks were onlined as 'movable' memory. If this was not the
-case, and the memory blocks are found to be in a different zone, then a
-warning is displayed. If it is desired that a different agent control the
-onlining of memory blocks, and the associated memory zone, then it is
-recommended to use the --no-online option described below. This will abridge
-the device reconfiguration operation to just hotplugging the memory, and
-refrain from then onlining it.
-
-In case daxctl detects that there is a kernel policy to auto-online blocks
-(via /sys/devices/system/memory/auto_online_blocks), then reconfiguring to
-system-ram will result in a failure. This can be overridden with '--force'.
OPTIONS
-------
--
2.27.0

View File

@ -0,0 +1,46 @@
From c55b18181281b2fffadb9e0e8955d74b8b719349 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Fri, 17 Dec 2021 19:25:11 -0700
Subject: [PATCH 061/217] libcxl: fix potential NULL dereference in
cxl_memdev_nvdimm_bridge_active()
Static analysis points out that the function above has a check for
'if (!bridge)', implying that bridge maybe NULL, but it is dereferenced
before the check, which could result in a NULL dereference.
Fix this by moving any accesses to the bridge structure after the NULL
check.
Link: https://lore.kernel.org/r/20211218022511.314928-1-vishal.l.verma@intel.com
Cc: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
cxl/lib/libcxl.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index f0664be..3390eb9 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -420,12 +420,15 @@ CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev)
{
struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
struct cxl_nvdimm_bridge *bridge = memdev->bridge;
- char *path = bridge->dev_buf;
- int len = bridge->buf_len;
+ char *path;
+ int len;
if (!bridge)
return 0;
+ path = bridge->dev_buf;
+ len = bridge->buf_len;
+
if (snprintf(path, len, "%s/driver", bridge->dev_path) >= len) {
err(ctx, "%s: nvdimm bridge buffer too small!\n",
cxl_memdev_get_devname(memdev));
--
2.27.0

View File

@ -0,0 +1,142 @@
From 25062cf34c70012f5d42ce1fef7e2dc129807c10 Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Fri, 17 Dec 2021 21:14:37 -0700
Subject: [PATCH 064/217] ndctl: release v72
This release incorporates functionality up to the 5.16 kernel.
Highlights include a new utility and library for interfacing with the
'CXL' drivers and devices, a policy based configuration mechanism for
ndctl and daxctl, fixes, test updates, and general additions for the
PAPR family of NVDIMMs, more seed device accounting fixes, misc unit
test and documentation updates, and fixes to NVDIMM bus scrubbing.
Commands:
cxl-cli: new utility providing list, {read,write,zero}-label commands
daxctl-reconfigure-device: new --check-config option
ndctl-monitor: add support for a new unified config file format
ndctl-*-namespace: seed namespace accounting fixes
Tests:
Fix device-dax mremap() test
Exercise soft_offline_page() corner cases
Fix btt expect table compile warning
monitor.sh: add checking the presence of jq command ahead of time
APIs:
ndctl_bus_nfit_translate_spa
ndctl_dimm_sizeof_namespace_index
ndctl_get_config_path
ndctl_set_config_path
daxctl_dev_has_online_memory
daxctl_dev_will_auto_online_memory
daxctl_get_config_path
daxctl_set_config_path
cxl_cmd_get_devname
cxl_cmd_get_mbox_status
cxl_cmd_get_out_size
cxl_cmd_health_info_get_dirty_shutdowns
cxl_cmd_health_info_get_ext_corrected_persistent_normal
cxl_cmd_health_info_get_ext_corrected_persistent_warning
cxl_cmd_health_info_get_ext_corrected_volatile_normal
cxl_cmd_health_info_get_ext_corrected_volatile_warning
cxl_cmd_health_info_get_ext_life_used_critical
cxl_cmd_health_info_get_ext_life_used_normal
cxl_cmd_health_info_get_ext_life_used_warning
cxl_cmd_health_info_get_ext_temperature_critical
cxl_cmd_health_info_get_ext_temperature_normal
cxl_cmd_health_info_get_ext_temperature_warning
cxl_cmd_health_info_get_hw_replacement_needed
cxl_cmd_health_info_get_life_used
cxl_cmd_health_info_get_maintenance_needed
cxl_cmd_health_info_get_media_data_loss_imminent
cxl_cmd_health_info_get_media_data_lost
cxl_cmd_health_info_get_media_normal
cxl_cmd_health_info_get_media_not_ready
cxl_cmd_health_info_get_media_persistence_loss_imminent
cxl_cmd_health_info_get_media_persistence_lost
cxl_cmd_health_info_get_media_powerloss_data_loss
cxl_cmd_health_info_get_media_powerloss_persistence_loss
cxl_cmd_health_info_get_media_shutdown_data_loss
cxl_cmd_health_info_get_media_shutdown_persistence_loss
cxl_cmd_health_info_get_performance_degraded
cxl_cmd_health_info_get_pmem_errors
cxl_cmd_health_info_get_temperature
cxl_cmd_health_info_get_volatile_errors
cxl_cmd_identify_get_fw_rev
cxl_cmd_identify_get_label_size
cxl_cmd_identify_get_partition_align
cxl_cmd_new_get_health_info
cxl_cmd_new_identify
cxl_cmd_new_raw
cxl_cmd_new_read_label
cxl_cmd_new_write_label
cxl_cmd_read_label_get_payload
cxl_cmd_ref
cxl_cmd_set_input_payload
cxl_cmd_set_output_payload
cxl_cmd_submit
cxl_cmd_unref
cxl_get_log_priority
cxl_get_private_data
cxl_get_userdata
cxl_memdev_get_ctx
cxl_memdev_get_devname
cxl_memdev_get_firmware_verison
cxl_memdev_get_first
cxl_memdev_get_id
cxl_memdev_get_label_size
cxl_memdev_get_major
cxl_memdev_get_minor
cxl_memdev_get_next
cxl_memdev_get_pmem_size
cxl_memdev_get_ram_size
cxl_memdev_nvdimm_bridge_active
cxl_memdev_read_label
cxl_memdev_write_label
cxl_memdev_zero_label
cxl_new
cxl_ref
cxl_set_log_fn
cxl_set_log_priority
cxl_set_private_data
cxl_set_userdata
cxl_unref
---
Makefile.am.in | 8 ++++----
git-version | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff -up ndctl-71.1/Makefile.am.in.orig ndctl-71.1/Makefile.am.in
--- ndctl-71.1/Makefile.am.in.orig 2022-10-07 15:20:47.982353042 -0400
+++ ndctl-71.1/Makefile.am.in 2022-10-07 15:21:02.174401362 -0400
@@ -36,13 +36,13 @@ SED_PROCESS = \
-e 's,@includedir\@,$(includedir),g' \
< $< > $@ || rm $@
-LIBNDCTL_CURRENT=25
+LIBNDCTL_CURRENT=26
LIBNDCTL_REVISION=1
-LIBNDCTL_AGE=19
+LIBNDCTL_AGE=20
-LIBDAXCTL_CURRENT=6
+LIBDAXCTL_CURRENT=7
LIBDAXCTL_REVISION=0
-LIBDAXCTL_AGE=5
+LIBDAXCTL_AGE=6
LIBCXL_CURRENT=1
LIBCXL_REVISION=0
diff -up ndctl-71.1/git-version.orig ndctl-71.1/git-version
--- ndctl-71.1/git-version.orig 2022-10-07 15:21:02.175401365 -0400
+++ ndctl-71.1/git-version 2022-10-07 15:21:27.267486796 -0400
@@ -19,7 +19,7 @@ dirty() {
fi
}
-DEF_VER=71.1
+DEF_VER=72
LF='
'

View File

@ -0,0 +1,32 @@
From 20a714fe89a7941ef99898821719a46f04f7488b Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Tue, 4 Jan 2022 17:18:23 -0700
Subject: [PATCH 067/217] ndctl: add repology graphic to README.md
Add a graphic/badge from repology showing the packaging status of ndctl
with various distros.
Link: https://lore.kernel.org/r/20220105001823.299797-1-vishal.l.verma@intel.com
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
README.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/README.md b/README.md
index 89dfc87..4ab4523 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,9 @@
Utility library for managing the libnvdimm (non-volatile memory device)
sub-system in the Linux kernel
+<a href="https://repology.org/project/ndctl/versions">
+ <img src="https://repology.org/badge/vertical-allrepos/ndctl.svg" alt="Packaging status" align="right">
+</a>
Build
=====
--
2.27.0

View File

@ -0,0 +1,29 @@
From 3f2a2973b23fa86c810aab49eeb8ff5f97a02720 Mon Sep 17 00:00:00 2001
From: Yasunori Goto <y-goto@fujitsu.com>
Date: Wed, 3 Feb 2021 19:17:07 +0900
Subject: [PATCH 068/217] Documentation/ndctl: fix self-reference of ndctl
disable-namespace
The man manual of ndctl disable-namespace link to itself at See
Also section. It should be enable-namespace instead of it.
Signed-off-by: Yasunori Goto <y-goto@fujitsu.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Link: https://github.com/pmem/ndctl/pull/160
---
Documentation/ndctl/ndctl-disable-namespace.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Documentation/ndctl/ndctl-disable-namespace.txt b/Documentation/ndctl/ndctl-disable-namespace.txt
index 5d3a8be..187348f 100644
--- a/Documentation/ndctl/ndctl-disable-namespace.txt
+++ b/Documentation/ndctl/ndctl-disable-namespace.txt
@@ -22,4 +22,4 @@ include::../copyright.txt[]
SEE ALSO
--------
-linkndctl:ndctl-disable-namespace[1]
+linkndctl:ndctl-enable-namespace[1]
--
2.27.0

View File

@ -0,0 +1,97 @@
From 475cb041a97d3c7140efd1b0cda820fb22b69d11 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 5 Jan 2022 13:31:44 -0800
Subject: [PATCH 069/217] ndctl/docs: Clarify update-firwmware activation
'overflow' conditions
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.
Link: https://lore.kernel.org/r/164141830490.3990253.6263569501446070716.stgit@dwillia2-desk3.amr.corp.intel.com
Tested-by: Alison Schofield <alison.schofield@intel.com>
Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
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 1080d62..6166457 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::
--
2.27.0

View File

@ -0,0 +1,171 @@
From e423b467e10e3405e6e09260b7669e7022b5f5f7 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 5 Jan 2022 13:31:50 -0800
Subject: [PATCH 070/217] ndctl/test: Prepare for BLK-aperture support removal
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.
Link: https://lore.kernel.org/r/164141830999.3990253.5021445352398348657.stgit@dwillia2-desk3.amr.corp.intel.com
Tested-by: Alison Schofield <alison.schofield@intel.com>
Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
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 2b03aa9..93e1dae 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 d9b50f4..c0e4b4c 100644
--- a/test/libndctl.c
+++ b/test/libndctl.c
@@ -2587,17 +2587,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)
@@ -2608,7 +2632,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)
@@ -2625,13 +2648,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;
}
/*
@@ -2649,14 +2669,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);
@@ -2671,6 +2691,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
--
2.27.0

View File

@ -0,0 +1,428 @@
From 6538529be5738f06543a0d7178f97e0b0e6b63c2 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 5 Jan 2022 13:31:55 -0800
Subject: [PATCH 071/217] ndctl/test: Move 'reset()' to function in 'common'
When BLK mode is removed, tests that expect the nfit_test region to allow
pmem namespace creation will need to 'init' rather than 'zero' labels. In
preparation, take the time opportunity to move reset() to a common
function. So that 'ndctl zero-labels' can be replaced with 'ndctl
init-labels' in one central location.
Link: https://lore.kernel.org/r/164141831509.3990253.14783946910211635678.stgit@dwillia2-desk3.amr.corp.intel.com
Tested-by: Alison Schofield <alison.schofield@intel.com>
Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
test/blk-exhaust.sh | 4 +---
test/btt-check.sh | 7 -------
test/btt-errors.sh | 12 +++---------
test/btt-pad-compat.sh | 7 -------
test/clear.sh | 4 +---
test/common | 15 +++++++++++++++
test/create.sh | 4 +---
test/daxctl-create.sh | 4 ++--
test/daxdev-errors.sh | 4 +---
test/firmware-update.sh | 8 +++-----
test/inject-error.sh | 7 -------
test/max_available_extent_ns.sh | 9 +--------
test/monitor.sh | 11 ++---------
test/multi-dax.sh | 4 +---
test/pfn-meta-errors.sh | 4 +---
test/pmem-errors.sh | 4 +---
test/rescan-partitions.sh | 7 -------
test/sector-mode.sh | 9 ++-------
test/track-uuid.sh | 4 +---
19 files changed, 36 insertions(+), 92 deletions(-)
diff --git a/test/blk-exhaust.sh b/test/blk-exhaust.sh
index 09c4aae..b6d3808 100755
--- a/test/blk-exhaust.sh
+++ b/test/blk-exhaust.sh
@@ -14,9 +14,7 @@ trap 'err $LINENO' ERR
# setup (reset nfit_test dimms)
modprobe nfit_test
-$NDCTL disable-region -b $NFIT_TEST_BUS0 all
-$NDCTL zero-labels -b $NFIT_TEST_BUS0 all
-$NDCTL enable-region -b $NFIT_TEST_BUS0 all
+reset
# if the kernel accounting is correct we should be able to create two
# pmem and two blk namespaces on nfit_test.0
diff --git a/test/btt-check.sh b/test/btt-check.sh
index 8e0b489..65b5c58 100755
--- a/test/btt-check.sh
+++ b/test/btt-check.sh
@@ -39,13 +39,6 @@ create()
[ $size -gt 0 ] || err "$LINENO"
}
-reset()
-{
- $NDCTL disable-region -b $NFIT_TEST_BUS0 all
- $NDCTL zero-labels -b $NFIT_TEST_BUS0 all
- $NDCTL enable-region -b $NFIT_TEST_BUS0 all
-}
-
# re-enable the BTT namespace, and do IO to it in an attempt to
# verify it still comes up ok, and functions as expected
post_repair_test()
diff --git a/test/btt-errors.sh b/test/btt-errors.sh
index 4e59f57..5a20d26 100755
--- a/test/btt-errors.sh
+++ b/test/btt-errors.sh
@@ -45,9 +45,7 @@ trap 'err $LINENO cleanup' ERR
# setup (reset nfit_test dimms)
modprobe nfit_test
-$NDCTL disable-region -b $NFIT_TEST_BUS0 all
-$NDCTL zero-labels -b $NFIT_TEST_BUS0 all
-$NDCTL enable-region -b $NFIT_TEST_BUS0 all
+reset
rc=1
@@ -126,9 +124,7 @@ dd if=$MNT/$FILE of=/dev/null iflag=direct bs=4096 count=1
# reset everything to get a clean log
if grep -q "$MNT" /proc/mounts; then umount $MNT; fi
-$NDCTL disable-region -b $NFIT_TEST_BUS0 all
-$NDCTL zero-labels -b $NFIT_TEST_BUS0 all
-$NDCTL enable-region -b $NFIT_TEST_BUS0 all
+reset
dev="x"
json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem -m sector)
eval "$(echo "$json" | json2var)"
@@ -148,9 +144,7 @@ force_raw 0
dd if=/dev/$blockdev of=/dev/null iflag=direct bs=4096 count=1 && err $LINENO || true
# done, exit
-$NDCTL disable-region -b $NFIT_TEST_BUS0 all
-$NDCTL zero-labels -b $NFIT_TEST_BUS0 all
-$NDCTL enable-region -b $NFIT_TEST_BUS0 all
+reset
cleanup
_cleanup
exit 0
diff --git a/test/btt-pad-compat.sh b/test/btt-pad-compat.sh
index bf1ea54..be538b7 100755
--- a/test/btt-pad-compat.sh
+++ b/test/btt-pad-compat.sh
@@ -37,13 +37,6 @@ create()
fi
}
-reset()
-{
- $NDCTL disable-region -b $NFIT_TEST_BUS0 all
- $NDCTL zero-labels -b $NFIT_TEST_BUS0 all
- $NDCTL enable-region -b $NFIT_TEST_BUS0 all
-}
-
verify_idx()
{
idx0="$1"
diff --git a/test/clear.sh b/test/clear.sh
index fb9d52c..c4d02d5 100755
--- a/test/clear.sh
+++ b/test/clear.sh
@@ -14,9 +14,7 @@ trap 'err $LINENO' ERR
# setup (reset nfit_test dimms)
modprobe nfit_test
-$NDCTL disable-region -b $NFIT_TEST_BUS0 all
-$NDCTL zero-labels -b $NFIT_TEST_BUS0 all
-$NDCTL enable-region -b $NFIT_TEST_BUS0 all
+reset
rc=1
diff --git a/test/common b/test/common
index 6bcefca..3c54d63 100644
--- a/test/common
+++ b/test/common
@@ -46,6 +46,21 @@ err()
exit $rc
}
+reset()
+{
+ $NDCTL disable-region -b $NFIT_TEST_BUS0 all
+ $NDCTL zero-labels -b $NFIT_TEST_BUS0 all
+ $NDCTL enable-region -b $NFIT_TEST_BUS0 all
+}
+
+reset1()
+{
+ $NDCTL disable-region -b $NFIT_TEST_BUS1 all
+ $NDCTL zero-labels -b $NFIT_TEST_BUS1 all
+ $NDCTL enable-region -b $NFIT_TEST_BUS1 all
+}
+
+
# check_min_kver
# $1: Supported kernel version. format: X.Y
#
diff --git a/test/create.sh b/test/create.sh
index b0fd99f..e9baaa0 100755
--- a/test/create.sh
+++ b/test/create.sh
@@ -15,9 +15,7 @@ trap 'err $LINENO' ERR
# setup (reset nfit_test dimms)
modprobe nfit_test
-$NDCTL disable-region -b $NFIT_TEST_BUS0 all
-$NDCTL zero-labels -b $NFIT_TEST_BUS0 all
-$NDCTL enable-region -b $NFIT_TEST_BUS0 all
+reset
rc=1
diff --git a/test/daxctl-create.sh b/test/daxctl-create.sh
index 198779a..d319a39 100755
--- a/test/daxctl-create.sh
+++ b/test/daxctl-create.sh
@@ -10,7 +10,7 @@ trap 'cleanup $LINENO' ERR
cleanup()
{
printf "Error at line %d\n" "$1"
- [[ $testdev ]] && reset
+ [[ $testdev ]] && reset_dax
exit $rc
}
@@ -70,7 +70,7 @@ reset_dev()
"$DAXCTL" enable-device "$testdev"
}
-reset()
+reset_dax()
{
test -n "$testdev"
diff --git a/test/daxdev-errors.sh b/test/daxdev-errors.sh
index 9547d78..e13453d 100755
--- a/test/daxdev-errors.sh
+++ b/test/daxdev-errors.sh
@@ -15,9 +15,7 @@ trap 'err $LINENO' ERR
# setup (reset nfit_test dimms)
modprobe nfit_test
-$NDCTL disable-region -b $NFIT_TEST_BUS0 all
-$NDCTL zero-labels -b $NFIT_TEST_BUS0 all
-$NDCTL enable-region -b $NFIT_TEST_BUS0 all
+reset
rc=1
diff --git a/test/firmware-update.sh b/test/firmware-update.sh
index 8cc9c41..93ce166 100755
--- a/test/firmware-update.sh
+++ b/test/firmware-update.sh
@@ -10,11 +10,9 @@ image="update-fw.img"
trap 'err $LINENO' ERR
-reset()
+fwupd_reset()
{
- $NDCTL disable-region -b $NFIT_TEST_BUS0 all
- $NDCTL zero-labels -b $NFIT_TEST_BUS0 all
- $NDCTL enable-region -b $NFIT_TEST_BUS0 all
+ reset
if [ -f $image ]; then
rm -f $image
fi
@@ -73,7 +71,7 @@ do_tests()
check_min_kver "4.16" || do_skip "may lack firmware update test handling"
modprobe nfit_test
-reset
+fwupd_reset
detect
rc=1
do_tests
diff --git a/test/inject-error.sh b/test/inject-error.sh
index 7d0b826..fd823b6 100755
--- a/test/inject-error.sh
+++ b/test/inject-error.sh
@@ -37,13 +37,6 @@ create()
[ $size -gt 0 ] || err "$LINENO"
}
-reset()
-{
- $NDCTL disable-region -b $NFIT_TEST_BUS0 all
- $NDCTL zero-labels -b $NFIT_TEST_BUS0 all
- $NDCTL enable-region -b $NFIT_TEST_BUS0 all
-}
-
check_status()
{
local sector="$1"
diff --git a/test/max_available_extent_ns.sh b/test/max_available_extent_ns.sh
index 343f3c9..47a921f 100755
--- a/test/max_available_extent_ns.sh
+++ b/test/max_available_extent_ns.sh
@@ -11,13 +11,6 @@ trap 'err $LINENO' ERR
check_min_kver "4.19" || do_skip "kernel $KVER may not support max_available_size"
check_prereq "jq"
-init()
-{
- $NDCTL disable-region -b $NFIT_TEST_BUS0 all
- $NDCTL zero-labels -b $NFIT_TEST_BUS0 all
- $NDCTL enable-region -b $NFIT_TEST_BUS0 all
-}
-
do_test()
{
region=$($NDCTL list -b $NFIT_TEST_BUS0 -R -t pmem | jq -r 'sort_by(-.size) | .[].dev' | head -1)
@@ -40,7 +33,7 @@ do_test()
modprobe nfit_test
rc=1
-init
+reset
do_test
_cleanup
exit 0
diff --git a/test/monitor.sh b/test/monitor.sh
index c015c11..6aa4196 100755
--- a/test/monitor.sh
+++ b/test/monitor.sh
@@ -19,13 +19,6 @@ trap 'err $LINENO' ERR
check_min_kver "4.15" || do_skip "kernel $KVER may not support monitor service"
-init()
-{
- $NDCTL disable-region -b $NFIT_TEST_BUS0 all
- $NDCTL zero-labels -b $NFIT_TEST_BUS0 all
- $NDCTL enable-region -b $NFIT_TEST_BUS0 all
-}
-
start_monitor()
{
logfile=$(mktemp)
@@ -112,7 +105,7 @@ test_filter_region()
test_filter_namespace()
{
- init
+ reset
monitor_namespace=$($NDCTL create-namespace -b $smart_supported_bus | jq -r .dev)
monitor_dimms=$(get_monitor_dimm "-n $monitor_namespace")
start_monitor "-n $monitor_namespace"
@@ -170,7 +163,7 @@ do_tests()
modprobe nfit_test
rc=1
-init
+reset
set_smart_supported_bus
do_tests
_cleanup
diff --git a/test/multi-dax.sh b/test/multi-dax.sh
index b343a38..04070ad 100755
--- a/test/multi-dax.sh
+++ b/test/multi-dax.sh
@@ -17,9 +17,7 @@ ALIGN_SIZE=`getconf PAGESIZE`
# setup (reset nfit_test dimms)
modprobe nfit_test
-$NDCTL disable-region -b $NFIT_TEST_BUS0 all
-$NDCTL zero-labels -b $NFIT_TEST_BUS0 all
-$NDCTL enable-region -b $NFIT_TEST_BUS0 all
+reset
rc=1
query=". | sort_by(.available_size) | reverse | .[0].dev"
diff --git a/test/pfn-meta-errors.sh b/test/pfn-meta-errors.sh
index 0ade2e5..6314897 100755
--- a/test/pfn-meta-errors.sh
+++ b/test/pfn-meta-errors.sh
@@ -29,9 +29,7 @@ trap 'err $LINENO' ERR
# setup (reset nfit_test dimms)
modprobe nfit_test
-$NDCTL disable-region -b $NFIT_TEST_BUS0 all
-$NDCTL zero-labels -b $NFIT_TEST_BUS0 all
-$NDCTL enable-region -b $NFIT_TEST_BUS0 all
+reset
rc=1
diff --git a/test/pmem-errors.sh b/test/pmem-errors.sh
index 4225c3b..2065780 100755
--- a/test/pmem-errors.sh
+++ b/test/pmem-errors.sh
@@ -28,9 +28,7 @@ trap 'err $LINENO cleanup' ERR
# setup (reset nfit_test dimms)
modprobe nfit_test
-$NDCTL disable-region -b $NFIT_TEST_BUS0 all
-$NDCTL zero-labels -b $NFIT_TEST_BUS0 all
-$NDCTL enable-region -b $NFIT_TEST_BUS0 all
+reset
rc=1
diff --git a/test/rescan-partitions.sh b/test/rescan-partitions.sh
index 1686de3..51bbd73 100755
--- a/test/rescan-partitions.sh
+++ b/test/rescan-partitions.sh
@@ -25,13 +25,6 @@ check_min_kver "4.16" || do_skip "may not contain fixes for partition rescanning
check_prereq "parted"
check_prereq "blockdev"
-reset()
-{
- $NDCTL disable-region -b $NFIT_TEST_BUS0 all
- $NDCTL zero-labels -b $NFIT_TEST_BUS0 all
- $NDCTL enable-region -b $NFIT_TEST_BUS0 all
-}
-
test_mode()
{
local mode="$1"
diff --git a/test/sector-mode.sh b/test/sector-mode.sh
index 7a2faea..439ef33 100755
--- a/test/sector-mode.sh
+++ b/test/sector-mode.sh
@@ -15,13 +15,8 @@ ALIGN_SIZE=`getconf PAGESIZE`
# setup (reset nfit_test dimms)
modprobe nfit_test
-$NDCTL disable-region -b $NFIT_TEST_BUS0 all
-$NDCTL zero-labels -b $NFIT_TEST_BUS0 all
-$NDCTL enable-region -b $NFIT_TEST_BUS0 all
-
-$NDCTL disable-region -b $NFIT_TEST_BUS1 all
-$NDCTL zero-labels -b $NFIT_TEST_BUS1 all
-$NDCTL enable-region -b $NFIT_TEST_BUS1 all
+reset
+reset1
rc=1
query=". | sort_by(.size) | reverse | .[0].dev"
diff --git a/test/track-uuid.sh b/test/track-uuid.sh
index be3cf9c..3bacd2c 100755
--- a/test/track-uuid.sh
+++ b/test/track-uuid.sh
@@ -12,9 +12,7 @@ trap 'err $LINENO' ERR
# setup (reset nfit_test dimms)
modprobe nfit_test
-$NDCTL disable-region -b $NFIT_TEST_BUS0 all
-$NDCTL zero-labels -b $NFIT_TEST_BUS0 all
-$NDCTL enable-region -b $NFIT_TEST_BUS0 all
+reset
rc=1
--
2.27.0

View File

@ -0,0 +1,104 @@
From fe37c85f1ffb0b2d04ef60e8ece6a9a44a145cc5 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 5 Jan 2022 13:32:00 -0800
Subject: [PATCH 072/217] ndctl/test: Initialize the label area by default
The removal of BLK-mode support causes nfit_test regions to not be
'aliased' by default, which means that the only way to enable labels is to
initialize the namespace label index block. In support of that the common
'reset()' helper is updated to initialize v1.1 labels instead of zero them.
Additionally, it highlighted that some btt tests have silent assumptions of
v1.1 vs v1.2 label support. Add a 'resetV()' alternative to the common
'reset()' function that initializes the label area to v1.2.
Link: https://lore.kernel.org/r/164141832017.3990253.10383328274835531066.stgit@dwillia2-desk3.amr.corp.intel.com
Tested-by: Alison Schofield <alison.schofield@intel.com>
Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
test/btt-errors.sh | 4 ++--
test/btt-pad-compat.sh | 2 +-
test/common | 11 +++++++++--
test/label-compat.sh | 2 +-
4 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/test/btt-errors.sh b/test/btt-errors.sh
index 5a20d26..6e69178 100755
--- a/test/btt-errors.sh
+++ b/test/btt-errors.sh
@@ -45,7 +45,7 @@ trap 'err $LINENO cleanup' ERR
# setup (reset nfit_test dimms)
modprobe nfit_test
-reset
+resetV
rc=1
@@ -124,7 +124,7 @@ dd if=$MNT/$FILE of=/dev/null iflag=direct bs=4096 count=1
# reset everything to get a clean log
if grep -q "$MNT" /proc/mounts; then umount $MNT; fi
-reset
+resetV
dev="x"
json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem -m sector)
eval "$(echo "$json" | json2var)"
diff --git a/test/btt-pad-compat.sh b/test/btt-pad-compat.sh
index be538b7..005316a 100755
--- a/test/btt-pad-compat.sh
+++ b/test/btt-pad-compat.sh
@@ -148,7 +148,7 @@ do_tests()
verify_idx 0 1
# do the same with an old format namespace
- reset
+ resetV
create_oldfmt_ns
verify_idx 0 2
diff --git a/test/common b/test/common
index 3c54d63..b6d4712 100644
--- a/test/common
+++ b/test/common
@@ -49,14 +49,21 @@ err()
reset()
{
$NDCTL disable-region -b $NFIT_TEST_BUS0 all
- $NDCTL zero-labels -b $NFIT_TEST_BUS0 all
+ $NDCTL init-labels -f -b $NFIT_TEST_BUS0 all
+ $NDCTL enable-region -b $NFIT_TEST_BUS0 all
+}
+
+resetV()
+{
+ $NDCTL disable-region -b $NFIT_TEST_BUS0 all
+ $NDCTL init-labels -f -V 1.2 -b $NFIT_TEST_BUS0 all
$NDCTL enable-region -b $NFIT_TEST_BUS0 all
}
reset1()
{
$NDCTL disable-region -b $NFIT_TEST_BUS1 all
- $NDCTL zero-labels -b $NFIT_TEST_BUS1 all
+ $NDCTL init-labels -f -b $NFIT_TEST_BUS1 all
$NDCTL enable-region -b $NFIT_TEST_BUS1 all
}
diff --git a/test/label-compat.sh b/test/label-compat.sh
index 8ab2858..7ae4d5e 100755
--- a/test/label-compat.sh
+++ b/test/label-compat.sh
@@ -17,7 +17,7 @@ trap 'err $LINENO' ERR
# setup (reset nfit_test dimms)
modprobe nfit_test
$NDCTL disable-region -b $NFIT_TEST_BUS0 all
-$NDCTL zero-labels -b $NFIT_TEST_BUS0 all
+$NDCTL init-labels -f -b $NFIT_TEST_BUS0 all
# grab the largest pmem region on -b $NFIT_TEST_BUS0
query=". | sort_by(.available_size) | reverse | .[0].dev"
--
2.27.0

View File

@ -0,0 +1,43 @@
From 756a6598a0fa6cebdd0e98564af089ca6b463fb1 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 5 Jan 2022 13:32:05 -0800
Subject: [PATCH 073/217] ndctl/test: Skip BLK flags checks
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.
Link: https://lore.kernel.org/r/164141832529.3990253.16538298357542644310.stgit@dwillia2-desk3.amr.corp.intel.com
Tested-by: Alison Schofield <alison.schofield@intel.com>
Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
test/libndctl.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/libndctl.c b/test/libndctl.c
index c0e4b4c..1e97926 100644
--- a/test/libndctl.c
+++ b/test/libndctl.c
@@ -2535,7 +2535,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]) {
@@ -2543,7 +2543,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");
}
}
}
--
2.27.0

View File

@ -0,0 +1,41 @@
From b787320498508192f1e04ac38d39da4eb3ca26e9 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 5 Jan 2022 13:32:10 -0800
Subject: [PATCH 074/217] ndctl/test: Move sector-mode to a different region
Previously the largest region on the nfit_test.1 bus belonged to a BLK-mode
region. With the removal of BLK-mode support update the test to instead
find a suitable PMEM region to perform the checkout.
Link: https://lore.kernel.org/r/164141833068.3990253.15694496866707006837.stgit@dwillia2-desk3.amr.corp.intel.com
Tested-by: Alison Schofield <alison.schofield@intel.com>
Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
test/sector-mode.sh | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/sector-mode.sh b/test/sector-mode.sh
index 439ef33..f70b0f1 100755
--- a/test/sector-mode.sh
+++ b/test/sector-mode.sh
@@ -19,11 +19,11 @@ reset
reset1
rc=1
-query=". | sort_by(.size) | reverse | .[0].dev"
-NAMESPACE=$($NDCTL list -b $NFIT_TEST_BUS1 -N | jq -r "$query")
-REGION=$($NDCTL list -R --namespace=$NAMESPACE | jq -r "(.[]) | .dev")
+query=". | sort_by(.available_size) | reverse | .[0].dev"
+REGION=$($NDCTL list -R -b $NFIT_TEST_BUS1 | jq -r "$query")
echo 0 > /sys/bus/nd/devices/$REGION/read_only
-$NDCTL create-namespace --no-autolabel -e $NAMESPACE -m sector -f -l 4K
+echo $ALIGN_SIZE > /sys/bus/nd/devices/$REGION/align
+NAMESPACE=$($NDCTL create-namespace --no-autolabel -r $REGION -m sector -f -l 4K | jq -r ".dev")
$NDCTL create-namespace --no-autolabel -e $NAMESPACE -m dax -f -a $ALIGN_SIZE
$NDCTL create-namespace --no-autolabel -e $NAMESPACE -m sector -f -l 4K
--
2.27.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,78 @@
From 9bfb567715d1b45e6598e6b38bef531312c72db3 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 5 Jan 2022 13:32:21 -0800
Subject: [PATCH 076/217] ndctl/test: Fix support for missing dax_pmem_compat
module
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.
Link: https://lore.kernel.org/r/164141834155.3990253.5388773351209410262.stgit@dwillia2-desk3.amr.corp.intel.com
Fixes: b7991dbc22f3 ("ndctl/test: Relax dax_pmem_compat requirement")
Tested-by: Alison Schofield <alison.schofield@intel.com>
Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
test/core.c | 25 +++++++++++--------------
1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/test/core.c b/test/core.c
index dc1405d..5d1aa23 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))
--
2.27.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,104 @@
From d1b966de2b32f6152bc3b9c3f5d842ba12407a87 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 5 Jan 2022 13:32:32 -0800
Subject: [PATCH 078/217] Documentation: Drop attrs.adoc include
In preparation for switching build systems, drop the attrs.adoc include for
communicating variables to asciidoc. Simply add the necessary variable
values to the invocation of the command using the --attribute argument.
Link: https://lore.kernel.org/r/164141835217.3990253.17678912974035740752.stgit@dwillia2-desk3.amr.corp.intel.com
Tested-by: Alison Schofield <alison.schofield@intel.com>
Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
.gitignore | 1 -
Documentation/daxctl/Makefile.am | 17 +++++++----------
.../daxctl/daxctl-reconfigure-device.txt | 2 --
Documentation/ndctl/Makefile.am | 17 +++++++----------
Documentation/ndctl/intel-nvdimm-security.txt | 2 --
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-passphrase.txt | 2 --
10 files changed, 14 insertions(+), 35 deletions(-)
diff -up ndctl-71.1/.gitignore.orig ndctl-71.1/.gitignore
--- ndctl-71.1/.gitignore.orig 2022-10-07 15:58:15.663005697 -0400
+++ ndctl-71.1/.gitignore 2022-10-07 15:58:57.238147247 -0400
@@ -23,7 +23,6 @@ Documentation/daxctl/asciidoctor-extensi
Documentation/ndctl/asciidoctor-extensions.rb
Documentation/cxl/asciidoctor-extensions.rb
Documentation/cxl/lib/asciidoctor-extensions.rb
-Documentation/ndctl/attrs.adoc
.dirstamp
daxctl/config.h
daxctl/daxctl
diff -up ndctl-71.1/Documentation/ndctl/intel-nvdimm-security.txt.orig ndctl-71.1/Documentation/ndctl/intel-nvdimm-security.txt
--- ndctl-71.1/Documentation/ndctl/intel-nvdimm-security.txt.orig 2020-12-22 16:44:57.000000000 -0500
+++ ndctl-71.1/Documentation/ndctl/intel-nvdimm-security.txt 2022-10-07 15:59:06.192177733 -0400
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-include::attrs.adoc[]
-
THEORY OF OPERATION
-------------------
The Intel Device Specific Methods (DSM) specification v1.7 and v1.8 [1]
diff -up ndctl-71.1/Documentation/ndctl/ndctl-load-keys.txt.orig ndctl-71.1/Documentation/ndctl/ndctl-load-keys.txt
--- ndctl-71.1/Documentation/ndctl/ndctl-load-keys.txt.orig 2020-12-22 16:44:57.000000000 -0500
+++ ndctl-71.1/Documentation/ndctl/ndctl-load-keys.txt 2022-10-07 15:59:06.192177733 -0400
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-include::attrs.adoc[]
-
ndctl-load-keys(1)
==================
diff -up ndctl-71.1/Documentation/ndctl/ndctl-monitor.txt.orig ndctl-71.1/Documentation/ndctl/ndctl-monitor.txt
--- ndctl-71.1/Documentation/ndctl/ndctl-monitor.txt.orig 2020-12-22 16:44:57.000000000 -0500
+++ ndctl-71.1/Documentation/ndctl/ndctl-monitor.txt 2022-10-07 15:59:06.192177733 -0400
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-include::attrs.adoc[]
-
ndctl-monitor(1)
================
diff -up ndctl-71.1/Documentation/ndctl/ndctl-sanitize-dimm.txt.orig ndctl-71.1/Documentation/ndctl/ndctl-sanitize-dimm.txt
--- ndctl-71.1/Documentation/ndctl/ndctl-sanitize-dimm.txt.orig 2020-12-22 16:44:57.000000000 -0500
+++ ndctl-71.1/Documentation/ndctl/ndctl-sanitize-dimm.txt 2022-10-07 15:59:06.192177733 -0400
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-include::attrs.adoc[]
-
ndctl-sanitize-dimm(1)
======================
diff -up ndctl-71.1/Documentation/ndctl/ndctl-setup-passphrase.txt.orig ndctl-71.1/Documentation/ndctl/ndctl-setup-passphrase.txt
--- ndctl-71.1/Documentation/ndctl/ndctl-setup-passphrase.txt.orig 2020-12-22 16:44:57.000000000 -0500
+++ ndctl-71.1/Documentation/ndctl/ndctl-setup-passphrase.txt 2022-10-07 15:59:06.193177737 -0400
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-include::attrs.adoc[]
-
ndctl-setup-passphrase(1)
=========================
diff -up ndctl-71.1/Documentation/ndctl/ndctl-update-passphrase.txt.orig ndctl-71.1/Documentation/ndctl/ndctl-update-passphrase.txt
--- ndctl-71.1/Documentation/ndctl/ndctl-update-passphrase.txt.orig 2020-12-22 16:44:57.000000000 -0500
+++ ndctl-71.1/Documentation/ndctl/ndctl-update-passphrase.txt 2022-10-07 15:59:06.193177737 -0400
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-include::attrs.adoc[]
-
ndctl-update-passphrase(1)
==========================

View File

@ -0,0 +1,53 @@
From 3297995248081d31d282fc9a339894989ff94e23 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 5 Jan 2022 13:32:37 -0800
Subject: [PATCH 079/217] build: Drop unnecessary $tool/config.h includes
In preparation for support for meson as the build infrastructure remove
some explicit config.h includes that will be replaced by a unified config.h
at the top of the project.
Link: https://lore.kernel.org/r/164141835727.3990253.12971738434561351928.stgit@dwillia2-desk3.amr.corp.intel.com
Tested-by: Alison Schofield <alison.schofield@intel.com>
Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
daxctl/migrate.c | 1 -
ndctl/keys.c | 1 -
ndctl/monitor.c | 1 -
3 files changed, 3 deletions(-)
diff -up ndctl-71.1/daxctl/migrate.c.orig ndctl-71.1/daxctl/migrate.c
--- ndctl-71.1/daxctl/migrate.c.orig 2020-12-22 16:44:57.000000000 -0500
+++ ndctl-71.1/daxctl/migrate.c 2022-10-07 16:01:20.316634385 -0400
@@ -5,7 +5,6 @@
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
-#include <daxctl/config.h>
#include <daxctl/libdaxctl.h>
#include <util/parse-options.h>
#include <ccan/array_size/array_size.h>
diff -up ndctl-71.1/ndctl/keys.c.orig ndctl-71.1/ndctl/keys.c
--- ndctl-71.1/ndctl/keys.c.orig 2022-10-07 16:01:03.161575978 -0400
+++ ndctl-71.1/ndctl/keys.c 2022-10-07 16:01:20.317634389 -0400
@@ -13,7 +13,6 @@
#include <keyutils.h>
#include <syslog.h>
-#include <ndctl/config.h>
#include <ndctl/ndctl.h>
#include <ndctl/libndctl.h>
diff -up ndctl-71.1/ndctl/monitor.c.orig ndctl-71.1/ndctl/monitor.c
--- ndctl-71.1/ndctl/monitor.c.orig 2022-10-07 16:01:03.164575988 -0400
+++ ndctl-71.1/ndctl/monitor.c 2022-10-07 16:01:20.318634392 -0400
@@ -10,7 +10,6 @@
#include <util/util.h>
#include <util/parse-options.h>
#include <util/strbuf.h>
-#include <ndctl/config.h>
#include <ndctl/ndctl.h>
#include <ndctl/libndctl.h>
#include <sys/epoll.h>

View File

@ -0,0 +1,355 @@
From d12d5f82755db50277e50c8daa97be15107f924d Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 5 Jan 2022 13:32:42 -0800
Subject: [PATCH 080/217] test: Prepare out of line builds
In preparation for converting to meson prepare the unit tests to run out of
a build directory rather than out of the source directory. Introduce
TEST_PATH for the location of the test executables.
Link: https://lore.kernel.org/r/164141836235.3990253.5237538466465550643.stgit@dwillia2-desk3.amr.corp.intel.com
Tested-by: Alison Schofield <alison.schofield@intel.com>
Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
test/btt-errors.sh | 4 +---
test/common | 37 +++++++++++++++++++++----------------
test/dax-pmd.c | 11 +++++++++--
test/dax.sh | 6 +++---
test/daxdev-errors.sh | 4 ++--
test/device-dax-fio.sh | 2 +-
test/dm.sh | 4 ++--
test/inject-smart.sh | 2 +-
test/mmap.sh | 6 +++---
test/monitor.sh | 6 +++---
test/pmem-errors.sh | 8 +++-----
test/sub-section.sh | 4 ++--
test/track-uuid.sh | 2 +-
13 files changed, 52 insertions(+), 44 deletions(-)
diff --git a/test/btt-errors.sh b/test/btt-errors.sh
index 6e69178..18518d5 100755
--- a/test/btt-errors.sh
+++ b/test/btt-errors.sh
@@ -11,14 +11,12 @@ rc=77
cleanup()
{
- rm -f $FILE
- rm -f $MNT/$FILE
if grep -q "$MNT" /proc/mounts; then
umount $MNT
else
rc=77
fi
- rmdir $MNT
+ rm -rf $MNT
}
force_raw()
diff --git a/test/common b/test/common
index b6d4712..fb48795 100644
--- a/test/common
+++ b/test/common
@@ -4,27 +4,32 @@
# Global variables
# NDCTL
-#
-if [ -f "../ndctl/ndctl" ] && [ -x "../ndctl/ndctl" ]; then
- export NDCTL=../ndctl/ndctl
-elif [ -f "./ndctl/ndctl" ] && [ -x "./ndctl/ndctl" ]; then
- export NDCTL=./ndctl/ndctl
-else
- echo "Couldn't find an ndctl binary"
- exit 1
+if [ -z $NDCTL ]; then
+ if [ -f "../ndctl/ndctl" ] && [ -x "../ndctl/ndctl" ]; then
+ export NDCTL=../ndctl/ndctl
+ elif [ -f "./ndctl/ndctl" ] && [ -x "./ndctl/ndctl" ]; then
+ export NDCTL=./ndctl/ndctl
+ else
+ echo "Couldn't find an ndctl binary"
+ exit 1
+ fi
fi
# DAXCTL
-#
-if [ -f "../daxctl/daxctl" ] && [ -x "../daxctl/daxctl" ]; then
- export DAXCTL=../daxctl/daxctl
-elif [ -f "./daxctl/daxctl" ] && [ -x "./daxctl/daxctl" ]; then
- export DAXCTL=./daxctl/daxctl
-else
- echo "Couldn't find an daxctl binary"
- exit 1
+if [ -z $DAXCTL ]; then
+ if [ -f "../daxctl/daxctl" ] && [ -x "../daxctl/daxctl" ]; then
+ export DAXCTL=../daxctl/daxctl
+ elif [ -f "./daxctl/daxctl" ] && [ -x "./daxctl/daxctl" ]; then
+ export DAXCTL=./daxctl/daxctl
+ else
+ echo "Couldn't find an daxctl binary"
+ exit 1
+ fi
fi
+if [ -z $TEST_PATH ]; then
+ export TEST_PATH=.
+fi
# NFIT_TEST_BUS[01]
#
diff --git a/test/dax-pmd.c b/test/dax-pmd.c
index 7648e34..f840875 100644
--- a/test/dax-pmd.c
+++ b/test/dax-pmd.c
@@ -24,7 +24,8 @@
__func__, __LINE__, strerror(errno))
#define faili(i) fprintf(stderr, "%s: failed at: %d: %d (%s)\n", \
__func__, __LINE__, i, strerror(errno))
-#define TEST_FILE "test_dax_data"
+#define TEST_DIR "test_dax_mnt"
+#define TEST_FILE TEST_DIR "/test_dax_data"
#define REGION_MEM_SIZE 4096*4
#define REGION_PM_SIZE 4096*512
@@ -171,8 +172,14 @@ int test_dax_directio(int dax_fd, unsigned long align, void *dax_addr, off_t off
}
rc = -ENXIO;
+ rc = mkdir(TEST_DIR, 0600);
+ if (rc < 0 && errno != EEXIST) {
+ faili(i);
+ munmap(addr, 2 * align);
+ break;
+ }
fd2 = open(TEST_FILE, O_CREAT|O_TRUNC|O_DIRECT|O_RDWR,
- DEFFILEMODE);
+ 0600);
if (fd2 < 0) {
faili(i);
munmap(addr, 2*align);
diff --git a/test/dax.sh b/test/dax.sh
index bcdd4e9..bb9848b 100755
--- a/test/dax.sh
+++ b/test/dax.sh
@@ -15,13 +15,13 @@ cleanup() {
else
rc=77
fi
- rmdir $MNT
+ rm -rf $MNT
exit $rc
}
run_test() {
rc=0
- if ! trace-cmd record -e fs_dax:dax_pmd_fault_done ./dax-pmd $MNT/$FILE; then
+ if ! trace-cmd record -e fs_dax:dax_pmd_fault_done $TEST_PATH/dax-pmd $MNT/$FILE; then
rc=$?
if [ "$rc" -ne 77 ] && [ "$rc" -ne 0 ]; then
cleanup "$1"
@@ -104,7 +104,7 @@ set -e
mkdir -p $MNT
trap 'err $LINENO cleanup' ERR
-dev=$(./dax-dev)
+dev=$($TEST_PATH/dax-dev)
json=$($NDCTL list -N -n $dev)
eval $(json2var <<< "$json")
rc=1
diff --git a/test/daxdev-errors.sh b/test/daxdev-errors.sh
index e13453d..7f79718 100755
--- a/test/daxdev-errors.sh
+++ b/test/daxdev-errors.sh
@@ -62,8 +62,8 @@ read sector len < /sys/bus/nd/devices/$region/badblocks
echo "sector: $sector len: $len"
# run the daxdev-errors test
-test -x ./daxdev-errors
-./daxdev-errors $busdev $region
+test -x $TEST_PATH/daxdev-errors
+$TEST_PATH/daxdev-errors $busdev $region
# check badblocks, should be empty
if read sector len < /sys/bus/platform/devices/nfit_test.0/$busdev/$region/badblocks; then
diff --git a/test/device-dax-fio.sh b/test/device-dax-fio.sh
index f57a9d2..c43ac05 100755
--- a/test/device-dax-fio.sh
+++ b/test/device-dax-fio.sh
@@ -18,7 +18,7 @@ if ! fio --enghelp | grep -q "dev-dax"; then
exit 77
fi
-dev=$(./dax-dev)
+dev=$($TEST_PATH/dax-dev)
for align in 4k 2m 1g
do
json=$($NDCTL create-namespace -m devdax -a $align -f -e $dev)
diff --git a/test/dm.sh b/test/dm.sh
index 4656e5b..b780a65 100755
--- a/test/dm.sh
+++ b/test/dm.sh
@@ -8,7 +8,7 @@ SKIP=77
FAIL=1
SUCCESS=0
-. ./common
+. $(dirname $0)/common
MNT=test_dax_mnt
TEST_DM_PMEM=/dev/mapper/test_pmem
@@ -30,7 +30,7 @@ cleanup() {
if [ -L $TEST_DM_PMEM ]; then
dmsetup remove $TEST_DM_PMEM
fi
- rmdir $MNT
+ rm -rf $MNT
# opportunistic cleanup, not fatal if these fail
namespaces=$($NDCTL list -N | jq -r ".[] | select(.name==\"$NAME\") | .dev")
for i in $namespaces
diff --git a/test/inject-smart.sh b/test/inject-smart.sh
index 4ca83b8..8b91360 100755
--- a/test/inject-smart.sh
+++ b/test/inject-smart.sh
@@ -170,7 +170,7 @@ check_prereq "jq"
modprobe nfit_test
rc=1
-jlist=$(./list-smart-dimm -b $bus)
+jlist=$($TEST_PATH/list-smart-dimm -b $bus)
dimm="$(jq '.[]."dev"?, ."dev"?' <<< $jlist | sort | head -1 | xargs)"
test -n "$dimm"
diff --git a/test/mmap.sh b/test/mmap.sh
index 50a1d34..760257d 100755
--- a/test/mmap.sh
+++ b/test/mmap.sh
@@ -7,7 +7,7 @@
MNT=test_mmap_mnt
FILE=image
DEV=""
-TEST=./mmap
+TEST=$TEST_PATH/mmap
rc=77
cleanup() {
@@ -17,7 +17,7 @@ cleanup() {
else
rc=77
fi
- rmdir $MNT
+ rm -rf $MNT
exit $rc
}
@@ -49,7 +49,7 @@ set -e
mkdir -p $MNT
trap 'err $LINENO cleanup' ERR
-dev=$(./dax-dev)
+dev=$($TEST_PATH/dax-dev)
json=$($NDCTL list -N -n $dev)
eval $(json2var <<< "$json")
DEV="/dev/${blockdev}"
diff --git a/test/monitor.sh b/test/monitor.sh
index 6aa4196..e58c908 100755
--- a/test/monitor.sh
+++ b/test/monitor.sh
@@ -31,7 +31,7 @@ start_monitor()
set_smart_supported_bus()
{
smart_supported_bus=$NFIT_TEST_BUS0
- monitor_dimms=$(./list-smart-dimm -b $smart_supported_bus | jq -r .[0].dev)
+ monitor_dimms=$($TEST_PATH/list-smart-dimm -b $smart_supported_bus | jq -r .[0].dev)
if [ -z $monitor_dimms ]; then
smart_supported_bus=$NFIT_TEST_BUS1
fi
@@ -39,14 +39,14 @@ set_smart_supported_bus()
get_monitor_dimm()
{
- jlist=$(./list-smart-dimm -b $smart_supported_bus $1)
+ jlist=$($TEST_PATH/list-smart-dimm -b $smart_supported_bus $1)
monitor_dimms=$(jq '.[]."dev"?, ."dev"?' <<<$jlist | sort | uniq | xargs)
echo $monitor_dimms
}
call_notify()
{
- ./smart-notify $smart_supported_bus
+ $TEST_PATH/smart-notify $smart_supported_bus
sync; sleep 3
}
diff --git a/test/pmem-errors.sh b/test/pmem-errors.sh
index 2065780..9a59c25 100755
--- a/test/pmem-errors.sh
+++ b/test/pmem-errors.sh
@@ -10,14 +10,12 @@ rc=77
cleanup()
{
- rm -f $FILE
- rm -f $MNT/$FILE
if [ -n "$blockdev" ]; then
umount /dev/$blockdev
else
rc=77
fi
- rmdir $MNT
+ rm -rf $MNT
}
check_min_kver "4.7" || do_skip "may lack dax error handling"
@@ -82,8 +80,8 @@ echo $start_sect 8 > /sys/block/$blockdev/badblocks
dd if=$MNT/$FILE of=/dev/null iflag=direct bs=4096 count=1 && err $LINENO || true
# run the dax-errors test
-test -x ./dax-errors
-./dax-errors $MNT/$FILE
+test -x $TEST_PATH/dax-errors
+$TEST_PATH/dax-errors $MNT/$FILE
# TODO: disable this check till we have clear-on-write in the kernel
#if read sector len < /sys/block/$blockdev/badblocks; then
diff --git a/test/sub-section.sh b/test/sub-section.sh
index 92ae816..77b9633 100755
--- a/test/sub-section.sh
+++ b/test/sub-section.sh
@@ -8,7 +8,7 @@ SKIP=77
FAIL=1
SUCCESS=0
-. ./common
+. $(dirname $0)/common
check_min_kver "5.3" || do_skip "may lack align sub-section hotplug support"
@@ -30,7 +30,7 @@ cleanup() {
if mountpoint -q $MNT; then
umount $MNT
fi
- rmdir $MNT
+ rm -rf $MNT
# opportunistic cleanup, not fatal if these fail
namespaces=$($NDCTL list -N | jq -r ".[] | select(.name==\"$NAME\") | .dev")
for i in $namespaces
diff --git a/test/track-uuid.sh b/test/track-uuid.sh
index 3bacd2c..a967d0e 100755
--- a/test/track-uuid.sh
+++ b/test/track-uuid.sh
@@ -5,7 +5,7 @@
blockdev=""
rc=77
-. ./common
+. $(dirname $0)/common
set -e
trap 'err $LINENO' ERR
--
2.27.0

View File

@ -0,0 +1,28 @@
From 7912cb0d19b5d17321439d118d41e57236b5484b Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 5 Jan 2022 13:32:47 -0800
Subject: [PATCH 081/217] ndctl: Drop executable bit for bash-completion script
The rpm build process warns:
*** WARNING: ./usr/share/bash-completion/completions/ndctl is executable but has no shebang, removing executable bit
Clear the unnecessary executable bit since completion helpers are sourced,
not executed.
Link: https://lore.kernel.org/r/164141836772.3990253.4996882214531720931.stgit@dwillia2-desk3.amr.corp.intel.com
Tested-by: Alison Schofield <alison.schofield@intel.com>
Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
contrib/ndctl | 0
1 file changed, 0 insertions(+), 0 deletions(-)
mode change 100755 => 100644 contrib/ndctl
diff --git a/contrib/ndctl b/contrib/ndctl
old mode 100755
new mode 100644
--
2.27.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,223 @@
From 8b5b941093521dd18fcc99659b3e3b1b9e9456b7 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 5 Jan 2022 13:32:58 -0800
Subject: [PATCH 083/217] build: Add meson rpmbuild support
Beyond being a prerequisite for removing autotools support, this capability
served as validation that the meson conversion generated all the same files
as autotools and installed them to the same expected locations.
The procedure to use the rpmbuild.sh script is:
meson setup build
meson compile -C build rhel/ndctl.spec
./rpmbuild.sh build/rhel/ndctl.spec
Link: https://lore.kernel.org/r/164141837841.3990253.11379060834465142446.stgit@dwillia2-desk3.amr.corp.intel.com
Tested-by: Alison Schofield <alison.schofield@intel.com>
Tested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
.gitignore | 2 +-
Makefile.am | 2 ++
meson.build | 6 ++++++
ndctl.spec.in | 23 +++++++++++++++++++++++
rhel/meson.build | 23 +++++++++++++++++++++++
rpmbuild.sh | 5 ++++-
sles/meson.build | 36 ++++++++++++++++++++++++++++++++++++
7 files changed, 95 insertions(+), 2 deletions(-)
create mode 100644 rhel/meson.build
create mode 100644 sles/meson.build
diff -up ndctl-71.1/.gitignore.orig ndctl-71.1/.gitignore
--- ndctl-71.1/.gitignore.orig 2022-10-07 16:34:40.712445112 -0400
+++ ndctl-71.1/.gitignore 2022-10-07 16:34:52.832486377 -0400
@@ -35,7 +35,7 @@ daxctl/lib/libdaxctl.pc
ndctl/config.h
ndctl/lib/libndctl.pc
ndctl/ndctl
-rhel/
+rhel/ndctl.spec
sles/ndctl.spec
version.m4
*.swp
diff -up ndctl-71.1/Makefile.am.orig ndctl-71.1/Makefile.am
--- ndctl-71.1/Makefile.am.orig 2022-10-07 16:34:40.687445027 -0400
+++ ndctl-71.1/Makefile.am 2022-10-07 16:34:52.832486377 -0400
@@ -22,6 +22,7 @@ noinst_SCRIPTS = rhel/ndctl.spec sles/nd
CLEANFILES += $(noinst_SCRIPTS)
do_rhel_subst = sed -e 's,VERSION,$(VERSION),g' \
+ -e 's,MESON,0,g' \
-e 's,DAX_DNAME,daxctl-devel,g' \
-e 's,CXL_DNAME,cxl-devel,g' \
-e 's,DNAME,ndctl-devel,g' \
@@ -31,6 +32,7 @@ do_rhel_subst = sed -e 's,VERSION,$(VERS
-e 's,LNAME,ndctl-libs,g'
do_sles_subst = sed -e 's,VERSION,$(VERSION),g' \
+ -e 's,MESON,0,g' \
-e 's,DAX_DNAME,libdaxctl-devel,g' \
-e 's,CXL_DNAME,libcxl-devel,g' \
-e 's,DNAME,libndctl-devel,g' \
diff -up ndctl-71.1/meson.build.orig ndctl-71.1/meson.build
--- ndctl-71.1/meson.build.orig 2022-10-07 16:34:40.715445122 -0400
+++ ndctl-71.1/meson.build 2022-10-07 16:34:52.833486380 -0400
@@ -278,3 +278,9 @@ if get_option('docs').enabled()
endif
subdir('test')
subdir('contrib')
+
+# only support spec file generation from git builds
+if version_tag == ''
+ subdir('rhel')
+ subdir('sles')
+endif
diff -up ndctl-71.1/ndctl.spec.in.orig ndctl-71.1/ndctl.spec.in
--- ndctl-71.1/ndctl.spec.in.orig 2022-10-07 16:34:40.645444884 -0400
+++ ndctl-71.1/ndctl.spec.in 2022-10-07 16:34:52.833486380 -0400
@@ -6,14 +6,20 @@ License: GPLv2
Url: https://github.com/pmem/ndctl
Source0: https://github.com/pmem/%{name}/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
+%define with_meson MESON
Requires: LNAME%{?_isa} = %{version}-%{release}
Requires: DAX_LNAME%{?_isa} = %{version}-%{release}
Requires: CXL_LNAME%{?_isa} = %{version}-%{release}
BuildRequires: autoconf
%if 0%{?rhel} < 9
BuildRequires: asciidoc
+%if !%{with_meson}
%define asciidoc --disable-asciidoctor
+%endif
%else
+%if %{with_meson}
+%define asciidoctor -Dasciidoctor=enabled
+%endif
BuildRequires: rubygem-asciidoctor
%endif
BuildRequires: xmlto
@@ -28,6 +34,10 @@ BuildRequires: pkgconfig(bash-completion
BuildRequires: pkgconfig(systemd)
BuildRequires: keyutils-libs-devel
+%if %{with_meson}
+BuildRequires: meson
+%endif
+
%description
Utility library for managing the "libnvdimm" subsystem. The "libnvdimm"
subsystem defines a kernel device model and control message interface for
@@ -115,17 +125,30 @@ libcxl is a library for enumerating and
%setup -q ndctl-%{version}
%build
+%if %{with_meson}
+%meson %{?asciidoctor} -Dversion-tag=%{version}
+%meson_build
+%else
echo %{version} > version
./autogen.sh
%configure --disable-static --disable-silent-rules %{?asciidoc}
make %{?_smp_mflags}
+%endif
%install
+%if %{with_meson}
+%meson_install
+%else
%make_install
find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
+%endif
%check
+%if %{with_meson}
+%meson_test
+%else
make check
+%endif
%ldconfig_scriptlets -n LNAME
diff -up ndctl-71.1/rhel/meson.build.orig ndctl-71.1/rhel/meson.build
--- ndctl-71.1/rhel/meson.build.orig 2022-10-07 16:34:52.834486384 -0400
+++ ndctl-71.1/rhel/meson.build 2022-10-07 16:34:52.834486384 -0400
@@ -0,0 +1,23 @@
+rhel_spec1 = vcs_tag(
+ input : '../ndctl.spec.in',
+ output : 'ndctl.spec.in',
+ command: vcs_tagger,
+ replace_string : 'VERSION',
+)
+
+rhel_spec2 = custom_target('ndctl.spec',
+ command : [
+ 'sed', '-e', 's,MESON,1,g',
+ '-e', 's,DAX_DNAME,daxctl-devel,g',
+ '-e', 's,CXL_DNAME,cxl-devel,g',
+ '-e', 's,DNAME,ndctl-devel,g',
+ '-e', '/^%defattr.*/d',
+ '-e', 's,DAX_LNAME,daxctl-libs,g',
+ '-e', 's,CXL_LNAME,cxl-libs,g',
+ '-e', 's,LNAME,ndctl-libs,g',
+ '@INPUT@'
+ ],
+ input : rhel_spec1,
+ output : 'ndctl.spec',
+ capture : true,
+)
diff -up ndctl-71.1/rpmbuild.sh.orig ndctl-71.1/rpmbuild.sh
--- ndctl-71.1/rpmbuild.sh.orig 2020-12-22 16:44:57.000000000 -0500
+++ ndctl-71.1/rpmbuild.sh 2022-10-07 16:34:52.834486384 -0400
@@ -1,6 +1,9 @@
#!/bin/bash
+
+spec=${1:-$(dirname $0)/rhel/ndctl.spec)}
+
pushd $(dirname $0) >/dev/null
[ ! -d ~/rpmbuild/SOURCES ] && echo "rpmdev tree not found" && exit 1
./make-git-snapshot.sh
popd > /dev/null
-rpmbuild -ba $(dirname $0)/rhel/ndctl.spec
+rpmbuild --nocheck -ba $spec
diff -up ndctl-71.1/sles/meson.build.orig ndctl-71.1/sles/meson.build
--- ndctl-71.1/sles/meson.build.orig 2022-10-07 16:34:52.836486391 -0400
+++ ndctl-71.1/sles/meson.build 2022-10-07 16:34:52.835486387 -0400
@@ -0,0 +1,36 @@
+sles_spec1 = vcs_tag(
+ input : '../ndctl.spec.in',
+ output : 'ndctl.spec.sles.in',
+ command: vcs_tagger,
+ replace_string : 'VERSION',
+)
+
+header = files('header')
+
+sles_spec2 = custom_target('ndctl.spec.in',
+ command : [
+ 'cat', header, '@INPUT@',
+ ],
+ input : sles_spec1,
+ output : 'ndctl.spec.in',
+ capture : true,
+)
+
+sles_spec3 = custom_target('ndctl.spec',
+ command : [
+ 'sed', '-e', 's,MESON,1,g',
+ '-e', 's,DAX_DNAME,libdaxctl-devel,g',
+ '-e', 's,CXL_DNAME,libcxl-devel,g',
+ '-e', 's,DNAME,libndctl-devel,g',
+ '-e', 's,%license,%doc,g',
+ '-e', 's,\(^License:.*GPL\)v2,\1-2.0,g',
+ '-e', 's,DAX_LNAME,libdaxctl@0@,g'.format(LIBDAXCTL_CURRENT - LIBDAXCTL_AGE),
+ '-e', 's,CXL_LNAME,libcxl@0@,g'.format(LIBCXL_CURRENT - LIBCXL_AGE),
+ '-e', 's,LNAME,libndctl@0@,g'.format(LIBNDCTL_CURRENT - LIBNDCTL_AGE),
+ '@INPUT@'
+ ],
+
+ input : sles_spec2,
+ output : 'ndctl.spec',
+ capture : true,
+)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
From 3a8d6e4bc90e899f751b881dc949e79daeeb04bb Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Fri, 7 Jan 2022 11:31:06 -0800
Subject: [PATCH 085/217] ndctl/build: Default asciidoctor to enabled
The autotools build infra previously defaulted asciidoctor to enabled, do
the same for Meson.
Link: https://lore.kernel.org/r/164158386600.302694.5479584050156277551.stgit@dwillia2-desk3.amr.corp.intel.com
Reported-by: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
meson_options.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/meson_options.txt b/meson_options.txt
index 95312bf..aa4a6dc 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,7 +1,7 @@
option('version-tag', type : 'string',
description : 'override the git version string')
option('docs', type : 'feature', value : 'enabled')
-option('asciidoctor', type : 'feature', value : 'disabled')
+option('asciidoctor', type : 'feature', value : 'enabled')
option('systemd', type : 'feature', value : 'enabled')
option('keyutils', type : 'feature', value : 'enabled',
description : 'enable nvdimm device passphrase management')
--
2.27.0

View File

@ -0,0 +1,88 @@
From 351badda9e5b6454e56f31992e9325c4656680bd Mon Sep 17 00:00:00 2001
From: Vishal Verma <vishal.l.verma@intel.com>
Date: Fri, 14 Jan 2022 18:32:29 -0700
Subject: [PATCH 086/217] ndctl: update README.md for meson build
Update the README to replace the autotools build and test instructions
with meson equivalents. Also provide an example for setting meson
configuration options by illustrating the destructive unit tests use
case.
Link: https://lore.kernel.org/r/20220115013229.1604139-1-vishal.l.verma@intel.com
Cc: Dan Williams <dan.j.williams@intel.com>
Reported-by: Alison Schofield <alison.schofield@intel.com>
Reported-by: Jane Chu <jane.chu@oracle.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
README.md | 33 ++++++++++++++++++++++-----------
1 file changed, 22 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index 6f36a6d..f3fe65b 100644
--- a/README.md
+++ b/README.md
@@ -9,11 +9,14 @@ Build
=====
```
-./autogen.sh
-./configure CFLAGS='-g -O2' --prefix=/usr --sysconfdir=/etc --libdir=/usr/lib64
-make
-make check
-sudo make install
+meson setup build;
+meson compile -C build;
+```
+
+Optionally, to install:
+
+```
+meson install -C build
```
There are a number of packages required for the build steps that may not
@@ -34,7 +37,7 @@ https://nvdimm.wiki.kernel.org/start
Unit Tests
==========
-The unit tests run by `make check` require the nfit_test.ko module to be
+The unit tests run by `meson test` require the nfit_test.ko module to be
loaded. To build and install nfit_test.ko:
1. Obtain the kernel source. For example,
@@ -78,8 +81,16 @@ loaded. To build and install nfit_test.ko:
sudo make modules_install
```
-1. Now run `make check` in the ndctl source directory, or `ndctl test`,
- if ndctl was built with `--enable-test`.
+1. Now run `meson test -C build` in the ndctl source directory, or `ndctl test`,
+ if ndctl was built with `-Dtest=enabled` as a configuration option to meson.
+
+1. To run the 'destructive' set of tests that may clobber existing pmem
+ configurations and data, configure meson with the destructive option after the
+ `meson setup` step:
+
+ ```
+ meson configure -Dtest=enabled -Ddestructive=enabled build;
+ ```
Troubleshooting
===============
@@ -87,9 +98,9 @@ Troubleshooting
The unit tests will validate that the environment is set up correctly
before they try to run. If the platform is misconfigured, i.e. the unit
test modules are not available, or the test versions of the modules are
-superseded by the "in-tree/production" version of the modules `make
-check` will skip tests and report a message like the following in
-test/test-suite.log:
+superseded by the "in-tree/production" version of the modules `meson
+test` will skip tests and report a message like the following in
+`build/meson-logs/testlog.txt`
```
SKIP: libndctl
--
2.27.0

View File

@ -0,0 +1,122 @@
From a61377ecf015929de27a665d0b5c937315f9e4aa Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:51:54 -0800
Subject: [PATCH 087/217] test: Add 'suite' identifiers to tests
In preparation for adding CXL tests, and in anticipation of wanting to only
run the CXL tests, label each test with a suite id.
Link: https://lore.kernel.org/r/164298551461.3021641.4591877842309963514.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
test/meson.build | 73 ++++++++++++++++++++++++------------------------
1 file changed, 37 insertions(+), 36 deletions(-)
diff --git a/test/meson.build b/test/meson.build
index 94287aa..07a5bb6 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -152,28 +152,28 @@ pfn_meta_errors = find_program('pfn-meta-errors.sh')
track_uuid = find_program('track-uuid.sh')
tests = [
- [ 'libndctl', libndctl ],
- [ 'dsm-fail', dsm_fail ],
- [ 'create.sh', create ],
- [ 'clear.sh', clear ],
- [ 'pmem-errors.sh', pmem_errors ],
- [ 'daxdev-errors.sh', daxdev_errors_sh ],
- [ 'multi-dax.sh', multi_dax ],
- [ 'btt-check.sh', btt_check ],
- [ 'label-compat.sh', label_compat ],
- [ 'sector-mode.sh', sector_mode ],
- [ 'inject-error.sh', inject_error ],
- [ 'btt-errors.sh', btt_errors ],
- [ 'hugetlb', hugetlb ],
- [ 'btt-pad-compat.sh', btt_pad_compat ],
- [ 'firmware-update.sh', firmware_update ],
- [ 'ack-shutdown-count-set', ack_shutdown_count ],
- [ 'rescan-partitions.sh', rescan_partitions ],
- [ 'inject-smart.sh', inject_smart ],
- [ 'monitor.sh', monitor ],
- [ 'max_extent_ns', max_extent ],
- [ 'pfn-meta-errors.sh', pfn_meta_errors ],
- [ 'track-uuid.sh', track_uuid ],
+ [ 'libndctl', libndctl, 'ndctl' ],
+ [ 'dsm-fail', dsm_fail, 'ndctl' ],
+ [ 'create.sh', create, 'ndctl' ],
+ [ 'clear.sh', clear, 'ndctl' ],
+ [ 'pmem-errors.sh', pmem_errors, 'ndctl' ],
+ [ 'daxdev-errors.sh', daxdev_errors_sh, 'dax' ],
+ [ 'multi-dax.sh', multi_dax, 'dax' ],
+ [ 'btt-check.sh', btt_check, 'ndctl' ],
+ [ 'label-compat.sh', label_compat, 'ndctl' ],
+ [ 'sector-mode.sh', sector_mode, 'ndctl' ],
+ [ 'inject-error.sh', inject_error, 'ndctl' ],
+ [ 'btt-errors.sh', btt_errors, 'ndctl' ],
+ [ 'hugetlb', hugetlb, 'ndctl' ],
+ [ 'btt-pad-compat.sh', btt_pad_compat, 'ndctl' ],
+ [ 'firmware-update.sh', firmware_update, 'ndctl' ],
+ [ 'ack-shutdown-count-set', ack_shutdown_count, 'ndctl' ],
+ [ 'rescan-partitions.sh', rescan_partitions, 'ndctl' ],
+ [ 'inject-smart.sh', inject_smart, 'ndctl' ],
+ [ 'monitor.sh', monitor, 'ndctl' ],
+ [ 'max_extent_ns', max_extent, 'ndctl' ],
+ [ 'pfn-meta-errors.sh', pfn_meta_errors, 'ndctl' ],
+ [ 'track-uuid.sh', track_uuid, 'ndctl' ],
]
if get_option('destructive').enabled()
@@ -188,26 +188,26 @@ if get_option('destructive').enabled()
mmap_test = find_program('mmap.sh')
tests += [
- [ 'pmem-ns', pmem_ns ],
- [ 'sub-section.sh', sub_section ],
- [ 'dax-dev', dax_dev ],
- [ 'dax-ext4.sh', dax_ext4 ],
- [ 'dax-xfs.sh', dax_xfs ],
- [ 'align.sh', align ],
- [ 'device-dax', device_dax ],
- [ 'revoke-devmem', revoke_devmem ],
- [ 'device-dax-fio.sh', device_dax_fio ],
- [ 'daxctl-devices.sh', daxctl_devices ],
- [ 'daxctl-create.sh', daxctl_create ],
- [ 'dm.sh', dm ],
- [ 'mmap.sh', mmap_test ],
+ [ 'pmem-ns', pmem_ns, 'ndctl' ],
+ [ 'sub-section.sh', sub_section, 'dax' ],
+ [ 'dax-dev', dax_dev, 'dax' ],
+ [ 'dax-ext4.sh', dax_ext4, 'dax' ],
+ [ 'dax-xfs.sh', dax_xfs, 'dax' ],
+ [ 'align.sh', align, 'ndctl' ],
+ [ 'device-dax', device_dax, 'dax' ],
+ [ 'revoke-devmem', revoke_devmem, 'dax' ],
+ [ 'device-dax-fio.sh', device_dax_fio, 'dax' ],
+ [ 'daxctl-devices.sh', daxctl_devices, 'dax' ],
+ [ 'daxctl-create.sh', daxctl_create, 'dax' ],
+ [ 'dm.sh', dm, 'dax' ],
+ [ 'mmap.sh', mmap_test, 'dax' ],
]
endif
if get_option('keyutils').enabled()
security = find_program('security.sh')
tests += [
- [ 'security.sh', security ]
+ [ 'security.sh', security, 'ndctl' ]
]
endif
@@ -226,6 +226,7 @@ foreach t : tests
dax_dev,
mmap,
],
+ suite: t[2],
timeout : 0,
env : [
'NDCTL=@0@'.format(ndctl_tool.full_path()),
--
2.27.0

View File

@ -0,0 +1,287 @@
From d7c5fa695a91d66485ca1febd6f29c3a483e20f6 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:52:00 -0800
Subject: [PATCH 088/217] ndctl: Rename util_filter to ndctl_filter
In preparation for introducing a cxl_filter_walk() implementation rename
the current filter_walk infrastructure with an ndctl_ prefix.
Link: https://lore.kernel.org/r/164298552014.3021641.16369576632179722489.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
ndctl/filter.c | 4 ++--
ndctl/filter.h | 21 +++++++++++----------
ndctl/list.c | 14 +++++++-------
ndctl/monitor.c | 12 ++++++------
test/list-smart-dimm.c | 12 ++++++------
5 files changed, 32 insertions(+), 31 deletions(-)
diff -up ndctl-71.1/ndctl/filter.c.orig ndctl-71.1/ndctl/filter.c
--- ndctl-71.1/ndctl/filter.c.orig 2022-10-07 17:54:40.799788014 -0400
+++ ndctl-71.1/ndctl/filter.c 2022-10-07 17:54:52.592828166 -0400
@@ -338,8 +338,8 @@ const char *util_nsmode_name(enum ndctl_
return modes[mode];
}
-int util_filter_walk(struct ndctl_ctx *ctx, struct util_filter_ctx *fctx,
- struct util_filter_params *param)
+int ndctl_filter_walk(struct ndctl_ctx *ctx, struct ndctl_filter_ctx *fctx,
+ struct ndctl_filter_params *param)
{
struct ndctl_bus *bus;
unsigned int type = 0;
diff -up ndctl-71.1/ndctl/filter.h.orig ndctl-71.1/ndctl/filter.h
--- ndctl-71.1/ndctl/filter.h.orig 2022-10-07 17:54:40.799788014 -0400
+++ ndctl-71.1/ndctl/filter.h 2022-10-07 17:54:52.593828169 -0400
@@ -31,7 +31,7 @@ const char *util_nsmode_name(enum ndctl_
struct json_object;
-/* json object hierarchy for the util_filter_walk() performed by cmd_list() */
+/* json object hierarchy for the ndctl_filter_walk() performed by cmd_list() */
struct list_filter_arg {
struct json_object *jnamespaces;
struct json_object *jregions;
@@ -50,19 +50,20 @@ struct monitor_filter_arg {
};
/*
- * struct util_filter_ctx - control and callbacks for util_filter_walk()
+ * struct ndctl_filter_ctx - control and callbacks for ndctl_filter_walk()
* ->filter_bus() and ->filter_region() return bool because the
* child-object filter routines can not be called if the parent context
* is not established. ->filter_dimm() and ->filter_namespace() are leaf
* objects, so no child dependencies to check.
*/
-struct util_filter_ctx {
- bool (*filter_bus)(struct ndctl_bus *bus, struct util_filter_ctx *ctx);
- void (*filter_dimm)(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx);
+struct ndctl_filter_ctx {
+ bool (*filter_bus)(struct ndctl_bus *bus, struct ndctl_filter_ctx *ctx);
+ void (*filter_dimm)(struct ndctl_dimm *dimm,
+ struct ndctl_filter_ctx *ctx);
bool (*filter_region)(struct ndctl_region *region,
- struct util_filter_ctx *ctx);
+ struct ndctl_filter_ctx *ctx);
void (*filter_namespace)(struct ndctl_namespace *ndns,
- struct util_filter_ctx *ctx);
+ struct ndctl_filter_ctx *ctx);
union {
void *arg;
struct list_filter_arg *list;
@@ -70,7 +71,7 @@ struct util_filter_ctx {
};
};
-struct util_filter_params {
+struct ndctl_filter_params {
const char *bus;
const char *region;
const char *type;
@@ -81,6 +82,6 @@ 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);
+int ndctl_filter_walk(struct ndctl_ctx *ctx, struct ndctl_filter_ctx *fctx,
+ struct ndctl_filter_params *param);
#endif /* _NDCTL_UTIL_FILTER_H_ */
diff -up ndctl-71.1/ndctl/list.c.orig ndctl-71.1/ndctl/list.c
--- ndctl-71.1/ndctl/list.c.orig 2022-10-07 17:54:40.806788038 -0400
+++ ndctl-71.1/ndctl/list.c 2022-10-07 17:54:52.593828169 -0400
@@ -55,7 +55,7 @@ static unsigned long listopts_to_flags(v
return flags;
}
-static struct util_filter_params param;
+static struct ndctl_filter_params param;
static int did_fail;
@@ -234,7 +234,7 @@ static struct json_object *region_to_jso
}
static void filter_namespace(struct ndctl_namespace *ndns,
- struct util_filter_ctx *ctx)
+ struct ndctl_filter_ctx *ctx)
{
struct json_object *jndns;
struct list_filter_arg *lfa = ctx->list;
@@ -272,7 +272,7 @@ static void filter_namespace(struct ndct
}
static bool filter_region(struct ndctl_region *region,
- struct util_filter_ctx *ctx)
+ struct ndctl_filter_ctx *ctx)
{
struct list_filter_arg *lfa = ctx->list;
struct json_object *jbus = lfa->jbus;
@@ -318,7 +318,7 @@ static bool filter_region(struct ndctl_r
return true;
}
-static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx)
+static void filter_dimm(struct ndctl_dimm *dimm, struct ndctl_filter_ctx *ctx)
{
struct list_filter_arg *lfa = ctx->list;
struct json_object *jdimm;
@@ -367,7 +367,7 @@ static void filter_dimm(struct ndctl_dim
json_object_array_add(lfa->jdimms, jdimm);
}
-static bool filter_bus(struct ndctl_bus *bus, struct util_filter_ctx *ctx)
+static bool filter_bus(struct ndctl_bus *bus, struct ndctl_filter_ctx *ctx)
{
struct list_filter_arg *lfa = ctx->list;
@@ -489,7 +489,7 @@ int cmd_list(int argc, const char **argv
NULL
};
bool lint = !!secure_getenv("NDCTL_LIST_LINT");
- struct util_filter_ctx fctx = { 0 };
+ struct ndctl_filter_ctx fctx = { 0 };
struct list_filter_arg lfa = { 0 };
int i, rc;
@@ -544,7 +544,7 @@ int cmd_list(int argc, const char **argv
fctx.list = &lfa;
lfa.flags = listopts_to_flags();
- rc = util_filter_walk(ctx, &fctx, &param);
+ rc = ndctl_filter_walk(ctx, &fctx, &param);
if (rc)
return rc;
diff -up ndctl-71.1/ndctl/monitor.c.orig ndctl-71.1/ndctl/monitor.c
--- ndctl-71.1/ndctl/monitor.c.orig 2022-10-07 17:54:40.824788100 -0400
+++ ndctl-71.1/ndctl/monitor.c 2022-10-07 17:55:08.025880711 -0400
@@ -48,7 +48,7 @@ struct monitor_dimm {
struct list_node list;
};
-static struct util_filter_params param;
+static struct ndctl_filter_params param;
static int did_fail;
@@ -263,12 +263,12 @@ out:
}
static bool filter_region(struct ndctl_region *region,
- struct util_filter_ctx *fctx)
+ struct ndctl_filter_ctx *fctx)
{
return true;
}
-static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *fctx)
+static void filter_dimm(struct ndctl_dimm *dimm, struct ndctl_filter_ctx *fctx)
{
struct monitor_dimm *mdimm;
struct monitor_filter_arg *mfa = fctx->monitor;
@@ -316,7 +316,7 @@ static void filter_dimm(struct ndctl_dim
return;
}
-static bool filter_bus(struct ndctl_bus *bus, struct util_filter_ctx *fctx)
+static bool filter_bus(struct ndctl_bus *bus, struct ndctl_filter_ctx *fctx)
{
return true;
}
@@ -481,7 +481,7 @@ static void parse_config(const char **ar
}
static int read_config_file(struct ndctl_ctx *ctx, struct monitor *_monitor,
- struct util_filter_params *_param)
+ struct ndctl_filter_params *_param)
{
FILE *f;
size_t len = 0;
@@ -603,7 +603,7 @@ int cmd_monitor(int argc, const char **a
NULL
};
const char *prefix = "./";
- struct util_filter_ctx fctx = { 0 };
+ struct ndctl_filter_ctx fctx = { 0 };
struct monitor_filter_arg mfa = { 0 };
int i, rc;
@@ -667,7 +667,7 @@ int cmd_monitor(int argc, const char **a
mfa.maxfd_dimm = -1;
mfa.flags = 0;
- rc = util_filter_walk(ctx, &fctx, &param);
+ rc = ndctl_filter_walk(ctx, &fctx, &param);
if (rc)
goto out;
diff -up ndctl-71.1/test/list-smart-dimm.c.orig ndctl-71.1/test/list-smart-dimm.c
--- ndctl-71.1/test/list-smart-dimm.c.orig 2022-10-07 17:54:40.813788062 -0400
+++ ndctl-71.1/test/list-smart-dimm.c 2022-10-07 17:54:52.595828176 -0400
@@ -11,7 +11,7 @@
#include <ndctl/ndctl.h>
#include <ndctl/json.h>
-struct util_filter_params param;
+struct ndctl_filter_params param;
static int did_fail;
static int jflag = JSON_C_TO_STRING_PRETTY;
@@ -23,12 +23,12 @@ do { \
} while (0)
static bool filter_region(struct ndctl_region *region,
- struct util_filter_ctx *ctx)
+ struct ndctl_filter_ctx *ctx)
{
return true;
}
-static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx)
+static void filter_dimm(struct ndctl_dimm *dimm, struct ndctl_filter_ctx *ctx)
{
struct list_filter_arg *lfa = ctx->list;
struct json_object *jdimm;
@@ -57,7 +57,7 @@ static void filter_dimm(struct ndctl_dim
json_object_array_add(lfa->jdimms, jdimm);
}
-static bool filter_bus(struct ndctl_bus *bus, struct util_filter_ctx *ctx)
+static bool filter_bus(struct ndctl_bus *bus, struct ndctl_filter_ctx *ctx)
{
return true;
}
@@ -89,7 +89,7 @@ int main(int argc, const char *argv[])
"list-smart-dimm [<options>]",
NULL
};
- struct util_filter_ctx fctx = { 0 };
+ struct ndctl_filter_ctx fctx = { 0 };
struct list_filter_arg lfa = { 0 };
rc = ndctl_new(&ctx);
@@ -108,7 +108,7 @@ int main(int argc, const char *argv[])
fctx.list = &lfa;
lfa.flags = 0;
- rc = util_filter_walk(ctx, &fctx, &param);
+ rc = ndctl_filter_walk(ctx, &fctx, &param);
if (rc)
return rc;
diff -up ndctl-71.1/util/filter.c.orig ndctl-71.1/util/filter.c
--- ndctl-71.1/util/filter.c.orig 2022-10-07 17:55:48.192017464 -0400
+++ ndctl-71.1/util/filter.c 2022-10-07 17:55:54.474038852 -0400
@@ -394,8 +394,8 @@ const char *util_nsmode_name(enum ndctl_
return modes[mode];
}
-int util_filter_walk(struct ndctl_ctx *ctx, struct util_filter_ctx *fctx,
- struct util_filter_params *param)
+int ndctl_filter_walk(struct ndctl_ctx *ctx, struct util_filter_ctx *fctx,
+ struct util_filter_params *param)
{
struct ndctl_bus *bus;
unsigned int type = 0;

View File

@ -0,0 +1,54 @@
From 6dafb0baf8fda14f25e0a764fe8f89d8a4727b0c Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:52:05 -0800
Subject: [PATCH 089/217] build: Add tags
Copy the systemd approach to generating tags with a file listing from git.
Link: https://lore.kernel.org/r/164298552547.3021641.2951502977152843738.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
meson.build | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/meson.build b/meson.build
index b22fb2e..68f3d0c 100644
--- a/meson.build
+++ b/meson.build
@@ -82,6 +82,7 @@ project_source_root = meson.current_source_dir()
# Cleanup the leftover config.h files to avoid conflicts with the meson
# generated config.h
git = find_program('git', required : false)
+env = find_program('env')
if git.found()
run_command('clean_config.sh',
env : 'GIT_DIR=@0@/.git'.format(project_source_root),
@@ -111,6 +112,24 @@ else
)
endif
+if git.found()
+ all_files = run_command(
+ env, '-u', 'GIT_WORK_TREE',
+ git, '--git-dir=@0@/.git'.format(project_source_root),
+ 'ls-files', ':/*.[ch]',
+ check : false)
+ if all_files.returncode() == 0
+ all_files = files(all_files.stdout().split())
+ custom_target(
+ 'tags',
+ output : 'tags',
+ command : [env, 'etags', '-o', '@0@/TAGS'.format(project_source_root)] + all_files)
+ run_target(
+ 'ctags',
+ command : [env, 'ctags', '-o', '@0@/tags'.format(project_source_root)] + all_files)
+ endif
+endif
+
versiondep = declare_dependency(
compile_args: ['-include', 'version.h'],
sources: version_h
--
2.27.0

View File

@ -0,0 +1,194 @@
From 691cd249750b505753680d2a766280698ce25b75 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:52:10 -0800
Subject: [PATCH 090/217] json: Add support for json_object_new_uint64()
Recent versions of json-c add a proper u64 type. However since ndctl still
needs to build against older json-c add build infrastructure to fallback to
s64.
Link: https://lore.kernel.org/r/164298553057.3021641.17232869374733997747.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
config.h.meson | 3 +++
cxl/json.c | 6 +++---
daxctl/json.c | 2 +-
meson.build | 6 ++++++
ndctl/dimm.c | 2 +-
ndctl/json.c | 10 +++++-----
util/json.c | 2 +-
util/json.h | 13 ++++++++++++-
8 files changed, 32 insertions(+), 12 deletions(-)
diff -up ndctl-71.1/config.h.meson.orig ndctl-71.1/config.h.meson
--- ndctl-71.1/config.h.meson.orig 2022-10-07 17:40:36.698914113 -0400
+++ ndctl-71.1/config.h.meson 2022-10-07 17:41:24.043075305 -0400
@@ -88,6 +88,9 @@
/* Define to 1 if you have the `__secure_getenv' function. */
#mesondefine HAVE___SECURE_GETENV
+/* Define to 1 if you have json_object_new_uint64 in json-c */
+#mesondefine HAVE_JSON_U64
+
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#mesondefine LT_OBJDIR
diff -up ndctl-71.1/cxl/json.c.orig ndctl-71.1/cxl/json.c
--- ndctl-71.1/cxl/json.c.orig 2022-10-07 17:40:36.668914011 -0400
+++ ndctl-71.1/cxl/json.c 2022-10-07 17:41:24.043075305 -0400
@@ -159,17 +159,17 @@ static struct json_object *util_cxl_memd
}
field = cxl_cmd_health_info_get_dirty_shutdowns(cmd);
- jobj = json_object_new_int64(field);
+ jobj = util_json_new_u64(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);
+ jobj = util_json_new_u64(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);
+ jobj = util_json_new_u64(field);
if (jobj)
json_object_object_add(jhealth, "pmem_errors", jobj);
diff -up ndctl-71.1/daxctl/json.c.orig ndctl-71.1/daxctl/json.c
--- ndctl-71.1/daxctl/json.c.orig 2022-10-07 17:40:36.671914021 -0400
+++ ndctl-71.1/daxctl/json.c 2022-10-07 17:41:24.043075305 -0400
@@ -190,7 +190,7 @@ struct json_object *util_daxctl_region_t
align = daxctl_region_get_align(region);
if (align < ULONG_MAX) {
- jobj = json_object_new_int64(align);
+ jobj = util_json_new_u64(align);
if (!jobj)
goto err;
json_object_object_add(jregion, "align", jobj);
diff -up ndctl-71.1/meson.build.orig ndctl-71.1/meson.build
--- ndctl-71.1/meson.build.orig 2022-10-07 17:40:36.720914188 -0400
+++ ndctl-71.1/meson.build 2022-10-07 17:41:24.044075308 -0400
@@ -240,6 +240,12 @@ foreach ident : ['secure_getenv', '__sec
conf.set10('HAVE_' + ident.to_upper(), cc.has_function(ident))
endforeach
+conf.set10('HAVE_JSON_U64',
+ cc.has_function('json_object_new_uint64',
+ prefix : '''#include <json-c/json.h>''',
+ dependencies : json,
+ )
+)
ndctlconf_dir = sysconfdir / 'ndctl'
ndctlconf = ndctlconf_dir / 'monitor.conf'
diff -up ndctl-71.1/ndctl/dimm.c.orig ndctl-71.1/ndctl/dimm.c
--- ndctl-71.1/ndctl/dimm.c.orig 2022-10-07 17:40:36.673914028 -0400
+++ ndctl-71.1/ndctl/dimm.c 2022-10-07 17:41:24.044075308 -0400
@@ -168,7 +168,7 @@ static struct json_object *dump_label_js
break;
json_object_object_add(jlabel, "isetcookie", jobj);
- jobj = json_object_new_int64(le64_to_cpu(nslabel.lbasize));
+ jobj = util_json_new_u64(le64_to_cpu(nslabel.lbasize));
if (!jobj)
break;
json_object_object_add(jlabel, "lbasize", jobj);
diff -up ndctl-71.1/ndctl/json.c.orig ndctl-71.1/ndctl/json.c
--- ndctl-71.1/ndctl/json.c.orig 2022-10-07 17:40:36.675914034 -0400
+++ ndctl-71.1/ndctl/json.c 2022-10-07 17:41:24.044075308 -0400
@@ -357,7 +357,7 @@ static struct json_object *util_##type##
int64_t align; \
\
align = get_elem(arg, i); \
- jobj = json_object_new_int64(align); \
+ jobj = util_json_new_u64(align); \
if (!jobj) \
goto err; \
json_object_array_add(arr, jobj); \
@@ -550,7 +550,7 @@ struct json_object *util_region_badblock
if (!jbb)
goto err_array;
- jobj = json_object_new_int64(bb->offset);
+ jobj = util_json_new_u64(bb->offset);
if (!jobj)
goto err;
json_object_object_add(jbb, "offset", jobj);
@@ -604,7 +604,7 @@ static struct json_object *util_namespac
if (!jbb)
goto err_array;
- jobj = json_object_new_int64(bb->offset);
+ jobj = util_json_new_u64(bb->offset);
if (!jobj)
goto err;
json_object_object_add(jbb, "offset", jobj);
@@ -682,7 +682,7 @@ static struct json_object *dev_badblocks
if (!jbb)
goto err_array;
- jobj = json_object_new_int64(offset);
+ jobj = util_json_new_u64(offset);
if (!jobj)
goto err;
json_object_object_add(jbb, "offset", jobj);
@@ -972,7 +972,7 @@ struct json_object *util_namespace_to_js
}
if (align) {
- jobj = json_object_new_int64(align);
+ jobj = util_json_new_u64(align);
if (!jobj)
goto err;
json_object_object_add(jndns, "align", jobj);
diff -up ndctl-71.1/util/json.c.orig ndctl-71.1/util/json.c
--- ndctl-71.1/util/json.c.orig 2022-10-07 17:40:36.682914058 -0400
+++ ndctl-71.1/util/json.c 2022-10-07 17:41:24.045075312 -0400
@@ -82,7 +82,7 @@ struct json_object *util_json_object_siz
struct json_object *util_json_object_hex(unsigned long long val,
unsigned long flags)
{
- struct json_object *jobj = json_object_new_int64(val);
+ struct json_object *jobj = util_json_new_u64(val);
if (jobj && (flags & UTIL_JSON_HUMAN))
json_object_set_serializer(jobj, display_hex, NULL, NULL);
diff -up ndctl-71.1/util/json.h.orig ndctl-71.1/util/json.h
--- ndctl-71.1/util/json.h.orig 2022-10-07 17:40:36.683914062 -0400
+++ ndctl-71.1/util/json.h 2022-10-07 17:41:24.046075315 -0400
@@ -4,6 +4,7 @@
#define __UTIL_JSON_H__
#include <stdio.h>
#include <stdbool.h>
+#include <json-c/json.h>
enum util_json_flags {
UTIL_JSON_IDLE = (1 << 0),
@@ -19,11 +20,21 @@ enum util_json_flags {
UTIL_JSON_HEALTH = (1 << 10),
};
-struct json_object;
void util_display_json_array(FILE *f_out, struct json_object *jarray,
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);
+#if HAVE_JSON_U64
+static inline struct json_object *util_json_new_u64(unsigned long long val)
+{
+ return json_object_new_uint64(val);
+}
+#else /* fallback to signed */
+static inline struct json_object *util_json_new_u64(unsigned long long val)
+{
+ return json_object_new_int64(val);
+}
+#endif /* HAVE_JSON_U64 */
#endif /* __UTIL_JSON_H__ */

View File

@ -0,0 +1,32 @@
From 8f457dc414ec27178828c86533910958542ce73d Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:52:15 -0800
Subject: [PATCH 091/217] cxl/json: Cleanup object leak false positive
As written it is a leak of the json object to return if devname is NULL.
However, the devname can not be NULL because the memdev would not have been
enumerated. Drop the error checking.
Link: https://lore.kernel.org/r/164298553566.3021641.11858634436119663877.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
cxl/json.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cxl/json.c b/cxl/json.c
index 97ed76b..3ef9f76 100644
--- a/cxl/json.c
+++ b/cxl/json.c
@@ -190,7 +190,7 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
struct json_object *jdev, *jobj;
jdev = json_object_new_object();
- if (!devname || !jdev)
+ if (!jdev)
return NULL;
jobj = json_object_new_string(devname);
--
2.27.0

View File

@ -0,0 +1,118 @@
From 0ce0152d8e29f85325a3a59f94051228540abf6a Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:52:20 -0800
Subject: [PATCH 092/217] cxl/list: Support multiple memdev device name filter
arguments
Similar to 'ndctl list', allow for a syntax like:
cxl list -m "$(seq -s ' ' 2 5)"
...to filter the output to just those 4 memdevs.
Link: https://lore.kernel.org/r/164298554075.3021641.17678360870961637912.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/cxl/cxl-list.txt | 21 ++++++++++++++++++-
cxl/filter.c | 38 ++++++++++++++++++++++++----------
2 files changed, 47 insertions(+), 12 deletions(-)
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
index c8d10fb..686e0ea 100644
--- a/Documentation/cxl/cxl-list.txt
+++ b/Documentation/cxl/cxl-list.txt
@@ -30,7 +30,7 @@ OPTIONS
-------
-m::
--memdev=::
- Specify a cxl memory device name to filter the listing. For example:
+ Specify CXL memory device name(s), or device id(s), to filter the listing. For example:
----
# cxl list --memdev=mem0
{
@@ -38,6 +38,25 @@ OPTIONS
"pmem_size":268435456,
"ram_size":0,
}
+
+# cxl list -m "0 mem1 2"
+[
+ {
+ "memdev":"mem0",
+ "pmem_size":268435456,
+ "ram_size":0
+ },
+ {
+ "memdev":"mem2",
+ "pmem_size":268435456,
+ "ram_size":268435456
+ },
+ {
+ "memdev":"mem1",
+ "pmem_size":268435456,
+ "ram_size":268435456
+ }
+]
----
-M::
diff --git a/cxl/filter.c b/cxl/filter.c
index 21322ed..efafaf5 100644
--- a/cxl/filter.c
+++ b/cxl/filter.c
@@ -2,24 +2,40 @@
// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
#include <cxl/libcxl.h>
#include "filter.h"
struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
- const char *ident)
+ const char *__ident)
{
- int memdev_id;
+ char *ident, *save;
+ const char *name;
+ int memdev_id;
- if (!ident || strcmp(ident, "all") == 0)
- return memdev;
+ if (!__ident)
+ return memdev;
- if (strcmp(ident, cxl_memdev_get_devname(memdev)) == 0)
- return memdev;
+ ident = strdup(__ident);
+ if (!ident)
+ return NULL;
- if ((sscanf(ident, "%d", &memdev_id) == 1
- || sscanf(ident, "mem%d", &memdev_id) == 1)
- && cxl_memdev_get_id(memdev) == memdev_id)
- return memdev;
+ for (name = strtok_r(ident, " ", &save); name;
+ name = strtok_r(NULL, " ", &save)) {
+ if (strcmp(name, "all") == 0)
+ break;
- return NULL;
+ if ((sscanf(name, "%d", &memdev_id) == 1 ||
+ sscanf(name, "mem%d", &memdev_id) == 1) &&
+ cxl_memdev_get_id(memdev) == memdev_id)
+ break;
+
+ if (strcmp(name, cxl_memdev_get_devname(memdev)) == 0)
+ break;
+ }
+
+ free(ident);
+ if (name)
+ return memdev;
+ return NULL;
}
--
2.27.0

View File

@ -0,0 +1,55 @@
From a36b8b815d2e8bfd8438b44d4775bdf3ffc3a6d8 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:52:26 -0800
Subject: [PATCH 093/217] cxl/list: Support comma separated lists
In addition to supporting a syntax like:
cxl list -m "0 1 2"
...support:
cxl list -m 0,1,2
Link: https://lore.kernel.org/r/164298554612.3021641.3315920699556984273.stgit@dwillia2-desk3.amr.corp.intel.com
Reported-by: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
cxl/filter.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/cxl/filter.c b/cxl/filter.c
index efafaf5..405b653 100644
--- a/cxl/filter.c
+++ b/cxl/filter.c
@@ -6,6 +6,15 @@
#include <cxl/libcxl.h>
#include "filter.h"
+static const char *which_sep(const char *filter)
+{
+ if (strchr(filter, ' '))
+ return " ";
+ if (strchr(filter, ','))
+ return ",";
+ return " ";
+}
+
struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
const char *__ident)
{
@@ -20,8 +29,8 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
if (!ident)
return NULL;
- for (name = strtok_r(ident, " ", &save); name;
- name = strtok_r(NULL, " ", &save)) {
+ for (name = strtok_r(ident, which_sep(__ident), &save); name;
+ name = strtok_r(NULL, which_sep(__ident), &save)) {
if (strcmp(name, "all") == 0)
break;
--
2.27.0

View File

@ -0,0 +1,292 @@
From f833845ce72490e4c80b3ccc9972d5329f69a381 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:52:31 -0800
Subject: [PATCH 094/217] cxl/list: Introduce cxl_filter_walk()
In preparation for introducing more objects and filtering options for 'cxl
list' introduce cxl_filter_walk() to centralize CXL topology walks. It
fills the same role as ndctl_filter_walk() as a way to distribute topology
interrogation beyond 'cxl list' to other commands, and serve as the
template for CXL object hierarchy in JSON output payloads.
Use the common dbg() logger for log messages.
Link: https://lore.kernel.org/r/164298555121.3021641.16127840206319352254.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/cxl/cxl-list.txt | 2 +
cxl/filter.c | 50 ++++++++++++++++
cxl/filter.h | 18 +++++-
cxl/list.c | 102 +++++++--------------------------
cxl/meson.build | 1 +
5 files changed, 90 insertions(+), 83 deletions(-)
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
index 686e0ea..4d409ba 100644
--- a/Documentation/cxl/cxl-list.txt
+++ b/Documentation/cxl/cxl-list.txt
@@ -15,6 +15,8 @@ SYNOPSIS
Walk the CXL capable device hierarchy in the system and list all device
instances along with some of their major attributes.
+Options can be specified to limit the output to specific objects.
+
EXAMPLE
-------
----
diff --git a/cxl/filter.c b/cxl/filter.c
index 405b653..d1ff4b6 100644
--- a/cxl/filter.c
+++ b/cxl/filter.c
@@ -1,10 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
+#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <util/log.h>
+#include <util/json.h>
#include <cxl/libcxl.h>
+#include <json-c/json.h>
+
#include "filter.h"
+#include "json.h"
static const char *which_sep(const char *filter)
{
@@ -48,3 +54,47 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
return memdev;
return NULL;
}
+
+static unsigned long params_to_flags(struct cxl_filter_params *param)
+{
+ unsigned long flags = 0;
+
+ if (param->idle)
+ flags |= UTIL_JSON_IDLE;
+ if (param->human)
+ flags |= UTIL_JSON_HUMAN;
+ if (param->health)
+ flags |= UTIL_JSON_HEALTH;
+ return flags;
+}
+
+int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
+{
+ struct json_object *jplatform = json_object_new_array();
+ unsigned long flags = params_to_flags(p);
+ struct cxl_memdev *memdev;
+
+ if (!jplatform) {
+ dbg(p, "platform object allocation failure\n");
+ return -ENOMEM;
+ }
+
+ cxl_memdev_foreach(ctx, memdev) {
+ struct json_object *jdev;
+
+ if (!util_cxl_memdev_filter(memdev, p->memdev_filter))
+ continue;
+ if (p->memdevs) {
+ jdev = util_cxl_memdev_to_json(memdev, flags);
+ if (!jdev) {
+ dbg(p, "memdev object allocation failure\n");
+ continue;
+ }
+ json_object_array_add(jplatform, jdev);
+ }
+ }
+
+ util_display_json_array(stdout, jplatform, flags);
+
+ return 0;
+}
diff --git a/cxl/filter.h b/cxl/filter.h
index da80033..664b74b 100644
--- a/cxl/filter.h
+++ b/cxl/filter.h
@@ -1,7 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */
+/* Copyright (C) 2021 Intel Corporation. All rights reserved. */
#ifndef _CXL_UTIL_FILTER_H_
#define _CXL_UTIL_FILTER_H_
+
+#include <stdbool.h>
+#include <util/log.h>
+
+struct cxl_filter_params {
+ const char *memdev_filter;
+ bool memdevs;
+ bool idle;
+ bool human;
+ bool health;
+ struct log_ctx ctx;
+};
+
struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
- const char *ident);
+ const char *ident);
+int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param);
#endif /* _CXL_UTIL_FILTER_H_ */
diff --git a/cxl/list.c b/cxl/list.c
index 7f7a04d..1730307 100644
--- a/cxl/list.c
+++ b/cxl/list.c
@@ -9,60 +9,27 @@
#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;
- bool human;
- bool health;
-} list;
-
-static unsigned long listopts_to_flags(void)
-{
- unsigned long flags = 0;
-
- if (list.idle)
- flags |= UTIL_JSON_IDLE;
- if (list.human)
- flags |= UTIL_JSON_HUMAN;
- if (list.health)
- flags |= UTIL_JSON_HEALTH;
- return flags;
-}
-
-static struct {
- const char *memdev;
-} param;
-
-static int did_fail;
-
-#define fail(fmt, ...) \
-do { \
- did_fail = 1; \
- fprintf(stderr, "cxl-%s:%s:%d: " fmt, \
- VERSION, __func__, __LINE__, ##__VA_ARGS__); \
-} while (0)
+static struct cxl_filter_params param;
static int num_list_flags(void)
{
- return list.memdevs;
+ return param.memdevs;
}
int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
{
const struct option options[] = {
- OPT_STRING('m', "memdev", &param.memdev, "memory device name",
+ OPT_STRING('m', "memdev", &param.memdev_filter, "memory device name",
"filter by CXL memory device name"),
- OPT_BOOLEAN('M', "memdevs", &list.memdevs,
+ OPT_BOOLEAN('M', "memdevs", &param.memdevs,
"include CXL memory device info"),
- OPT_BOOLEAN('i', "idle", &list.idle, "include idle devices"),
- OPT_BOOLEAN('u', "human", &list.human,
+ OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),
+ OPT_BOOLEAN('u', "human", &param.human,
"use human friendly number formats "),
- OPT_BOOLEAN('H', "health", &list.health,
+ OPT_BOOLEAN('H', "health", &param.health,
"include memory device health information "),
OPT_END(),
};
@@ -70,9 +37,6 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
"cxl list [<options>]",
NULL
};
- struct json_object *jdevs = NULL;
- unsigned long list_flags;
- struct cxl_memdev *memdev;
int i;
argc = parse_options(argc, argv, options, u, 0);
@@ -83,46 +47,22 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
usage_with_options(u, options);
if (num_list_flags() == 0) {
- /*
- * TODO: We likely want to list regions by default if nothing
- * was explicitly asked for. But until we have region support,
- * print this error asking for devices explicitly.
- * Once region support is added, this TODO can be removed.
- */
- error("please specify entities to list, e.g. using -m/-M\n");
- usage_with_options(u, options);
- }
-
- list_flags = listopts_to_flags();
-
- cxl_memdev_foreach(ctx, memdev) {
- struct json_object *jdev = NULL;
-
- if (!util_cxl_memdev_filter(memdev, param.memdev))
- continue;
-
- if (list.memdevs) {
- if (!jdevs) {
- jdevs = json_object_new_array();
- if (!jdevs) {
- fail("\n");
- continue;
- }
- }
-
- jdev = util_cxl_memdev_to_json(memdev, list_flags);
- if (!jdev) {
- fail("\n");
- continue;
- }
- json_object_array_add(jdevs, jdev);
+ if (param.memdev_filter)
+ param.memdevs = true;
+ else {
+ /*
+ * TODO: We likely want to list regions by default if
+ * nothing was explicitly asked for. But until we have
+ * region support, print this error asking for devices
+ * explicitly. Once region support is added, this TODO
+ * can be removed.
+ */
+ error("please specify entities to list, e.g. using -m/-M\n");
+ usage_with_options(u, options);
}
}
- if (jdevs)
- util_display_json_array(stdout, jdevs, list_flags);
+ log_init(&param.ctx, "cxl list", "CXL_LIST_LOG");
- if (did_fail)
- return -ENOMEM;
- return 0;
+ return cxl_filter_walk(ctx, &param);
}
diff --git a/cxl/meson.build b/cxl/meson.build
index 805924b..fc7ee71 100644
--- a/cxl/meson.build
+++ b/cxl/meson.build
@@ -3,6 +3,7 @@ cxl_src = [
'list.c',
'memdev.c',
'../util/json.c',
+ '../util/log.c',
'json.c',
'filter.c',
]
--
2.27.0

View File

@ -0,0 +1,159 @@
From 2d1b8cea119ca2bb0eec8ebb2dfb1b6c4d844ddd Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:52:36 -0800
Subject: [PATCH 095/217] cxl/list: Emit device serial numbers
Starting with the v5.17 kernel the CXL driver emits the mandatory device
serial number for each memory device. Include it in the memory device
listing.
Link: https://lore.kernel.org/r/164298555630.3021641.3246226448369816200.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/cxl/cxl-list.txt | 15 +++++++++------
cxl/json.c | 11 ++++++++++-
cxl/lib/libcxl.c | 11 +++++++++++
cxl/lib/libcxl.sym | 5 +++++
cxl/lib/private.h | 1 +
cxl/libcxl.h | 1 +
6 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
index 4d409ba..bd0207e 100644
--- a/Documentation/cxl/cxl-list.txt
+++ b/Documentation/cxl/cxl-list.txt
@@ -41,22 +41,25 @@ OPTIONS
"ram_size":0,
}
-# cxl list -m "0 mem1 2"
+# cxl list -M --memdev="0 mem3 5"
[
{
"memdev":"mem0",
"pmem_size":268435456,
- "ram_size":0
+ "ram_size":0,
+ "serial":0
},
{
- "memdev":"mem2",
+ "memdev":"mem3",
"pmem_size":268435456,
- "ram_size":268435456
+ "ram_size":268435456,
+ "serial":2
},
{
- "memdev":"mem1",
+ "memdev":"mem5",
"pmem_size":268435456,
- "ram_size":268435456
+ "ram_size":268435456,
+ "serial":4
}
]
----
diff --git a/cxl/json.c b/cxl/json.c
index 3ef9f76..d8e65df 100644
--- a/cxl/json.c
+++ b/cxl/json.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
+// Copyright (C) 2015-2021 Intel Corporation. All rights reserved.
+#include <limits.h>
#include <util/json.h>
#include <uuid/uuid.h>
#include <cxl/libcxl.h>
@@ -188,6 +189,7 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
{
const char *devname = cxl_memdev_get_devname(memdev);
struct json_object *jdev, *jobj;
+ unsigned long long serial;
jdev = json_object_new_object();
if (!jdev)
@@ -210,5 +212,12 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
if (jobj)
json_object_object_add(jdev, "health", jobj);
}
+
+ serial = cxl_memdev_get_serial(memdev);
+ if (serial < ULLONG_MAX) {
+ jobj = util_json_object_hex(serial, flags);
+ if (jobj)
+ json_object_object_add(jdev, "serial", jobj);
+ }
return jdev;
}
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 3390eb9..8d3cf80 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -296,6 +296,12 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)
if (memdev->lsa_size == ULLONG_MAX)
goto err_read;
+ sprintf(path, "%s/serial", cxlmem_base);
+ if (sysfs_read_attr(ctx, path, buf) < 0)
+ memdev->serial = ULLONG_MAX;
+ else
+ memdev->serial = strtoull(buf, NULL, 0);
+
memdev->dev_path = strdup(cxlmem_base);
if (!memdev->dev_path)
goto err_read;
@@ -371,6 +377,11 @@ CXL_EXPORT int cxl_memdev_get_id(struct cxl_memdev *memdev)
return memdev->id;
}
+CXL_EXPORT unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev)
+{
+ return memdev->serial;
+}
+
CXL_EXPORT const char *cxl_memdev_get_devname(struct cxl_memdev *memdev)
{
return devpath_to_devname(memdev->dev_path);
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 077d104..4411035 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -73,3 +73,8 @@ global:
local:
*;
};
+
+LIBCXL_2 {
+global:
+ cxl_memdev_get_serial;
+} LIBCXL_1;
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index a1b8b50..28f7e16 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -31,6 +31,7 @@ struct cxl_memdev {
size_t lsa_size;
struct kmod_module *module;
struct cxl_nvdimm_bridge *bridge;
+ unsigned long long serial;
};
enum cxl_cmd_query_status {
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index 89d35ba..bcdede8 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -35,6 +35,7 @@ struct cxl_memdev;
struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx);
struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev);
int cxl_memdev_get_id(struct cxl_memdev *memdev);
+unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev);
const char *cxl_memdev_get_devname(struct cxl_memdev *memdev);
int cxl_memdev_get_major(struct cxl_memdev *memdev);
int cxl_memdev_get_minor(struct cxl_memdev *memdev);
--
2.27.0

View File

@ -0,0 +1,163 @@
From d7854adcd1e517d2372ec51f4a1ede2d549975e8 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:52:41 -0800
Subject: [PATCH 096/217] cxl/list: Add filter by serial support
Given that serial numbers are intended to be unique device identifiers,
enable them as a memdev filter option.
Link: https://lore.kernel.org/r/164298556167.3021641.5470955268978068465.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/cxl/cxl-list.txt | 4 ++++
cxl/filter.c | 38 ++++++++++++++++++++++++++++++----
cxl/filter.h | 4 +++-
cxl/list.c | 4 +++-
cxl/memdev.c | 2 +-
5 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
index bd0207e..224c972 100644
--- a/Documentation/cxl/cxl-list.txt
+++ b/Documentation/cxl/cxl-list.txt
@@ -64,6 +64,10 @@ OPTIONS
]
----
+-s::
+--serial=::
+ Specify CXL memory device serial number(s) to filter the listing
+
-M::
--memdevs::
Include CXL memory devices in the listing
diff --git a/cxl/filter.c b/cxl/filter.c
index d1ff4b6..26efc65 100644
--- a/cxl/filter.c
+++ b/cxl/filter.c
@@ -21,15 +21,45 @@ static const char *which_sep(const char *filter)
return " ";
}
+static struct cxl_memdev *
+util_cxl_memdev_serial_filter(struct cxl_memdev *memdev, const char *__serials)
+{
+ unsigned long long serial = 0;
+ char *serials, *save, *end;
+ const char *arg;
+
+ if (!__serials)
+ return memdev;
+
+ serials = strdup(__serials);
+ if (!serials)
+ return NULL;
+
+ for (arg = strtok_r(serials, which_sep(__serials), &save); arg;
+ arg = strtok_r(NULL, which_sep(__serials), &save)) {
+ serial = strtoull(arg, &end, 0);
+ if (!arg[0] || end[0] != 0)
+ continue;
+ if (cxl_memdev_get_serial(memdev) == serial)
+ break;
+ }
+
+ free(serials);
+ if (arg)
+ return memdev;
+ return NULL;
+}
+
struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
- const char *__ident)
+ const char *__ident,
+ const char *serials)
{
char *ident, *save;
const char *name;
int memdev_id;
if (!__ident)
- return memdev;
+ return util_cxl_memdev_serial_filter(memdev, serials);
ident = strdup(__ident);
if (!ident)
@@ -51,7 +81,7 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
free(ident);
if (name)
- return memdev;
+ return util_cxl_memdev_serial_filter(memdev, serials);
return NULL;
}
@@ -82,7 +112,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
cxl_memdev_foreach(ctx, memdev) {
struct json_object *jdev;
- if (!util_cxl_memdev_filter(memdev, p->memdev_filter))
+ if (!util_cxl_memdev_filter(memdev, p->memdev_filter, p->serial_filter))
continue;
if (p->memdevs) {
jdev = util_cxl_memdev_to_json(memdev, flags);
diff --git a/cxl/filter.h b/cxl/filter.h
index 664b74b..12d9344 100644
--- a/cxl/filter.h
+++ b/cxl/filter.h
@@ -8,6 +8,7 @@
struct cxl_filter_params {
const char *memdev_filter;
+ const char *serial_filter;
bool memdevs;
bool idle;
bool human;
@@ -16,6 +17,7 @@ struct cxl_filter_params {
};
struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
- const char *ident);
+ const char *__ident,
+ const char *serials);
int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param);
#endif /* _CXL_UTIL_FILTER_H_ */
diff --git a/cxl/list.c b/cxl/list.c
index 1730307..6bc48df 100644
--- a/cxl/list.c
+++ b/cxl/list.c
@@ -24,6 +24,8 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
const struct option options[] = {
OPT_STRING('m', "memdev", &param.memdev_filter, "memory device name",
"filter by CXL memory device name"),
+ OPT_STRING('s', "serial", &param.serial_filter, "memory device serial",
+ "filter by CXL memory device serial number"),
OPT_BOOLEAN('M', "memdevs", &param.memdevs,
"include CXL memory device info"),
OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),
@@ -47,7 +49,7 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
usage_with_options(u, options);
if (num_list_flags() == 0) {
- if (param.memdev_filter)
+ if (param.memdev_filter || param.serial_filter)
param.memdevs = true;
else {
/*
diff --git a/cxl/memdev.c b/cxl/memdev.c
index d063d51..b9141be 100644
--- a/cxl/memdev.c
+++ b/cxl/memdev.c
@@ -248,7 +248,7 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,
continue;
cxl_memdev_foreach (ctx, memdev) {
- if (!util_cxl_memdev_filter(memdev, argv[i]))
+ if (!util_cxl_memdev_filter(memdev, argv[i], NULL))
continue;
if (action == action_write) {
--
2.27.0

View File

@ -0,0 +1,164 @@
From 0be46d9c6638903978d16388c765a1907d5970bc Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:52:47 -0800
Subject: [PATCH 097/217] cxl/lib: Rename nvdimm bridge to pmem
The kernel has 2 object classes for connecting CXL to NVDIMM. There is an
'nvdimm-bridge' object (one per root CXL port) that represents a CXL NVDIMM
Bus, and there are 'pmem' object that represent CXL NVDIMM DIMM devices.
The object that the library is currently calling an nvdimm-bridge is
actually the 'pmem' object. Rename accordingly.
The exported function cxl_memdev_nvdimm_bridge_active() is not renamed, but
since it is a cxl_memdev operation and 'struct cxl_pmem' is an
implementation detail it is fine as is.
Link: https://lore.kernel.org/r/164298556712.3021641.15612755067301105130.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
cxl/lib/libcxl.c | 56 +++++++++++++++++++++++------------------------
cxl/lib/private.h | 4 ++--
2 files changed, 30 insertions(+), 30 deletions(-)
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 8d3cf80..9839f26 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -45,11 +45,11 @@ struct cxl_ctx {
void *private_data;
};
-static void free_bridge(struct cxl_nvdimm_bridge *bridge)
+static void free_pmem(struct cxl_pmem *pmem)
{
- free(bridge->dev_buf);
- free(bridge->dev_path);
- free(bridge);
+ free(pmem->dev_buf);
+ free(pmem->dev_path);
+ free(pmem);
}
static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)
@@ -57,7 +57,7 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)
if (head)
list_del_from(head, &memdev->list);
kmod_module_unref(memdev->module);
- free_bridge(memdev->bridge);
+ free_pmem(memdev->pmem);
free(memdev->firmware_version);
free(memdev->dev_buf);
free(memdev->dev_path);
@@ -213,36 +213,36 @@ CXL_EXPORT void cxl_set_log_priority(struct cxl_ctx *ctx, int priority)
ctx->ctx.log_priority = priority;
}
-static void *add_cxl_bridge(void *parent, int id, const char *br_base)
+static void *add_cxl_pmem(void *parent, int id, const char *br_base)
{
const char *devname = devpath_to_devname(br_base);
struct cxl_memdev *memdev = parent;
struct cxl_ctx *ctx = memdev->ctx;
- struct cxl_nvdimm_bridge *bridge;
+ struct cxl_pmem *pmem;
- dbg(ctx, "%s: bridge_base: \'%s\'\n", devname, br_base);
+ dbg(ctx, "%s: pmem_base: \'%s\'\n", devname, br_base);
- bridge = calloc(1, sizeof(*bridge));
- if (!bridge)
+ pmem = calloc(1, sizeof(*pmem));
+ if (!pmem)
goto err_dev;
- bridge->id = id;
+ pmem->id = id;
- bridge->dev_path = strdup(br_base);
- if (!bridge->dev_path)
+ pmem->dev_path = strdup(br_base);
+ if (!pmem->dev_path)
goto err_read;
- bridge->dev_buf = calloc(1, strlen(br_base) + 50);
- if (!bridge->dev_buf)
+ pmem->dev_buf = calloc(1, strlen(br_base) + 50);
+ if (!pmem->dev_buf)
goto err_read;
- bridge->buf_len = strlen(br_base) + 50;
+ pmem->buf_len = strlen(br_base) + 50;
- memdev->bridge = bridge;
- return bridge;
+ memdev->pmem = pmem;
+ return pmem;
err_read:
- free(bridge->dev_buf);
- free(bridge->dev_path);
- free(bridge);
+ free(pmem->dev_buf);
+ free(pmem->dev_path);
+ free(pmem);
err_dev:
return NULL;
}
@@ -319,7 +319,7 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)
goto err_read;
memdev->buf_len = strlen(cxlmem_base) + 50;
- sysfs_device_parse(ctx, cxlmem_base, "pmem", memdev, add_cxl_bridge);
+ sysfs_device_parse(ctx, cxlmem_base, "pmem", memdev, add_cxl_pmem);
cxl_memdev_foreach(ctx, memdev_dup)
if (memdev_dup->id == memdev->id) {
@@ -430,18 +430,18 @@ static int is_enabled(const char *drvpath)
CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev)
{
struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
- struct cxl_nvdimm_bridge *bridge = memdev->bridge;
+ struct cxl_pmem *pmem = memdev->pmem;
char *path;
int len;
- if (!bridge)
+ if (!pmem)
return 0;
- path = bridge->dev_buf;
- len = bridge->buf_len;
+ path = pmem->dev_buf;
+ len = pmem->buf_len;
- if (snprintf(path, len, "%s/driver", bridge->dev_path) >= len) {
- err(ctx, "%s: nvdimm bridge buffer too small!\n",
+ if (snprintf(path, len, "%s/driver", pmem->dev_path) >= len) {
+ err(ctx, "%s: nvdimm pmem buffer too small!\n",
cxl_memdev_get_devname(memdev));
return 0;
}
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index 28f7e16..7c81e24 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -10,7 +10,7 @@
#define CXL_EXPORT __attribute__ ((visibility("default")))
-struct cxl_nvdimm_bridge {
+struct cxl_pmem {
int id;
void *dev_buf;
size_t buf_len;
@@ -30,7 +30,7 @@ struct cxl_memdev {
int payload_max;
size_t lsa_size;
struct kmod_module *module;
- struct cxl_nvdimm_bridge *bridge;
+ struct cxl_pmem *pmem;
unsigned long long serial;
};
--
2.27.0

View File

@ -0,0 +1,61 @@
From 5d20a4d2cca923e63cb1604da51788c0fd078ce1 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:52:52 -0800
Subject: [PATCH 098/217] cxl/list: Cleanup options definitions
Clarify which options take lists by adding a "(s)" to the object name, and
move the option block out of cmd_list() to reduce the column-80 collisions.
Link: https://lore.kernel.org/r/164298557263.3021641.8121105326167408001.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
cxl/list.c | 30 ++++++++++++++++--------------
1 file changed, 16 insertions(+), 14 deletions(-)
diff --git a/cxl/list.c b/cxl/list.c
index 6bc48df..7e2744d 100644
--- a/cxl/list.c
+++ b/cxl/list.c
@@ -19,22 +19,24 @@ static int num_list_flags(void)
return param.memdevs;
}
+static const struct option options[] = {
+ OPT_STRING('m', "memdev", &param.memdev_filter, "memory device name(s)",
+ "filter by CXL memory device name(s)"),
+ OPT_STRING('s', "serial", &param.serial_filter,
+ "memory device serial(s)",
+ "filter by CXL memory device serial number(s)"),
+ OPT_BOOLEAN('M', "memdevs", &param.memdevs,
+ "include CXL memory device info"),
+ OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),
+ OPT_BOOLEAN('u', "human", &param.human,
+ "use human friendly number formats "),
+ OPT_BOOLEAN('H', "health", &param.health,
+ "include memory device health information "),
+ OPT_END(),
+};
+
int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
{
- const struct option options[] = {
- OPT_STRING('m', "memdev", &param.memdev_filter, "memory device name",
- "filter by CXL memory device name"),
- OPT_STRING('s', "serial", &param.serial_filter, "memory device serial",
- "filter by CXL memory device serial number"),
- OPT_BOOLEAN('M', "memdevs", &param.memdevs,
- "include CXL memory device info"),
- OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),
- OPT_BOOLEAN('u', "human", &param.human,
- "use human friendly number formats "),
- OPT_BOOLEAN('H', "health", &param.health,
- "include memory device health information "),
- OPT_END(),
- };
const char * const u[] = {
"cxl list [<options>]",
NULL
--
2.27.0

View File

@ -0,0 +1,170 @@
From 7b9ed7e065c6de029385d40de1f7cb0aed3a9108 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:52:57 -0800
Subject: [PATCH 099/217] Documentation: Enhance libcxl memdev API
documentation
In preparation for adding documentation for more objects, organize the
current into subsections and flesh out descriptions for the current APIs.
Link: https://lore.kernel.org/r/164298557771.3021641.14904324834528700206.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/copyright.txt | 2 +-
Documentation/cxl/lib/libcxl.txt | 111 +++++++++++++++++++++++++++----
2 files changed, 99 insertions(+), 14 deletions(-)
diff --git a/Documentation/copyright.txt b/Documentation/copyright.txt
index a9380e1..af9caf7 100644
--- a/Documentation/copyright.txt
+++ b/Documentation/copyright.txt
@@ -2,7 +2,7 @@
COPYRIGHT
---------
-Copyright (C) 2016 - 2020, Intel Corporation. License GPLv2: GNU GPL
+Copyright (C) 2016 - 2022, Intel Corporation. License GPLv2: GNU GPL
version 2 <http://gnu.org/licenses/gpl.html>. This is free software:
you are free to change and redistribute it. There is NO WARRANTY, to
the extent permitted by law.
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
index 2539369..c127326 100644
--- a/Documentation/cxl/lib/libcxl.txt
+++ b/Documentation/cxl/lib/libcxl.txt
@@ -20,27 +20,100 @@ libcxl provides interfaces to interact with CXL devices in Linux, using sysfs
interfaces for most kernel interactions, and the ioctl() interface for command
submission.
-The starting point for all library interfaces is a 'cxl_ctx' object, returned
-by linklibcxl:cxl_new[3]. CXL 'Type 3' memory devices are children of the
-cxl_ctx object, and can be iterated through using an iterator API.
+The starting point for all library interfaces is a 'cxl_ctx' object,
+returned by linklibcxl:cxl_new[3]. CXL 'Type 3' memory devices and other
+CXL device objects are descendants of the cxl_ctx object, and can be
+iterated via an object an iterator API of the form
+cxl_<object>_foreach(<parent object>, <object iterator>).
-Library level interfaces that are agnostic to any device, or a specific
-subclass of operations have the prefix 'cxl_'
+MEMDEVS
+-------
+The object representing a CXL memory expander (Type 3 device) is 'struct
+cxl_memdev'. Library interfaces related to these devices have the prefix
+'cxl_memdev_'. These interfaces are mostly associated with sysfs
+interactions (unless otherwise noted in their respective documentation
+sections). They are typically used to retrieve data published by the
+kernel, or to send data or trigger kernel operations for a given device.
-The object representing a CXL Type 3 device is 'cxl_memdev'. Library interfaces
-related to these devices have the prefix 'cxl_memdev_'. These interfaces are
-mostly associated with sysfs interactions (unless otherwise noted in their
-respective documentation pages). They are typically used to retrieve data
-published by the kernel, or to send data or trigger kernel operations for a
-given device.
+=== MEMDEV: Enumeration
+----
+struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx);
+struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev);
+struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev);
+
+#define cxl_memdev_foreach(ctx, memdev) \
+ for (memdev = cxl_memdev_get_first(ctx); \
+ memdev != NULL; \
+ memdev = cxl_memdev_get_next(memdev))
+
+----
+
+CXL memdev instances are enumerated from the global library context
+'struct cxl_ctx'. By default a memdev only offers a portal to submit
+memory device commands, see the port, decoder, and endpoint APIs to
+determine what if any CXL Memory Resources are reachable given a
+specific memdev.
+
+=== MEMDEV: Attributes
+----
+int cxl_memdev_get_id(struct cxl_memdev *memdev);
+unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev);
+const char *cxl_memdev_get_devname(struct cxl_memdev *memdev);
+int cxl_memdev_get_major(struct cxl_memdev *memdev);
+int cxl_memdev_get_minor(struct cxl_memdev *memdev);
+unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev);
+unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev);
+const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);
+size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev);
+int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev);
+----
+
+A memdev is given a kernel device name of the form "mem%d" where an id
+(cxl_memdev_get_id()) is dynamically allocated as devices are
+discovered. Note that there are no guarantees that ids / kernel device
+names for memdevs are stable from one boot to the next, devices are
+enumerated asynchronously. If a stable identifier is use
+cxl_memdev_get_serial() which returns a value according to the 'Device
+Serial Number Extended Capability' in the PCIe 5.0 Base Specification.
+
+The character device node for command submission can be found by default
+at /dev/cxl/mem%d, or created with a major / minor returned from
+cxl_memdev_get_{major,minor}().
+
+The 'pmem_size' and 'ram_size' attributes return the current
+provisioning of DPA (Device Physical Address / local capacity) in the
+device.
+
+=== MEMDEV: Commands
+----
+struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);
+struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev);
+struct cxl_cmd *cxl_cmd_new_get_health_info(struct cxl_memdev *memdev);
+struct cxl_cmd *cxl_cmd_new_read_label(struct cxl_memdev *memdev,
+ unsigned int offset, unsigned int length);
+struct cxl_cmd *cxl_cmd_new_write_label(struct cxl_memdev *memdev, void *buf,
+ unsigned int offset, unsigned int length);
+int cxl_memdev_zero_label(struct cxl_memdev *memdev, size_t length,
+ size_t offset);
+int cxl_memdev_read_label(struct cxl_memdev *memdev, void *buf, size_t length,
+ size_t offset);
+int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf, size_t length,
+ size_t offset);
+
+----
A 'cxl_cmd' is a reference counted object which is used to perform 'Mailbox'
commands as described in the CXL Specification. A 'cxl_cmd' object is tied to a
'cxl_memdev'. Associated library interfaces have the prefix 'cxl_cmd_'. Within
this sub-class of interfaces, there are:
- * 'cxl_cmd_new_*' interfaces that allocate a new cxl_cmd object for a given
- command type.
+ * 'cxl_cmd_new_*()' interfaces that allocate a new cxl_cmd object for a given
+ command type targeted at a given memdev. As part of the command
+ instantiation process the library validates that the command is
+ supported by the memory device, otherwise it returns NULL to indicate
+ 'no support'. The libcxl command id is translated by the kernel into
+ a CXL standard opcode. See the potential command ids in
+ /usr/include/linux/cxl_mem.h.
* 'cxl_cmd_submit' which submits the command via ioctl()
@@ -49,6 +122,18 @@ this sub-class of interfaces, there are:
* 'cxl_cmd_get_*' interfaces to get general command related information.
+cxl_cmd_new_raw() supports so called 'RAW' commands where the command id
+is 'RAW' and it carries an unmodified CXL memory device command payload
+associated with the 'opcode' argument. Given the kernel does minimal
+input validation on these commands typically raw commands are not
+supported by the kernel outside debug build scenarios. libcxl is limited
+to supporting commands that appear in the CXL standard / public
+specifications.
+
+cxl_memdev{read,write,zero}_label() are helpers for marshaling multiple
+label access commands over an arbitrary extent of the device's label
+area.
+
include::../../copyright.txt[]
SEE ALSO
--
2.27.0

View File

@ -0,0 +1,739 @@
From 9dce91c303720a336c55ecdc2e01e423589b85b2 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:53:02 -0800
Subject: [PATCH 100/217] cxl/list: Add bus objects
A 'struct cxl_bus' represents a CXL.mem domain. It is the root of a
Host-managed Device Memory (HDM) hierarchy. When memory devices are enabled
for CXL operation they appear underneath a bus in a 'cxl list -BM' listing,
otherwise they display as disconnected.
A 'bus' is identical to the kernel's CXL root port object, but given the
confusion between CXL root ports, and PCIe root ports, the 'bus' name is
less ambiguous. It also serves a similar role in the object hierarchy as a
'struct ndctl_bus' object. It is also the case that the "root" name will
appear as the kernel device-name, so the association will be clear.
Link: https://lore.kernel.org/r/164298558278.3021641.16323855851736615358.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
.clang-format | 1 +
Documentation/cxl/cxl-list.txt | 88 ++++++++++++++++---
Documentation/cxl/lib/libcxl.txt | 30 +++++++
cxl/filter.c | 117 ++++++++++++++++++++++++-
cxl/filter.h | 2 +
cxl/json.c | 21 +++++
cxl/json.h | 5 +-
cxl/lib/libcxl.c | 142 +++++++++++++++++++++++++++++++
cxl/lib/libcxl.sym | 5 ++
cxl/lib/private.h | 14 +++
cxl/libcxl.h | 11 +++
cxl/list.c | 19 +++--
12 files changed, 431 insertions(+), 24 deletions(-)
diff --git a/.clang-format b/.clang-format
index d2e77d0..1154c76 100644
--- a/.clang-format
+++ b/.clang-format
@@ -78,6 +78,7 @@ ExperimentalAutoDetectBinPacking: false
# | sort -u)
ForEachMacros:
- 'cxl_memdev_foreach'
+ - 'cxl_bus_foreach'
- 'daxctl_dev_foreach'
- 'daxctl_mapping_foreach'
- 'daxctl_region_foreach'
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
index 224c972..be131ae 100644
--- a/Documentation/cxl/cxl-list.txt
+++ b/Documentation/cxl/cxl-list.txt
@@ -15,17 +15,60 @@ SYNOPSIS
Walk the CXL capable device hierarchy in the system and list all device
instances along with some of their major attributes.
-Options can be specified to limit the output to specific objects.
+Options can be specified to limit the output to specific objects. When a
+single object type is specified the return json object is an array of
+just those objects, when multiple objects types are specified the
+returned the returned object may be an array of arrays with the inner
+array named for the given object type.
+
+Filters can by specifed as either a single identidier, a space separated
+quoted string, or a comma separated list. When multiple filter
+identifiers are specified within a filter string, like "-m
+mem0,mem1,mem2", they are combined as an 'OR' filter. When multiple
+filter string types are specified, like "-m mem0,mem1,mem2 -p port10",
+they are combined as an 'AND' filter. So, "-m mem0,mem1,mem2 -p port10"
+would only list objects that are beneath port10 AND map mem0, mem1, OR
+mem2.
+
+The --human option in addition to reformatting some fields to more human
+friendly strings also unwraps the array to reduce the number of lines of
+output.
EXAMPLE
-------
----
# cxl list --memdevs
-{
- "memdev":"mem0",
- "pmem_size":268435456,
- "ram_size":0,
-}
+[
+ {
+ "memdev":"mem0",
+ "pmem_size":268435456,
+ "ram_size":0,
+ "serial":0
+ }
+]
+
+# cxl list -BMu
+[
+ {
+ "anon memdevs":[
+ {
+ "memdev":"mem0",
+ "pmem_size":"256.00 MiB (268.44 MB)",
+ "ram_size":0,
+ "serial":"0"
+ }
+ ]
+ },
+ {
+ "buses":[
+ {
+ "bus":"root0",
+ "provider":"ACPI.CXL"
+ }
+ ]
+ }
+]
+
----
OPTIONS
@@ -34,13 +77,6 @@ OPTIONS
--memdev=::
Specify CXL memory device name(s), or device id(s), to filter the listing. For example:
----
-# cxl list --memdev=mem0
-{
- "memdev":"mem0",
- "pmem_size":268435456,
- "ram_size":0,
-}
-
# cxl list -M --memdev="0 mem3 5"
[
{
@@ -114,6 +150,32 @@ OPTIONS
]
----
+-B::
+--buses::
+ Include 'bus' / CXL root object(s) in the listing. Typically, on ACPI
+ systems the bus object is a singleton associated with the ACPI0017
+ device, but there are test scenerios where there may be multiple CXL
+ memory hierarchies.
+----
+# cxl list -B
+[
+ {
+ "bus":"root3",
+ "provider":"cxl_test"
+ },
+ {
+ "bus":"root0",
+ "provider":"ACPI.CXL"
+ }
+]
+----
+
+-b::
+--bus=::
+ Specify CXL root device name(s), device id(s), and / or CXL bus provider
+ names to filter the listing. The supported provider names are "ACPI.CXL"
+ and "cxl_test".
+
include::human-option.txt[]
include::verbose-option.txt[]
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
index c127326..84af66a 100644
--- a/Documentation/cxl/lib/libcxl.txt
+++ b/Documentation/cxl/lib/libcxl.txt
@@ -134,6 +134,36 @@ cxl_memdev{read,write,zero}_label() are helpers for marshaling multiple
label access commands over an arbitrary extent of the device's label
area.
+BUSES
+-----
+The CXL Memory space is CPU and Device coherent. The address ranges that
+support coherent access are described by platform firmware and
+communicated to the operating system via a CXL root object 'struct
+cxl_bus'.
+
+=== BUS: Enumeration
+----
+struct cxl_bus *cxl_bus_get_first(struct cxl_ctx *ctx);
+struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus);
+
+#define cxl_bus_foreach(ctx, bus) \
+ for (bus = cxl_bus_get_first(ctx); bus != NULL; \
+ bus = cxl_bus_get_next(bus))
+----
+
+=== BUS: Attributes
+----
+const char *cxl_bus_get_provider(struct cxl_bus *bus);
+const char *cxl_bus_get_devname(struct cxl_bus *bus);
+int cxl_bus_get_id(struct cxl_bus *bus);
+----
+
+The provider name of a bus is a persistent name that is independent of
+discovery order. The possible provider names are 'ACPI.CXL' and
+'cxl_test'. The devname and id attributes, like other objects, are just
+the kernel device names that are subject to change based on discovery
+order.
+
include::../../copyright.txt[]
SEE ALSO
diff --git a/cxl/filter.c b/cxl/filter.c
index 26efc65..5f4844b 100644
--- a/cxl/filter.c
+++ b/cxl/filter.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
+// Copyright (C) 2015-2022 Intel Corporation. All rights reserved.
#include <errno.h>
#include <stdio.h>
#include <string.h>
@@ -21,6 +21,43 @@ static const char *which_sep(const char *filter)
return " ";
}
+static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus,
+ const char *__ident)
+{
+ char *ident, *save;
+ const char *arg;
+ int bus_id;
+
+ if (!__ident)
+ return bus;
+
+ ident = strdup(__ident);
+ if (!ident)
+ return NULL;
+
+ for (arg = strtok_r(ident, which_sep(__ident), &save); arg;
+ arg = strtok_r(NULL, which_sep(__ident), &save)) {
+ if (strcmp(arg, "all") == 0)
+ break;
+
+ if ((sscanf(arg, "%d", &bus_id) == 1 ||
+ sscanf(arg, "root%d", &bus_id) == 1) &&
+ cxl_bus_get_id(bus) == bus_id)
+ break;
+
+ if (strcmp(arg, cxl_bus_get_devname(bus)) == 0)
+ break;
+
+ if (strcmp(arg, cxl_bus_get_provider(bus)) == 0)
+ break;
+ }
+
+ free(ident);
+ if (arg)
+ return bus;
+ return NULL;
+}
+
static struct cxl_memdev *
util_cxl_memdev_serial_filter(struct cxl_memdev *memdev, const char *__serials)
{
@@ -98,21 +135,67 @@ static unsigned long params_to_flags(struct cxl_filter_params *param)
return flags;
}
+static void splice_array(struct cxl_filter_params *p, struct json_object *jobjs,
+ struct json_object *platform,
+ const char *container_name, bool do_container)
+{
+ size_t count;
+
+ if (!json_object_array_length(jobjs)) {
+ json_object_put(jobjs);
+ return;
+ }
+
+ if (do_container) {
+ struct json_object *container = json_object_new_object();
+
+ if (!container) {
+ err(p, "failed to list: %s\n", container_name);
+ return;
+ }
+
+ json_object_object_add(container, container_name, jobjs);
+ json_object_array_add(platform, container);
+ return;
+ }
+
+ for (count = json_object_array_length(jobjs); count; count--) {
+ struct json_object *jobj = json_object_array_get_idx(jobjs, 0);
+
+ json_object_get(jobj);
+ json_object_array_del_idx(jobjs, 0, 1);
+ json_object_array_add(platform, jobj);
+ }
+ json_object_put(jobjs);
+}
+
int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
{
struct json_object *jplatform = json_object_new_array();
+ struct json_object *jdevs = NULL, *jbuses = NULL;
unsigned long flags = params_to_flags(p);
struct cxl_memdev *memdev;
+ int top_level_objs = 0;
+ struct cxl_bus *bus;
if (!jplatform) {
dbg(p, "platform object allocation failure\n");
return -ENOMEM;
}
+ jdevs = json_object_new_array();
+ if (!jdevs)
+ goto err;
+
+ jbuses = json_object_new_array();
+ if (!jbuses)
+ goto err;
+
cxl_memdev_foreach(ctx, memdev) {
struct json_object *jdev;
- if (!util_cxl_memdev_filter(memdev, p->memdev_filter, p->serial_filter))
+ if (!util_cxl_memdev_filter(memdev, p->memdev_filter,
+ p->serial_filter))
continue;
if (p->memdevs) {
jdev = util_cxl_memdev_to_json(memdev, flags);
@@ -120,11 +203,39 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
dbg(p, "memdev object allocation failure\n");
continue;
}
- json_object_array_add(jplatform, jdev);
+ json_object_array_add(jdevs, jdev);
+ }
+ }
+
+ cxl_bus_foreach(ctx, bus) {
+ struct json_object *jbus;
+
+ if (!util_cxl_bus_filter(bus, p->bus_filter))
+ continue;
+ if (p->buses) {
+ jbus = util_cxl_bus_to_json(bus, flags);
+ if (!jbus) {
+ dbg(p, "bus object allocation failure\n");
+ continue;
+ }
+ json_object_array_add(jbuses, jbus);
}
}
+ if (json_object_array_length(jdevs))
+ top_level_objs++;
+ if (json_object_array_length(jbuses))
+ top_level_objs++;
+
+ splice_array(p, jdevs, jplatform, "anon memdevs", top_level_objs > 1);
+ splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1);
+
util_display_json_array(stdout, jplatform, flags);
return 0;
+err:
+ json_object_put(jdevs);
+ json_object_put(jbuses);
+ json_object_put(jplatform);
+ return -ENOMEM;
}
diff --git a/cxl/filter.h b/cxl/filter.h
index 12d9344..d41e757 100644
--- a/cxl/filter.h
+++ b/cxl/filter.h
@@ -9,7 +9,9 @@
struct cxl_filter_params {
const char *memdev_filter;
const char *serial_filter;
+ const char *bus_filter;
bool memdevs;
+ bool buses;
bool idle;
bool human;
bool health;
diff --git a/cxl/json.c b/cxl/json.c
index d8e65df..a584594 100644
--- a/cxl/json.c
+++ b/cxl/json.c
@@ -221,3 +221,24 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
}
return jdev;
}
+
+struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,
+ unsigned long flags)
+{
+ const char *devname = cxl_bus_get_devname(bus);
+ struct json_object *jbus, *jobj;
+
+ jbus = json_object_new_object();
+ if (!jbus)
+ return NULL;
+
+ jobj = json_object_new_string(devname);
+ if (jobj)
+ json_object_object_add(jbus, "bus", jobj);
+
+ jobj = json_object_new_string(cxl_bus_get_provider(bus));
+ if (jobj)
+ json_object_object_add(jbus, "provider", jobj);
+
+ return jbus;
+}
diff --git a/cxl/json.h b/cxl/json.h
index 3abcfe6..4abf6e5 100644
--- a/cxl/json.h
+++ b/cxl/json.h
@@ -1,8 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */
+/* Copyright (C) 2015-2022 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);
+struct cxl_bus;
+struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,
+ unsigned long flags);
#endif /* __CXL_UTIL_JSON_H__ */
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 9839f26..8548a45 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -40,7 +40,9 @@ struct cxl_ctx {
int refcount;
void *userdata;
int memdevs_init;
+ int buses_init;
struct list_head memdevs;
+ struct list_head buses;
struct kmod_ctx *kmod_ctx;
void *private_data;
};
@@ -64,6 +66,21 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)
free(memdev);
}
+static void __free_port(struct cxl_port *port, struct list_head *head)
+{
+ if (head)
+ list_del_from(head, &port->list);
+ free(port->dev_buf);
+ free(port->dev_path);
+ free(port->uport);
+}
+
+static void free_bus(struct cxl_bus *bus, struct list_head *head)
+{
+ __free_port(&bus->port, head);
+ free(bus);
+}
+
/**
* cxl_get_userdata - retrieve stored data pointer from library context
* @ctx: cxl library context
@@ -130,6 +147,7 @@ CXL_EXPORT int cxl_new(struct cxl_ctx **ctx)
dbg(c, "log_priority=%d\n", c->ctx.log_priority);
*ctx = c;
list_head_init(&c->memdevs);
+ list_head_init(&c->buses);
c->kmod_ctx = kmod_ctx;
return 0;
@@ -160,6 +178,7 @@ CXL_EXPORT struct cxl_ctx *cxl_ref(struct cxl_ctx *ctx)
CXL_EXPORT void cxl_unref(struct cxl_ctx *ctx)
{
struct cxl_memdev *memdev, *_d;
+ struct cxl_bus *bus, *_b;
if (ctx == NULL)
return;
@@ -170,6 +189,9 @@ CXL_EXPORT void cxl_unref(struct cxl_ctx *ctx)
list_for_each_safe(&ctx->memdevs, memdev, _d, list)
free_memdev(memdev, &ctx->memdevs);
+ list_for_each_safe(&ctx->buses, bus, _b, port.list)
+ free_bus(bus, &ctx->buses);
+
kmod_unref(ctx->kmod_ctx);
info(ctx, "context %p released\n", ctx);
free(ctx);
@@ -449,6 +471,126 @@ CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev)
return is_enabled(path);
}
+static int cxl_port_init(struct cxl_port *port, struct cxl_ctx *ctx, int id,
+ const char *cxlport_base)
+{
+ char *path = calloc(1, strlen(cxlport_base) + 100);
+ size_t rc;
+
+ if (!path)
+ return -ENOMEM;
+
+ port->id = id;
+ port->ctx = ctx;
+
+ port->dev_path = strdup(cxlport_base);
+ if (!port->dev_path)
+ goto err;
+
+ port->dev_buf = calloc(1, strlen(cxlport_base) + 50);
+ if (!port->dev_buf)
+ goto err;
+ port->buf_len = strlen(cxlport_base) + 50;
+
+ rc = snprintf(port->dev_buf, port->buf_len, "%s/uport", cxlport_base);
+ if (rc >= port->buf_len)
+ goto err;
+ port->uport = realpath(port->dev_buf, NULL);
+ if (!port->uport)
+ goto err;
+
+ return 0;
+err:
+ free(port->dev_path);
+ free(port->dev_buf);
+ free(path);
+ return -ENOMEM;
+}
+
+static void *add_cxl_bus(void *parent, int id, const char *cxlbus_base)
+{
+ const char *devname = devpath_to_devname(cxlbus_base);
+ struct cxl_bus *bus, *bus_dup;
+ struct cxl_ctx *ctx = parent;
+ struct cxl_port *port;
+ int rc;
+
+ dbg(ctx, "%s: base: \'%s\'\n", devname, cxlbus_base);
+
+ bus = calloc(1, sizeof(*bus));
+ if (!bus)
+ return NULL;
+
+ port = &bus->port;
+ rc = cxl_port_init(port, ctx, id, cxlbus_base);
+ if (rc)
+ goto err;
+
+ cxl_bus_foreach(ctx, bus_dup)
+ if (bus_dup->port.id == bus->port.id) {
+ free_bus(bus, NULL);
+ return bus_dup;
+ }
+
+ list_add(&ctx->buses, &port->list);
+ return bus;
+
+err:
+ free(bus);
+ return NULL;
+}
+
+static void cxl_buses_init(struct cxl_ctx *ctx)
+{
+ if (ctx->buses_init)
+ return;
+
+ ctx->buses_init = 1;
+
+ sysfs_device_parse(ctx, "/sys/bus/cxl/devices", "root", ctx,
+ add_cxl_bus);
+}
+
+CXL_EXPORT struct cxl_bus *cxl_bus_get_first(struct cxl_ctx *ctx)
+{
+ cxl_buses_init(ctx);
+
+ return list_top(&ctx->buses, struct cxl_bus, port.list);
+}
+
+CXL_EXPORT struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus)
+{
+ struct cxl_ctx *ctx = bus->port.ctx;
+
+ return list_next(&ctx->buses, bus, port.list);
+}
+
+CXL_EXPORT const char *cxl_bus_get_devname(struct cxl_bus *bus)
+{
+ struct cxl_port *port = &bus->port;
+
+ return devpath_to_devname(port->dev_path);
+}
+
+CXL_EXPORT int cxl_bus_get_id(struct cxl_bus *bus)
+{
+ struct cxl_port *port = &bus->port;
+
+ return port->id;
+}
+
+CXL_EXPORT const char *cxl_bus_get_provider(struct cxl_bus *bus)
+{
+ struct cxl_port *port = &bus->port;
+ const char *devname = devpath_to_devname(port->uport);
+
+ if (strcmp(devname, "ACPI0017:00") == 0)
+ return "ACPI.CXL";
+ if (strcmp(devname, "cxl_acpi.0") == 0)
+ return "cxl_test";
+ return devname;
+}
+
CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd)
{
if (!cmd)
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 4411035..781ff99 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -77,4 +77,9 @@ local:
LIBCXL_2 {
global:
cxl_memdev_get_serial;
+ cxl_bus_get_first;
+ cxl_bus_get_next;
+ cxl_bus_get_provider;
+ cxl_bus_get_devname;
+ cxl_bus_get_id;
} LIBCXL_1;
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index 7c81e24..0758d05 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -34,6 +34,20 @@ struct cxl_memdev {
unsigned long long serial;
};
+struct cxl_port {
+ int id;
+ void *dev_buf;
+ size_t buf_len;
+ char *dev_path;
+ char *uport;
+ struct cxl_ctx *ctx;
+ struct list_node list;
+};
+
+struct cxl_bus {
+ struct cxl_port port;
+};
+
enum cxl_cmd_query_status {
CXL_CMD_QUERY_NOT_RUN = 0,
CXL_CMD_QUERY_OK,
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index bcdede8..da66eb2 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -57,6 +57,17 @@ int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf, size_t length,
memdev != NULL; \
memdev = cxl_memdev_get_next(memdev))
+struct cxl_bus;
+struct cxl_bus *cxl_bus_get_first(struct cxl_ctx *ctx);
+struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus);
+const char *cxl_bus_get_provider(struct cxl_bus *bus);
+const char *cxl_bus_get_devname(struct cxl_bus *bus);
+int cxl_bus_get_id(struct cxl_bus *bus);
+
+#define cxl_bus_foreach(ctx, bus) \
+ for (bus = cxl_bus_get_first(ctx); bus != NULL; \
+ bus = cxl_bus_get_next(bus))
+
struct cxl_cmd;
const char *cxl_cmd_get_devname(struct cxl_cmd *cmd);
struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);
diff --git a/cxl/list.c b/cxl/list.c
index 7e2744d..9500e61 100644
--- a/cxl/list.c
+++ b/cxl/list.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/* Copyright (C) 2020-2021 Intel Corporation. All rights reserved. */
+/* Copyright (C) 2020-2022 Intel Corporation. All rights reserved. */
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
@@ -14,11 +14,6 @@
static struct cxl_filter_params param;
-static int num_list_flags(void)
-{
- return param.memdevs;
-}
-
static const struct option options[] = {
OPT_STRING('m', "memdev", &param.memdev_filter, "memory device name(s)",
"filter by CXL memory device name(s)"),
@@ -27,6 +22,9 @@ static const struct option options[] = {
"filter by CXL memory device serial number(s)"),
OPT_BOOLEAN('M', "memdevs", &param.memdevs,
"include CXL memory device info"),
+ OPT_STRING('b', "bus", &param.bus_filter, "bus device name",
+ "filter by CXL bus device name(s)"),
+ OPT_BOOLEAN('B', "buses", &param.buses, "include CXL bus info"),
OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),
OPT_BOOLEAN('u', "human", &param.human,
"use human friendly number formats "),
@@ -35,6 +33,11 @@ static const struct option options[] = {
OPT_END(),
};
+static int num_list_flags(void)
+{
+ return !!param.memdevs + !!param.buses;
+}
+
int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
{
const char * const u[] = {
@@ -53,7 +56,9 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
if (num_list_flags() == 0) {
if (param.memdev_filter || param.serial_filter)
param.memdevs = true;
- else {
+ if (param.bus_filter)
+ param.buses = true;
+ if (num_list_flags() == 0) {
/*
* TODO: We likely want to list regions by default if
* nothing was explicitly asked for. But until we have
--
2.27.0

View File

@ -0,0 +1,44 @@
From 91f78bbcda7fc644041dfabfa679c6a627f90e76 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:53:08 -0800
Subject: [PATCH 101/217] util/json: Warn on stderr about empty list results
Help interactive users notice something is wrong with the list parameters
by warning that no devices matched the specified filter settings.
Link: https://lore.kernel.org/r/164298558814.3021641.13051269428355986099.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
util/json.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/util/json.c b/util/json.c
index bd5f8fc..f8cc81f 100644
--- a/util/json.c
+++ b/util/json.c
@@ -3,6 +3,7 @@
#include <limits.h>
#include <string.h>
#include <stdio.h>
+#include <util/util.h>
#include <util/json.h>
#include <json-c/json.h>
#include <json-c/printbuf.h>
@@ -95,9 +96,11 @@ void util_display_json_array(FILE *f_out, struct json_object *jarray,
int len = json_object_array_length(jarray);
int jflag = JSON_C_TO_STRING_PRETTY;
- if (json_object_array_length(jarray) > 1 || !(flags & UTIL_JSON_HUMAN))
+ if (len > 1 || !(flags & UTIL_JSON_HUMAN)) {
+ if (len == 0)
+ warning("no matching devices found\n");
fprintf(f_out, "%s\n", json_object_to_json_string_ext(jarray, jflag));
- else if (len) {
+ } else if (len) {
struct json_object *jobj;
jobj = json_object_array_get_idx(jarray, 0);
--
2.27.0

View File

@ -0,0 +1,165 @@
From ecd7e6e7aabfa2592f3f739a725d135eb43d6314 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:53:13 -0800
Subject: [PATCH 102/217] util/sysfs: Uplevel modalias lookup helper to util/
The to_module() helper looks up modules relative to a modalias. Uplevel
this to share with libcxl.
Link: https://lore.kernel.org/r/164298559346.3021641.11059026790676662837.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
ndctl/lib/libndctl.c | 33 +++++----------------------------
util/sysfs.c | 27 +++++++++++++++++++++++++++
util/sysfs.h | 8 ++++++++
3 files changed, 40 insertions(+), 28 deletions(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 47a234c..1374ad9 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -1668,7 +1668,6 @@ static enum ndctl_fwa_result fwa_result_to_result(const char *result)
static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module,
const char *devname);
static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath);
-static struct kmod_module *to_module(struct ndctl_ctx *ctx, const char *alias);
static int populate_dimm_attributes(struct ndctl_dimm *dimm,
const char *dimm_base,
@@ -1878,7 +1877,7 @@ static void *add_dimm(void *parent, int id, const char *dimm_base)
sprintf(path, "%s/modalias", dimm_base);
if (sysfs_read_attr(ctx, path, buf) < 0)
goto err_read;
- dimm->module = to_module(ctx, buf);
+ dimm->module = util_modalias_to_module(ctx, buf);
dimm->handle = -1;
dimm->phys_id = -1;
@@ -2597,7 +2596,7 @@ static void *add_region(void *parent, int id, const char *region_base)
sprintf(path, "%s/modalias", region_base);
if (sysfs_read_attr(ctx, path, buf) < 0)
goto err_read;
- region->module = to_module(ctx, buf);
+ region->module = util_modalias_to_module(ctx, buf);
sprintf(path, "%s/numa_node", region_base);
if ((rc = sysfs_read_attr(ctx, path, buf)) == 0)
@@ -3885,28 +3884,6 @@ NDCTL_EXPORT struct ndctl_ctx *ndctl_mapping_get_ctx(
return ndctl_mapping_get_bus(mapping)->ctx;
}
-static struct kmod_module *to_module(struct ndctl_ctx *ctx, const char *alias)
-{
- struct kmod_list *list = NULL;
- struct kmod_module *mod;
- int rc;
-
- if (!ctx->kmod_ctx)
- return NULL;
-
- rc = kmod_module_new_from_lookup(ctx->kmod_ctx, alias, &list);
- if (rc < 0 || !list) {
- dbg(ctx, "failed to find module for alias: %s %d list: %s\n",
- alias, rc, list ? "populated" : "empty");
- return NULL;
- }
- mod = kmod_module_get_module(list);
- dbg(ctx, "alias: %s module: %s\n", alias, kmod_module_get_name(mod));
- kmod_module_unref_list(list);
-
- return mod;
-}
-
static char *get_block_device(struct ndctl_ctx *ctx, const char *block_path)
{
char *bdev_name = NULL;
@@ -4069,7 +4046,7 @@ static void *add_namespace(void *parent, int id, const char *ndns_base)
sprintf(path, "%s/modalias", ndns_base);
if (sysfs_read_attr(ctx, path, buf) < 0)
goto err_read;
- ndns->module = to_module(ctx, buf);
+ ndns->module = util_modalias_to_module(ctx, buf);
ndctl_namespace_foreach(region, ndns_dup)
if (ndns_dup->id == ndns->id) {
@@ -5182,7 +5159,7 @@ static void *add_btt(void *parent, int id, const char *btt_base)
sprintf(path, "%s/modalias", btt_base);
if (sysfs_read_attr(ctx, path, buf) < 0)
goto err_read;
- btt->module = to_module(ctx, buf);
+ btt->module = util_modalias_to_module(ctx, buf);
sprintf(path, "%s/uuid", btt_base);
if (sysfs_read_attr(ctx, path, buf) < 0)
@@ -5533,7 +5510,7 @@ static void *__add_pfn(struct ndctl_pfn *pfn, const char *pfn_base)
sprintf(path, "%s/modalias", pfn_base);
if (sysfs_read_attr(ctx, path, buf) < 0)
goto err_read;
- pfn->module = to_module(ctx, buf);
+ pfn->module = util_modalias_to_module(ctx, buf);
sprintf(path, "%s/uuid", pfn_base);
if (sysfs_read_attr(ctx, path, buf) < 0)
diff --git a/util/sysfs.c b/util/sysfs.c
index cfbab7d..23330cb 100644
--- a/util/sysfs.c
+++ b/util/sysfs.c
@@ -10,6 +10,7 @@
#include <ctype.h>
#include <fcntl.h>
#include <dirent.h>
+#include <libkmod.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
@@ -118,3 +119,29 @@ int __sysfs_device_parse(struct log_ctx *ctx, const char *base_path,
return add_errors;
}
+
+struct kmod_module *__util_modalias_to_module(struct kmod_ctx *kmod_ctx,
+ const char *alias,
+ struct log_ctx *log)
+{
+ struct kmod_list *list = NULL;
+ struct kmod_module *mod;
+ int rc;
+
+ if (!kmod_ctx)
+ return NULL;
+
+ rc = kmod_module_new_from_lookup(kmod_ctx, alias, &list);
+ if (rc < 0 || !list) {
+ log_dbg(log,
+ "failed to find module for alias: %s %d list: %s\n",
+ alias, rc, list ? "populated" : "empty");
+ return NULL;
+ }
+ mod = kmod_module_get_module(list);
+ log_dbg(log, "alias: %s module: %s\n", alias,
+ kmod_module_get_name(mod));
+ kmod_module_unref_list(list);
+
+ return mod;
+}
diff --git a/util/sysfs.h b/util/sysfs.h
index 6485a73..bdee4f5 100644
--- a/util/sysfs.h
+++ b/util/sysfs.h
@@ -27,4 +27,12 @@ static inline const char *devpath_to_devname(const char *devpath)
{
return strrchr(devpath, '/') + 1;
}
+
+struct kmod_ctx;
+struct kmod_module;
+struct kmod_module *__util_modalias_to_module(struct kmod_ctx *kmod_ctx,
+ const char *alias,
+ struct log_ctx *log);
+#define util_modalias_to_module(ctx, buf) \
+ __util_modalias_to_module((ctx)->kmod_ctx, buf, &(ctx)->ctx)
#endif /* __UTIL_SYSFS_H__ */
--
2.27.0

View File

@ -0,0 +1,862 @@
From fef3f05ca8cdfd8d783162042d5cf20325c8b64b Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:53:18 -0800
Subject: [PATCH 103/217] cxl/list: Add port enumeration
Between a cxl_bus (root port) and an endpoint there can be an arbitrary
level of switches. Add enumeration for these ports at each level of the
hierarchy.
However, given the CXL root ports are also "ports" infer that if the port
filter argument is the word "root" or "root%d" then include root ports in
the listing. The keyword "switch" is also provided to filter only the ports
beneath the root that are not endpoint ports.
Link: https://lore.kernel.org/r/164298559854.3021641.17724828997703051001.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
.clang-format | 1 +
Documentation/cxl/cxl-list.txt | 24 ++++
Documentation/cxl/lib/libcxl.txt | 42 ++++++
cxl/filter.c | 224 ++++++++++++++++++++++++++++++-
cxl/filter.h | 4 +
cxl/json.c | 23 ++++
cxl/json.h | 3 +
cxl/lib/libcxl.c | 160 +++++++++++++++++++++-
cxl/lib/libcxl.sym | 12 ++
cxl/lib/private.h | 11 ++
cxl/libcxl.h | 19 +++
cxl/list.c | 17 ++-
12 files changed, 534 insertions(+), 6 deletions(-)
diff --git a/.clang-format b/.clang-format
index 1154c76..391cd34 100644
--- a/.clang-format
+++ b/.clang-format
@@ -79,6 +79,7 @@ ExperimentalAutoDetectBinPacking: false
ForEachMacros:
- 'cxl_memdev_foreach'
- 'cxl_bus_foreach'
+ - 'cxl_port_foreach'
- 'daxctl_dev_foreach'
- 'daxctl_mapping_foreach'
- 'daxctl_region_foreach'
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
index be131ae..3076deb 100644
--- a/Documentation/cxl/cxl-list.txt
+++ b/Documentation/cxl/cxl-list.txt
@@ -176,6 +176,30 @@ OPTIONS
names to filter the listing. The supported provider names are "ACPI.CXL"
and "cxl_test".
+-P::
+--ports::
+ Include port objects (CXL / PCIe root ports + Upstream Switch Ports) in
+ the listing.
+
+-p::
+--port=::
+ Specify CXL Port device name(s), device id(s), and or port type
+ names to filter the listing. The supported port type names are "root"
+ and "switch". Note that since a bus object is also a port, the following
+ two syntaxes are equivalent:
+----
+# cxl list -B
+# cxl list -P -p root
+----
+ By default, only 'switch' ports are listed.
+
+-S::
+--single::
+ Specify whether the listing should emit all the objects that are
+ descendants of a port that matches the port filter, or only direct
+ descendants of the individual ports that match the filter. By default
+ all descendant objects are listed.
+
include::human-option.txt[]
include::verbose-option.txt[]
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
index 84af66a..804e9ca 100644
--- a/Documentation/cxl/lib/libcxl.txt
+++ b/Documentation/cxl/lib/libcxl.txt
@@ -164,6 +164,48 @@ discovery order. The possible provider names are 'ACPI.CXL' and
the kernel device names that are subject to change based on discovery
order.
+PORTS
+-----
+CXL ports track the PCIe hierarchy between a platform firmware CXL root
+object, through CXL / PCIe Host Bridges, CXL / PCIe Root Ports, and CXL
+/ PCIe Switch Ports.
+
+=== PORT: Enumeration
+----
+struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus);
+struct cxl_port *cxl_port_get_first(struct cxl_port *parent);
+struct cxl_port *cxl_port_get_next(struct cxl_port *port);
+struct cxl_port *cxl_port_get_parent(struct cxl_port *port);
+struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);
+struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port);
+
+#define cxl_port_foreach(parent, port) \
+ for (port = cxl_port_get_first(parent); port != NULL; \
+ port = cxl_port_get_next(port))
+----
+A bus object encapsulates a CXL port object. Use cxl_bus_get_port() to
+use generic port APIs on root objects.
+
+Ports are hierarchical. All but the a root object have another CXL port
+as a parent object retrievable via cxl_port_get_parent().
+
+The root port of a hiearchy can be retrieved via any port instance in
+that hierarchy via cxl_port_get_bus().
+
+=== PORT: Attributes
+----
+const char *cxl_port_get_devname(struct cxl_port *port);
+int cxl_port_get_id(struct cxl_port *port);
+int cxl_port_is_enabled(struct cxl_port *port);
+bool cxl_port_is_root(struct cxl_port *port);
+bool cxl_port_is_switch(struct cxl_port *port);
+----
+The port type is communicated via cxl_port_is_<type>(). An 'enabled' port
+is one that has succeeded in discovering the CXL component registers in
+the host device and has enumerated its downstream ports. In order for a
+memdev to be enabled for CXL memory operation all CXL ports in its
+ancestry must also be enabled.
+
include::../../copyright.txt[]
SEE ALSO
diff --git a/cxl/filter.c b/cxl/filter.c
index 5f4844b..8b79db3 100644
--- a/cxl/filter.c
+++ b/cxl/filter.c
@@ -21,6 +21,101 @@ static const char *which_sep(const char *filter)
return " ";
}
+bool cxl_filter_has(const char *__filter, const char *needle)
+{
+ char *filter, *save;
+ const char *arg;
+
+ if (!needle)
+ return true;
+
+ if (!__filter)
+ return false;
+
+ filter = strdup(__filter);
+ if (!filter)
+ return false;
+
+ for (arg = strtok_r(filter, which_sep(__filter), &save); arg;
+ arg = strtok_r(NULL, which_sep(__filter), &save))
+ if (strstr(arg, needle))
+ break;
+
+ free(filter);
+ if (arg)
+ return true;
+ return false;
+}
+
+static struct cxl_port *__util_cxl_port_filter(struct cxl_port *port,
+ const char *__ident)
+{
+ char *ident, *save;
+ const char *arg;
+ int port_id;
+
+ if (!__ident)
+ return port;
+
+ ident = strdup(__ident);
+ if (!ident)
+ return NULL;
+
+ for (arg = strtok_r(ident, which_sep(__ident), &save); arg;
+ arg = strtok_r(NULL, which_sep(__ident), &save)) {
+ if (strcmp(arg, "all") == 0)
+ break;
+
+ if (strcmp(arg, "root") == 0 && cxl_port_is_root(port))
+ break;
+
+ if (strcmp(arg, "switch") == 0 && cxl_port_is_switch(port))
+ break;
+
+ if ((sscanf(arg, "%d", &port_id) == 1 ||
+ sscanf(arg, "port%d", &port_id) == 1) &&
+ cxl_port_get_id(port) == port_id)
+ break;
+
+ if (strcmp(arg, cxl_port_get_devname(port)) == 0)
+ break;
+ }
+
+ free(ident);
+ if (arg)
+ return port;
+ return NULL;
+}
+
+enum cxl_port_filter_mode {
+ CXL_PF_SINGLE,
+ CXL_PF_ANCESTRY,
+};
+
+static enum cxl_port_filter_mode pf_mode(struct cxl_filter_params *p)
+{
+ if (p->single)
+ return CXL_PF_SINGLE;
+ return CXL_PF_ANCESTRY;
+}
+
+static struct cxl_port *util_cxl_port_filter(struct cxl_port *port,
+ const char *ident,
+ enum cxl_port_filter_mode mode)
+{
+ struct cxl_port *iter = port;
+
+ while (iter) {
+ if (__util_cxl_port_filter(iter, ident))
+ return port;
+ if (mode == CXL_PF_SINGLE)
+ return NULL;
+ iter = cxl_port_get_parent(iter);
+ }
+
+ return NULL;
+}
+
static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus,
const char *__ident)
{
@@ -58,6 +153,31 @@ static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus,
return NULL;
}
+static struct cxl_port *util_cxl_port_filter_by_bus(struct cxl_port *port,
+ const char *__ident)
+{
+ struct cxl_ctx *ctx = cxl_port_get_ctx(port);
+ struct cxl_bus *bus;
+
+ if (!__ident)
+ return port;
+
+ if (cxl_port_is_root(port)) {
+ bus = cxl_port_to_bus(port);
+ bus = util_cxl_bus_filter(bus, __ident);
+ return bus ? port : NULL;
+ }
+
+ cxl_bus_foreach(ctx, bus) {
+ if (!util_cxl_bus_filter(bus, __ident))
+ continue;
+ if (bus == cxl_port_get_bus(port))
+ return port;
+ }
+
+ return NULL;
+}
+
static struct cxl_memdev *
util_cxl_memdev_serial_filter(struct cxl_memdev *memdev, const char *__serials)
{
@@ -169,10 +289,82 @@ static void splice_array(struct cxl_filter_params *p, struct json_object *jobjs,
json_object_put(jobjs);
}
+static bool cond_add_put_array(struct json_object *jobj, const char *key,
+ struct json_object *array)
+{
+ if (jobj && array && json_object_array_length(array) > 0) {
+ json_object_object_add(jobj, key, array);
+ return true;
+ } else {
+ json_object_put(array);
+ return false;
+ }
+}
+
+static bool cond_add_put_array_suffix(struct json_object *jobj, const char *key,
+ const char *suffix,
+ struct json_object *array)
+{
+ char *name;
+ bool rc;
+
+ if (asprintf(&name, "%s:%s", key, suffix) < 0)
+ return false;
+ rc = cond_add_put_array(jobj, name, array);
+ free(name);
+ return rc;
+}
+
+static struct json_object *pick_array(struct json_object *child,
+ struct json_object *container)
+{
+ if (child)
+ return child;
+ if (container)
+ return container;
+ return NULL;
+}
+
+static void walk_child_ports(struct cxl_port *parent_port,
+ struct cxl_filter_params *p,
+ struct json_object *jports,
+ unsigned long flags)
+{
+ struct cxl_port *port;
+
+ cxl_port_foreach(parent_port, port) {
+ const char *devname = cxl_port_get_devname(port);
+ struct json_object *jport = NULL;
+ struct json_object *jchildports = NULL;
+
+ if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p)))
+ goto walk_children;
+ if (!util_cxl_port_filter_by_bus(port, p->bus_filter))
+ goto walk_children;
+ if (!p->idle && !cxl_port_is_enabled(port))
+ continue;
+ if (p->ports)
+ jport = util_cxl_port_to_json(port, flags);
+ if (!jport)
+ continue;
+ json_object_array_add(jports, jport);
+ jchildports = json_object_new_array();
+ if (!jchildports) {
+ err(p, "%s: failed to enumerate child ports\n",
+ devname);
+ continue;
+ }
+walk_children:
+ walk_child_ports(port, p, pick_array(jchildports, jports),
+ flags);
+ cond_add_put_array_suffix(jport, "ports", devname, jchildports);
+ }
+}
+
int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
{
+ struct json_object *jdevs = NULL, *jbuses = NULL, *jports = NULL;
struct json_object *jplatform = json_object_new_array();
- struct json_object *jdevs = NULL, *jbuses = NULL;
unsigned long flags = params_to_flags(p);
struct cxl_memdev *memdev;
int top_level_objs = 0;
@@ -191,6 +383,10 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
if (!jbuses)
goto err;
+ jports = json_object_new_array();
+ if (!jports)
+ goto err;
+
cxl_memdev_foreach(ctx, memdev) {
struct json_object *jdev;
@@ -208,10 +404,15 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
}
cxl_bus_foreach(ctx, bus) {
- struct json_object *jbus;
+ struct json_object *jbus = NULL;
+ struct json_object *jchildports = NULL;
+ struct cxl_port *port = cxl_bus_get_port(bus);
+ const char *devname = cxl_bus_get_devname(bus);
if (!util_cxl_bus_filter(bus, p->bus_filter))
- continue;
+ goto walk_children;
+ if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p)))
+ goto walk_children;
if (p->buses) {
jbus = util_cxl_bus_to_json(bus, flags);
if (!jbus) {
@@ -219,16 +420,32 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
continue;
}
json_object_array_add(jbuses, jbus);
+ if (p->ports) {
+ jchildports = json_object_new_array();
+ if (!jchildports) {
+ err(p,
+ "%s: failed to enumerate child ports\n",
+ devname);
+ continue;
+ }
+ }
}
+walk_children:
+ walk_child_ports(port, p, pick_array(jchildports, jports),
+ flags);
+ cond_add_put_array_suffix(jbus, "ports", devname, jchildports);
}
if (json_object_array_length(jdevs))
top_level_objs++;
if (json_object_array_length(jbuses))
top_level_objs++;
+ if (json_object_array_length(jports))
+ top_level_objs++;
splice_array(p, jdevs, jplatform, "anon memdevs", top_level_objs > 1);
splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1);
+ splice_array(p, jports, jplatform, "ports", top_level_objs > 1);
util_display_json_array(stdout, jplatform, flags);
@@ -236,6 +453,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
err:
json_object_put(jdevs);
json_object_put(jbuses);
+ json_object_put(jports);
json_object_put(jplatform);
return -ENOMEM;
}
diff --git a/cxl/filter.h b/cxl/filter.h
index d41e757..0d83304 100644
--- a/cxl/filter.h
+++ b/cxl/filter.h
@@ -10,7 +10,10 @@ struct cxl_filter_params {
const char *memdev_filter;
const char *serial_filter;
const char *bus_filter;
+ const char *port_filter;
+ bool single;
bool memdevs;
+ bool ports;
bool buses;
bool idle;
bool human;
@@ -22,4 +25,5 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
const char *__ident,
const char *serials);
int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param);
+bool cxl_filter_has(const char *needle, const char *__filter);
#endif /* _CXL_UTIL_FILTER_H_ */
diff --git a/cxl/json.c b/cxl/json.c
index a584594..d9f864e 100644
--- a/cxl/json.c
+++ b/cxl/json.c
@@ -242,3 +242,26 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,
return jbus;
}
+
+struct json_object *util_cxl_port_to_json(struct cxl_port *port,
+ unsigned long flags)
+{
+ const char *devname = cxl_port_get_devname(port);
+ struct json_object *jport, *jobj;
+
+ jport = json_object_new_object();
+ if (!jport)
+ return NULL;
+
+ jobj = json_object_new_string(devname);
+ if (jobj)
+ json_object_object_add(jport, "port", jobj);
+
+ if (!cxl_port_is_enabled(port)) {
+ jobj = json_object_new_string("disabled");
+ if (jobj)
+ json_object_object_add(jport, "state", jobj);
+ }
+
+ return jport;
+}
diff --git a/cxl/json.h b/cxl/json.h
index 4abf6e5..36653db 100644
--- a/cxl/json.h
+++ b/cxl/json.h
@@ -8,4 +8,7 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
struct cxl_bus;
struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,
unsigned long flags);
+struct cxl_port;
+struct json_object *util_cxl_port_to_json(struct cxl_port *port,
+ unsigned long flags);
#endif /* __CXL_UTIL_JSON_H__ */
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 8548a45..03eff3c 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -66,15 +66,27 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)
free(memdev);
}
+static void free_port(struct cxl_port *port, struct list_head *head);
static void __free_port(struct cxl_port *port, struct list_head *head)
{
+ struct cxl_port *child, *_c;
+
if (head)
list_del_from(head, &port->list);
+ list_for_each_safe(&port->child_ports, child, _c, list)
+ free_port(child, &port->child_ports);
+ kmod_module_unref(port->module);
free(port->dev_buf);
free(port->dev_path);
free(port->uport);
}
+static void free_port(struct cxl_port *port, struct list_head *head)
+{
+ __free_port(port, head);
+ free(port);
+}
+
static void free_bus(struct cxl_bus *bus, struct list_head *head)
{
__free_port(&bus->port, head);
@@ -471,10 +483,12 @@ CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev)
return is_enabled(path);
}
-static int cxl_port_init(struct cxl_port *port, struct cxl_ctx *ctx, int id,
+static int cxl_port_init(struct cxl_port *port, struct cxl_port *parent_port,
+ enum cxl_port_type type, struct cxl_ctx *ctx, int id,
const char *cxlport_base)
{
char *path = calloc(1, strlen(cxlport_base) + 100);
+ char buf[SYSFS_ATTR_SIZE];
size_t rc;
if (!path)
@@ -482,6 +496,10 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_ctx *ctx, int id,
port->id = id;
port->ctx = ctx;
+ port->type = type;
+ port->parent = parent_port;
+
+ list_head_init(&port->child_ports);
port->dev_path = strdup(cxlport_base);
if (!port->dev_path)
@@ -499,6 +517,10 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_ctx *ctx, int id,
if (!port->uport)
goto err;
+ sprintf(path, "%s/modalias", cxlport_base);
+ if (sysfs_read_attr(ctx, path, buf) == 0)
+ port->module = util_modalias_to_module(ctx, buf);
+
return 0;
err:
free(port->dev_path);
@@ -507,6 +529,135 @@ err:
return -ENOMEM;
}
+static void *add_cxl_port(void *parent, int id, const char *cxlport_base)
+{
+ const char *devname = devpath_to_devname(cxlport_base);
+ struct cxl_port *port, *port_dup;
+ struct cxl_port *parent_port = parent;
+ struct cxl_ctx *ctx = cxl_port_get_ctx(parent_port);
+ int rc;
+
+ dbg(ctx, "%s: base: \'%s\'\n", devname, cxlport_base);
+
+ port = calloc(1, sizeof(*port));
+ if (!port)
+ return NULL;
+
+ rc = cxl_port_init(port, parent_port, CXL_PORT_SWITCH, ctx, id,
+ cxlport_base);
+ if (rc)
+ goto err;
+
+ cxl_port_foreach(parent_port, port_dup)
+ if (port_dup->id == port->id) {
+ free_port(port, NULL);
+ return port_dup;
+ }
+
+ list_add(&parent_port->child_ports, &port->list);
+ return port;
+
+err:
+ free(port);
+ return NULL;
+
+}
+
+static void cxl_ports_init(struct cxl_port *port)
+{
+ struct cxl_ctx *ctx = cxl_port_get_ctx(port);
+
+ if (port->ports_init)
+ return;
+
+ port->ports_init = 1;
+
+ sysfs_device_parse(ctx, port->dev_path, "port", port, add_cxl_port);
+}
+
+CXL_EXPORT struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port)
+{
+ return port->ctx;
+}
+
+CXL_EXPORT struct cxl_port *cxl_port_get_first(struct cxl_port *port)
+{
+ cxl_ports_init(port);
+
+ return list_top(&port->child_ports, struct cxl_port, list);
+}
+
+CXL_EXPORT struct cxl_port *cxl_port_get_next(struct cxl_port *port)
+{
+ struct cxl_port *parent_port = port->parent;
+
+ return list_next(&parent_port->child_ports, port, list);
+}
+
+CXL_EXPORT const char *cxl_port_get_devname(struct cxl_port *port)
+{
+ return devpath_to_devname(port->dev_path);
+}
+
+CXL_EXPORT int cxl_port_get_id(struct cxl_port *port)
+{
+ return port->id;
+}
+
+CXL_EXPORT struct cxl_port *cxl_port_get_parent(struct cxl_port *port)
+{
+ return port->parent;
+}
+
+CXL_EXPORT bool cxl_port_is_root(struct cxl_port *port)
+{
+ return port->type == CXL_PORT_ROOT;
+}
+
+CXL_EXPORT bool cxl_port_is_switch(struct cxl_port *port)
+{
+ return port->type == CXL_PORT_SWITCH;
+}
+
+CXL_EXPORT struct cxl_bus *cxl_port_get_bus(struct cxl_port *port)
+{
+ struct cxl_bus *bus;
+
+ if (!cxl_port_is_enabled(port))
+ return NULL;
+
+ if (port->bus)
+ return port->bus;
+
+ while (port->parent)
+ port = port->parent;
+
+ bus = container_of(port, typeof(*bus), port);
+ port->bus = bus;
+ return bus;
+}
+
+CXL_EXPORT int cxl_port_is_enabled(struct cxl_port *port)
+{
+ struct cxl_ctx *ctx = cxl_port_get_ctx(port);
+ char *path = port->dev_buf;
+ int len = port->buf_len;
+
+ if (snprintf(path, len, "%s/driver", port->dev_path) >= len) {
+ err(ctx, "%s: buffer too small!\n", cxl_port_get_devname(port));
+ return 0;
+ }
+
+ return is_enabled(path);
+}
+
+CXL_EXPORT struct cxl_bus *cxl_port_to_bus(struct cxl_port *port)
+{
+ if (!cxl_port_is_root(port))
+ return NULL;
+ return container_of(port, struct cxl_bus, port);
+}
+
static void *add_cxl_bus(void *parent, int id, const char *cxlbus_base)
{
const char *devname = devpath_to_devname(cxlbus_base);
@@ -522,7 +673,7 @@ static void *add_cxl_bus(void *parent, int id, const char *cxlbus_base)
return NULL;
port = &bus->port;
- rc = cxl_port_init(port, ctx, id, cxlbus_base);
+ rc = cxl_port_init(port, NULL, CXL_PORT_ROOT, ctx, id, cxlbus_base);
if (rc)
goto err;
@@ -579,6 +730,11 @@ CXL_EXPORT int cxl_bus_get_id(struct cxl_bus *bus)
return port->id;
}
+CXL_EXPORT struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus)
+{
+ return &bus->port;
+}
+
CXL_EXPORT const char *cxl_bus_get_provider(struct cxl_bus *bus)
{
struct cxl_port *port = &bus->port;
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 781ff99..a7e923f 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -82,4 +82,16 @@ global:
cxl_bus_get_provider;
cxl_bus_get_devname;
cxl_bus_get_id;
+ cxl_bus_get_port;
+ cxl_port_get_first;
+ cxl_port_get_next;
+ cxl_port_get_devname;
+ cxl_port_get_id;
+ cxl_port_get_ctx;
+ cxl_port_is_enabled;
+ cxl_port_get_parent;
+ cxl_port_is_root;
+ cxl_port_is_switch;
+ cxl_port_to_bus;
+ cxl_port_get_bus;
} LIBCXL_1;
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index 0758d05..637f90d 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -34,14 +34,25 @@ struct cxl_memdev {
unsigned long long serial;
};
+enum cxl_port_type {
+ CXL_PORT_ROOT,
+ CXL_PORT_SWITCH,
+};
+
struct cxl_port {
int id;
void *dev_buf;
size_t buf_len;
char *dev_path;
char *uport;
+ int ports_init;
struct cxl_ctx *ctx;
+ struct cxl_bus *bus;
+ enum cxl_port_type type;
+ struct cxl_port *parent;
+ struct kmod_module *module;
struct list_node list;
+ struct list_head child_ports;
};
struct cxl_bus {
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index da66eb2..efbb397 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -5,6 +5,7 @@
#include <stdarg.h>
#include <unistd.h>
+#include <stdbool.h>
#ifdef HAVE_UUID
#include <uuid/uuid.h>
@@ -63,11 +64,29 @@ struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus);
const char *cxl_bus_get_provider(struct cxl_bus *bus);
const char *cxl_bus_get_devname(struct cxl_bus *bus);
int cxl_bus_get_id(struct cxl_bus *bus);
+struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus);
#define cxl_bus_foreach(ctx, bus) \
for (bus = cxl_bus_get_first(ctx); bus != NULL; \
bus = cxl_bus_get_next(bus))
+struct cxl_port;
+struct cxl_port *cxl_port_get_first(struct cxl_port *parent);
+struct cxl_port *cxl_port_get_next(struct cxl_port *port);
+const char *cxl_port_get_devname(struct cxl_port *port);
+int cxl_port_get_id(struct cxl_port *port);
+struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port);
+int cxl_port_is_enabled(struct cxl_port *port);
+struct cxl_port *cxl_port_get_parent(struct cxl_port *port);
+bool cxl_port_is_root(struct cxl_port *port);
+bool cxl_port_is_switch(struct cxl_port *port);
+struct cxl_bus *cxl_port_to_bus(struct cxl_port *port);
+struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);
+
+#define cxl_port_foreach(parent, port) \
+ for (port = cxl_port_get_first(parent); port != NULL; \
+ port = cxl_port_get_next(port))
+
struct cxl_cmd;
const char *cxl_cmd_get_devname(struct cxl_cmd *cmd);
struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);
diff --git a/cxl/list.c b/cxl/list.c
index 9500e61..1ef91b4 100644
--- a/cxl/list.c
+++ b/cxl/list.c
@@ -25,6 +25,11 @@ static const struct option options[] = {
OPT_STRING('b', "bus", &param.bus_filter, "bus device name",
"filter by CXL bus device name(s)"),
OPT_BOOLEAN('B', "buses", &param.buses, "include CXL bus info"),
+ OPT_STRING('p', "port", &param.port_filter, "port device name",
+ "filter by CXL port device name(s)"),
+ OPT_BOOLEAN('P', "ports", &param.ports, "include CXL port info"),
+ OPT_BOOLEAN('S', "single", &param.single,
+ "skip listing descendant objects"),
OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),
OPT_BOOLEAN('u', "human", &param.human,
"use human friendly number formats "),
@@ -35,7 +40,7 @@ static const struct option options[] = {
static int num_list_flags(void)
{
- return !!param.memdevs + !!param.buses;
+ return !!param.memdevs + !!param.buses + !!param.ports;
}
int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
@@ -53,11 +58,18 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
if (argc)
usage_with_options(u, options);
+ if (param.single && !param.port_filter) {
+ error("-S/--single expects a port filter: -p/--port=\n");
+ usage_with_options(u, options);
+ }
+
if (num_list_flags() == 0) {
if (param.memdev_filter || param.serial_filter)
param.memdevs = true;
if (param.bus_filter)
param.buses = true;
+ if (param.port_filter)
+ param.ports = true;
if (num_list_flags() == 0) {
/*
* TODO: We likely want to list regions by default if
@@ -73,5 +85,8 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
log_init(&param.ctx, "cxl list", "CXL_LIST_LOG");
+ if (cxl_filter_has(param.port_filter, "root") && param.ports)
+ param.buses = true;
+
return cxl_filter_walk(ctx, &param);
}
--
2.27.0

View File

@ -0,0 +1,103 @@
From 2a43dce3913b392a13a5ee918c8ee831a25d720e Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:53:24 -0800
Subject: [PATCH 104/217] cxl/list: Add --debug option
Add an option to turn on libray and cxl_filter_walk() messages. Gate it
based on the global ENABLE_DEBUG configuration setting.
Link: https://lore.kernel.org/r/164298560409.3021641.11040422738199381922.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/cxl/cxl-list.txt | 6 ++++--
cxl/filter.c | 3 +++
cxl/list.c | 9 +++++++++
3 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
index 3076deb..42b6de6 100644
--- a/Documentation/cxl/cxl-list.txt
+++ b/Documentation/cxl/cxl-list.txt
@@ -200,9 +200,11 @@ OPTIONS
descendants of the individual ports that match the filter. By default
all descendant objects are listed.
-include::human-option.txt[]
+--debug::
+ If the cxl tool was built with debug enabled, turn on debug
+ messages.
-include::verbose-option.txt[]
+include::human-option.txt[]
include::../copyright.txt[]
diff --git a/cxl/filter.c b/cxl/filter.c
index 8b79db3..32171a4 100644
--- a/cxl/filter.c
+++ b/cxl/filter.c
@@ -387,6 +387,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
if (!jports)
goto err;
+ dbg(p, "walk memdevs\n");
cxl_memdev_foreach(ctx, memdev) {
struct json_object *jdev;
@@ -403,6 +404,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
}
}
+ dbg(p, "walk buses\n");
cxl_bus_foreach(ctx, bus) {
struct json_object *jbus = NULL;
struct json_object *jchildports = NULL;
@@ -431,6 +433,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
}
}
walk_children:
+ dbg(p, "walk ports\n");
walk_child_ports(port, p, pick_array(jchildports, jports),
flags);
cond_add_put_array_suffix(jbus, "ports", devname, jchildports);
diff --git a/cxl/list.c b/cxl/list.c
index 1ef91b4..01ab19b 100644
--- a/cxl/list.c
+++ b/cxl/list.c
@@ -13,6 +13,7 @@
#include "filter.h"
static struct cxl_filter_params param;
+static bool debug;
static const struct option options[] = {
OPT_STRING('m', "memdev", &param.memdev_filter, "memory device name(s)",
@@ -35,6 +36,9 @@ static const struct option options[] = {
"use human friendly number formats "),
OPT_BOOLEAN('H', "health", &param.health,
"include memory device health information "),
+#ifdef ENABLE_DEBUG
+ OPT_BOOLEAN(0, "debug", &debug, "debug list walk"),
+#endif
OPT_END(),
};
@@ -84,9 +88,14 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
}
log_init(&param.ctx, "cxl list", "CXL_LIST_LOG");
+ if (debug) {
+ cxl_set_log_priority(ctx, LOG_DEBUG);
+ param.ctx.log_priority = LOG_DEBUG;
+ }
if (cxl_filter_has(param.port_filter, "root") && param.ports)
param.buses = true;
+ dbg(&param, "walk topology\n");
return cxl_filter_walk(ctx, &param);
}
--
2.27.0

View File

@ -0,0 +1,746 @@
From 7eb06a5293531854e7a28666e955106094d3552b Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:53:29 -0800
Subject: [PATCH 105/217] cxl/list: Add endpoints
Endpoints are port-like objects that represent the HDM decoders at terminal
end of a decode chain. Unlike port decoders that route to downstream ports,
endpoint decoders route to endpoint DPA (Device Physical Address) ranges.
Link: https://lore.kernel.org/r/164298560917.3021641.13753578554905796298.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
.clang-format | 1 +
Documentation/cxl/cxl-list.txt | 16 ++++
Documentation/cxl/lib/libcxl.txt | 31 ++++++-
cxl/filter.c | 147 ++++++++++++++++++++++++++++---
cxl/filter.h | 2 +
cxl/json.c | 20 ++++-
cxl/json.h | 2 +
cxl/lib/libcxl.c | 107 ++++++++++++++++++++++
cxl/lib/libcxl.sym | 9 ++
cxl/lib/private.h | 10 +++
cxl/libcxl.h | 15 ++++
cxl/list.c | 13 ++-
12 files changed, 355 insertions(+), 18 deletions(-)
diff --git a/.clang-format b/.clang-format
index 391cd34..106bc5e 100644
--- a/.clang-format
+++ b/.clang-format
@@ -80,6 +80,7 @@ ForEachMacros:
- 'cxl_memdev_foreach'
- 'cxl_bus_foreach'
- 'cxl_port_foreach'
+ - 'cxl_endpoint_foreach'
- 'daxctl_dev_foreach'
- 'daxctl_mapping_foreach'
- 'daxctl_region_foreach'
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
index 42b6de6..d342da2 100644
--- a/Documentation/cxl/cxl-list.txt
+++ b/Documentation/cxl/cxl-list.txt
@@ -190,6 +190,12 @@ OPTIONS
----
# cxl list -B
# cxl list -P -p root
+----
+ Additionally, endpoint objects are also ports so the following commands
+ are also equivalent.
+----
+# cxl list -E
+# cxl list -P -p endpoint
----
By default, only 'switch' ports are listed.
@@ -200,6 +206,16 @@ OPTIONS
descendants of the individual ports that match the filter. By default
all descendant objects are listed.
+-E::
+--endpoints::
+ Include endpoint objects (CXL Memory Device decoders) in the
+ listing.
+
+-e::
+--endpoint::
+ Specify CXL endpoint device name(s), or device id(s) to filter
+ the emitted endpoint(s).
+
--debug::
If the cxl tool was built with debug enabled, turn on debug
messages.
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
index 804e9ca..eebab37 100644
--- a/Documentation/cxl/lib/libcxl.txt
+++ b/Documentation/cxl/lib/libcxl.txt
@@ -199,12 +199,41 @@ int cxl_port_get_id(struct cxl_port *port);
int cxl_port_is_enabled(struct cxl_port *port);
bool cxl_port_is_root(struct cxl_port *port);
bool cxl_port_is_switch(struct cxl_port *port);
+bool cxl_port_is_endpoint(struct cxl_port *port);
----
The port type is communicated via cxl_port_is_<type>(). An 'enabled' port
is one that has succeeded in discovering the CXL component registers in
the host device and has enumerated its downstream ports. In order for a
memdev to be enabled for CXL memory operation all CXL ports in its
-ancestry must also be enabled.
+ancestry must also be enabled including a root port, an arbitrary number
+of intervening switch ports, and a terminal endpoint port.
+
+ENDPOINTS
+---------
+CXL endpoint objects encapsulate the set of host-managed device-memory
+(HDM) decoders in a physical memory device. The endpoint is the last hop
+in a decoder chain that translate SPA to DPA (system-physical-address to
+device-local-physical-address).
+
+=== ENDPOINT: Enumeration
+----
+struct cxl_endpoint *cxl_endpoint_get_first(struct cxl_port *parent);
+struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint);
+struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint);
+struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);
+struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);
+
+#define cxl_endpoint_foreach(port, endpoint) \
+ for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \
+ endpoint = cxl_endpoint_get_next(endpoint))
+----
+
+=== ENDPOINT: Attributes
+----
+const char *cxl_endpoint_get_devname(struct cxl_endpoint *endpoint);
+int cxl_endpoint_get_id(struct cxl_endpoint *endpoint);
+int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint);
+----
include::../../copyright.txt[]
diff --git a/cxl/filter.c b/cxl/filter.c
index 32171a4..5d80d1b 100644
--- a/cxl/filter.c
+++ b/cxl/filter.c
@@ -47,8 +47,42 @@ bool cxl_filter_has(const char *__filter, const char *needle)
return false;
}
+static struct cxl_endpoint *
+util_cxl_endpoint_filter(struct cxl_endpoint *endpoint, const char *__ident)
+{
+ char *ident, *save;
+ const char *arg;
+ int endpoint_id;
+
+ if (!__ident)
+ return endpoint;
+
+ ident = strdup(__ident);
+ if (!ident)
+ return NULL;
+
+ for (arg = strtok_r(ident, which_sep(__ident), &save); arg;
+ arg = strtok_r(NULL, which_sep(__ident), &save)) {
+ if (strcmp(arg, "all") == 0)
+ break;
+
+ if ((sscanf(arg, "%d", &endpoint_id) == 1 ||
+ sscanf(arg, "endpoint%d", &endpoint_id) == 1) &&
+ cxl_endpoint_get_id(endpoint) == endpoint_id)
+ break;
+
+ if (strcmp(arg, cxl_endpoint_get_devname(endpoint)) == 0)
+ break;
+ }
+
+ free(ident);
+ if (arg)
+ return endpoint;
+ return NULL;
+}
+
static struct cxl_port *__util_cxl_port_filter(struct cxl_port *port,
- const char *__ident)
+ const char *__ident)
{
char *ident, *save;
const char *arg;
@@ -72,6 +106,9 @@ static struct cxl_port *__util_cxl_port_filter(struct cxl_port *port,
if (strcmp(arg, "switch") == 0 && cxl_port_is_switch(port))
break;
+ if (strcmp(arg, "endpoint") == 0 && cxl_port_is_endpoint(port))
+ break;
+
if ((sscanf(arg, "%d", &port_id) == 1 ||
sscanf(arg, "port%d", &port_id) == 1) &&
cxl_port_get_id(port) == port_id)
@@ -116,6 +153,24 @@ static struct cxl_port *util_cxl_port_filter(struct cxl_port *port,
return NULL;
}
+static struct cxl_endpoint *
+util_cxl_endpoint_filter_by_port(struct cxl_endpoint *endpoint,
+ const char *ident,
+ enum cxl_port_filter_mode mode)
+{
+ struct cxl_port *iter = cxl_endpoint_get_port(endpoint);
+
+ if (util_cxl_port_filter(iter, ident, CXL_PF_SINGLE))
+ return endpoint;
+ iter = cxl_port_get_parent(iter);
+ if (!iter)
+ return NULL;
+ if (util_cxl_port_filter(iter, ident, mode))
+ return endpoint;
+
+ return NULL;
+}
+
static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus,
const char *__ident)
{
@@ -325,10 +380,34 @@ static struct json_object *pick_array(struct json_object *child,
return NULL;
}
+static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p,
+ struct json_object *jeps, unsigned long flags)
+{
+ struct cxl_endpoint *endpoint;
+
+ cxl_endpoint_foreach(port, endpoint) {
+ struct cxl_port *ep_port = cxl_endpoint_get_port(endpoint);
+ struct json_object *jendpoint;
+
+ if (!util_cxl_endpoint_filter(endpoint, p->endpoint_filter))
+ continue;
+ if (!util_cxl_port_filter_by_bus(ep_port, p->bus_filter))
+ continue;
+ if (!util_cxl_endpoint_filter_by_port(endpoint, p->port_filter,
+ pf_mode(p)))
+ continue;
+ if (!p->idle && !cxl_endpoint_is_enabled(endpoint))
+ continue;
+ jendpoint = util_cxl_endpoint_to_json(endpoint, flags);
+ if (jendpoint)
+ json_object_array_add(jeps, jendpoint);
+ }
+}
+
static void walk_child_ports(struct cxl_port *parent_port,
struct cxl_filter_params *p,
struct json_object *jports,
- unsigned long flags)
+ struct json_object *jeps, unsigned long flags)
{
struct cxl_port *port;
@@ -336,6 +415,7 @@ static void walk_child_ports(struct cxl_port *parent_port,
const char *devname = cxl_port_get_devname(port);
struct json_object *jport = NULL;
struct json_object *jchildports = NULL;
+ struct json_object *jchildendpoints = NULL;
if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p)))
goto walk_children;
@@ -343,21 +423,41 @@ static void walk_child_ports(struct cxl_port *parent_port,
goto walk_children;
if (!p->idle && !cxl_port_is_enabled(port))
continue;
- if (p->ports)
+ if (p->ports) {
jport = util_cxl_port_to_json(port, flags);
- if (!jport)
- continue;
- json_object_array_add(jports, jport);
- jchildports = json_object_new_array();
- if (!jchildports) {
- err(p, "%s: failed to enumerate child ports\n",
- devname);
- continue;
+ if (!jport) {
+ err(p, "%s: failed to list\n", devname);
+ continue;
+ }
+ json_object_array_add(jports, jport);
+ jchildports = json_object_new_array();
+ if (!jchildports) {
+ err(p, "%s: failed to enumerate child ports\n",
+ devname);
+ continue;
+ }
+ }
+
+ if (p->ports && p->endpoints) {
+ jchildendpoints = json_object_new_array();
+ if (!jchildendpoints) {
+ err(p,
+ "%s: failed to enumerate child endpoints\n",
+ devname);
+ continue;
+ }
}
+
walk_children:
+ if (p->endpoints)
+ walk_endpoints(port, p, pick_array(jchildendpoints, jeps),
+ flags);
+
walk_child_ports(port, p, pick_array(jchildports, jports),
- flags);
+ pick_array(jchildendpoints, jeps), flags);
cond_add_put_array_suffix(jport, "ports", devname, jchildports);
+ cond_add_put_array_suffix(jport, "endpoints", devname,
+ jchildendpoints);
}
}
@@ -366,6 +466,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
struct json_object *jdevs = NULL, *jbuses = NULL, *jports = NULL;
struct json_object *jplatform = json_object_new_array();
unsigned long flags = params_to_flags(p);
+ struct json_object *jeps = NULL;
struct cxl_memdev *memdev;
int top_level_objs = 0;
struct cxl_bus *bus;
@@ -387,6 +488,10 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
if (!jports)
goto err;
+ jeps = json_object_new_array();
+ if (!jeps)
+ goto err;
+
dbg(p, "walk memdevs\n");
cxl_memdev_foreach(ctx, memdev) {
struct json_object *jdev;
@@ -408,6 +513,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
cxl_bus_foreach(ctx, bus) {
struct json_object *jbus = NULL;
struct json_object *jchildports = NULL;
+ struct json_object *jchildeps = NULL;
struct cxl_port *port = cxl_bus_get_port(bus);
const char *devname = cxl_bus_get_devname(bus);
@@ -431,12 +537,23 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
continue;
}
}
+ if (p->endpoints) {
+ jchildeps = json_object_new_array();
+ if (!jchildeps) {
+ err(p,
+ "%s: failed to enumerate child endpoints\n",
+ devname);
+ continue;
+ }
+ }
}
walk_children:
dbg(p, "walk ports\n");
walk_child_ports(port, p, pick_array(jchildports, jports),
- flags);
+ pick_array(jchildeps, jeps), flags);
cond_add_put_array_suffix(jbus, "ports", devname, jchildports);
+ cond_add_put_array_suffix(jbus, "endpoints", devname,
+ jchildeps);
}
if (json_object_array_length(jdevs))
@@ -445,10 +562,13 @@ walk_children:
top_level_objs++;
if (json_object_array_length(jports))
top_level_objs++;
+ if (json_object_array_length(jeps))
+ top_level_objs++;
splice_array(p, jdevs, jplatform, "anon memdevs", top_level_objs > 1);
splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1);
splice_array(p, jports, jplatform, "ports", top_level_objs > 1);
+ splice_array(p, jeps, jplatform, "endpoints", top_level_objs > 1);
util_display_json_array(stdout, jplatform, flags);
@@ -457,6 +577,7 @@ err:
json_object_put(jdevs);
json_object_put(jbuses);
json_object_put(jports);
+ json_object_put(jeps);
json_object_put(jplatform);
return -ENOMEM;
}
diff --git a/cxl/filter.h b/cxl/filter.h
index 0d83304..bbd341c 100644
--- a/cxl/filter.h
+++ b/cxl/filter.h
@@ -11,7 +11,9 @@ struct cxl_filter_params {
const char *serial_filter;
const char *bus_filter;
const char *port_filter;
+ const char *endpoint_filter;
bool single;
+ bool endpoints;
bool memdevs;
bool ports;
bool buses;
diff --git a/cxl/json.c b/cxl/json.c
index d9f864e..08f6192 100644
--- a/cxl/json.c
+++ b/cxl/json.c
@@ -243,8 +243,9 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,
return jbus;
}
-struct json_object *util_cxl_port_to_json(struct cxl_port *port,
- unsigned long flags)
+static struct json_object *__util_cxl_port_to_json(struct cxl_port *port,
+ const char *name_key,
+ unsigned long flags)
{
const char *devname = cxl_port_get_devname(port);
struct json_object *jport, *jobj;
@@ -255,7 +256,7 @@ struct json_object *util_cxl_port_to_json(struct cxl_port *port,
jobj = json_object_new_string(devname);
if (jobj)
- json_object_object_add(jport, "port", jobj);
+ json_object_object_add(jport, name_key, jobj);
if (!cxl_port_is_enabled(port)) {
jobj = json_object_new_string("disabled");
@@ -265,3 +266,16 @@ struct json_object *util_cxl_port_to_json(struct cxl_port *port,
return jport;
}
+
+struct json_object *util_cxl_port_to_json(struct cxl_port *port,
+ unsigned long flags)
+{
+ return __util_cxl_port_to_json(port, "port", flags);
+}
+
+struct json_object *util_cxl_endpoint_to_json(struct cxl_endpoint *endpoint,
+ unsigned long flags)
+{
+ return __util_cxl_port_to_json(cxl_endpoint_get_port(endpoint),
+ "endpoint", flags);
+}
diff --git a/cxl/json.h b/cxl/json.h
index 36653db..8f45190 100644
--- a/cxl/json.h
+++ b/cxl/json.h
@@ -11,4 +11,6 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus,
struct cxl_port;
struct json_object *util_cxl_port_to_json(struct cxl_port *port,
unsigned long flags);
+struct json_object *util_cxl_endpoint_to_json(struct cxl_endpoint *endpoint,
+ unsigned long flags);
#endif /* __CXL_UTIL_JSON_H__ */
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 03eff3c..a25e715 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -67,14 +67,18 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)
}
static void free_port(struct cxl_port *port, struct list_head *head);
+static void free_endpoint(struct cxl_endpoint *endpoint, struct list_head *head);
static void __free_port(struct cxl_port *port, struct list_head *head)
{
struct cxl_port *child, *_c;
+ struct cxl_endpoint *endpoint, *_e;
if (head)
list_del_from(head, &port->list);
list_for_each_safe(&port->child_ports, child, _c, list)
free_port(child, &port->child_ports);
+ list_for_each_safe(&port->endpoints, endpoint, _e, port.list)
+ free_endpoint(endpoint, &port->endpoints);
kmod_module_unref(port->module);
free(port->dev_buf);
free(port->dev_path);
@@ -87,6 +91,12 @@ static void free_port(struct cxl_port *port, struct list_head *head)
free(port);
}
+static void free_endpoint(struct cxl_endpoint *endpoint, struct list_head *head)
+{
+ __free_port(&endpoint->port, head);
+ free(endpoint);
+}
+
static void free_bus(struct cxl_bus *bus, struct list_head *head)
{
__free_port(&bus->port, head);
@@ -500,6 +510,7 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_port *parent_port,
port->parent = parent_port;
list_head_init(&port->child_ports);
+ list_head_init(&port->endpoints);
port->dev_path = strdup(cxlport_base);
if (!port->dev_path)
@@ -529,6 +540,97 @@ err:
return -ENOMEM;
}
+static void *add_cxl_endpoint(void *parent, int id, const char *cxlep_base)
+{
+ const char *devname = devpath_to_devname(cxlep_base);
+ struct cxl_endpoint *endpoint, *endpoint_dup;
+ struct cxl_port *port = parent;
+ struct cxl_ctx *ctx = cxl_port_get_ctx(port);
+ int rc;
+
+ dbg(ctx, "%s: base: \'%s\'\n", devname, cxlep_base);
+
+ endpoint = calloc(1, sizeof(*endpoint));
+ if (!endpoint)
+ return NULL;
+
+ rc = cxl_port_init(&endpoint->port, port, CXL_PORT_ENDPOINT, ctx, id,
+ cxlep_base);
+ if (rc)
+ goto err;
+
+ cxl_endpoint_foreach(port, endpoint_dup)
+ if (endpoint_dup->port.id == endpoint->port.id) {
+ free_endpoint(endpoint, NULL);
+ return endpoint_dup;
+ }
+
+ list_add(&port->endpoints, &endpoint->port.list);
+ return endpoint;
+
+err:
+ free(endpoint);
+ return NULL;
+
+}
+
+static void cxl_endpoints_init(struct cxl_port *port)
+{
+ struct cxl_ctx *ctx = cxl_port_get_ctx(port);
+
+ if (port->endpoints_init)
+ return;
+
+ port->endpoints_init = 1;
+
+ sysfs_device_parse(ctx, port->dev_path, "endpoint", port,
+ add_cxl_endpoint);
+}
+
+CXL_EXPORT struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint)
+{
+ return endpoint->port.ctx;
+}
+
+CXL_EXPORT struct cxl_endpoint *cxl_endpoint_get_first(struct cxl_port *port)
+{
+ cxl_endpoints_init(port);
+
+ return list_top(&port->endpoints, struct cxl_endpoint, port.list);
+}
+
+CXL_EXPORT struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint)
+{
+ struct cxl_port *port = endpoint->port.parent;
+
+ return list_next(&port->endpoints, endpoint, port.list);
+}
+
+CXL_EXPORT const char *cxl_endpoint_get_devname(struct cxl_endpoint *endpoint)
+{
+ return devpath_to_devname(endpoint->port.dev_path);
+}
+
+CXL_EXPORT int cxl_endpoint_get_id(struct cxl_endpoint *endpoint)
+{
+ return endpoint->port.id;
+}
+
+CXL_EXPORT struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint)
+{
+ return endpoint->port.parent;
+}
+
+CXL_EXPORT struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint)
+{
+ return &endpoint->port;
+}
+
+CXL_EXPORT int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint)
+{
+ return cxl_port_is_enabled(&endpoint->port);
+}
+
static void *add_cxl_port(void *parent, int id, const char *cxlport_base)
{
const char *devname = devpath_to_devname(cxlport_base);
@@ -619,6 +721,11 @@ CXL_EXPORT bool cxl_port_is_switch(struct cxl_port *port)
return port->type == CXL_PORT_SWITCH;
}
+CXL_EXPORT bool cxl_port_is_endpoint(struct cxl_port *port)
+{
+ return port->type == CXL_PORT_ENDPOINT;
+}
+
CXL_EXPORT struct cxl_bus *cxl_port_get_bus(struct cxl_port *port)
{
struct cxl_bus *bus;
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index a7e923f..7a51a0c 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -93,5 +93,14 @@ global:
cxl_port_is_root;
cxl_port_is_switch;
cxl_port_to_bus;
+ cxl_port_is_endpoint;
cxl_port_get_bus;
+ cxl_endpoint_get_first;
+ cxl_endpoint_get_next;
+ cxl_endpoint_get_devname;
+ cxl_endpoint_get_id;
+ cxl_endpoint_get_ctx;
+ cxl_endpoint_is_enabled;
+ cxl_endpoint_get_parent;
+ cxl_endpoint_get_port;
} LIBCXL_1;
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index 637f90d..cedd2f2 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -17,6 +17,7 @@ struct cxl_pmem {
char *dev_path;
};
+struct cxl_endpoint;
struct cxl_memdev {
int id, major, minor;
void *dev_buf;
@@ -32,11 +33,13 @@ struct cxl_memdev {
struct kmod_module *module;
struct cxl_pmem *pmem;
unsigned long long serial;
+ struct cxl_endpoint *endpoint;
};
enum cxl_port_type {
CXL_PORT_ROOT,
CXL_PORT_SWITCH,
+ CXL_PORT_ENDPOINT,
};
struct cxl_port {
@@ -46,6 +49,7 @@ struct cxl_port {
char *dev_path;
char *uport;
int ports_init;
+ int endpoints_init;
struct cxl_ctx *ctx;
struct cxl_bus *bus;
enum cxl_port_type type;
@@ -53,12 +57,18 @@ struct cxl_port {
struct kmod_module *module;
struct list_node list;
struct list_head child_ports;
+ struct list_head endpoints;
};
struct cxl_bus {
struct cxl_port port;
};
+struct cxl_endpoint {
+ struct cxl_port port;
+ struct cxl_memdev *memdev;
+};
+
enum cxl_cmd_query_status {
CXL_CMD_QUERY_NOT_RUN = 0,
CXL_CMD_QUERY_OK,
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index efbb397..f6ba9a1 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -81,12 +81,27 @@ struct cxl_port *cxl_port_get_parent(struct cxl_port *port);
bool cxl_port_is_root(struct cxl_port *port);
bool cxl_port_is_switch(struct cxl_port *port);
struct cxl_bus *cxl_port_to_bus(struct cxl_port *port);
+bool cxl_port_is_endpoint(struct cxl_port *port);
struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);
#define cxl_port_foreach(parent, port) \
for (port = cxl_port_get_first(parent); port != NULL; \
port = cxl_port_get_next(port))
+struct cxl_endpoint;
+struct cxl_endpoint *cxl_endpoint_get_first(struct cxl_port *parent);
+struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint);
+const char *cxl_endpoint_get_devname(struct cxl_endpoint *endpoint);
+int cxl_endpoint_get_id(struct cxl_endpoint *endpoint);
+struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint);
+int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint);
+struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);
+struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);
+
+#define cxl_endpoint_foreach(port, endpoint) \
+ for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \
+ endpoint = cxl_endpoint_get_next(endpoint))
+
struct cxl_cmd;
const char *cxl_cmd_get_devname(struct cxl_cmd *cmd);
struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);
diff --git a/cxl/list.c b/cxl/list.c
index 01ab19b..b15e01c 100644
--- a/cxl/list.c
+++ b/cxl/list.c
@@ -31,6 +31,11 @@ static const struct option options[] = {
OPT_BOOLEAN('P', "ports", &param.ports, "include CXL port info"),
OPT_BOOLEAN('S', "single", &param.single,
"skip listing descendant objects"),
+ OPT_STRING('e', "endpoint", &param.endpoint_filter,
+ "endpoint device name",
+ "filter by CXL endpoint device name(s)"),
+ OPT_BOOLEAN('E', "endpoints", &param.endpoints,
+ "include CXL endpoint info"),
OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),
OPT_BOOLEAN('u', "human", &param.human,
"use human friendly number formats "),
@@ -44,7 +49,8 @@ static const struct option options[] = {
static int num_list_flags(void)
{
- return !!param.memdevs + !!param.buses + !!param.ports;
+ return !!param.memdevs + !!param.buses + !!param.ports +
+ !!param.endpoints;
}
int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
@@ -74,6 +80,8 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
param.buses = true;
if (param.port_filter)
param.ports = true;
+ if (param.endpoint_filter)
+ param.endpoints = true;
if (num_list_flags() == 0) {
/*
* TODO: We likely want to list regions by default if
@@ -96,6 +104,9 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
if (cxl_filter_has(param.port_filter, "root") && param.ports)
param.buses = true;
+ if (cxl_filter_has(param.port_filter, "endpoint") && param.ports)
+ param.endpoints = true;
+
dbg(&param, "walk topology\n");
return cxl_filter_walk(ctx, &param);
}
--
2.27.0

View File

@ -0,0 +1,154 @@
From f39735be3c1157fdfa7dd5c781048a411ebe4dc5 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:53:34 -0800
Subject: [PATCH 106/217] cxl/list: Add 'host' entries for port-like objects
Add the device name of the "host" device for a given CXL port object. The
kernel calls this the 'uport' attribute.
Link: https://lore.kernel.org/r/164298561473.3021641.16508989603599026269.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/cxl/cxl-list.txt | 9 +++++++++
Documentation/cxl/lib/libcxl.txt | 5 +++++
cxl/json.c | 4 ++++
cxl/lib/libcxl.c | 10 ++++++++++
cxl/lib/libcxl.sym | 2 ++
cxl/libcxl.h | 2 ++
6 files changed, 32 insertions(+)
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
index d342da2..30b6161 100644
--- a/Documentation/cxl/cxl-list.txt
+++ b/Documentation/cxl/cxl-list.txt
@@ -210,6 +210,15 @@ OPTIONS
--endpoints::
Include endpoint objects (CXL Memory Device decoders) in the
listing.
+----
+# cxl list -E
+[
+ {
+ "endpoint":"endpoint2",
+ "host":"mem0"
+ }
+]
+----
-e::
--endpoint::
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
index eebab37..e4b372d 100644
--- a/Documentation/cxl/lib/libcxl.txt
+++ b/Documentation/cxl/lib/libcxl.txt
@@ -178,6 +178,7 @@ struct cxl_port *cxl_port_get_next(struct cxl_port *port);
struct cxl_port *cxl_port_get_parent(struct cxl_port *port);
struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);
struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port);
+const char *cxl_port_get_host(struct cxl_port *port);
#define cxl_port_foreach(parent, port) \
for (port = cxl_port_get_first(parent); port != NULL; \
@@ -192,6 +193,9 @@ as a parent object retrievable via cxl_port_get_parent().
The root port of a hiearchy can be retrieved via any port instance in
that hierarchy via cxl_port_get_bus().
+The host of a port is the corresponding device name of the PCIe Root
+Port, or Switch Upstream Port with CXL capabilities.
+
=== PORT: Attributes
----
const char *cxl_port_get_devname(struct cxl_port *port);
@@ -222,6 +226,7 @@ struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint);
struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint);
struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);
struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);
+const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint);
#define cxl_endpoint_foreach(port, endpoint) \
for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \
diff --git a/cxl/json.c b/cxl/json.c
index 08f6192..af3b4fe 100644
--- a/cxl/json.c
+++ b/cxl/json.c
@@ -258,6 +258,10 @@ static struct json_object *__util_cxl_port_to_json(struct cxl_port *port,
if (jobj)
json_object_object_add(jport, name_key, jobj);
+ jobj = json_object_new_string(cxl_port_get_host(port));
+ if (jobj)
+ json_object_object_add(jport, "host", jobj);
+
if (!cxl_port_is_enabled(port)) {
jobj = json_object_new_string("disabled");
if (jobj)
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index a25e715..5f48202 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -626,6 +626,11 @@ CXL_EXPORT struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint)
return &endpoint->port;
}
+CXL_EXPORT const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint)
+{
+ return cxl_port_get_host(&endpoint->port);
+}
+
CXL_EXPORT int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint)
{
return cxl_port_is_enabled(&endpoint->port);
@@ -744,6 +749,11 @@ CXL_EXPORT struct cxl_bus *cxl_port_get_bus(struct cxl_port *port)
return bus;
}
+CXL_EXPORT const char *cxl_port_get_host(struct cxl_port *port)
+{
+ return devpath_to_devname(port->uport);
+}
+
CXL_EXPORT int cxl_port_is_enabled(struct cxl_port *port)
{
struct cxl_ctx *ctx = cxl_port_get_ctx(port);
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 7a51a0c..dc2863e 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -95,6 +95,7 @@ global:
cxl_port_to_bus;
cxl_port_is_endpoint;
cxl_port_get_bus;
+ cxl_port_get_host;
cxl_endpoint_get_first;
cxl_endpoint_get_next;
cxl_endpoint_get_devname;
@@ -103,4 +104,5 @@ global:
cxl_endpoint_is_enabled;
cxl_endpoint_get_parent;
cxl_endpoint_get_port;
+ cxl_endpoint_get_host;
} LIBCXL_1;
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index f6ba9a1..a60777e 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -83,6 +83,7 @@ bool cxl_port_is_switch(struct cxl_port *port);
struct cxl_bus *cxl_port_to_bus(struct cxl_port *port);
bool cxl_port_is_endpoint(struct cxl_port *port);
struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);
+const char *cxl_port_get_host(struct cxl_port *port);
#define cxl_port_foreach(parent, port) \
for (port = cxl_port_get_first(parent); port != NULL; \
@@ -97,6 +98,7 @@ struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint);
int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint);
struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);
struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);
+const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint);
#define cxl_endpoint_foreach(port, endpoint) \
for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \
--
2.27.0

View File

@ -0,0 +1,175 @@
From eec8c953a840a1cbdca63352c64cec3e48e86afe Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:53:39 -0800
Subject: [PATCH 107/217] cxl/list: Add 'host' entries for memdevs
For debugging CXL port connectivity issues it will be useful to have the
PCI device name for the memory expander in the 'memdev' listing.
Link: https://lore.kernel.org/r/164298561980.3021641.9636572507721689266.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/cxl/cxl-list.txt | 3 ++-
Documentation/cxl/lib/libcxl.txt | 4 ++++
cxl/json.c | 5 +++++
cxl/lib/libcxl.c | 24 ++++++++++++++++++++++++
cxl/lib/libcxl.sym | 1 +
cxl/lib/private.h | 1 +
cxl/libcxl.h | 1 +
7 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
index 30b6161..9c21ab7 100644
--- a/Documentation/cxl/cxl-list.txt
+++ b/Documentation/cxl/cxl-list.txt
@@ -43,7 +43,8 @@ EXAMPLE
"memdev":"mem0",
"pmem_size":268435456,
"ram_size":0,
- "serial":0
+ "serial":0,
+ "host":"0000:35:00.0"
}
]
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
index e4b372d..91fd33e 100644
--- a/Documentation/cxl/lib/libcxl.txt
+++ b/Documentation/cxl/lib/libcxl.txt
@@ -40,6 +40,7 @@ kernel, or to send data or trigger kernel operations for a given device.
struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx);
struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev);
struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev);
+const char *cxl_memdev_get_host(struct cxl_memdev *memdev)
#define cxl_memdev_foreach(ctx, memdev) \
for (memdev = cxl_memdev_get_first(ctx); \
@@ -54,6 +55,9 @@ memory device commands, see the port, decoder, and endpoint APIs to
determine what if any CXL Memory Resources are reachable given a
specific memdev.
+The host of a memdev is the PCIe Endpoint device that registered its CXL
+capabilities with the Linux CXL core.
+
=== MEMDEV: Attributes
----
int cxl_memdev_get_id(struct cxl_memdev *memdev);
diff --git a/cxl/json.c b/cxl/json.c
index af3b4fe..1868686 100644
--- a/cxl/json.c
+++ b/cxl/json.c
@@ -219,6 +219,11 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
if (jobj)
json_object_object_add(jdev, "serial", jobj);
}
+
+ jobj = json_object_new_string(cxl_memdev_get_host(memdev));
+ if (jobj)
+ json_object_object_add(jdev, "host", jobj);
+
return jdev;
}
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 5f48202..c4ddc7d 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -63,6 +63,7 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)
free(memdev->firmware_version);
free(memdev->dev_buf);
free(memdev->dev_path);
+ free(memdev->host);
free(memdev);
}
@@ -297,6 +298,7 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)
char *path = calloc(1, strlen(cxlmem_base) + 100);
struct cxl_ctx *ctx = parent;
struct cxl_memdev *memdev, *memdev_dup;
+ char *host, *rpath = NULL;
char buf[SYSFS_ATTR_SIZE];
struct stat st;
@@ -350,6 +352,22 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)
if (!memdev->dev_path)
goto err_read;
+ rpath = realpath(cxlmem_base, NULL);
+ if (!rpath)
+ goto err_read;
+ host = strrchr(rpath, '/');
+ if (host) {
+ host[0] = '\0';
+ host = strrchr(rpath, '/');
+ }
+ if (!host)
+ goto err_read;
+ memdev->host = strdup(host + 1);
+ if (!memdev->host)
+ goto err_read;
+ free(rpath);
+ rpath = NULL;
+
sprintf(path, "%s/firmware_version", cxlmem_base);
if (sysfs_read_attr(ctx, path, buf) < 0)
goto err_read;
@@ -381,6 +399,7 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)
free(memdev->dev_buf);
free(memdev->dev_path);
free(memdev);
+ free(rpath);
err_dev:
free(path);
return NULL;
@@ -431,6 +450,11 @@ CXL_EXPORT const char *cxl_memdev_get_devname(struct cxl_memdev *memdev)
return devpath_to_devname(memdev->dev_path);
}
+CXL_EXPORT const char *cxl_memdev_get_host(struct cxl_memdev *memdev)
+{
+ return memdev->host;
+}
+
CXL_EXPORT int cxl_memdev_get_major(struct cxl_memdev *memdev)
{
return memdev->major;
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index dc2863e..8f0688a 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -77,6 +77,7 @@ local:
LIBCXL_2 {
global:
cxl_memdev_get_serial;
+ cxl_memdev_get_host;
cxl_bus_get_first;
cxl_bus_get_next;
cxl_bus_get_provider;
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index cedd2f2..b097bdf 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -22,6 +22,7 @@ struct cxl_memdev {
int id, major, minor;
void *dev_buf;
size_t buf_len;
+ char *host;
char *dev_path;
char *firmware_version;
struct cxl_ctx *ctx;
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index a60777e..5487b55 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -38,6 +38,7 @@ struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev);
int cxl_memdev_get_id(struct cxl_memdev *memdev);
unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev);
const char *cxl_memdev_get_devname(struct cxl_memdev *memdev);
+const char *cxl_memdev_get_host(struct cxl_memdev *memdev);
int cxl_memdev_get_major(struct cxl_memdev *memdev);
int cxl_memdev_get_minor(struct cxl_memdev *memdev);
struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev);
--
2.27.0

View File

@ -0,0 +1,499 @@
From 41d6769393f449008abf934e815f137360889633 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:53:45 -0800
Subject: [PATCH 108/217] cxl/list: Move enabled memdevs underneath their
endpoint
When a memdev is enabled it means that the kernel was able to validate a
CXL connection from the CXL root, through intervening switches, and to the
endpoint. Reflect that state by listing memdevs as child objects of
endpoints, or aggregated into an array if individual endpoints are not
listed.
Link: https://lore.kernel.org/r/164298562531.3021641.10620937879296964476.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/cxl/cxl-list.txt | 11 ++-
Documentation/cxl/lib/libcxl.txt | 2 +
cxl/filter.c | 130 ++++++++++++++++++++++++-------
cxl/json.c | 6 ++
cxl/lib/libcxl.c | 97 +++++++++++++++++++++++
cxl/lib/libcxl.sym | 3 +
cxl/libcxl.h | 4 +
7 files changed, 223 insertions(+), 30 deletions(-)
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
index 9c21ab7..1751868 100644
--- a/Documentation/cxl/cxl-list.txt
+++ b/Documentation/cxl/cxl-list.txt
@@ -19,7 +19,16 @@ Options can be specified to limit the output to specific objects. When a
single object type is specified the return json object is an array of
just those objects, when multiple objects types are specified the
returned the returned object may be an array of arrays with the inner
-array named for the given object type.
+array named for the given object type. The top-level arrays are ellided
+when the objects can nest under a higher object-type in the hierararchy.
+The potential top-level array names and their nesting properties are:
+
+"anon memdevs":: (disabled memory devices) do not nest
+"buses":: do not nest
+"ports":: nest under buses
+"endpoints":: nest under ports or buses (if ports are not emitted)
+"memdevs":: nest under endpoints or ports (if endpoints are not
+ emitted) or buses (if endpoints and ports are not emitted)
Filters can by specifed as either a single identidier, a space separated
quoted string, or a comma separated list. When multiple filter
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
index 91fd33e..73b0fb9 100644
--- a/Documentation/cxl/lib/libcxl.txt
+++ b/Documentation/cxl/lib/libcxl.txt
@@ -41,6 +41,7 @@ struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx);
struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev);
struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev);
const char *cxl_memdev_get_host(struct cxl_memdev *memdev)
+struct cxl_memdev *cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint);
#define cxl_memdev_foreach(ctx, memdev) \
for (memdev = cxl_memdev_get_first(ctx); \
@@ -231,6 +232,7 @@ struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint);
struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);
struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);
const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint);
+struct cxl_endpoint *cxl_memdev_get_endpoint(struct cxl_memdev *memdev);
#define cxl_endpoint_foreach(port, endpoint) \
for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \
diff --git a/cxl/filter.c b/cxl/filter.c
index 5d80d1b..2130816 100644
--- a/cxl/filter.c
+++ b/cxl/filter.c
@@ -381,13 +381,16 @@ static struct json_object *pick_array(struct json_object *child,
}
static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p,
- struct json_object *jeps, unsigned long flags)
+ struct json_object *jeps, struct json_object *jdevs,
+ unsigned long flags)
{
struct cxl_endpoint *endpoint;
cxl_endpoint_foreach(port, endpoint) {
struct cxl_port *ep_port = cxl_endpoint_get_port(endpoint);
- struct json_object *jendpoint;
+ const char *devname = cxl_endpoint_get_devname(endpoint);
+ struct json_object *jendpoint = NULL;
+ struct cxl_memdev *memdev;
if (!util_cxl_endpoint_filter(endpoint, p->endpoint_filter))
continue;
@@ -398,24 +401,54 @@ static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p,
continue;
if (!p->idle && !cxl_endpoint_is_enabled(endpoint))
continue;
- jendpoint = util_cxl_endpoint_to_json(endpoint, flags);
- if (jendpoint)
+ if (p->endpoints) {
+ jendpoint = util_cxl_endpoint_to_json(endpoint, flags);
+ if (!jendpoint) {
+ err(p, "%s: failed to list\n", devname);
+ continue;
+ }
json_object_array_add(jeps, jendpoint);
+ }
+ if (p->memdevs) {
+ struct json_object *jobj;
+
+ memdev = cxl_endpoint_get_memdev(endpoint);
+ if (!memdev)
+ continue;
+ if (!util_cxl_memdev_filter(memdev, p->memdev_filter,
+ p->serial_filter))
+ continue;
+ if (!p->idle && !cxl_memdev_is_enabled(memdev))
+ continue;
+ jobj = util_cxl_memdev_to_json(memdev, flags);
+ if (!jobj) {
+ err(p, "failed to json serialize %s\n",
+ cxl_memdev_get_devname(memdev));
+ continue;
+ }
+ if (p->endpoints)
+ json_object_object_add(jendpoint, "memdev",
+ jobj);
+ else
+ json_object_array_add(jdevs, jobj);
+ }
}
}
static void walk_child_ports(struct cxl_port *parent_port,
struct cxl_filter_params *p,
struct json_object *jports,
- struct json_object *jeps, unsigned long flags)
+ struct json_object *jeps,
+ struct json_object *jdevs, unsigned long flags)
{
struct cxl_port *port;
cxl_port_foreach(parent_port, port) {
const char *devname = cxl_port_get_devname(port);
struct json_object *jport = NULL;
+ struct json_object *jchilddevs = NULL;
struct json_object *jchildports = NULL;
- struct json_object *jchildendpoints = NULL;
+ struct json_object *jchildeps = NULL;
if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p)))
goto walk_children;
@@ -436,28 +469,41 @@ static void walk_child_ports(struct cxl_port *parent_port,
devname);
continue;
}
- }
- if (p->ports && p->endpoints) {
- jchildendpoints = json_object_new_array();
- if (!jchildendpoints) {
- err(p,
- "%s: failed to enumerate child endpoints\n",
- devname);
- continue;
+ if (p->memdevs && !p->endpoints) {
+ jchilddevs = json_object_new_array();
+ if (!jchilddevs) {
+ err(p,
+ "%s: failed to enumerate child memdevs\n",
+ devname);
+ continue;
+ }
+ }
+
+ if (p->endpoints) {
+ jchildeps = json_object_new_array();
+ if (!jchildeps) {
+ err(p,
+ "%s: failed to enumerate child endpoints\n",
+ devname);
+ continue;
+ }
}
}
walk_children:
- if (p->endpoints)
- walk_endpoints(port, p, pick_array(jchildendpoints, jeps),
- flags);
+ if (p->endpoints || p->memdevs)
+ walk_endpoints(port, p, pick_array(jchildeps, jeps),
+ pick_array(jchilddevs, jdevs), flags);
walk_child_ports(port, p, pick_array(jchildports, jports),
- pick_array(jchildendpoints, jeps), flags);
+ pick_array(jchildeps, jeps),
+ pick_array(jchilddevs, jdevs), flags);
cond_add_put_array_suffix(jport, "ports", devname, jchildports);
cond_add_put_array_suffix(jport, "endpoints", devname,
- jchildendpoints);
+ jchildeps);
+ cond_add_put_array_suffix(jport, "memdevs", devname,
+ jchilddevs);
}
}
@@ -466,6 +512,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
struct json_object *jdevs = NULL, *jbuses = NULL, *jports = NULL;
struct json_object *jplatform = json_object_new_array();
unsigned long flags = params_to_flags(p);
+ struct json_object *janondevs = NULL;
struct json_object *jeps = NULL;
struct cxl_memdev *memdev;
int top_level_objs = 0;
@@ -476,8 +523,8 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
return -ENOMEM;
}
- jdevs = json_object_new_array();
- if (!jdevs)
+ janondevs = json_object_new_array();
+ if (!janondevs)
goto err;
jbuses = json_object_new_array();
@@ -492,20 +539,28 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
if (!jeps)
goto err;
+ jdevs = json_object_new_array();
+ if (!jdevs)
+ goto err;
+
dbg(p, "walk memdevs\n");
cxl_memdev_foreach(ctx, memdev) {
- struct json_object *jdev;
+ struct json_object *janondev;
if (!util_cxl_memdev_filter(memdev, p->memdev_filter,
p->serial_filter))
continue;
+ if (cxl_memdev_is_enabled(memdev))
+ continue;
+ if (!p->idle)
+ continue;
if (p->memdevs) {
- jdev = util_cxl_memdev_to_json(memdev, flags);
- if (!jdev) {
+ janondev = util_cxl_memdev_to_json(memdev, flags);
+ if (!janondev) {
dbg(p, "memdev object allocation failure\n");
continue;
}
- json_object_array_add(jdevs, jdev);
+ json_object_array_add(janondevs, janondev);
}
}
@@ -513,6 +568,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
cxl_bus_foreach(ctx, bus) {
struct json_object *jbus = NULL;
struct json_object *jchildports = NULL;
+ struct json_object *jchilddevs = NULL;
struct json_object *jchildeps = NULL;
struct cxl_port *port = cxl_bus_get_port(bus);
const char *devname = cxl_bus_get_devname(bus);
@@ -546,17 +602,29 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
continue;
}
}
+
+ if (p->memdevs && !p->ports && !p->endpoints) {
+ jchilddevs = json_object_new_array();
+ if (!jchilddevs) {
+ err(p,
+ "%s: failed to enumerate child memdevs\n",
+ devname);
+ continue;
+ }
+ }
}
walk_children:
dbg(p, "walk ports\n");
walk_child_ports(port, p, pick_array(jchildports, jports),
- pick_array(jchildeps, jeps), flags);
+ pick_array(jchildeps, jeps),
+ pick_array(jchilddevs, jdevs), flags);
cond_add_put_array_suffix(jbus, "ports", devname, jchildports);
cond_add_put_array_suffix(jbus, "endpoints", devname,
jchildeps);
+ cond_add_put_array_suffix(jbus, "memdevs", devname, jchilddevs);
}
- if (json_object_array_length(jdevs))
+ if (json_object_array_length(janondevs))
top_level_objs++;
if (json_object_array_length(jbuses))
top_level_objs++;
@@ -564,20 +632,24 @@ walk_children:
top_level_objs++;
if (json_object_array_length(jeps))
top_level_objs++;
+ if (json_object_array_length(jdevs))
+ top_level_objs++;
- splice_array(p, jdevs, jplatform, "anon memdevs", top_level_objs > 1);
+ splice_array(p, janondevs, jplatform, "anon memdevs", top_level_objs > 1);
splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1);
splice_array(p, jports, jplatform, "ports", top_level_objs > 1);
splice_array(p, jeps, jplatform, "endpoints", top_level_objs > 1);
+ splice_array(p, jdevs, jplatform, "memdevs", top_level_objs > 1);
util_display_json_array(stdout, jplatform, flags);
return 0;
err:
- json_object_put(jdevs);
+ json_object_put(janondevs);
json_object_put(jbuses);
json_object_put(jports);
json_object_put(jeps);
+ json_object_put(jdevs);
json_object_put(jplatform);
return -ENOMEM;
}
diff --git a/cxl/json.c b/cxl/json.c
index 1868686..b809332 100644
--- a/cxl/json.c
+++ b/cxl/json.c
@@ -224,6 +224,12 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
if (jobj)
json_object_object_add(jdev, "host", jobj);
+ if (!cxl_memdev_is_enabled(memdev)) {
+ jobj = json_object_new_string("disabled");
+ if (jobj)
+ json_object_object_add(jdev, "state", jobj);
+ }
+
return jdev;
}
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index c4ddc7d..4523ca6 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -480,6 +480,60 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev
return memdev->firmware_version;
}
+static struct cxl_endpoint *cxl_port_find_endpoint(struct cxl_port *parent_port,
+ struct cxl_memdev *memdev)
+{
+ struct cxl_endpoint *endpoint;
+ struct cxl_port *port;
+
+ cxl_port_foreach(parent_port, port) {
+ cxl_endpoint_foreach(port, endpoint)
+ if (strcmp(cxl_endpoint_get_host(endpoint),
+ cxl_memdev_get_devname(memdev)) == 0)
+ return endpoint;
+ endpoint = cxl_port_find_endpoint(port, memdev);
+ if (endpoint)
+ return endpoint;
+ }
+
+ return NULL;
+}
+
+CXL_EXPORT struct cxl_endpoint *
+cxl_memdev_get_endpoint(struct cxl_memdev *memdev)
+{
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ struct cxl_endpoint *endpoint = NULL;
+ struct cxl_bus *bus;
+
+ if (memdev->endpoint)
+ return memdev->endpoint;
+
+ if (!cxl_memdev_is_enabled(memdev))
+ return NULL;
+
+ cxl_bus_foreach (ctx, bus) {
+ struct cxl_port *port = cxl_bus_get_port(bus);
+
+ endpoint = cxl_port_find_endpoint(port, memdev);
+ if (endpoint)
+ break;
+ }
+
+ if (!endpoint)
+ return NULL;
+
+ if (endpoint->memdev && endpoint->memdev != memdev)
+ err(ctx, "%s assigned to %s not %s\n",
+ cxl_endpoint_get_devname(endpoint),
+ cxl_memdev_get_devname(endpoint->memdev),
+ cxl_memdev_get_devname(memdev));
+ memdev->endpoint = endpoint;
+ endpoint->memdev = memdev;
+
+ return endpoint;
+}
+
CXL_EXPORT size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev)
{
return memdev->lsa_size;
@@ -495,6 +549,21 @@ static int is_enabled(const char *drvpath)
return 1;
}
+CXL_EXPORT int cxl_memdev_is_enabled(struct cxl_memdev *memdev)
+{
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ char *path = memdev->dev_buf;
+ int len = memdev->buf_len;
+
+ if (snprintf(path, len, "%s/driver", memdev->dev_path) >= len) {
+ err(ctx, "%s: buffer too small!\n",
+ cxl_memdev_get_devname(memdev));
+ return 0;
+ }
+
+ return is_enabled(path);
+}
+
CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev)
{
struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
@@ -660,6 +729,34 @@ CXL_EXPORT int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint)
return cxl_port_is_enabled(&endpoint->port);
}
+CXL_EXPORT struct cxl_memdev *
+cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint)
+{
+ struct cxl_ctx *ctx = cxl_endpoint_get_ctx(endpoint);
+ struct cxl_memdev *memdev;
+
+ if (endpoint->memdev)
+ return endpoint->memdev;
+
+ if (!cxl_endpoint_is_enabled(endpoint))
+ return NULL;
+
+ cxl_memdev_foreach(ctx, memdev)
+ if (strcmp(cxl_memdev_get_devname(memdev),
+ cxl_endpoint_get_host(endpoint)) == 0) {
+ if (memdev->endpoint && memdev->endpoint != endpoint)
+ err(ctx, "%s assigned to %s not %s\n",
+ cxl_memdev_get_devname(memdev),
+ cxl_endpoint_get_devname(memdev->endpoint),
+ cxl_endpoint_get_devname(endpoint));
+ endpoint->memdev = memdev;
+ memdev->endpoint = endpoint;
+ return memdev;
+ }
+
+ return NULL;
+}
+
static void *add_cxl_port(void *parent, int id, const char *cxlport_base)
{
const char *devname = devpath_to_devname(cxlport_base);
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 8f0688a..321acac 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -106,4 +106,7 @@ global:
cxl_endpoint_get_parent;
cxl_endpoint_get_port;
cxl_endpoint_get_host;
+ cxl_endpoint_get_memdev;
+ cxl_memdev_get_endpoint;
+ cxl_memdev_is_enabled;
} LIBCXL_1;
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index 5487b55..790ece8 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -46,6 +46,8 @@ unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev);
unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev);
const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);
size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev);
+struct cxl_endpoint;
+struct cxl_endpoint *cxl_memdev_get_endpoint(struct cxl_memdev *memdev);
int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev);
int cxl_memdev_zero_label(struct cxl_memdev *memdev, size_t length,
size_t offset);
@@ -100,6 +102,8 @@ int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint);
struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);
struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);
const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint);
+struct cxl_memdev *cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint);
+int cxl_memdev_is_enabled(struct cxl_memdev *memdev);
#define cxl_endpoint_foreach(port, endpoint) \
for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \
--
2.27.0

View File

@ -0,0 +1,329 @@
From b90fc91e1034668cfde06f0fd8a7293df8b7690d Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:53:50 -0800
Subject: [PATCH 109/217] cxl/list: Filter memdev by ancestry
Whenever a memdev filter is specified limit output of buses, ports and
endpoints to those that are in the memdev's ancestry.
Link: https://lore.kernel.org/r/164298563039.3021641.5253222797042241091.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/cxl/cxl-list.txt | 19 +++++++++
Documentation/cxl/lib/libcxl.txt | 11 +++++
cxl/filter.c | 69 ++++++++++++++++++++++++++++++++
cxl/lib/libcxl.c | 36 +++++++++++++++++
cxl/lib/libcxl.sym | 5 +++
cxl/libcxl.h | 4 ++
6 files changed, 144 insertions(+)
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
index 1751868..bac27c7 100644
--- a/Documentation/cxl/cxl-list.txt
+++ b/Documentation/cxl/cxl-list.txt
@@ -39,6 +39,25 @@ they are combined as an 'AND' filter. So, "-m mem0,mem1,mem2 -p port10"
would only list objects that are beneath port10 AND map mem0, mem1, OR
mem2.
+Given that many topology queries seek to answer questions relative to a
+given memdev, buses, ports, and endpoints can be filtered by one or more
+memdevs. For example:
+----
+# cxl list -P -p switch,endpoint -m mem0
+[
+ {
+ "port":"port1",
+ "host":"ACPI0016:00",
+ "endpoints:port1":[
+ {
+ "endpoint":"endpoint2",
+ "host":"mem0"
+ }
+ ]
+ }
+]
+----
+
The --human option in addition to reformatting some fields to more human
friendly strings also unwraps the array to reduce the number of lines of
output.
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
index 73b0fb9..b0253d7 100644
--- a/Documentation/cxl/lib/libcxl.txt
+++ b/Documentation/cxl/lib/libcxl.txt
@@ -150,11 +150,18 @@ cxl_bus'.
----
struct cxl_bus *cxl_bus_get_first(struct cxl_ctx *ctx);
struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus);
+struct cxl_ctx *cxl_bus_get_ctx(struct cxl_bus *bus);
+struct cxl_bus *cxl_memdev_get_bus(struct cxl_memdev *memdev);
+struct cxl_bus *cxl_endpoint_get_bus(struct cxl_endpoint *endpoint);
#define cxl_bus_foreach(ctx, bus) \
for (bus = cxl_bus_get_first(ctx); bus != NULL; \
bus = cxl_bus_get_next(bus))
----
+When a memdev is active it has established a CXL port hierarchy between
+itself and the root of its associated CXL topology. The
+cxl_{memdev,endpoint}_get_bus() helpers walk that topology to retrieve
+the associated bus object.
=== BUS: Attributes
----
@@ -209,6 +216,7 @@ int cxl_port_is_enabled(struct cxl_port *port);
bool cxl_port_is_root(struct cxl_port *port);
bool cxl_port_is_switch(struct cxl_port *port);
bool cxl_port_is_endpoint(struct cxl_port *port);
+bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev);
----
The port type is communicated via cxl_port_is_<type>(). An 'enabled' port
is one that has succeeded in discovering the CXL component registers in
@@ -217,6 +225,9 @@ memdev to be enabled for CXL memory operation all CXL ports in its
ancestry must also be enabled including a root port, an arbitrary number
of intervening switch ports, and a terminal endpoint port.
+cxl_port_hosts_memdev() returns true if the port's host appears in the
+memdev host's device topology ancestry.
+
ENDPOINTS
---------
CXL endpoint objects encapsulate the set of host-managed device-memory
diff --git a/cxl/filter.c b/cxl/filter.c
index 2130816..6dc61a1 100644
--- a/cxl/filter.c
+++ b/cxl/filter.c
@@ -297,6 +297,66 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
return NULL;
}
+static struct cxl_bus *util_cxl_bus_filter_by_memdev(struct cxl_bus *bus,
+ const char *ident,
+ const char *serial)
+{
+ struct cxl_ctx *ctx = cxl_bus_get_ctx(bus);
+ struct cxl_memdev *memdev;
+
+ if (!ident && !serial)
+ return bus;
+
+ cxl_memdev_foreach(ctx, memdev) {
+ if (!util_cxl_memdev_filter(memdev, ident, serial))
+ continue;
+ if (cxl_memdev_get_bus(memdev) == bus)
+ return bus;
+ }
+
+ return NULL;
+}
+
+static struct cxl_endpoint *
+util_cxl_endpoint_filter_by_memdev(struct cxl_endpoint *endpoint,
+ const char *ident, const char *serial)
+{
+ struct cxl_ctx *ctx = cxl_endpoint_get_ctx(endpoint);
+ struct cxl_memdev *memdev;
+
+ if (!ident && !serial)
+ return endpoint;
+
+ cxl_memdev_foreach(ctx, memdev) {
+ if (!util_cxl_memdev_filter(memdev, ident, serial))
+ continue;
+ if (cxl_memdev_get_endpoint(memdev) == endpoint)
+ return endpoint;
+ }
+
+ return NULL;
+}
+
+static struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port,
+ const char *ident,
+ const char *serial)
+{
+ struct cxl_ctx *ctx = cxl_port_get_ctx(port);
+ struct cxl_memdev *memdev;
+
+ if (!ident && !serial)
+ return port;
+
+ cxl_memdev_foreach(ctx, memdev) {
+ if (!util_cxl_memdev_filter(memdev, ident, serial))
+ continue;
+ if (cxl_port_hosts_memdev(port, memdev))
+ return port;
+ }
+
+ return NULL;
+}
+
static unsigned long params_to_flags(struct cxl_filter_params *param)
{
unsigned long flags = 0;
@@ -399,6 +459,9 @@ static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p,
if (!util_cxl_endpoint_filter_by_port(endpoint, p->port_filter,
pf_mode(p)))
continue;
+ if (!util_cxl_endpoint_filter_by_memdev(
+ endpoint, p->memdev_filter, p->serial_filter))
+ continue;
if (!p->idle && !cxl_endpoint_is_enabled(endpoint))
continue;
if (p->endpoints) {
@@ -450,6 +513,9 @@ static void walk_child_ports(struct cxl_port *parent_port,
struct json_object *jchildports = NULL;
struct json_object *jchildeps = NULL;
+ if (!util_cxl_port_filter_by_memdev(port, p->memdev_filter,
+ p->serial_filter))
+ continue;
if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p)))
goto walk_children;
if (!util_cxl_port_filter_by_bus(port, p->bus_filter))
@@ -573,6 +639,9 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p)
struct cxl_port *port = cxl_bus_get_port(bus);
const char *devname = cxl_bus_get_devname(bus);
+ if (!util_cxl_bus_filter_by_memdev(bus, p->memdev_filter,
+ p->serial_filter))
+ continue;
if (!util_cxl_bus_filter(bus, p->bus_filter))
goto walk_children;
if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p)))
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 4523ca6..0065f6b 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -455,6 +455,15 @@ CXL_EXPORT const char *cxl_memdev_get_host(struct cxl_memdev *memdev)
return memdev->host;
}
+CXL_EXPORT struct cxl_bus *cxl_memdev_get_bus(struct cxl_memdev *memdev)
+{
+ struct cxl_endpoint *endpoint = cxl_memdev_get_endpoint(memdev);
+
+ if (!endpoint)
+ return NULL;
+ return cxl_endpoint_get_bus(endpoint);
+}
+
CXL_EXPORT int cxl_memdev_get_major(struct cxl_memdev *memdev)
{
return memdev->major;
@@ -724,6 +733,13 @@ CXL_EXPORT const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint)
return cxl_port_get_host(&endpoint->port);
}
+CXL_EXPORT struct cxl_bus *cxl_endpoint_get_bus(struct cxl_endpoint *endpoint)
+{
+ struct cxl_port *port = &endpoint->port;
+
+ return cxl_port_get_bus(port);
+}
+
CXL_EXPORT int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint)
{
return cxl_port_is_enabled(&endpoint->port);
@@ -875,6 +891,21 @@ CXL_EXPORT const char *cxl_port_get_host(struct cxl_port *port)
return devpath_to_devname(port->uport);
}
+CXL_EXPORT bool cxl_port_hosts_memdev(struct cxl_port *port,
+ struct cxl_memdev *memdev)
+{
+ struct cxl_endpoint *endpoint = cxl_memdev_get_endpoint(memdev);
+ struct cxl_port *iter;
+
+ if (!endpoint)
+ return false;
+
+ iter = cxl_endpoint_get_port(endpoint);
+ while (iter && iter != port)
+ iter = iter->parent;
+ return iter != NULL;
+}
+
CXL_EXPORT int cxl_port_is_enabled(struct cxl_port *port)
{
struct cxl_ctx *ctx = cxl_port_get_ctx(port);
@@ -985,6 +1016,11 @@ CXL_EXPORT const char *cxl_bus_get_provider(struct cxl_bus *bus)
return devname;
}
+CXL_EXPORT struct cxl_ctx *cxl_bus_get_ctx(struct cxl_bus *bus)
+{
+ return cxl_port_get_ctx(&bus->port);
+}
+
CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd)
{
if (!cmd)
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 321acac..29f3498 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -84,6 +84,7 @@ global:
cxl_bus_get_devname;
cxl_bus_get_id;
cxl_bus_get_port;
+ cxl_bus_get_ctx;
cxl_port_get_first;
cxl_port_get_next;
cxl_port_get_devname;
@@ -97,6 +98,8 @@ global:
cxl_port_is_endpoint;
cxl_port_get_bus;
cxl_port_get_host;
+ cxl_port_get_bus;
+ cxl_port_hosts_memdev;
cxl_endpoint_get_first;
cxl_endpoint_get_next;
cxl_endpoint_get_devname;
@@ -107,6 +110,8 @@ global:
cxl_endpoint_get_port;
cxl_endpoint_get_host;
cxl_endpoint_get_memdev;
+ cxl_endpoint_get_bus;
cxl_memdev_get_endpoint;
cxl_memdev_is_enabled;
+ cxl_memdev_get_bus;
} LIBCXL_1;
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index 790ece8..e7b675e 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -39,6 +39,7 @@ int cxl_memdev_get_id(struct cxl_memdev *memdev);
unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev);
const char *cxl_memdev_get_devname(struct cxl_memdev *memdev);
const char *cxl_memdev_get_host(struct cxl_memdev *memdev);
+struct cxl_bus *cxl_memdev_get_bus(struct cxl_memdev *memdev);
int cxl_memdev_get_major(struct cxl_memdev *memdev);
int cxl_memdev_get_minor(struct cxl_memdev *memdev);
struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev);
@@ -68,6 +69,7 @@ const char *cxl_bus_get_provider(struct cxl_bus *bus);
const char *cxl_bus_get_devname(struct cxl_bus *bus);
int cxl_bus_get_id(struct cxl_bus *bus);
struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus);
+struct cxl_ctx *cxl_bus_get_ctx(struct cxl_bus *bus);
#define cxl_bus_foreach(ctx, bus) \
for (bus = cxl_bus_get_first(ctx); bus != NULL; \
@@ -87,6 +89,7 @@ struct cxl_bus *cxl_port_to_bus(struct cxl_port *port);
bool cxl_port_is_endpoint(struct cxl_port *port);
struct cxl_bus *cxl_port_get_bus(struct cxl_port *port);
const char *cxl_port_get_host(struct cxl_port *port);
+bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev);
#define cxl_port_foreach(parent, port) \
for (port = cxl_port_get_first(parent); port != NULL; \
@@ -102,6 +105,7 @@ int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint);
struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint);
struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint);
const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint);
+struct cxl_bus *cxl_endpoint_get_bus(struct cxl_endpoint *endpoint);
struct cxl_memdev *cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint);
int cxl_memdev_is_enabled(struct cxl_memdev *memdev);
--
2.27.0

View File

@ -0,0 +1,173 @@
From 5e1c1ab5bf6b6257552ad9fa242483ec1c1de006 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:53:55 -0800
Subject: [PATCH 110/217] cxl/memdev: Use a local logger for debug
The "fail()" macro skips some of the nicer features of the centralized
logger. Add one to supplement the library logger.
Link: https://lore.kernel.org/r/164298563547.3021641.16504008034705274247.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
cxl/memdev.c | 48 ++++++++++++++++++++++++------------------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/cxl/memdev.c b/cxl/memdev.c
index b9141be..327c260 100644
--- a/cxl/memdev.c
+++ b/cxl/memdev.c
@@ -26,11 +26,7 @@ static struct parameters {
bool verbose;
} param;
-#define fail(fmt, ...) \
-do { \
- fprintf(stderr, "cxl-%s:%s:%d: " fmt, \
- VERSION, __func__, __LINE__, ##__VA_ARGS__); \
-} while (0)
+static struct log_ctx ml;
#define BASE_OPTIONS() \
OPT_BOOLEAN('v',"verbose", &param.verbose, "turn on debug")
@@ -79,7 +75,7 @@ static int action_zero(struct cxl_memdev *memdev, struct action_context *actx)
size = cxl_memdev_get_label_size(memdev);
if (cxl_memdev_nvdimm_bridge_active(memdev)) {
- fprintf(stderr,
+ log_err(&ml,
"%s: has active nvdimm bridge, abort label write\n",
cxl_memdev_get_devname(memdev));
return -EBUSY;
@@ -87,7 +83,7 @@ static int action_zero(struct cxl_memdev *memdev, struct action_context *actx)
rc = cxl_memdev_zero_label(memdev, size, param.offset);
if (rc < 0)
- fprintf(stderr, "%s: label zeroing failed: %s\n",
+ log_err(&ml, "%s: label zeroing failed: %s\n",
cxl_memdev_get_devname(memdev), strerror(-rc));
return rc;
@@ -100,7 +96,7 @@ static int action_write(struct cxl_memdev *memdev, struct action_context *actx)
int rc;
if (cxl_memdev_nvdimm_bridge_active(memdev)) {
- fprintf(stderr,
+ log_err(&ml,
"%s: has active nvdimm bridge, abort label write\n",
cxl_memdev_get_devname(memdev));
return -EBUSY;
@@ -114,7 +110,7 @@ static int action_write(struct cxl_memdev *memdev, struct action_context *actx)
fseek(actx->f_in, 0L, SEEK_SET);
if (size > label_size) {
- fprintf(stderr,
+ log_err(&ml,
"File size (%zu) greater than label area size (%zu), aborting\n",
size, label_size);
return -EINVAL;
@@ -133,7 +129,7 @@ static int action_write(struct cxl_memdev *memdev, struct action_context *actx)
rc = cxl_memdev_write_label(memdev, buf, size, param.offset);
if (rc < 0)
- fprintf(stderr, "%s: label write failed: %s\n",
+ log_err(&ml, "%s: label write failed: %s\n",
cxl_memdev_get_devname(memdev), strerror(-rc));
out:
@@ -158,7 +154,7 @@ static int action_read(struct cxl_memdev *memdev, struct action_context *actx)
rc = cxl_memdev_read_label(memdev, buf, size, param.offset);
if (rc < 0) {
- fprintf(stderr, "%s: label read failed: %s\n",
+ log_err(&ml, "%s: label read failed: %s\n",
cxl_memdev_get_devname(memdev), strerror(-rc));
goto out;
}
@@ -188,6 +184,7 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,
};
unsigned long id;
+ log_init(&ml, "cxl memdev", "CXL_MEMDEV_LOG");
argc = parse_options(argc, argv, options, u, 0);
if (argc == 0)
@@ -200,8 +197,8 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,
}
if (sscanf(argv[i], "mem%lu", &id) != 1) {
- fprintf(stderr, "'%s' is not a valid memdev name\n",
- argv[i]);
+ log_err(&ml, "'%s' is not a valid memdev name\n",
+ argv[i]);
err++;
}
}
@@ -216,8 +213,8 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,
else {
actx.f_out = fopen(param.outfile, "w+");
if (!actx.f_out) {
- fprintf(stderr, "failed to open: %s: (%s)\n",
- param.outfile, strerror(errno));
+ log_err(&ml, "failed to open: %s: (%s)\n",
+ param.outfile, strerror(errno));
rc = -errno;
goto out;
}
@@ -228,15 +225,18 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,
} else {
actx.f_in = fopen(param.infile, "r");
if (!actx.f_in) {
- fprintf(stderr, "failed to open: %s: (%s)\n",
- param.infile, strerror(errno));
+ log_err(&ml, "failed to open: %s: (%s)\n", param.infile,
+ strerror(errno));
rc = -errno;
goto out_close_fout;
}
}
- if (param.verbose)
+ if (param.verbose) {
cxl_set_log_priority(ctx, LOG_DEBUG);
+ ml.log_priority = LOG_DEBUG;
+ } else
+ ml.log_priority = LOG_INFO;
rc = 0;
err = 0;
@@ -299,8 +299,8 @@ int cmd_write_labels(int argc, const char **argv, struct cxl_ctx *ctx)
int count = memdev_action(argc, argv, ctx, action_write, write_options,
"cxl write-labels <memdev> [-i <filename>]");
- fprintf(stderr, "wrote %d mem%s\n", count >= 0 ? count : 0,
- count > 1 ? "s" : "");
+ log_info(&ml, "wrote %d mem%s\n", count >= 0 ? count : 0,
+ count > 1 ? "s" : "");
return count >= 0 ? 0 : EXIT_FAILURE;
}
@@ -309,8 +309,8 @@ int cmd_read_labels(int argc, const char **argv, struct cxl_ctx *ctx)
int count = memdev_action(argc, argv, ctx, action_read, read_options,
"cxl read-labels <mem0> [<mem1>..<memN>] [-o <filename>]");
- fprintf(stderr, "read %d mem%s\n", count >= 0 ? count : 0,
- count > 1 ? "s" : "");
+ log_info(&ml, "read %d mem%s\n", count >= 0 ? count : 0,
+ count > 1 ? "s" : "");
return count >= 0 ? 0 : EXIT_FAILURE;
}
@@ -319,7 +319,7 @@ int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx)
int count = memdev_action(argc, argv, ctx, action_zero, zero_options,
"cxl zero-labels <mem0> [<mem1>..<memN>] [<options>]");
- fprintf(stderr, "zeroed %d mem%s\n", count >= 0 ? count : 0,
- count > 1 ? "s" : "");
+ log_info(&ml, "zeroed %d mem%s\n", count >= 0 ? count : 0,
+ count > 1 ? "s" : "");
return count >= 0 ? 0 : EXIT_FAILURE;
}
--
2.27.0

View File

@ -0,0 +1,64 @@
From 6cab8e0186e73af75f0a15ce87c4db20ef0089df Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:54:01 -0800
Subject: [PATCH 111/217] cxl/memdev: Cleanup memdev filter
util_cxl_memdev_filter() already handles the difference between 'mem%d',
'%d', and 'all' for the identifier format. Drop the duplicate / incomplete
format checking.
If the checking for bad formats was dropped too then this command could
support "0,1,2" syntax in addition to "0 1 2" like 'cxl list'. However, it is
not clear that's worthwhile since 'list' is ok to be imprecise, but memdev
commands need to be stricter.
Link: https://lore.kernel.org/r/164298564100.3021641.9410483964085163708.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
cxl/memdev.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/cxl/memdev.c b/cxl/memdev.c
index 327c260..4cca8b8 100644
--- a/cxl/memdev.c
+++ b/cxl/memdev.c
@@ -191,16 +191,16 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,
usage_with_options(u, options);
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "all") == 0) {
- argv[0] = "all";
argc = 1;
break;
}
+ if (sscanf(argv[i], "mem%lu", &id) == 1)
+ continue;
+ if (sscanf(argv[i], "%lu", &id) == 1)
+ continue;
- if (sscanf(argv[i], "mem%lu", &id) != 1) {
- log_err(&ml, "'%s' is not a valid memdev name\n",
- argv[i]);
- err++;
- }
+ log_err(&ml, "'%s' is not a valid memdev name\n", argv[i]);
+ err++;
}
if (err == argc) {
@@ -243,11 +243,7 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,
count = 0;
for (i = 0; i < argc; i++) {
- if (sscanf(argv[i], "mem%lu", &id) != 1
- && strcmp(argv[i], "all") != 0)
- continue;
-
- cxl_memdev_foreach (ctx, memdev) {
+ cxl_memdev_foreach(ctx, memdev) {
if (!util_cxl_memdev_filter(memdev, argv[i], NULL))
continue;
--
2.27.0

View File

@ -0,0 +1,133 @@
From c09c507e5a608718ac96af088fdc8cb441b09d0b Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:54:06 -0800
Subject: [PATCH 112/217] cxl/memdev: Add serial support for memdev-related
commands
Allow for a "-s, --serial" option to turn the argument list into serial
identifiers.
Link: https://lore.kernel.org/r/164298564631.3021641.5552442288217413180.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/cxl/memdev-option.txt | 5 ++++
Documentation/cxl/meson.build | 4 ++-
cxl/memdev.c | 45 +++++++++++++++++++++--------
3 files changed, 41 insertions(+), 13 deletions(-)
diff --git a/Documentation/cxl/memdev-option.txt b/Documentation/cxl/memdev-option.txt
index e778582..64348be 100644
--- a/Documentation/cxl/memdev-option.txt
+++ b/Documentation/cxl/memdev-option.txt
@@ -2,3 +2,8 @@
A 'memX' device name, or a memdev id number. Restrict the operation to
the specified memdev(s). The keyword 'all' can be specified to indicate
the lack of any restriction.
+
+-S::
+--serial::
+ Rather an a memdev id number, interpret the <memdev> argument(s)
+ as a list of serial numbers.
diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build
index 64ce13f..0a6346b 100644
--- a/Documentation/cxl/meson.build
+++ b/Documentation/cxl/meson.build
@@ -19,7 +19,9 @@ else
endif
filedeps = [
- '../copyright.txt',
+ '../copyright.txt',
+ 'memdev-option.txt',
+ 'labels-options.txt',
]
cxl_manpages = [
diff --git a/cxl/memdev.c b/cxl/memdev.c
index 4cca8b8..ef5343a 100644
--- a/cxl/memdev.c
+++ b/cxl/memdev.c
@@ -24,12 +24,14 @@ static struct parameters {
unsigned len;
unsigned offset;
bool verbose;
+ bool serial;
} param;
static struct log_ctx ml;
#define BASE_OPTIONS() \
-OPT_BOOLEAN('v',"verbose", &param.verbose, "turn on debug")
+OPT_BOOLEAN('v',"verbose", &param.verbose, "turn on debug"), \
+OPT_BOOLEAN('S', "serial", &param.serial, "user serials numbers to id memdevs")
#define READ_OPTIONS() \
OPT_STRING('o', "output", &param.outfile, "output-file", \
@@ -172,8 +174,9 @@ out:
}
static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,
- int (*action)(struct cxl_memdev *memdev, struct action_context *actx),
- const struct option *options, const char *usage)
+ int (*action)(struct cxl_memdev *memdev,
+ struct action_context *actx),
+ const struct option *options, const char *usage)
{
struct cxl_memdev *memdev, *single = NULL;
struct action_context actx = { 0 };
@@ -190,16 +193,25 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,
if (argc == 0)
usage_with_options(u, options);
for (i = 0; i < argc; i++) {
- if (strcmp(argv[i], "all") == 0) {
- argc = 1;
- break;
+ if (param.serial) {
+ char *end;
+
+ strtoull(argv[i], &end, 0);
+ if (end[0] == 0)
+ continue;
+ } else {
+ if (strcmp(argv[i], "all") == 0) {
+ argc = 1;
+ break;
+ }
+ if (sscanf(argv[i], "mem%lu", &id) == 1)
+ continue;
+ if (sscanf(argv[i], "%lu", &id) == 1)
+ continue;
}
- if (sscanf(argv[i], "mem%lu", &id) == 1)
- continue;
- if (sscanf(argv[i], "%lu", &id) == 1)
- continue;
- log_err(&ml, "'%s' is not a valid memdev name\n", argv[i]);
+ log_err(&ml, "'%s' is not a valid memdev %s\n", argv[i],
+ param.serial ? "serial number" : "name");
err++;
}
@@ -244,7 +256,16 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,
for (i = 0; i < argc; i++) {
cxl_memdev_foreach(ctx, memdev) {
- if (!util_cxl_memdev_filter(memdev, argv[i], NULL))
+ const char *memdev_filter = NULL;
+ const char *serial_filter = NULL;
+
+ if (param.serial)
+ serial_filter = argv[i];
+ else
+ memdev_filter = argv[i];
+
+ if (!util_cxl_memdev_filter(memdev, memdev_filter,
+ serial_filter))
continue;
if (action == action_write) {
--
2.27.0

View File

@ -0,0 +1,136 @@
From ca582b2003a2335eafac382e71afdf0a6caaef18 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:54:11 -0800
Subject: [PATCH 113/217] cxl/list: Add 'numa_node' to memdev listings
If the kernel exports a valid numa_node, >= 0, include it in memdev objects
listings.
Link: https://lore.kernel.org/r/164298565156.3021641.14097226245654611710.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/cxl/lib/libcxl.txt | 4 ++++
cxl/json.c | 8 ++++++++
cxl/lib/libcxl.c | 11 +++++++++++
cxl/lib/libcxl.sym | 1 +
cxl/lib/private.h | 1 +
cxl/libcxl.h | 1 +
6 files changed, 26 insertions(+)
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
index b0253d7..de88d19 100644
--- a/Documentation/cxl/lib/libcxl.txt
+++ b/Documentation/cxl/lib/libcxl.txt
@@ -71,6 +71,7 @@ unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev);
const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);
size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev);
int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev);
+int cxl_memdev_get_numa_node(struct cxl_memdev *memdev);
----
A memdev is given a kernel device name of the form "mem%d" where an id
@@ -89,6 +90,9 @@ The 'pmem_size' and 'ram_size' attributes return the current
provisioning of DPA (Device Physical Address / local capacity) in the
device.
+cxl_memdev_get_numa_node() returns the affinitized CPU node number if
+available or -1 otherwise.
+
=== MEMDEV: Commands
----
struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);
diff --git a/cxl/json.c b/cxl/json.c
index b809332..51918d6 100644
--- a/cxl/json.c
+++ b/cxl/json.c
@@ -190,6 +190,7 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
const char *devname = cxl_memdev_get_devname(memdev);
struct json_object *jdev, *jobj;
unsigned long long serial;
+ int numa_node;
jdev = json_object_new_object();
if (!jdev)
@@ -220,6 +221,13 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
json_object_object_add(jdev, "serial", jobj);
}
+ numa_node = cxl_memdev_get_numa_node(memdev);
+ if (numa_node >= 0) {
+ jobj = json_object_new_int(numa_node);
+ if (jobj)
+ json_object_object_add(jdev, "numa_node", jobj);
+ }
+
jobj = json_object_new_string(cxl_memdev_get_host(memdev));
if (jobj)
json_object_object_add(jdev, "host", jobj);
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 0065f6b..14c7db8 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -348,6 +348,12 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)
else
memdev->serial = strtoull(buf, NULL, 0);
+ sprintf(path, "%s/numa_node", cxlmem_base);
+ if (sysfs_read_attr(ctx, path, buf) < 0)
+ memdev->numa_node = -1;
+ else
+ memdev->numa_node = strtol(buf, NULL, 0);
+
memdev->dev_path = strdup(cxlmem_base);
if (!memdev->dev_path)
goto err_read;
@@ -445,6 +451,11 @@ CXL_EXPORT unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev)
return memdev->serial;
}
+CXL_EXPORT int cxl_memdev_get_numa_node(struct cxl_memdev *memdev)
+{
+ return memdev->numa_node;
+}
+
CXL_EXPORT const char *cxl_memdev_get_devname(struct cxl_memdev *memdev)
{
return devpath_to_devname(memdev->dev_path);
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 29f3498..b13a2d6 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -77,6 +77,7 @@ local:
LIBCXL_2 {
global:
cxl_memdev_get_serial;
+ cxl_memdev_get_numa_node;
cxl_memdev_get_host;
cxl_bus_get_first;
cxl_bus_get_next;
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index b097bdf..c00bb36 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -20,6 +20,7 @@ struct cxl_pmem {
struct cxl_endpoint;
struct cxl_memdev {
int id, major, minor;
+ int numa_node;
void *dev_buf;
size_t buf_len;
char *host;
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index e7b675e..be656ed 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -37,6 +37,7 @@ struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx);
struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev);
int cxl_memdev_get_id(struct cxl_memdev *memdev);
unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev);
+int cxl_memdev_get_numa_node(struct cxl_memdev *memdev);
const char *cxl_memdev_get_devname(struct cxl_memdev *memdev);
const char *cxl_memdev_get_host(struct cxl_memdev *memdev);
struct cxl_bus *cxl_memdev_get_bus(struct cxl_memdev *memdev);
--
2.27.0

View File

@ -0,0 +1,329 @@
From e31fc778998b4d02ffec68e61869aaeccfd99be8 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:54:17 -0800
Subject: [PATCH 114/217] util: Implement common bind/unbind helpers
Refactor ndctl_{bind,unbind}() into util_{bind,unbind}() for libcxl to
reuse.
daxctl can not join the party for now as it needs to play games with
'new_id'.
Link: https://lore.kernel.org/r/164298565707.3021641.7763459936156744907.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
ndctl/lib/libndctl.c | 103 +++++--------------------------------------
util/sysfs.c | 76 +++++++++++++++++++++++++++++++
util/sysfs.h | 8 ++++
3 files changed, 96 insertions(+), 91 deletions(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 1374ad9..98d184b 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -1665,10 +1665,6 @@ static enum ndctl_fwa_result fwa_result_to_result(const char *result)
return NDCTL_FWA_RESULT_INVALID;
}
-static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module,
- const char *devname);
-static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath);
-
static int populate_dimm_attributes(struct ndctl_dimm *dimm,
const char *dimm_base,
const char *bus_prefix)
@@ -2305,7 +2301,7 @@ NDCTL_EXPORT int ndctl_dimm_disable(struct ndctl_dimm *dimm)
if (!ndctl_dimm_is_enabled(dimm))
return 0;
- ndctl_unbind(ctx, dimm->dimm_path);
+ util_unbind(dimm->dimm_path, ctx);
if (ndctl_dimm_is_enabled(dimm)) {
err(ctx, "%s: failed to disable\n", devname);
@@ -2324,7 +2320,7 @@ NDCTL_EXPORT int ndctl_dimm_enable(struct ndctl_dimm *dimm)
if (ndctl_dimm_is_enabled(dimm))
return 0;
- ndctl_bind(ctx, dimm->module, devname);
+ util_bind(devname, dimm->module, "nd", ctx);
if (!ndctl_dimm_is_enabled(dimm)) {
err(ctx, "%s: failed to enable\n", devname);
@@ -3573,7 +3569,7 @@ NDCTL_EXPORT int ndctl_region_enable(struct ndctl_region *region)
if (ndctl_region_is_enabled(region))
return 0;
- ndctl_bind(ctx, region->module, devname);
+ util_bind(devname, region->module, "nd", ctx);
if (!ndctl_region_is_enabled(region)) {
err(ctx, "%s: failed to enable\n", devname);
@@ -3610,7 +3606,7 @@ static int ndctl_region_disable(struct ndctl_region *region, int cleanup)
if (!ndctl_region_is_enabled(region))
return 0;
- ndctl_unbind(ctx, region->region_path);
+ util_unbind(region->region_path, ctx);
if (ndctl_region_is_enabled(region)) {
err(ctx, "%s: failed to disable\n", devname);
@@ -4373,81 +4369,6 @@ NDCTL_EXPORT struct badblock *ndctl_namespace_get_first_badblock(
return badblocks_iter_first(&ndns->bb_iter, ctx, path);
}
-static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module,
- const char *devname)
-{
- DIR *dir;
- int rc = 0;
- char path[200];
- struct dirent *de;
- const int len = sizeof(path);
-
- if (!devname) {
- err(ctx, "missing devname\n");
- return -EINVAL;
- }
-
- if (module) {
- rc = kmod_module_probe_insert_module(module,
- KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL,
- NULL);
- if (rc < 0) {
- err(ctx, "%s: insert failure: %d\n", __func__, rc);
- return rc;
- }
- }
-
- if (snprintf(path, len, "/sys/bus/nd/drivers") >= len) {
- err(ctx, "%s: buffer too small!\n", devname);
- return -ENXIO;
- }
-
- dir = opendir(path);
- if (!dir) {
- err(ctx, "%s: opendir(\"%s\") failed\n", devname, path);
- return -ENXIO;
- }
-
- while ((de = readdir(dir)) != NULL) {
- char *drv_path;
-
- if (de->d_ino == 0)
- continue;
- if (de->d_name[0] == '.')
- continue;
- if (asprintf(&drv_path, "%s/%s/bind", path, de->d_name) < 0) {
- err(ctx, "%s: path allocation failure\n", devname);
- continue;
- }
-
- rc = sysfs_write_attr_quiet(ctx, drv_path, devname);
- free(drv_path);
- if (rc == 0)
- break;
- }
- closedir(dir);
-
- if (rc) {
- dbg(ctx, "%s: bind failed\n", devname);
- return -ENXIO;
- }
- return 0;
-}
-
-static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath)
-{
- const char *devname = devpath_to_devname(devpath);
- char path[200];
- const int len = sizeof(path);
-
- if (snprintf(path, len, "%s/driver/unbind", devpath) >= len) {
- err(ctx, "%s: buffer too small!\n", devname);
- return -ENXIO;
- }
-
- return sysfs_write_attr(ctx, path, devname);
-}
-
static void *add_btt(void *parent, int id, const char *btt_base);
static void *add_pfn(void *parent, int id, const char *pfn_base);
static void *add_dax(void *parent, int id, const char *dax_base);
@@ -4533,7 +4454,7 @@ NDCTL_EXPORT int ndctl_namespace_enable(struct ndctl_namespace *ndns)
if (ndctl_namespace_is_enabled(ndns))
return 0;
- rc = ndctl_bind(ctx, ndns->module, devname);
+ rc = util_bind(devname, ndns->module, "nd", ctx);
/*
* Rescan now as successfully enabling a namespace device leads
@@ -4581,7 +4502,7 @@ NDCTL_EXPORT int ndctl_namespace_disable(struct ndctl_namespace *ndns)
if (!ndctl_namespace_is_enabled(ndns))
return 0;
- ndctl_unbind(ctx, ndns->ndns_path);
+ util_unbind(ndns->ndns_path, ctx);
if (ndctl_namespace_is_enabled(ndns)) {
err(ctx, "%s: failed to disable\n", devname);
@@ -5420,7 +5341,7 @@ NDCTL_EXPORT int ndctl_btt_enable(struct ndctl_btt *btt)
if (ndctl_btt_is_enabled(btt))
return 0;
- ndctl_bind(ctx, btt->module, devname);
+ util_bind(devname, btt->module, "nd", ctx);
if (!ndctl_btt_is_enabled(btt)) {
err(ctx, "%s: failed to enable\n", devname);
@@ -5457,7 +5378,7 @@ NDCTL_EXPORT int ndctl_btt_delete(struct ndctl_btt *btt)
return 0;
}
- ndctl_unbind(ctx, btt->btt_path);
+ util_unbind(btt->btt_path, ctx);
rc = ndctl_btt_set_namespace(btt, NULL);
if (rc) {
@@ -5908,7 +5829,7 @@ NDCTL_EXPORT int ndctl_pfn_enable(struct ndctl_pfn *pfn)
if (ndctl_pfn_is_enabled(pfn))
return 0;
- ndctl_bind(ctx, pfn->module, devname);
+ util_bind(devname, pfn->module, "nd", ctx);
if (!ndctl_pfn_is_enabled(pfn)) {
err(ctx, "%s: failed to enable\n", devname);
@@ -5945,7 +5866,7 @@ NDCTL_EXPORT int ndctl_pfn_delete(struct ndctl_pfn *pfn)
return 0;
}
- ndctl_unbind(ctx, pfn->pfn_path);
+ util_unbind(pfn->pfn_path, ctx);
rc = ndctl_pfn_set_namespace(pfn, NULL);
if (rc) {
@@ -6101,7 +6022,7 @@ NDCTL_EXPORT int ndctl_dax_enable(struct ndctl_dax *dax)
if (ndctl_dax_is_enabled(dax))
return 0;
- ndctl_bind(ctx, pfn->module, devname);
+ util_bind(devname, pfn->module, "nd", ctx);
if (!ndctl_dax_is_enabled(dax)) {
err(ctx, "%s: failed to enable\n", devname);
@@ -6132,7 +6053,7 @@ NDCTL_EXPORT int ndctl_dax_delete(struct ndctl_dax *dax)
return 0;
}
- ndctl_unbind(ctx, pfn->pfn_path);
+ util_unbind(pfn->pfn_path, ctx);
rc = ndctl_dax_set_namespace(dax, NULL);
if (rc) {
diff --git a/util/sysfs.c b/util/sysfs.c
index 23330cb..968683b 100644
--- a/util/sysfs.c
+++ b/util/sysfs.c
@@ -145,3 +145,79 @@ struct kmod_module *__util_modalias_to_module(struct kmod_ctx *kmod_ctx,
return mod;
}
+
+int __util_bind(const char *devname, struct kmod_module *module,
+ const char *bus, struct log_ctx *ctx)
+{
+ DIR *dir;
+ int rc = 0;
+ char path[200];
+ struct dirent *de;
+ const int len = sizeof(path);
+
+ if (!devname) {
+ log_err(ctx, "missing devname\n");
+ return -EINVAL;
+ }
+
+ if (module) {
+ rc = kmod_module_probe_insert_module(module,
+ KMOD_PROBE_APPLY_BLACKLIST,
+ NULL, NULL, NULL, NULL);
+ if (rc < 0) {
+ log_err(ctx, "%s: insert failure: %d\n", __func__, rc);
+ return rc;
+ }
+ }
+
+ if (snprintf(path, len, "/sys/bus/%s/drivers", bus) >= len) {
+ log_err(ctx, "%s: buffer too small!\n", devname);
+ return -ENXIO;
+ }
+
+ dir = opendir(path);
+ if (!dir) {
+ log_err(ctx, "%s: opendir(\"%s\") failed\n", devname, path);
+ return -ENXIO;
+ }
+
+ while ((de = readdir(dir)) != NULL) {
+ char *drv_path;
+
+ if (de->d_ino == 0)
+ continue;
+ if (de->d_name[0] == '.')
+ continue;
+
+ if (asprintf(&drv_path, "%s/%s/bind", path, de->d_name) < 0) {
+ log_err(ctx, "%s: path allocation failure\n", devname);
+ continue;
+ }
+
+ rc = __sysfs_write_attr_quiet(ctx, drv_path, devname);
+ free(drv_path);
+ if (rc == 0)
+ break;
+ }
+ closedir(dir);
+
+ if (rc) {
+ log_dbg(ctx, "%s: bind failed\n", devname);
+ return -ENXIO;
+ }
+ return 0;
+}
+
+int __util_unbind(const char *devpath, struct log_ctx *ctx)
+{
+ const char *devname = devpath_to_devname(devpath);
+ char path[200];
+ const int len = sizeof(path);
+
+ if (snprintf(path, len, "%s/driver/unbind", devpath) >= len) {
+ log_err(ctx, "%s: buffer too small!\n", devname);
+ return -ENXIO;
+ }
+
+ return __sysfs_write_attr(ctx, path, devname);
+}
diff --git a/util/sysfs.h b/util/sysfs.h
index bdee4f5..4c95c70 100644
--- a/util/sysfs.h
+++ b/util/sysfs.h
@@ -35,4 +35,12 @@ struct kmod_module *__util_modalias_to_module(struct kmod_ctx *kmod_ctx,
struct log_ctx *log);
#define util_modalias_to_module(ctx, buf) \
__util_modalias_to_module((ctx)->kmod_ctx, buf, &(ctx)->ctx)
+
+int __util_bind(const char *devname, struct kmod_module *module, const char *bus,
+ struct log_ctx *ctx);
+#define util_bind(n, m, b, c) __util_bind(n, m, b, &(c)->ctx)
+
+int __util_unbind(const char *devpath, struct log_ctx *ctx);
+#define util_unbind(p, c) __util_unbind(p, &(c)->ctx)
+
#endif /* __UTIL_SYSFS_H__ */
--
2.27.0

View File

@ -0,0 +1,379 @@
From 782694f9aeff6e146cfd00b31822995790546175 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:54:22 -0800
Subject: [PATCH 115/217] cxl/memdev: Enable / disable support
Introduce the 'cxl {enable,disable}-memdev' commands. When a memdev is
disabled the ports in the topology may be unregistered. CXL memory regions
require each endpoint in the interleave to attach to the cxl_mem driver
before regions are activated.
Note that this starts out with the deliberate bug that it has false
positive detection of active memdevs. The fix for that bug requires kernel
support to detect the device's active participation in a region, until then
require all disable attempts to specify the --force override. This way
there are never any releases of cxl-cli that lack disable-memdev safety.
Link: https://lore.kernel.org/r/164298566245.3021641.12696907310209056878.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
Documentation/cxl/cxl-disable-memdev.txt | 37 +++++++++++++++
Documentation/cxl/cxl-enable-memdev.txt | 34 ++++++++++++++
Documentation/cxl/lib/libcxl.txt | 23 +++++++++
Documentation/cxl/meson.build | 2 +
cxl/builtin.h | 2 +
cxl/cxl.c | 2 +
cxl/lib/libcxl.c | 58 +++++++++++++++++++++++
cxl/lib/libcxl.sym | 2 +
cxl/libcxl.h | 2 +
cxl/memdev.c | 60 +++++++++++++++++++++++-
10 files changed, 221 insertions(+), 1 deletion(-)
create mode 100644 Documentation/cxl/cxl-disable-memdev.txt
create mode 100644 Documentation/cxl/cxl-enable-memdev.txt
diff --git a/Documentation/cxl/cxl-disable-memdev.txt b/Documentation/cxl/cxl-disable-memdev.txt
new file mode 100644
index 0000000..edd5385
--- /dev/null
+++ b/Documentation/cxl/cxl-disable-memdev.txt
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+
+cxl-disable-memdev(1)
+=====================
+
+NAME
+----
+cxl-disable-memdev - deactivate / hot-remove a given CXL memdev
+
+SYNOPSIS
+--------
+[verse]
+'cxl disable-memdev' <mem0> [<mem1>..<memN>] [<options>]
+
+
+OPTIONS
+-------
+<memory device(s)>::
+include::memdev-option.txt[]
+
+-f::
+--force::
+ DANGEROUS: Override the safety measure that blocks attempts to disable
+ a device if the tool determines the memdev is in active usage. Recall
+ that CXL memory ranges might have been established by platform
+ firmware and disabling an active device is akin to force removing
+ memory from a running system.
+
+-v::
+ Turn on verbose debug messages in the library (if libcxl was built with
+ logging and debug enabled).
+
+include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkcxl:cxl-enable-memdev[1]
diff --git a/Documentation/cxl/cxl-enable-memdev.txt b/Documentation/cxl/cxl-enable-memdev.txt
new file mode 100644
index 0000000..088d5e0
--- /dev/null
+++ b/Documentation/cxl/cxl-enable-memdev.txt
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+
+cxl-enable-memdev(1)
+====================
+
+NAME
+----
+cxl-enable-memdev - activate / hot-add a given CXL memdev
+
+SYNOPSIS
+--------
+[verse]
+'cxl enable-memdev' <mem0> [<mem1>..<memN>] [<options>]
+
+A memdev typically autoenables at initial device discovery. However, if
+it was manually disabled this command can trigger the kernel to activate
+it again. This involves detecting the state of the HDM (Host Managed
+Device Memory) Decoders and validating that CXL.mem is enabled for each
+port in the device's hierarchy.
+
+OPTIONS
+-------
+<memory device(s)>::
+include::memdev-option.txt[]
+
+-v::
+ Turn on verbose debug messages in the library (if libcxl was built with
+ logging and debug enabled).
+
+include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkcxl:cxl-disable-memdev[1]
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
index de88d19..49edb71 100644
--- a/Documentation/cxl/lib/libcxl.txt
+++ b/Documentation/cxl/lib/libcxl.txt
@@ -93,6 +93,29 @@ device.
cxl_memdev_get_numa_node() returns the affinitized CPU node number if
available or -1 otherwise.
+=== MEMDEV: Control
+----
+int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev);
+int cxl_memdev_enable(struct cxl_memdev *memdev);
+----
+When a memory device is disabled it unregisters its associated endpoints
+and potentially intervening switch ports if there are no other memdevs
+pinning that port active. That means that any existing port objects that
+the library has previously returned are in valid and need to be re-read.
+Callers must be careful to re-retrieve port objects after
+cxl_memdev_disable_invalidate(). Any usage of a previously obtained port
+object after a cxl_memdev_disable_invalidate() call is a use-after-free
+programming error. It follows that after cxl_memdev_enable() new ports
+may appear in the topology that were not previously enumerable.
+
+NOTE: cxl_memdev_disable_invalidate() will force disable the memdev
+regardless of whether the memory provided by the device is in active use
+by the operating system. Callers take responisbility for assuring that
+it is safe to disable the memory device. Otherwise, this call can be as
+destructive as ripping a DIMM out of a running system. Like all other
+libcxl calls that mutate the system state or divulge security sensitive
+information this call requires root / CAP_SYS_ADMIN.
+
=== MEMDEV: Commands
----
struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode);
diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build
index 0a6346b..7618c97 100644
--- a/Documentation/cxl/meson.build
+++ b/Documentation/cxl/meson.build
@@ -30,6 +30,8 @@ cxl_manpages = [
'cxl-read-labels.txt',
'cxl-write-labels.txt',
'cxl-zero-labels.txt',
+ 'cxl-enable-memdev.txt',
+ 'cxl-disable-memdev.txt',
]
foreach man : cxl_manpages
diff --git a/cxl/builtin.h b/cxl/builtin.h
index 78eca6e..621c85c 100644
--- a/cxl/builtin.h
+++ b/cxl/builtin.h
@@ -10,4 +10,6 @@ int cmd_read_labels(int argc, const char **argv, struct cxl_ctx *ctx);
int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx);
int cmd_init_labels(int argc, const char **argv, struct cxl_ctx *ctx);
int cmd_check_labels(int argc, const char **argv, struct cxl_ctx *ctx);
+int cmd_disable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);
+int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx);
#endif /* _CXL_BUILTIN_H_ */
diff --git a/cxl/cxl.c b/cxl/cxl.c
index 4b1661d..78d2e9a 100644
--- a/cxl/cxl.c
+++ b/cxl/cxl.c
@@ -64,6 +64,8 @@ static struct cmd_struct commands[] = {
{ "zero-labels", .c_fn = cmd_zero_labels },
{ "read-labels", .c_fn = cmd_read_labels },
{ "write-labels", .c_fn = cmd_write_labels },
+ { "disable-memdev", .c_fn = cmd_disable_memdev },
+ { "enable-memdev", .c_fn = cmd_enable_memdev },
};
int main(int argc, const char **argv)
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 14c7db8..2fdaf71 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -500,6 +500,64 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev
return memdev->firmware_version;
}
+CXL_EXPORT int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev)
+{
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ const char *devname = cxl_memdev_get_devname(memdev);
+ struct cxl_port *port, *_p, *bus_port;
+ struct cxl_bus *bus;
+
+ if (!cxl_memdev_is_enabled(memdev))
+ return 0;
+
+ bus = cxl_memdev_get_bus(memdev);
+ if (!bus) {
+ err(ctx, "%s: failed to invalidate\n", devname);
+ return -ENXIO;
+ }
+
+ util_unbind(memdev->dev_path, ctx);
+
+ if (cxl_memdev_is_enabled(memdev)) {
+ err(ctx, "%s: failed to disable\n", devname);
+ return -EBUSY;
+ }
+
+ /*
+ * The state of all ports is now indeterminate, delete them all
+ * and start over.
+ */
+ bus_port = cxl_bus_get_port(bus);
+ list_for_each_safe(&bus_port->child_ports, port, _p, list)
+ free_port(port, &bus_port->child_ports);
+ bus_port->ports_init = 0;
+ memdev->endpoint = NULL;
+
+ dbg(ctx, "%s: disabled\n", devname);
+
+ return 0;
+}
+
+CXL_EXPORT int cxl_memdev_enable(struct cxl_memdev *memdev)
+{
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ const char *devname = cxl_memdev_get_devname(memdev);
+
+ if (cxl_memdev_is_enabled(memdev))
+ return 0;
+
+ util_bind(devname, memdev->module, "cxl", ctx);
+
+ if (!cxl_memdev_is_enabled(memdev)) {
+ err(ctx, "%s: failed to enable\n", devname);
+ return -ENXIO;
+ }
+
+ dbg(ctx, "%s: enabled\n", devname);
+
+ return 0;
+}
+
static struct cxl_endpoint *cxl_port_find_endpoint(struct cxl_port *parent_port,
struct cxl_memdev *memdev)
{
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index b13a2d6..f235e99 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -115,4 +115,6 @@ global:
cxl_memdev_get_endpoint;
cxl_memdev_is_enabled;
cxl_memdev_get_bus;
+ cxl_memdev_disable_invalidate;
+ cxl_memdev_enable;
} LIBCXL_1;
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index be656ed..53f68dd 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -48,6 +48,8 @@ unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev);
unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev);
const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);
size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev);
+int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev);
+int cxl_memdev_enable(struct cxl_memdev *memdev);
struct cxl_endpoint;
struct cxl_endpoint *cxl_memdev_get_endpoint(struct cxl_memdev *memdev);
int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev);
diff --git a/cxl/memdev.c b/cxl/memdev.c
index ef5343a..90b33e1 100644
--- a/cxl/memdev.c
+++ b/cxl/memdev.c
@@ -25,13 +25,14 @@ static struct parameters {
unsigned offset;
bool verbose;
bool serial;
+ bool force;
} param;
static struct log_ctx ml;
#define BASE_OPTIONS() \
OPT_BOOLEAN('v',"verbose", &param.verbose, "turn on debug"), \
-OPT_BOOLEAN('S', "serial", &param.serial, "user serials numbers to id memdevs")
+OPT_BOOLEAN('S', "serial", &param.serial, "use serial numbers to id memdevs")
#define READ_OPTIONS() \
OPT_STRING('o', "output", &param.outfile, "output-file", \
@@ -46,6 +47,10 @@ OPT_UINTEGER('s', "size", &param.len, "number of label bytes to operate"), \
OPT_UINTEGER('O', "offset", &param.offset, \
"offset into the label area to start operation")
+#define DISABLE_OPTIONS() \
+OPT_BOOLEAN('f', "force", &param.force, \
+ "DANGEROUS: override active memdev safety checks")
+
static const struct option read_options[] = {
BASE_OPTIONS(),
LABEL_OPTIONS(),
@@ -66,6 +71,37 @@ static const struct option zero_options[] = {
OPT_END(),
};
+static const struct option disable_options[] = {
+ BASE_OPTIONS(),
+ DISABLE_OPTIONS(),
+ OPT_END(),
+};
+
+static const struct option enable_options[] = {
+ BASE_OPTIONS(),
+ OPT_END(),
+};
+
+static int action_disable(struct cxl_memdev *memdev, struct action_context *actx)
+{
+ if (!cxl_memdev_is_enabled(memdev))
+ return 0;
+
+ if (!param.force) {
+ /* TODO: actually detect rather than assume active */
+ log_err(&ml, "%s is part of an active region\n",
+ cxl_memdev_get_devname(memdev));
+ return -EBUSY;
+ }
+
+ return cxl_memdev_disable_invalidate(memdev);
+}
+
+static int action_enable(struct cxl_memdev *memdev, struct action_context *actx)
+{
+ return cxl_memdev_enable(memdev);
+}
+
static int action_zero(struct cxl_memdev *memdev, struct action_context *actx)
{
size_t size;
@@ -340,3 +376,25 @@ int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx)
count > 1 ? "s" : "");
return count >= 0 ? 0 : EXIT_FAILURE;
}
+
+int cmd_disable_memdev(int argc, const char **argv, struct cxl_ctx *ctx)
+{
+ int count = memdev_action(
+ argc, argv, ctx, action_disable, disable_options,
+ "cxl disable-memdev <mem0> [<mem1>..<memN>] [<options>]");
+
+ log_info(&ml, "disabled %d mem%s\n", count >= 0 ? count : 0,
+ count > 1 ? "s" : "");
+ return count >= 0 ? 0 : EXIT_FAILURE;
+}
+
+int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx)
+{
+ int count = memdev_action(
+ argc, argv, ctx, action_enable, enable_options,
+ "cxl enable-memdev <mem0> [<mem1>..<memN>] [<options>]");
+
+ log_info(&ml, "enabled %d mem%s\n", count >= 0 ? count : 0,
+ count > 1 ? "s" : "");
+ return count >= 0 ? 0 : EXIT_FAILURE;
+}
--
2.27.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,537 @@
From 1279d1989ef77085d214a193c1458b624039c612 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sun, 23 Jan 2022 16:54:34 -0800
Subject: [PATCH 117/217] cxl/list: Extend decoder objects with target
information
A target combines information about a dport along with its position in the
intereleave order. With targets enumerated decoders can also be filtered be
memory devices by seeing which decoders have a dport in the memory-device's
ancestry.
$ cxl list -D -d 3.1 -T -u
{
"decoder":"decoder3.1",
"resource":"0x8030000000",
"size":"512.00 MiB (536.87 MB)",
"volatile_capable":true,
"nr_targets":2,
"targets":[
{
"target":"cxl_host_bridge.1",
"position":1,
"id":"0x1"
},
{
"target":"cxl_host_bridge.0",
"position":0,
"id":"0"
}
]
}
Link: https://lore.kernel.org/r/164298567435.3021641.3771899644901785666.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
.clang-format | 1 +
Documentation/cxl/cxl-list.txt | 8 ++-
Documentation/cxl/lib/libcxl.txt | 58 ++++++++++++++++
cxl/filter.c | 25 +++++++
cxl/filter.h | 1 +
cxl/json.c | 46 +++++++++++++
cxl/lib/libcxl.c | 115 +++++++++++++++++++++++++++++++
cxl/lib/libcxl.sym | 10 +++
cxl/libcxl.h | 19 +++++
cxl/list.c | 2 +
10 files changed, 283 insertions(+), 2 deletions(-)
diff --git a/.clang-format b/.clang-format
index 16e28ac..47fb657 100644
--- a/.clang-format
+++ b/.clang-format
@@ -81,6 +81,7 @@ ForEachMacros:
- 'cxl_bus_foreach'
- 'cxl_port_foreach'
- 'cxl_decoder_foreach'
+ - 'cxl_target_foreach'
- 'cxl_endpoint_foreach'
- 'daxctl_dev_foreach'
- 'daxctl_mapping_foreach'
diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
index 84872b9..20ff2cb 100644
--- a/Documentation/cxl/cxl-list.txt
+++ b/Documentation/cxl/cxl-list.txt
@@ -44,8 +44,8 @@ would only list objects that are beneath port10 AND map mem0, mem1, OR
mem2.
Given that many topology queries seek to answer questions relative to a
-given memdev, buses, ports, and endpoints can be filtered by one or more
-memdevs. For example:
+given memdev, buses, ports, endpoints, and decoders can be filtered by
+one or more memdevs. For example:
----
# cxl list -P -p switch,endpoint -m mem0
[
@@ -270,6 +270,10 @@ OPTIONS
"decoder<port_id>.<instance_id>". The possible decoder type names are
"root", "switch", or "endpoint", similar to the port filter syntax.
+-T::
+--targets::
+ Extend decoder listings with downstream port target information.
+
--debug::
If the cxl tool was built with debug enabled, turn on debug
messages.
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
index 73af3d0..bd92fef 100644
--- a/Documentation/cxl/lib/libcxl.txt
+++ b/Documentation/cxl/lib/libcxl.txt
@@ -300,6 +300,7 @@ device-local-physical-address).
struct cxl_decoder *cxl_decoder_get_first(struct cxl_port *port);
struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder);
struct cxl_ctx *cxl_decoder_get_ctx(struct cxl_decoder *decoder);
+struct cxl_decoder *cxl_target_get_decoder(struct cxl_target *target);
#define cxl_decoder_foreach(port, decoder) \
for (decoder = cxl_decoder_get_first(port); decoder != NULL; \
@@ -314,6 +315,7 @@ unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder);
unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder);
const char *cxl_decoder_get_devname(struct cxl_decoder *decoder);
int cxl_decoder_get_id(struct cxl_decoder *decoder);
+int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder);
enum cxl_decoder_target_type {
CXL_DECODER_TTYPE_UNKNOWN,
@@ -352,6 +354,62 @@ Platform firmware may setup the CXL decode hierarchy before the OS
boots, and may additionally require that the OS not change the decode
settings. This property is indicated by the cxl_decoder_is_locked() API.
+==== TARGETS
+A root or switch level decoder takes an SPA (system-physical-address) as
+input and routes it to a downstream port. Which downstream port depends
+on the downstream port's position in the interleave. A 'struct
+cxl_target' object represents the properties of a given downstream port
+relative to its interleave configuration.
+
+===== TARGET: Enumeration
+----
+struct cxl_target *cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder,
+ struct cxl_memdev *memdev);
+struct cxl_target *
+cxl_decoder_get_target_by_position(struct cxl_decoder *decoder, int position);
+struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder);
+struct cxl_target *cxl_target_get_next(struct cxl_target *target);
+
+#define cxl_target_foreach(decoder, target) \
+ for (target = cxl_target_get_first(decoder); target != NULL; \
+ target = cxl_target_get_next(target))
+----
+Target objects can only be enumerated if the decoder has been
+configured, for switch decoders. For root decoders they are always
+available since the root decoder target mapping is static. The
+cxl_decoder_get_target_by_memdev() helper walks the topology to validate
+if the given memory device is capable of receiving cycles from this
+upstream decoder. It does not validate if the memory device is currently
+configured to participate in that decode.
+
+===== TARGET: Attributes
+----
+int cxl_target_get_position(struct cxl_target *target);
+unsigned long cxl_target_get_id(struct cxl_target *target);
+const char *cxl_target_get_devname(struct cxl_target *target);
+bool cxl_target_maps_memdev(struct cxl_target *target,
+ struct cxl_memdev *memdev);
+----
+The position of a decoder along with the interleave granularity dictate
+which address in the decoder's resource range map to which port.
+
+The target id is an identifier that the CXL port uses to reference this
+downstream port. For CXL / PCIe downstream switch ports the id is
+defined by the PCIe Link Capability Port Number field. For root decoders
+the id is specified by platform firmware specific mechanism. For
+ACPI.CXL defined root ports the id comes from the CEDT.CHBS / ACPI0016
+_UID.
+
+The device name of a target is the name of the host device for the
+downstream port. For CXL / PCIe downstream ports the devname is
+downstream switch port PCI device. For CXL root ports the devname is a
+platform firmware object for the host bridge like a ACPI0016 device
+instance.
+
+The cxl_target_maps_memdev() helper is the companion of
+cxl_decoder_get_target_by_memdev() to determine which downstream ports /
+targets are capable of mapping which memdevs.
+
include::../../copyright.txt[]
SEE ALSO
diff --git a/cxl/filter.c b/cxl/filter.c
index dc052f6..05ede91 100644
--- a/cxl/filter.c
+++ b/cxl/filter.c
@@ -421,6 +421,26 @@ static struct cxl_decoder *util_cxl_decoder_filter(struct cxl_decoder *decoder,
return NULL;
}
+static struct cxl_decoder *
+util_cxl_decoder_filter_by_memdev(struct cxl_decoder *decoder,
+ const char *ident, const char *serial)
+{
+ struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);
+ struct cxl_memdev *memdev;
+
+ if (!ident && !serial)
+ return decoder;
+
+ cxl_memdev_foreach(ctx, memdev) {
+ if (!util_cxl_memdev_filter(memdev, ident, serial))
+ continue;
+ if (cxl_decoder_get_target_by_memdev(decoder, memdev))
+ return decoder;
+ }
+
+ return NULL;
+}
+
static unsigned long params_to_flags(struct cxl_filter_params *param)
{
unsigned long flags = 0;
@@ -431,6 +451,8 @@ static unsigned long params_to_flags(struct cxl_filter_params *param)
flags |= UTIL_JSON_HUMAN;
if (param->health)
flags |= UTIL_JSON_HEALTH;
+ if (param->targets)
+ flags |= UTIL_JSON_TARGETS;
return flags;
}
@@ -521,6 +543,9 @@ static void walk_decoders(struct cxl_port *port, struct cxl_filter_params *p,
if (!util_cxl_decoder_filter_by_port(decoder, p->port_filter,
pf_mode(p)))
continue;
+ if (!util_cxl_decoder_filter_by_memdev(
+ decoder, p->memdev_filter, p->serial_filter))
+ continue;
if (!p->idle && cxl_decoder_get_size(decoder) == 0)
continue;
jdecoder = util_cxl_decoder_to_json(decoder, flags);
diff --git a/cxl/filter.h b/cxl/filter.h
index 5d7bf45..6fd469f 100644
--- a/cxl/filter.h
+++ b/cxl/filter.h
@@ -16,6 +16,7 @@ struct cxl_filter_params {
bool single;
bool endpoints;
bool decoders;
+ bool targets;
bool memdevs;
bool ports;
bool buses;
diff --git a/cxl/json.c b/cxl/json.c
index 548bc52..3a37909 100644
--- a/cxl/json.c
+++ b/cxl/json.c
@@ -268,6 +268,8 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,
const char *devname = cxl_decoder_get_devname(decoder);
struct cxl_port *port = cxl_decoder_get_port(decoder);
struct json_object *jdecoder, *jobj;
+ struct json_object *jtargets;
+ struct cxl_target *target;
u64 val;
jdecoder = json_object_new_object();
@@ -321,7 +323,51 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,
jobj);
}
+ /* Endpoints don't have targets, they *are* targets */
+ if (cxl_port_is_endpoint(port))
+ return jdecoder;
+
+ val = cxl_decoder_get_nr_targets(decoder);
+ jobj = json_object_new_int(val);
+ if (jobj)
+ json_object_object_add(jdecoder, "nr_targets", jobj);
+
+ if (!(flags & UTIL_JSON_TARGETS) ||
+ !cxl_decoder_get_nr_targets(decoder))
+ return jdecoder;
+
+ jtargets = json_object_new_array();
+ if (!jtargets)
+ return jdecoder;
+
+ cxl_target_foreach(decoder, target) {
+ struct json_object *jtarget = json_object_new_object();
+
+ if (!jtarget)
+ continue;
+
+ devname = cxl_target_get_devname(target);
+ jobj = json_object_new_string(devname);
+ if (jobj)
+ json_object_object_add(jtarget, "target", jobj);
+
+ val = cxl_target_get_position(target);
+ jobj = json_object_new_int(val);
+ if (jobj)
+ json_object_object_add(jtarget, "position", jobj);
+
+ val = cxl_target_get_id(target);
+ jobj = util_json_object_hex(val, flags);
+ if (jobj)
+ json_object_object_add(jtarget, "id", jobj);
+
+ json_object_array_add(jtargets, jtarget);
+ }
+
+ json_object_object_add(jdecoder, "targets", jtargets);
+
return jdecoder;
+
}
static struct json_object *__util_cxl_port_to_json(struct cxl_port *port,
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 5e30923..877f42c 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -67,10 +67,22 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head)
free(memdev);
}
+static void free_target(struct cxl_target *target, struct list_head *head)
+{
+ if (head)
+ list_del_from(head, &target->list);
+ free(target->dev_path);
+ free(target);
+}
+
static void free_decoder(struct cxl_decoder *decoder, struct list_head *head)
{
+ struct cxl_target *target, *_t;
+
if (head)
list_del_from(head, &decoder->list);
+ list_for_each_safe(&decoder->targets, target, _t, list)
+ free_target(target, &decoder->targets);
free(decoder->dev_buf);
free(decoder->dev_path);
free(decoder);
@@ -856,6 +868,7 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)
struct cxl_port *port = parent;
struct cxl_ctx *ctx = cxl_port_get_ctx(port);
char buf[SYSFS_ATTR_SIZE];
+ char *target_id, *save;
size_t i;
dbg(ctx, "%s: base: \'%s\'\n", devname, cxldecoder_base);
@@ -870,6 +883,7 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)
decoder->id = id;
decoder->ctx = ctx;
decoder->port = port;
+ list_head_init(&decoder->targets);
decoder->dev_path = strdup(cxldecoder_base);
if (!decoder->dev_path)
@@ -935,6 +949,36 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)
}
}
+ sprintf(path, "%s/target_list", cxldecoder_base);
+ if (sysfs_read_attr(ctx, path, buf) < 0)
+ buf[0] = '\0';
+
+ for (i = 0, target_id = strtok_r(buf, ",", &save); target_id;
+ target_id = strtok_r(NULL, ",", &save), i++) {
+ int did = strtoul(target_id, NULL, 0);
+ struct cxl_target *target = calloc(1, sizeof(*target));
+
+ if (!target)
+ break;
+
+ target->id = did;
+ target->position = i;
+ target->decoder = decoder;
+ sprintf(port->dev_buf, "%s/dport%d", port->dev_path, did);
+ target->dev_path = realpath(port->dev_buf, NULL);
+ if (!target->dev_path) {
+ free(target);
+ break;
+ }
+ dbg(ctx, "%s: target%ld %s\n", devname, i, target->dev_path);
+ list_add(&decoder->targets, &target->list);
+ }
+
+ if (target_id)
+ err(ctx, "%s: failed to parse target%ld\n",
+ devpath_to_devname(cxldecoder_base), i);
+ decoder->nr_targets = i;
+
cxl_decoder_foreach(port, decoder_dup)
if (decoder_dup->id == decoder->id) {
free_decoder(decoder, NULL);
@@ -1044,11 +1088,82 @@ CXL_EXPORT bool cxl_decoder_is_locked(struct cxl_decoder *decoder)
return decoder->locked;
}
+CXL_EXPORT int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder)
+{
+ return decoder->nr_targets;
+}
+
CXL_EXPORT const char *cxl_decoder_get_devname(struct cxl_decoder *decoder)
{
return devpath_to_devname(decoder->dev_path);
}
+CXL_EXPORT struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder)
+{
+ return list_top(&decoder->targets, struct cxl_target, list);
+}
+
+CXL_EXPORT struct cxl_decoder *cxl_target_get_decoder(struct cxl_target *target)
+{
+ return target->decoder;
+}
+
+CXL_EXPORT struct cxl_target *cxl_target_get_next(struct cxl_target *target)
+{
+ struct cxl_decoder *decoder = cxl_target_get_decoder(target);
+
+ return list_next(&decoder->targets, target, list);
+}
+
+CXL_EXPORT const char *cxl_target_get_devname(struct cxl_target *target)
+{
+ return devpath_to_devname(target->dev_path);
+}
+
+CXL_EXPORT unsigned long cxl_target_get_id(struct cxl_target *target)
+{
+ return target->id;
+}
+
+CXL_EXPORT int cxl_target_get_position(struct cxl_target *target)
+{
+ return target->position;
+}
+
+CXL_EXPORT bool cxl_target_maps_memdev(struct cxl_target *target,
+ struct cxl_memdev *memdev)
+{
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+
+ dbg(ctx, "memdev: %s target: %s\n", memdev->host_path,
+ target->dev_path);
+
+ return !!strstr(memdev->host_path, target->dev_path);
+}
+
+CXL_EXPORT struct cxl_target *
+cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder,
+ struct cxl_memdev *memdev)
+{
+ struct cxl_target *target;
+
+ cxl_target_foreach(decoder, target)
+ if (cxl_target_maps_memdev(target, memdev))
+ return target;
+ return NULL;
+}
+
+CXL_EXPORT struct cxl_target *
+cxl_decoder_get_target_by_position(struct cxl_decoder *decoder, int position)
+{
+ struct cxl_target *target;
+
+ cxl_target_foreach(decoder, target)
+ if (target->position == position)
+ return target;
+ return NULL;
+}
+
static void *add_cxl_port(void *parent, int id, const char *cxlport_base)
{
const char *devname = devpath_to_devname(cxlport_base);
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 22babb7..cb33180 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -125,10 +125,20 @@ global:
cxl_decoder_get_resource;
cxl_decoder_get_size;
cxl_decoder_get_devname;
+ cxl_decoder_get_target_by_memdev;
+ cxl_decoder_get_target_by_position;
+ cxl_decoder_get_nr_targets;
cxl_decoder_get_target_type;
cxl_decoder_is_pmem_capable;
cxl_decoder_is_volatile_capable;
cxl_decoder_is_mem_capable;
cxl_decoder_is_accelmem_capable;
cxl_decoder_is_locked;
+ cxl_target_get_first;
+ cxl_target_get_next;
+ cxl_target_get_decoder;
+ cxl_target_get_position;
+ cxl_target_get_id;
+ cxl_target_get_devname;
+ cxl_target_maps_memdev;
} LIBCXL_1;
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index 439ed93..abda0e5 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -104,6 +104,11 @@ struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder);
unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder);
unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder);
const char *cxl_decoder_get_devname(struct cxl_decoder *decoder);
+struct cxl_target *cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder,
+ struct cxl_memdev *memdev);
+struct cxl_target *
+cxl_decoder_get_target_by_position(struct cxl_decoder *decoder, int position);
+int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder);
struct cxl_ctx *cxl_decoder_get_ctx(struct cxl_decoder *decoder);
int cxl_decoder_get_id(struct cxl_decoder *decoder);
struct cxl_port *cxl_decoder_get_port(struct cxl_decoder *decoder);
@@ -126,6 +131,20 @@ bool cxl_decoder_is_locked(struct cxl_decoder *decoder);
for (decoder = cxl_decoder_get_first(port); decoder != NULL; \
decoder = cxl_decoder_get_next(decoder))
+struct cxl_target;
+struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder);
+struct cxl_target *cxl_target_get_next(struct cxl_target *target);
+struct cxl_decoder *cxl_target_get_decoder(struct cxl_target *target);
+int cxl_target_get_position(struct cxl_target *target);
+unsigned long cxl_target_get_id(struct cxl_target *target);
+const char *cxl_target_get_devname(struct cxl_target *target);
+bool cxl_target_maps_memdev(struct cxl_target *target,
+ struct cxl_memdev *memdev);
+
+#define cxl_target_foreach(decoder, target) \
+ for (target = cxl_target_get_first(decoder); target != NULL; \
+ target = cxl_target_get_next(target))
+
struct cxl_endpoint;
struct cxl_endpoint *cxl_endpoint_get_first(struct cxl_port *parent);
struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint);
diff --git a/cxl/list.c b/cxl/list.c
index d70192a..27c963a 100644
--- a/cxl/list.c
+++ b/cxl/list.c
@@ -41,6 +41,8 @@ static const struct option options[] = {
"filter by CXL decoder device name(s) / class"),
OPT_BOOLEAN('D', "decoders", &param.decoders,
"include CXL decoder info"),
+ OPT_BOOLEAN('T', "targets", &param.targets,
+ "include CXL target data with decoders"),
OPT_BOOLEAN('i', "idle", &param.idle, "include disabled devices"),
OPT_BOOLEAN('u', "human", &param.human,
"use human friendly number formats "),
--
2.27.0

Some files were not shown because too many files have changed in this diff Show More