cxl fixes for 6.7-rc6

- Fix alloc_free_mem_region()'s scan for address space, prevent false
   negative out-of-space events
 
 - Fix sleeping lock acquisition from CXL trace event (atomic context)
 
 - Fix put_device() like for the new CXL PMU driver
 
 - Fix wrong pointer freed on error path
 
 - Fixup several lockdep reports (missing lock hold) from new assertion
   in cxl_num_decoders_committed() and new tests
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQSbo+XnGs+rwLz9XGXfioYZHlFsZwUCZX6oZwAKCRDfioYZHlFs
 ZyLRAPwLXinja3lpUab4mV6P6w87oO7qz1n4ly8vKpTTZZxaJAD/QGlqYS6YtiPo
 IXA8QiHe9RX3bGKhYmzSOd2/JFjyhQc=
 =2+M9
 -----END PGP SIGNATURE-----

Merge tag 'cxl-fixes-6.7-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl

Pull CXL (Compute Express Link) fixes from Dan Williams:
 "A collection of CXL fixes.

  The touch outside of drivers/cxl/ is for a helper that allocates
  physical address space. Device hotplug tests showed that the driver
  failed to utilize (skipped over) valid capacity when allocating a new
  memory region. Outside of that, new tests uncovered a small crop of
  lockdep reports.

  There is also some miscellaneous error path and leak fixups that are
  not urgent, but useful to cleanup now.

   - Fix alloc_free_mem_region()'s scan for address space, prevent false
     negative out-of-space events

   - Fix sleeping lock acquisition from CXL trace event (atomic context)

   - Fix put_device() like for the new CXL PMU driver

   - Fix wrong pointer freed on error path

   - Fixup several lockdep reports (missing lock hold) from new
     assertion in cxl_num_decoders_committed() and new tests"

* tag 'cxl-fixes-6.7-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl:
  cxl/pmu: Ensure put_device on pmu devices
  cxl/cdat: Free correct buffer on checksum error
  cxl/hdm: Fix dpa translation locking
  kernel/resource: Increment by align value in get_free_mem_region()
  cxl: Add cxl_num_decoders_committed() usage to cxl_test
  cxl/memdev: Hold region_rwsem during inject and clear poison ops
  cxl/core: Always hold region_rwsem while reading poison lists
  cxl/hdm: Fix a benign lockdep splat
This commit is contained in:
Linus Torvalds 2023-12-17 09:07:34 -08:00
commit 134fdb80bc
10 changed files with 49 additions and 24 deletions

View file

@ -363,10 +363,9 @@ resource_size_t cxl_dpa_resource_start(struct cxl_endpoint_decoder *cxled)
{
resource_size_t base = -1;
down_read(&cxl_dpa_rwsem);
lockdep_assert_held(&cxl_dpa_rwsem);
if (cxled->dpa_res)
base = cxled->dpa_res->start;
up_read(&cxl_dpa_rwsem);
return base;
}
@ -839,6 +838,8 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
cxld->target_type = CXL_DECODER_HOSTONLYMEM;
else
cxld->target_type = CXL_DECODER_DEVMEM;
guard(rwsem_write)(&cxl_region_rwsem);
if (cxld->id != cxl_num_decoders_committed(port)) {
dev_warn(&port->dev,
"decoder%d.%d: Committed out of order\n",

View file

@ -227,10 +227,16 @@ int cxl_trigger_poison_list(struct cxl_memdev *cxlmd)
if (!port || !is_cxl_endpoint(port))
return -EINVAL;
rc = down_read_interruptible(&cxl_dpa_rwsem);
rc = down_read_interruptible(&cxl_region_rwsem);
if (rc)
return rc;
rc = down_read_interruptible(&cxl_dpa_rwsem);
if (rc) {
up_read(&cxl_region_rwsem);
return rc;
}
if (cxl_num_decoders_committed(port) == 0) {
/* No regions mapped to this memdev */
rc = cxl_get_poison_by_memdev(cxlmd);
@ -239,6 +245,7 @@ int cxl_trigger_poison_list(struct cxl_memdev *cxlmd)
rc = cxl_get_poison_by_endpoint(port);
}
up_read(&cxl_dpa_rwsem);
up_read(&cxl_region_rwsem);
return rc;
}
@ -324,10 +331,16 @@ int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa)
if (!IS_ENABLED(CONFIG_DEBUG_FS))
return 0;
rc = down_read_interruptible(&cxl_dpa_rwsem);
rc = down_read_interruptible(&cxl_region_rwsem);
if (rc)
return rc;
rc = down_read_interruptible(&cxl_dpa_rwsem);
if (rc) {
up_read(&cxl_region_rwsem);
return rc;
}
rc = cxl_validate_poison_dpa(cxlmd, dpa);
if (rc)
goto out;
@ -355,6 +368,7 @@ int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa)
trace_cxl_poison(cxlmd, cxlr, &record, 0, 0, CXL_POISON_TRACE_INJECT);
out:
up_read(&cxl_dpa_rwsem);
up_read(&cxl_region_rwsem);
return rc;
}
@ -372,10 +386,16 @@ int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa)
if (!IS_ENABLED(CONFIG_DEBUG_FS))
return 0;
rc = down_read_interruptible(&cxl_dpa_rwsem);
rc = down_read_interruptible(&cxl_region_rwsem);
if (rc)
return rc;
rc = down_read_interruptible(&cxl_dpa_rwsem);
if (rc) {
up_read(&cxl_region_rwsem);
return rc;
}
rc = cxl_validate_poison_dpa(cxlmd, dpa);
if (rc)
goto out;
@ -412,6 +432,7 @@ int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa)
trace_cxl_poison(cxlmd, cxlr, &record, 0, 0, CXL_POISON_TRACE_CLEAR);
out:
up_read(&cxl_dpa_rwsem);
up_read(&cxl_region_rwsem);
return rc;
}

View file

@ -620,7 +620,7 @@ void read_cdat_data(struct cxl_port *port)
struct pci_dev *pdev = NULL;
struct cxl_memdev *cxlmd;
size_t cdat_length;
void *cdat_table;
void *cdat_table, *cdat_buf;
int rc;
if (is_cxl_memdev(uport)) {
@ -651,16 +651,15 @@ void read_cdat_data(struct cxl_port *port)
return;
}
cdat_table = devm_kzalloc(dev, cdat_length + sizeof(__le32),
GFP_KERNEL);
if (!cdat_table)
cdat_buf = devm_kzalloc(dev, cdat_length + sizeof(__le32), GFP_KERNEL);
if (!cdat_buf)
return;
rc = cxl_cdat_read_table(dev, cdat_doe, cdat_table, &cdat_length);
rc = cxl_cdat_read_table(dev, cdat_doe, cdat_buf, &cdat_length);
if (rc)
goto err;
cdat_table = cdat_table + sizeof(__le32);
cdat_table = cdat_buf + sizeof(__le32);
if (cdat_checksum(cdat_table, cdat_length))
goto err;
@ -670,7 +669,7 @@ void read_cdat_data(struct cxl_port *port)
err:
/* Don't leave table data allocated on error */
devm_kfree(dev, cdat_table);
devm_kfree(dev, cdat_buf);
dev_err(dev, "Failed to read/validate CDAT.\n");
}
EXPORT_SYMBOL_NS_GPL(read_cdat_data, CXL);

View file

@ -23,7 +23,7 @@ const struct device_type cxl_pmu_type = {
static void remove_dev(void *dev)
{
device_del(dev);
device_unregister(dev);
}
int devm_cxl_pmu_add(struct device *parent, struct cxl_pmu_regs *regs,

View file

@ -226,9 +226,9 @@ static ssize_t dpa_resource_show(struct device *dev, struct device_attribute *at
char *buf)
{
struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
u64 base = cxl_dpa_resource_start(cxled);
return sysfs_emit(buf, "%#llx\n", base);
guard(rwsem_read)(&cxl_dpa_rwsem);
return sysfs_emit(buf, "%#llx\n", (u64)cxl_dpa_resource_start(cxled));
}
static DEVICE_ATTR_RO(dpa_resource);

View file

@ -2467,10 +2467,6 @@ int cxl_get_poison_by_endpoint(struct cxl_port *port)
struct cxl_poison_context ctx;
int rc = 0;
rc = down_read_interruptible(&cxl_region_rwsem);
if (rc)
return rc;
ctx = (struct cxl_poison_context) {
.port = port
};
@ -2480,7 +2476,6 @@ int cxl_get_poison_by_endpoint(struct cxl_port *port)
rc = cxl_get_poison_unmapped(to_cxl_memdev(port->uport_dev),
&ctx);
up_read(&cxl_region_rwsem);
return rc;
}

View file

@ -1844,8 +1844,8 @@ get_free_mem_region(struct device *dev, struct resource *base,
write_lock(&resource_lock);
for (addr = gfr_start(base, size, align, flags);
gfr_continue(base, addr, size, flags);
addr = gfr_next(addr, size, flags)) {
gfr_continue(base, addr, align, flags);
addr = gfr_next(addr, align, flags)) {
if (__region_intersects(base, addr, size, 0, IORES_DESC_NONE) !=
REGION_DISJOINT)
continue;

View file

@ -62,5 +62,6 @@ cxl_core-$(CONFIG_TRACING) += $(CXL_CORE_SRC)/trace.o
cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o
cxl_core-y += config_check.o
cxl_core-y += cxl_core_test.o
cxl_core-y += cxl_core_exports.o
obj-m += test/

View file

@ -0,0 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
#include "cxl.h"
/* Exporting of cxl_core symbols that are only used by cxl_test */
EXPORT_SYMBOL_NS_GPL(cxl_num_decoders_committed, CXL);

View file

@ -669,10 +669,11 @@ static int mock_decoder_commit(struct cxl_decoder *cxld)
return 0;
dev_dbg(&port->dev, "%s commit\n", dev_name(&cxld->dev));
if (port->commit_end + 1 != id) {
if (cxl_num_decoders_committed(port) != id) {
dev_dbg(&port->dev,
"%s: out of order commit, expected decoder%d.%d\n",
dev_name(&cxld->dev), port->id, port->commit_end + 1);
dev_name(&cxld->dev), port->id,
cxl_num_decoders_committed(port));
return -EBUSY;
}