Skip to contentSkip to conversation

cxl: Format the device serial number as unsigned

PATCH In review Alison Schofield 2 participants 5 messages Jul 24 – Aug 5

Subsystems (2)
lore
Share & tools
lore

Alison Schofield

author maintainer
#0 lore raw

v3 cover cxl: Format the device serial number as unsigned

Changes in v3:
- PATCH 1 commit messaged updated with link to work-around direction
- No other changes.

This series supersedes the previously posted standalone fix:
cxl/pmem: Format nvdimm serial number as decimal

That patch addressed the immediate auto-unlock failure caused by the kernel formatting the nvdimm security key description differently than the decimal 'id' sysfs attribute used by ndctl.

Further review uncovered a second formatting issue affecting the same serial number. The CXL device serial number is a u64 PCIe Device Serial Number, yet several kernel interfaces format it with signed "%lld". Devices whose vendor OUI sets bit 63 therefore appear with negative decimal serial numbers.

Serials with bit 64 set are expected. The most significant byte of the PCIe Device Serial Number contains the vendor OUI, so vendors such as Montage naturally produce serial numbers with bit 63 set.

Rather than merge the decimal-format fix and immediately follow it with another patch changing the same code to "%llu", fold both fixes into a single series that consistently formats CXL serial numbers as unsigned where appropriate and adds cxl_test coverage for the large serial case.

Alison Schofield (3):
cxl/pmem: Format the nvdimm serial number as unsigned decimal cxl/core: Format the memdev serial number as unsigned in TP_printk cxl/test: Assign one mock memdev a full-width serial number

 Documentation/ABI/testing/sysfs-bus-nvdimm |  3 ++-
 drivers/cxl/core/pmem.c                    | 10 ++++++----
 drivers/cxl/core/trace.h                   | 10 +++++-----
 drivers/cxl/cxl.h                          |  3 ++-
 drivers/cxl/pmem.c                         |  2 +-
 tools/testing/cxl/test/mem.c               | 15 ++++++++++++++-
 6 files changed, 30 insertions(+), 13 deletions(-)

base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482

Signature · 1 line
2.37.3
author maintainer
#1 lore raw

PATCH v3 1/3 cxl/pmem: Format the nvdimm serial number as unsigned decimal

The CXL NVDIMM security passphrase key description and the nvdimm 'id' sysfs attribute are both derived from the CXL device serial number, but the serial number is not formatted consistently.

The key description is formatted in hexadecimal while the 'id' attribute is formatted in decimal. As a result, ndctl stores the key using a decimal description while the kernel later looks it up using a hexadecimal description. For serial numbers of 10 and above, the descriptions no longer match, preventing automatic unlock after reboot.

The decimal formatting has a second problem: both the key description and the 'id' attribute use the signed %lld format for a u64 PCIe Device Serial Number. Devices whose vendor OUI sets bit 63, such as Montage CXL devices, appear with negative decimal serial numbers.

Format the security key description and 'id' attribute as unsigned decimal, %llu, and document that the 'id' attribute is an unsigned decimal value.

The key lookup mismatch was exposed by CXL unit test cxl-security.sh when cxl_test mock serial numbers were extended to 10 and above.

A work around is described for ndctl load-key users here:
https://github.com/pmem/ndctl/issues/299

Fixes b5807c80b5bc ("cxl: add dimm_id support for __nvdimm_create()")
---
 Documentation/ABI/testing/sysfs-bus-nvdimm |  3 ++-
 drivers/cxl/core/pmem.c                    | 10 ++++++----
 drivers/cxl/cxl.h                          |  3 ++-
 drivers/cxl/pmem.c                         |  2 +-
 4 files changed, 11 insertions(+), 7 deletions(-)
Documentation/ABI/testing/sysfs-bus-nvdimm +2 -1
index 64eb8f4c6a41..46dafd8482b9 100644
@@ -48,7 +48,8 @@ What:		/sys/bus/nd/devices/nmemX/cxl/id
 Date:		November 2022
 KernelVersion:	6.2
 Contact:	Dave Jiang <[email protected]>
-Description:	(RO) Show the id (serial) of the device. This is CXL specific.
+Description:	(RO) Show the id (serial) of the device, formatted as an
+		unsigned 64-bit decimal value. This is CXL specific.
 
 What:		/sys/bus/nd/devices/nmemX/cxl/provider
 Date:		November 2022
drivers/cxl/core/pmem.c +6 -4
index 68462e38a977..5a3bb7e8a1f1 100644
@@ -219,12 +219,14 @@ static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_nvdimm_bridge *cxl_nvb,
 	dev->bus = &cxl_bus_type;
 	dev->type = &cxl_nvdimm_type;
 	/*
-	 * A "%llx" string is 17-bytes vs dimm_id that is max
-	 * NVDIMM_KEY_DESC_LEN
+	 * dev_id is the nvdimm dimm_id used for security key lookup.
+	 * It must match id_show(), which emits the CXL serial as an
+	 * unsigned decimal. A u64 decimal string is at most 20 digits
+	 * plus NUL.
 	 */
-	BUILD_BUG_ON(sizeof(cxl_nvd->dev_id) < 17 ||
+	BUILD_BUG_ON(sizeof(cxl_nvd->dev_id) < 21 ||
 		     sizeof(cxl_nvd->dev_id) > NVDIMM_KEY_DESC_LEN);
-	sprintf(cxl_nvd->dev_id, "%llx", cxlmd->cxlds->serial);
+	sprintf(cxl_nvd->dev_id, "%llu", cxlmd->cxlds->serial);
 
 	return cxl_nvd;
 }
drivers/cxl/cxl.h +2 -1
index c0e5308e4d1b..d683ae5e0f7d 100644
@@ -503,7 +503,8 @@ struct cxl_nvdimm_bridge {
 	struct nvdimm_bus_descriptor nd_desc;
 };
 
-#define CXL_DEV_ID_LEN 19
+/* Holds a u64 serial as a decimal string: up to 20 digits + NUL */
+#define CXL_DEV_ID_LEN 21
 
 enum {
 	CXL_NVD_F_INVALIDATED = 0,
drivers/cxl/pmem.c +1 -1
index 261dff7ced9f..a9f50281875d 100644
@@ -52,7 +52,7 @@ static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *
 	struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
 	struct cxl_dev_state *cxlds = cxl_nvd->cxlmd->cxlds;
 
-	return sysfs_emit(buf, "%lld\n", cxlds->serial);
+	return sysfs_emit(buf, "%llu\n", cxlds->serial);
 }
 static DEVICE_ATTR_RO(id);
 
Signature · 1 line
2.37.3
author maintainer
#2 lore raw

PATCH v3 2/3 cxl/core: Format the memdev serial number as unsigned in TP_printk

In reply to Alison Schofield

The CXL memdev serial number is a u64 PCIe Device Serial Number, but the tracepoints format it with %lld. Devices whose vendor OUI sets bit 63 therefore appear with negative serial numbers in formatted trace output.

Note that the trace data itself is already stored correctly as u64.

Format the TP_printk serial as unsigned decimal, %llu, to match the underlying value.

---
 drivers/cxl/core/trace.h | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/cxl/core/trace.h +5 -5
index d37876096dd7..c379d60047fc 100644
@@ -107,7 +107,7 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
 		memcpy(__entry->header_log, hl,
 			CXL_HEADERLOG_TRACE_SIZE_U32 * sizeof(u32));
 	),
-	TP_printk("memdev=%s host=%s serial=%lld: status: '%s' first_error: '%s'",
+	TP_printk("memdev=%s host=%s serial=%llu: status: '%s' first_error: '%s'",
 		  __get_str(memdev), __get_str(host), __entry->serial,
 		  show_uc_errs(__entry->status),
 		  show_uc_errs(__entry->first_error)
@@ -166,7 +166,7 @@ TRACE_EVENT(cxl_aer_correctable_error,
 		__entry->serial = cxlmd->cxlds->serial;
 		__entry->status = status;
 	),
-	TP_printk("memdev=%s host=%s serial=%lld: status: '%s'",
+	TP_printk("memdev=%s host=%s serial=%llu: status: '%s'",
 		  __get_str(memdev), __get_str(host), __entry->serial,
 		  show_ce_errs(__entry->status)
 	)
@@ -206,7 +206,7 @@ TRACE_EVENT(cxl_overflow,
 		__entry->last_ts = le64_to_cpu(payload->last_overflow_timestamp);
 	),
 
-	TP_printk("memdev=%s host=%s serial=%lld: log=%s : %u records from %llu to %llu",
+	TP_printk("memdev=%s host=%s serial=%llu: log=%s : %u records from %llu to %llu",
 		__get_str(memdev), __get_str(host), __entry->serial,
 		cxl_event_log_type_str(__entry->log), __entry->count,
 		__entry->first_ts, __entry->last_ts)
@@ -279,7 +279,7 @@ TRACE_EVENT(cxl_overflow,
 	__entry->hdr_head_id = (hdr).head_id
 
 #define CXL_EVT_TP_printk(fmt, ...) \
-	TP_printk("memdev=%s host=%s serial=%lld log=%s : time=%llu uuid=%pUb "	\
+	TP_printk("memdev=%s host=%s serial=%llu log=%s : time=%llu uuid=%pUb "	\
 		"len=%d flags='%s' handle=%x related_handle=%x "		\
 		"maint_op_class=%u maint_op_sub_class=%u "			\
 		"ld_id=%x head_id=%x : " fmt,					\
@@ -1088,7 +1088,7 @@ TRACE_EVENT(cxl_poison,
 		}
 	    ),
 
-	TP_printk("memdev=%s host=%s serial=%lld trace_type=%s region=%s "  \
+	TP_printk("memdev=%s host=%s serial=%llu trace_type=%s region=%s "  \
 		"region_uuid=%pU hpa=0x%llx hpa_alias0=0x%llx dpa=0x%llx " \
 		"dpa_length=0x%x source=%s flags=%s overflow_time=%llu",
 		__get_str(memdev),
Signature · 1 line
2.37.3
author maintainer
#3 lore raw

PATCH v3 3/3 cxl/test: Assign one mock memdev a full-width serial number

In reply to Alison Schofield

Mock memdev serial numbers have historically been derived from pdev->id, leaving them single-digit. As a result they never exercised either the decimal-vs-hex security-key lookup or unsigned formatting of large serial numbers.

Give one mock memdev a full-width serial with bit 63 set. This mirrors real hardware (for example, Montage devices) and provides a test device that exposes both the hexadecimal-vs-decimal and signed-vs- unsigned formatting differences.

pdev->id 7 is unused by the auto-region topology so the larger serial does not affect existing tests.

This enables adding a new test case to cxl-security.sh that verify auto-unlock using a mock device whose serial exposes both formatting differences.

---
 tools/testing/cxl/test/mem.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)
tools/testing/cxl/test/mem.c +14 -1
index a1d170f88fee..42f5ffd29651 100644
@@ -1714,6 +1714,7 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
 	struct cxl_mockmem_data *mdata;
 	struct cxl_mailbox *cxl_mbox;
 	struct cxl_dpa_info range_info = { 0 };
+	u64 serial;
 	int rc;
 
 	/* Increase async probe race window */
@@ -1740,7 +1741,19 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
 	if (rc)
 		return rc;
 
-	mds = cxl_memdev_state_create(dev, pdev->id + 1, 0);
+	/*
+	 * Mock serials have historically been derived from pdev->id and stayed
+	 * single-digit, so they never exercised either decimal-vs-hex key
+	 * lookup or unsigned formatting. Give one mock device a full-width
+	 * serial with bit 63 set, matching real hardware such as Montage CXL
+	 * devices. pdev->id 7 is unused by the auto-region topology.
+	 */
+	if (pdev->id == 7)
+		serial = 0x8a34567890abcdef;
+	else
+		serial = pdev->id + 1;
+
+	mds = cxl_memdev_state_create(dev, serial, 0);
 	if (IS_ERR(mds))
 		return PTR_ERR(mds);
 
Signature · 1 line
2.37.3
maintainer
#4 lore raw
In reply to Alison Schofield
Quoted 43 lines · Alison Schofield

Changes in v3:
- PATCH 1 commit messaged updated with link to work-around direction
- No other changes.

This series supersedes the previously posted standalone fix:
cxl/pmem: Format nvdimm serial number as decimal

That patch addressed the immediate auto-unlock failure caused by the kernel formatting the nvdimm security key description differently than the decimal 'id' sysfs attribute used by ndctl.

Further review uncovered a second formatting issue affecting the same serial number. The CXL device serial number is a u64 PCIe Device Serial Number, yet several kernel interfaces format it with signed "%lld". Devices whose vendor OUI sets bit 63 therefore appear with negative decimal serial numbers.

Serials with bit 64 set are expected. The most significant byte of the PCIe Device Serial Number contains the vendor OUI, so vendors such as Montage naturally produce serial numbers with bit 63 set.

Rather than merge the decimal-format fix and immediately follow it with another patch changing the same code to "%llu", fold both fixes into a single series that consistently formats CXL serial numbers as unsigned where appropriate and adds cxl_test coverage for the large serial case.

Alison Schofield (3):
cxl/pmem: Format the nvdimm serial number as unsigned decimal cxl/core: Format the memdev serial number as unsigned in TP_printk cxl/test: Assign one mock memdev a full-width serial number

 Documentation/ABI/testing/sysfs-bus-nvdimm |  3 ++-
 drivers/cxl/core/pmem.c                    | 10 ++++++----
 drivers/cxl/core/trace.h                   | 10 +++++-----
 drivers/cxl/cxl.h                          |  3 ++-
 drivers/cxl/pmem.c                         |  2 +-
 tools/testing/cxl/test/mem.c               | 15 ++++++++++++++-
 6 files changed, 30 insertions(+), 13 deletions(-)
Quoted 1 line

base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482

Applied to cxl/next
94d84e3d8959
95a84b7cb4bb
8a80d3d65cd0