mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-16 01:54:00 +00:00
cxl/pmem: Fix offline_nvdimm_bus() to offline by bridge
Be careful to only disable cxl_pmem objects related to a given cxl_nvdimm_bridge. Otherwise, offline_nvdimm_bus() reaches across CXL domains and disables more than is expected. Fixes: 21083f51521f ("cxl/pmem: Register 'pmem' / cxl_nvdimm devices") Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Link: https://lore.kernel.org/r/165784339569.1758207.1557084545278004577.stgit@dwillia2-xfh.jf.intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
8d48817df6
commit
99183d26ed
@ -418,6 +418,7 @@ struct cxl_nvdimm_bridge {
|
||||
struct cxl_nvdimm {
|
||||
struct device dev;
|
||||
struct cxl_memdev *cxlmd;
|
||||
struct cxl_nvdimm_bridge *bridge;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -26,7 +26,10 @@ static void clear_exclusive(void *cxlds)
|
||||
|
||||
static void unregister_nvdimm(void *nvdimm)
|
||||
{
|
||||
struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
|
||||
|
||||
nvdimm_delete(nvdimm);
|
||||
cxl_nvd->bridge = NULL;
|
||||
}
|
||||
|
||||
static int cxl_nvdimm_probe(struct device *dev)
|
||||
@ -66,6 +69,7 @@ static int cxl_nvdimm_probe(struct device *dev)
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, nvdimm);
|
||||
cxl_nvd->bridge = cxl_nvb;
|
||||
rc = devm_add_action_or_reset(dev, unregister_nvdimm, nvdimm);
|
||||
out:
|
||||
device_unlock(&cxl_nvb->dev);
|
||||
@ -204,15 +208,23 @@ static bool online_nvdimm_bus(struct cxl_nvdimm_bridge *cxl_nvb)
|
||||
return cxl_nvb->nvdimm_bus != NULL;
|
||||
}
|
||||
|
||||
static int cxl_nvdimm_release_driver(struct device *dev, void *data)
|
||||
static int cxl_nvdimm_release_driver(struct device *dev, void *cxl_nvb)
|
||||
{
|
||||
struct cxl_nvdimm *cxl_nvd;
|
||||
|
||||
if (!is_cxl_nvdimm(dev))
|
||||
return 0;
|
||||
|
||||
cxl_nvd = to_cxl_nvdimm(dev);
|
||||
if (cxl_nvd->bridge != cxl_nvb)
|
||||
return 0;
|
||||
|
||||
device_release_driver(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void offline_nvdimm_bus(struct nvdimm_bus *nvdimm_bus)
|
||||
static void offline_nvdimm_bus(struct cxl_nvdimm_bridge *cxl_nvb,
|
||||
struct nvdimm_bus *nvdimm_bus)
|
||||
{
|
||||
if (!nvdimm_bus)
|
||||
return;
|
||||
@ -222,7 +234,8 @@ static void offline_nvdimm_bus(struct nvdimm_bus *nvdimm_bus)
|
||||
* nvdimm_bus_unregister() rips the nvdimm objects out from
|
||||
* underneath them.
|
||||
*/
|
||||
bus_for_each_dev(&cxl_bus_type, NULL, NULL, cxl_nvdimm_release_driver);
|
||||
bus_for_each_dev(&cxl_bus_type, NULL, cxl_nvb,
|
||||
cxl_nvdimm_release_driver);
|
||||
nvdimm_bus_unregister(nvdimm_bus);
|
||||
}
|
||||
|
||||
@ -260,7 +273,7 @@ static void cxl_nvb_update_state(struct work_struct *work)
|
||||
|
||||
dev_dbg(&cxl_nvb->dev, "rescan: %d\n", rc);
|
||||
}
|
||||
offline_nvdimm_bus(victim_bus);
|
||||
offline_nvdimm_bus(cxl_nvb, victim_bus);
|
||||
|
||||
put_device(&cxl_nvb->dev);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user