Skip to content

Commit 5f2da19

Browse files
committed
cxl/pci: Fix sanitize notifier setup
Fix a race condition between the mailbox-background command interrupt firing and the security-state sysfs attribute being removed. The race is difficult to see due to the awkward placement of the sanitize-notifier setup code and the multiple places the teardown calls are made, cxl_memdev_security_init() and cxl_memdev_security_shutdown(). Unify setup in one place, cxl_sanitize_setup_notifier(). Arrange for the paired cxl_sanitize_teardown_notifier() to safely quiet the notifier and let the cxl_memdev + irq be unregistered later in the flow. Note: The special wrinkle of the sanitize notifier is that it interacts with interrupts, which are enabled early in the flow, and it interacts with memdev sysfs which is not initialized until late in the flow. Hence why this setup routine takes an @cxlmd argument, and not just @mds. This fix is also needed as a preparation fix for a memdev unregistration crash. Reported-by: Jonathan Cameron <Jonathan.Cameron@Huawei.com> Closes: http://lore.kernel.org/r/20230929100316.00004546@Huawei.com Cc: Dave Jiang <dave.jiang@intel.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Fixes: 0c36b6a ("cxl/mbox: Add sanitization handling machinery") Reviewed-by: Dave Jiang <dave.jiang@intel.com> Reviewed-by: Ira Weiny <ira.weiny@intel.com> Reviewed-by: Davidlohr Bueso <dave@stgolabs.net> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent f29a824 commit 5f2da19

File tree

3 files changed

+50
-42
lines changed

3 files changed

+50
-42
lines changed

drivers/cxl/core/memdev.c

Lines changed: 44 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -556,20 +556,11 @@ void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds,
556556
}
557557
EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL);
558558

559-
static void cxl_memdev_security_shutdown(struct device *dev)
560-
{
561-
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
562-
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
563-
564-
cancel_delayed_work_sync(&mds->security.poll_dwork);
565-
}
566-
567559
static void cxl_memdev_shutdown(struct device *dev)
568560
{
569561
struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
570562

571563
down_write(&cxl_memdev_rwsem);
572-
cxl_memdev_security_shutdown(dev);
573564
cxlmd->cxlds = NULL;
574565
up_write(&cxl_memdev_rwsem);
575566
}
@@ -991,35 +982,6 @@ static const struct file_operations cxl_memdev_fops = {
991982
.llseek = noop_llseek,
992983
};
993984

994-
static void put_sanitize(void *data)
995-
{
996-
struct cxl_memdev_state *mds = data;
997-
998-
sysfs_put(mds->security.sanitize_node);
999-
}
1000-
1001-
static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
1002-
{
1003-
struct cxl_dev_state *cxlds = cxlmd->cxlds;
1004-
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
1005-
struct device *dev = &cxlmd->dev;
1006-
struct kernfs_node *sec;
1007-
1008-
sec = sysfs_get_dirent(dev->kobj.sd, "security");
1009-
if (!sec) {
1010-
dev_err(dev, "sysfs_get_dirent 'security' failed\n");
1011-
return -ENODEV;
1012-
}
1013-
mds->security.sanitize_node = sysfs_get_dirent(sec, "state");
1014-
sysfs_put(sec);
1015-
if (!mds->security.sanitize_node) {
1016-
dev_err(dev, "sysfs_get_dirent 'state' failed\n");
1017-
return -ENODEV;
1018-
}
1019-
1020-
return devm_add_action_or_reset(cxlds->dev, put_sanitize, mds);
1021-
}
1022-
1023985
struct cxl_memdev *devm_cxl_add_memdev(struct device *host,
1024986
struct cxl_dev_state *cxlds)
1025987
{
@@ -1049,10 +1011,6 @@ struct cxl_memdev *devm_cxl_add_memdev(struct device *host,
10491011
if (rc)
10501012
goto err;
10511013

1052-
rc = cxl_memdev_security_init(cxlmd);
1053-
if (rc)
1054-
goto err;
1055-
10561014
rc = devm_add_action_or_reset(host, cxl_memdev_unregister, cxlmd);
10571015
if (rc)
10581016
return ERR_PTR(rc);
@@ -1069,6 +1027,50 @@ struct cxl_memdev *devm_cxl_add_memdev(struct device *host,
10691027
}
10701028
EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL);
10711029

1030+
static void sanitize_teardown_notifier(void *data)
1031+
{
1032+
struct cxl_memdev_state *mds = data;
1033+
struct kernfs_node *state;
1034+
1035+
/*
1036+
* Prevent new irq triggered invocations of the workqueue and
1037+
* flush inflight invocations.
1038+
*/
1039+
mutex_lock(&mds->mbox_mutex);
1040+
state = mds->security.sanitize_node;
1041+
mds->security.sanitize_node = NULL;
1042+
mutex_unlock(&mds->mbox_mutex);
1043+
1044+
cancel_delayed_work_sync(&mds->security.poll_dwork);
1045+
sysfs_put(state);
1046+
}
1047+
1048+
int devm_cxl_sanitize_setup_notifier(struct device *host,
1049+
struct cxl_memdev *cxlmd)
1050+
{
1051+
struct cxl_dev_state *cxlds = cxlmd->cxlds;
1052+
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
1053+
struct kernfs_node *sec;
1054+
1055+
if (!test_bit(CXL_SEC_ENABLED_SANITIZE, mds->security.enabled_cmds))
1056+
return 0;
1057+
1058+
/*
1059+
* Note, the expectation is that @cxlmd would have failed to be
1060+
* created if these sysfs_get_dirent calls fail.
1061+
*/
1062+
sec = sysfs_get_dirent(cxlmd->dev.kobj.sd, "security");
1063+
if (!sec)
1064+
return -ENOENT;
1065+
mds->security.sanitize_node = sysfs_get_dirent(sec, "state");
1066+
sysfs_put(sec);
1067+
if (!mds->security.sanitize_node)
1068+
return -ENOENT;
1069+
1070+
return devm_add_action_or_reset(host, sanitize_teardown_notifier, mds);
1071+
}
1072+
EXPORT_SYMBOL_NS_GPL(devm_cxl_sanitize_setup_notifier, CXL);
1073+
10721074
__init int cxl_memdev_init(void)
10731075
{
10741076
dev_t devt;

drivers/cxl/cxlmem.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ static inline bool is_cxl_endpoint(struct cxl_port *port)
8686

8787
struct cxl_memdev *devm_cxl_add_memdev(struct device *host,
8888
struct cxl_dev_state *cxlds);
89+
int devm_cxl_sanitize_setup_notifier(struct device *host,
90+
struct cxl_memdev *cxlmd);
8991
struct cxl_memdev_state;
9092
int devm_cxl_setup_fw_upload(struct device *host, struct cxl_memdev_state *mds);
9193
int devm_cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,

drivers/cxl/pci.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,10 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
875875
if (rc)
876876
return rc;
877877

878+
rc = devm_cxl_sanitize_setup_notifier(&pdev->dev, cxlmd);
879+
if (rc)
880+
return rc;
881+
878882
pmu_count = cxl_count_regblock(pdev, CXL_REGLOC_RBI_PMU);
879883
for (i = 0; i < pmu_count; i++) {
880884
struct cxl_pmu_regs pmu_regs;

0 commit comments

Comments
 (0)