diff mbox series

[v2,3/4] cxl/pci: Fix sanitize notifier setup

Message ID 169602898447.904193.4454973423100628922.stgit@dwillia2-xfh.jf.intel.com
State Superseded
Headers show
Series cxl/mem: Fix shutdown order | expand

Commit Message

Dan Williams Sept. 29, 2023, 11:09 p.m. UTC
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.

This fix is also needed as a preparation fix for a memdev unregistration
crash.

Reported-by: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
Cc: Dave Jiang <dave.jiang@intel.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Fixes: 0c36b6ad436a ("cxl/mbox: Add sanitization handling machinery")
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/cxl/core/memdev.c |   42 ----------------------------------------
 drivers/cxl/pci.c         |   47 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 42 deletions(-)

Comments

Ira Weiny Sept. 30, 2023, 2:42 a.m. UTC | #1
Dan Williams wrote:
> 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.
> 
> This fix is also needed as a preparation fix for a memdev unregistration
> crash.
> 
> Reported-by: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
> Cc: Dave Jiang <dave.jiang@intel.com>
> Cc: Davidlohr Bueso <dave@stgolabs.net>
> Fixes: 0c36b6ad436a ("cxl/mbox: Add sanitization handling machinery")
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>

Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Jonathan Cameron Oct. 2, 2023, 10:10 a.m. UTC | #2
On Fri, 29 Sep 2023 16:09:44 -0700
Dan Williams <dan.j.williams@intel.com> wrote:

> 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.
> 
> This fix is also needed as a preparation fix for a memdev unregistration
> crash.
> 
> Reported-by: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
> Cc: Dave Jiang <dave.jiang@intel.com>
> Cc: Davidlohr Bueso <dave@stgolabs.net>
> Fixes: 0c36b6ad436a ("cxl/mbox: Add sanitization handling machinery")
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>

One trivial question inline about which parameter to pass in from the
many many interlocking state structures...

If you do make the suggested change, it's just complex enough I want another
look so I'm not giving a tag for now.

> ---
>  drivers/cxl/core/memdev.c |   42 ----------------------------------------
>  drivers/cxl/pci.c         |   47 +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 47 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
> index 2a7a07f6d165..a950091e5640 100644
> --- a/drivers/cxl/core/memdev.c
> +++ b/drivers/cxl/core/memdev.c
> @@ -556,20 +556,11 @@ void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds,
>  }
>  EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL);
>  
> -static void cxl_memdev_security_shutdown(struct device *dev)
> -{
> -	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
> -	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
> -
> -	cancel_delayed_work_sync(&mds->security.poll_dwork);
> -}
> -
>  static void cxl_memdev_shutdown(struct device *dev)
>  {
>  	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
>  
>  	down_write(&cxl_memdev_rwsem);
> -	cxl_memdev_security_shutdown(dev);
>  	cxlmd->cxlds = NULL;
>  	up_write(&cxl_memdev_rwsem);
>  }
> @@ -1001,35 +992,6 @@ static const struct file_operations cxl_memdev_fops = {
>  	.llseek = noop_llseek,
>  };
>  
> -static void put_sanitize(void *data)
> -{
> -	struct cxl_memdev_state *mds = data;
> -
> -	sysfs_put(mds->security.sanitize_node);
> -}
> -
> -static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
> -{
> -	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> -	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
> -	struct device *dev = &cxlmd->dev;
> -	struct kernfs_node *sec;
> -
> -	sec = sysfs_get_dirent(dev->kobj.sd, "security");
> -	if (!sec) {
> -		dev_err(dev, "sysfs_get_dirent 'security' failed\n");
> -		return -ENODEV;
> -	}
> -	mds->security.sanitize_node = sysfs_get_dirent(sec, "state");
> -	sysfs_put(sec);
> -	if (!mds->security.sanitize_node) {
> -		dev_err(dev, "sysfs_get_dirent 'state' failed\n");
> -		return -ENODEV;
> -	}
> -
> -	return devm_add_action_or_reset(cxlds->dev, put_sanitize, mds);
> - }
> -
>  struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
>  {
>  	struct cxl_memdev *cxlmd;
> @@ -1058,10 +1020,6 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
>  	if (rc)
>  		goto err;
>  
> -	rc = cxl_memdev_security_init(cxlmd);
> -	if (rc)
> -		goto err;
> -
>  	rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd);
>  	if (rc)
>  		return ERR_PTR(rc);
> diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> index ac4e434b0806..b0023e479315 100644
> --- a/drivers/cxl/pci.c
> +++ b/drivers/cxl/pci.c
> @@ -165,6 +165,49 @@ static void cxl_mbox_sanitize_work(struct work_struct *work)
>  	mutex_unlock(&mds->mbox_mutex);
>  }
>  
> +static void cxl_sanitize_teardown_notifier(void *data)
> +{
> +	struct cxl_memdev_state *mds = data;
> +	struct kernfs_node *state;
> +
> +	/*
> +	 * Prevent new irq triggered invocations of the workqueue and
> +	 * flush inflight invocations.
> +	 */
> +	mutex_lock(&mds->mbox_mutex);
> +	state = mds->security.sanitize_node;
> +	mds->security.sanitize_node = NULL;
> +	mutex_unlock(&mds->mbox_mutex);
> +
> +	cancel_delayed_work_sync(&mds->security.poll_dwork);
> +	sysfs_put(state);
> +}
> +
> +static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
> +{

Almost everything in cxl_pci_probe() passes in the mds.
Why not do the same here?

 
> +	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> +	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
> +	struct device *dev = cxlds->dev;
> +	struct kernfs_node *sec;
> +
> +	if (!test_bit(CXL_SEC_ENABLED_SANITIZE, mds->security.enabled_cmds))
> +		return 0;
> +
> +	sec = sysfs_get_dirent(dev->kobj.sd, "security");
> +	if (!sec) {
> +		dev_err(dev, "sanitize notification setup failure\n");
> +		return -ENOENT;
> +	}
> +	mds->security.sanitize_node = sysfs_get_dirent(sec, "state");
> +	sysfs_put(sec);
> +	if (!mds->security.sanitize_node) {
> +		dev_err(dev, "sanitize notification setup failure\n");
> +		return -ENOENT;
> +	}
> +
> +	return devm_add_action_or_reset(dev, cxl_sanitize_teardown_notifier, mds);
> +}
> +
>  /**
>   * __cxl_pci_mbox_send_cmd() - Execute a mailbox command
>   * @mds: The memory device driver data
> @@ -875,6 +918,10 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  	if (rc)
>  		return rc;
>  
> +	rc = cxl_sanitize_setup_notifier(cxlmd);
> +	if (rc)
> +		return rc;
> +
>  	pmu_count = cxl_count_regblock(pdev, CXL_REGLOC_RBI_PMU);
>  	for (i = 0; i < pmu_count; i++) {
>  		struct cxl_pmu_regs pmu_regs;
>
Dave Jiang Oct. 2, 2023, 4:59 p.m. UTC | #3
On 9/29/23 16:09, Dan Williams wrote:
> 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.
> 
> This fix is also needed as a preparation fix for a memdev unregistration
> crash.
> 
> Reported-by: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
> Cc: Dave Jiang <dave.jiang@intel.com>
> Cc: Davidlohr Bueso <dave@stgolabs.net>
> Fixes: 0c36b6ad436a ("cxl/mbox: Add sanitization handling machinery")
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>

Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> ---
>  drivers/cxl/core/memdev.c |   42 ----------------------------------------
>  drivers/cxl/pci.c         |   47 +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 47 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
> index 2a7a07f6d165..a950091e5640 100644
> --- a/drivers/cxl/core/memdev.c
> +++ b/drivers/cxl/core/memdev.c
> @@ -556,20 +556,11 @@ void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds,
>  }
>  EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL);
>  
> -static void cxl_memdev_security_shutdown(struct device *dev)
> -{
> -	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
> -	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
> -
> -	cancel_delayed_work_sync(&mds->security.poll_dwork);
> -}
> -
>  static void cxl_memdev_shutdown(struct device *dev)
>  {
>  	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
>  
>  	down_write(&cxl_memdev_rwsem);
> -	cxl_memdev_security_shutdown(dev);
>  	cxlmd->cxlds = NULL;
>  	up_write(&cxl_memdev_rwsem);
>  }
> @@ -1001,35 +992,6 @@ static const struct file_operations cxl_memdev_fops = {
>  	.llseek = noop_llseek,
>  };
>  
> -static void put_sanitize(void *data)
> -{
> -	struct cxl_memdev_state *mds = data;
> -
> -	sysfs_put(mds->security.sanitize_node);
> -}
> -
> -static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
> -{
> -	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> -	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
> -	struct device *dev = &cxlmd->dev;
> -	struct kernfs_node *sec;
> -
> -	sec = sysfs_get_dirent(dev->kobj.sd, "security");
> -	if (!sec) {
> -		dev_err(dev, "sysfs_get_dirent 'security' failed\n");
> -		return -ENODEV;
> -	}
> -	mds->security.sanitize_node = sysfs_get_dirent(sec, "state");
> -	sysfs_put(sec);
> -	if (!mds->security.sanitize_node) {
> -		dev_err(dev, "sysfs_get_dirent 'state' failed\n");
> -		return -ENODEV;
> -	}
> -
> -	return devm_add_action_or_reset(cxlds->dev, put_sanitize, mds);
> - }
> -
>  struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
>  {
>  	struct cxl_memdev *cxlmd;
> @@ -1058,10 +1020,6 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
>  	if (rc)
>  		goto err;
>  
> -	rc = cxl_memdev_security_init(cxlmd);
> -	if (rc)
> -		goto err;
> -
>  	rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd);
>  	if (rc)
>  		return ERR_PTR(rc);
> diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> index ac4e434b0806..b0023e479315 100644
> --- a/drivers/cxl/pci.c
> +++ b/drivers/cxl/pci.c
> @@ -165,6 +165,49 @@ static void cxl_mbox_sanitize_work(struct work_struct *work)
>  	mutex_unlock(&mds->mbox_mutex);
>  }
>  
> +static void cxl_sanitize_teardown_notifier(void *data)
> +{
> +	struct cxl_memdev_state *mds = data;
> +	struct kernfs_node *state;
> +
> +	/*
> +	 * Prevent new irq triggered invocations of the workqueue and
> +	 * flush inflight invocations.
> +	 */
> +	mutex_lock(&mds->mbox_mutex);
> +	state = mds->security.sanitize_node;
> +	mds->security.sanitize_node = NULL;
> +	mutex_unlock(&mds->mbox_mutex);
> +
> +	cancel_delayed_work_sync(&mds->security.poll_dwork);
> +	sysfs_put(state);
> +}
> +
> +static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
> +{
> +	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> +	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
> +	struct device *dev = cxlds->dev;
> +	struct kernfs_node *sec;
> +
> +	if (!test_bit(CXL_SEC_ENABLED_SANITIZE, mds->security.enabled_cmds))
> +		return 0;
> +
> +	sec = sysfs_get_dirent(dev->kobj.sd, "security");
> +	if (!sec) {
> +		dev_err(dev, "sanitize notification setup failure\n");
> +		return -ENOENT;
> +	}
> +	mds->security.sanitize_node = sysfs_get_dirent(sec, "state");
> +	sysfs_put(sec);
> +	if (!mds->security.sanitize_node) {
> +		dev_err(dev, "sanitize notification setup failure\n");
> +		return -ENOENT;
> +	}
> +
> +	return devm_add_action_or_reset(dev, cxl_sanitize_teardown_notifier, mds);
> +}
> +
>  /**
>   * __cxl_pci_mbox_send_cmd() - Execute a mailbox command
>   * @mds: The memory device driver data
> @@ -875,6 +918,10 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  	if (rc)
>  		return rc;
>  
> +	rc = cxl_sanitize_setup_notifier(cxlmd);
> +	if (rc)
> +		return rc;
> +
>  	pmu_count = cxl_count_regblock(pdev, CXL_REGLOC_RBI_PMU);
>  	for (i = 0; i < pmu_count; i++) {
>  		struct cxl_pmu_regs pmu_regs;
>
Davidlohr Bueso Oct. 4, 2023, 12:52 a.m. UTC | #4
On Fri, 29 Sep 2023, Dan Williams wrote:

>+static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
>+{
>+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
>+	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
>+	struct device *dev = cxlds->dev;

This wants to be dev = &cxlmd->dev;

>+	struct kernfs_node *sec;
>+
>+	if (!test_bit(CXL_SEC_ENABLED_SANITIZE, mds->security.enabled_cmds))
>+		return 0;
>+
>+	sec = sysfs_get_dirent(dev->kobj.sd, "security");
>+	if (!sec) {
>+		dev_err(dev, "sanitize notification setup failure\n");

Nit: Should the error message differ from the next one? Maybe s/sanitize/security?

>+		return -ENOENT;
>+	}
>+	mds->security.sanitize_node = sysfs_get_dirent(sec, "state");
>+	sysfs_put(sec);
>+	if (!mds->security.sanitize_node) {
>+		dev_err(dev, "sanitize notification setup failure\n");
>+		return -ENOENT;
>+	}
>+
>+	return devm_add_action_or_reset(dev, cxl_sanitize_teardown_notifier, mds);
>+}
Dan Williams Oct. 4, 2023, 12:59 a.m. UTC | #5
Jonathan Cameron wrote:
> On Fri, 29 Sep 2023 16:09:44 -0700
> Dan Williams <dan.j.williams@intel.com> wrote:
> 
> > 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.
> > 
> > This fix is also needed as a preparation fix for a memdev unregistration
> > crash.
> > 
> > Reported-by: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
> > Cc: Dave Jiang <dave.jiang@intel.com>
> > Cc: Davidlohr Bueso <dave@stgolabs.net>
> > Fixes: 0c36b6ad436a ("cxl/mbox: Add sanitization handling machinery")
> > Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> 
> One trivial question inline about which parameter to pass in from the
> many many interlocking state structures...
> 
> If you do make the suggested change, it's just complex enough I want another
> look so I'm not giving a tag for now.
> 
> > ---
> >  drivers/cxl/core/memdev.c |   42 ----------------------------------------
> >  drivers/cxl/pci.c         |   47 +++++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 47 insertions(+), 42 deletions(-)
> > 
> > diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
> > index 2a7a07f6d165..a950091e5640 100644
> > --- a/drivers/cxl/core/memdev.c
> > +++ b/drivers/cxl/core/memdev.c
> > @@ -556,20 +556,11 @@ void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds,
> >  }
> >  EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL);
> >  
> > -static void cxl_memdev_security_shutdown(struct device *dev)
> > -{
> > -	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
> > -	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
> > -
> > -	cancel_delayed_work_sync(&mds->security.poll_dwork);
> > -}
> > -
> >  static void cxl_memdev_shutdown(struct device *dev)
> >  {
> >  	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
> >  
> >  	down_write(&cxl_memdev_rwsem);
> > -	cxl_memdev_security_shutdown(dev);
> >  	cxlmd->cxlds = NULL;
> >  	up_write(&cxl_memdev_rwsem);
> >  }
> > @@ -1001,35 +992,6 @@ static const struct file_operations cxl_memdev_fops = {
> >  	.llseek = noop_llseek,
> >  };
> >  
> > -static void put_sanitize(void *data)
> > -{
> > -	struct cxl_memdev_state *mds = data;
> > -
> > -	sysfs_put(mds->security.sanitize_node);
> > -}
> > -
> > -static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
> > -{
> > -	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> > -	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
> > -	struct device *dev = &cxlmd->dev;
> > -	struct kernfs_node *sec;
> > -
> > -	sec = sysfs_get_dirent(dev->kobj.sd, "security");
> > -	if (!sec) {
> > -		dev_err(dev, "sysfs_get_dirent 'security' failed\n");
> > -		return -ENODEV;
> > -	}
> > -	mds->security.sanitize_node = sysfs_get_dirent(sec, "state");
> > -	sysfs_put(sec);
> > -	if (!mds->security.sanitize_node) {
> > -		dev_err(dev, "sysfs_get_dirent 'state' failed\n");
> > -		return -ENODEV;
> > -	}
> > -
> > -	return devm_add_action_or_reset(cxlds->dev, put_sanitize, mds);
> > - }
> > -
> >  struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
> >  {
> >  	struct cxl_memdev *cxlmd;
> > @@ -1058,10 +1020,6 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
> >  	if (rc)
> >  		goto err;
> >  
> > -	rc = cxl_memdev_security_init(cxlmd);
> > -	if (rc)
> > -		goto err;
> > -
> >  	rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd);
> >  	if (rc)
> >  		return ERR_PTR(rc);
> > diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> > index ac4e434b0806..b0023e479315 100644
> > --- a/drivers/cxl/pci.c
> > +++ b/drivers/cxl/pci.c
> > @@ -165,6 +165,49 @@ static void cxl_mbox_sanitize_work(struct work_struct *work)
> >  	mutex_unlock(&mds->mbox_mutex);
> >  }
> >  
> > +static void cxl_sanitize_teardown_notifier(void *data)
> > +{
> > +	struct cxl_memdev_state *mds = data;
> > +	struct kernfs_node *state;
> > +
> > +	/*
> > +	 * Prevent new irq triggered invocations of the workqueue and
> > +	 * flush inflight invocations.
> > +	 */
> > +	mutex_lock(&mds->mbox_mutex);
> > +	state = mds->security.sanitize_node;
> > +	mds->security.sanitize_node = NULL;
> > +	mutex_unlock(&mds->mbox_mutex);
> > +
> > +	cancel_delayed_work_sync(&mds->security.poll_dwork);
> > +	sysfs_put(state);
> > +}
> > +
> > +static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
> > +{
> 
> Almost everything in cxl_pci_probe() passes in the mds.
> Why not do the same here?

Because this one really is built on top of a stack of things and needs
the 'device' because it is tying the device's sysfs attributes to the
completion notifications of the background workqueue.

I mentioned this in the cover, but failed to mention it again in this
changelog:

"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."

There are no sysfs attributes reachable from an @mds.
Dan Williams Oct. 4, 2023, 1:09 a.m. UTC | #6
Davidlohr Bueso wrote:
> On Fri, 29 Sep 2023, Dan Williams wrote:
> 
> >+static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
> >+{
> >+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> >+	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
> >+	struct device *dev = cxlds->dev;
> 
> This wants to be dev = &cxlmd->dev;

No, the notifier needs to be torn down in the cxl_pci teardown path. If
cxlmd->dev was the devm operations host then this notifier would need to
be setup from the cxl_mem driver, not cxl_pci. The teardown order of
cxl_pci ends with @cxlds->dev as the devm host ends up as:

cxl_sanitize_teardown_notifier()
cxl_memdev_unregister()

...otherwise if the @cxlmd->dev is used then the devm callback may not
fire until device_release() time since it is possible that the cxl_mem
driver never attaches to trigger the typical devm action around
->remove() time.

> >+	struct kernfs_node *sec;
> >+
> >+	if (!test_bit(CXL_SEC_ENABLED_SANITIZE, mds->security.enabled_cmds))
> >+		return 0;
> >+
> >+	sec = sysfs_get_dirent(dev->kobj.sd, "security");
> >+	if (!sec) {
> >+		dev_err(dev, "sanitize notification setup failure\n");
> 
> Nit: Should the error message differ from the next one? Maybe s/sanitize/security?

Maybe, but these things will likely never fire, as devm_cxl_add_memdev()
would have failed before getting here. Maybe just delete them?
Jonathan Cameron Oct. 4, 2023, 10:12 a.m. UTC | #7
On Tue, 3 Oct 2023 17:59:46 -0700
Dan Williams <dan.j.williams@intel.com> wrote:

> Jonathan Cameron wrote:
> > On Fri, 29 Sep 2023 16:09:44 -0700
> > Dan Williams <dan.j.williams@intel.com> wrote:
> >   
> > > 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.
> > > 
> > > This fix is also needed as a preparation fix for a memdev unregistration
> > > crash.
> > > 
> > > Reported-by: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
> > > Cc: Dave Jiang <dave.jiang@intel.com>
> > > Cc: Davidlohr Bueso <dave@stgolabs.net>
> > > Fixes: 0c36b6ad436a ("cxl/mbox: Add sanitization handling machinery")
> > > Signed-off-by: Dan Williams <dan.j.williams@intel.com>  
> > 
> > One trivial question inline about which parameter to pass in from the
> > many many interlocking state structures...
> > 
> > If you do make the suggested change, it's just complex enough I want another
> > look so I'm not giving a tag for now.
> >   
> > > ---
> > >  drivers/cxl/core/memdev.c |   42 ----------------------------------------
> > >  drivers/cxl/pci.c         |   47 +++++++++++++++++++++++++++++++++++++++++++++
> > >  2 files changed, 47 insertions(+), 42 deletions(-)
> > > 
> > > diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
> > > index 2a7a07f6d165..a950091e5640 100644
> > > --- a/drivers/cxl/core/memdev.c
> > > +++ b/drivers/cxl/core/memdev.c
> > > @@ -556,20 +556,11 @@ void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds,
> > >  }
> > >  EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL);
> > >  
> > > -static void cxl_memdev_security_shutdown(struct device *dev)
> > > -{
> > > -	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
> > > -	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
> > > -
> > > -	cancel_delayed_work_sync(&mds->security.poll_dwork);
> > > -}
> > > -
> > >  static void cxl_memdev_shutdown(struct device *dev)
> > >  {
> > >  	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
> > >  
> > >  	down_write(&cxl_memdev_rwsem);
> > > -	cxl_memdev_security_shutdown(dev);
> > >  	cxlmd->cxlds = NULL;
> > >  	up_write(&cxl_memdev_rwsem);
> > >  }
> > > @@ -1001,35 +992,6 @@ static const struct file_operations cxl_memdev_fops = {
> > >  	.llseek = noop_llseek,
> > >  };
> > >  
> > > -static void put_sanitize(void *data)
> > > -{
> > > -	struct cxl_memdev_state *mds = data;
> > > -
> > > -	sysfs_put(mds->security.sanitize_node);
> > > -}
> > > -
> > > -static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
> > > -{
> > > -	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> > > -	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
> > > -	struct device *dev = &cxlmd->dev;
> > > -	struct kernfs_node *sec;
> > > -
> > > -	sec = sysfs_get_dirent(dev->kobj.sd, "security");
> > > -	if (!sec) {
> > > -		dev_err(dev, "sysfs_get_dirent 'security' failed\n");
> > > -		return -ENODEV;
> > > -	}
> > > -	mds->security.sanitize_node = sysfs_get_dirent(sec, "state");
> > > -	sysfs_put(sec);
> > > -	if (!mds->security.sanitize_node) {
> > > -		dev_err(dev, "sysfs_get_dirent 'state' failed\n");
> > > -		return -ENODEV;
> > > -	}
> > > -
> > > -	return devm_add_action_or_reset(cxlds->dev, put_sanitize, mds);
> > > - }
> > > -
> > >  struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
> > >  {
> > >  	struct cxl_memdev *cxlmd;
> > > @@ -1058,10 +1020,6 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
> > >  	if (rc)
> > >  		goto err;
> > >  
> > > -	rc = cxl_memdev_security_init(cxlmd);
> > > -	if (rc)
> > > -		goto err;
> > > -
> > >  	rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd);
> > >  	if (rc)
> > >  		return ERR_PTR(rc);
> > > diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> > > index ac4e434b0806..b0023e479315 100644
> > > --- a/drivers/cxl/pci.c
> > > +++ b/drivers/cxl/pci.c
> > > @@ -165,6 +165,49 @@ static void cxl_mbox_sanitize_work(struct work_struct *work)
> > >  	mutex_unlock(&mds->mbox_mutex);
> > >  }
> > >  
> > > +static void cxl_sanitize_teardown_notifier(void *data)
> > > +{
> > > +	struct cxl_memdev_state *mds = data;
> > > +	struct kernfs_node *state;
> > > +
> > > +	/*
> > > +	 * Prevent new irq triggered invocations of the workqueue and
> > > +	 * flush inflight invocations.
> > > +	 */
> > > +	mutex_lock(&mds->mbox_mutex);
> > > +	state = mds->security.sanitize_node;
> > > +	mds->security.sanitize_node = NULL;
> > > +	mutex_unlock(&mds->mbox_mutex);
> > > +
> > > +	cancel_delayed_work_sync(&mds->security.poll_dwork);
> > > +	sysfs_put(state);
> > > +}
> > > +
> > > +static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
> > > +{  
> > 
> > Almost everything in cxl_pci_probe() passes in the mds.
> > Why not do the same here?  
> 
> Because this one really is built on top of a stack of things and needs
> the 'device' because it is tying the device's sysfs attributes to the
> completion notifications of the background workqueue.
> 
> I mentioned this in the cover, but failed to mention it again in this
> changelog:
> 
> "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."
> 
> There are no sysfs attributes reachable from an @mds.

I'm confused.  This accesses the sysfs stuff via
sec = sysfs_get_dirent(dev->kobj.sd, "security");
where dev = cxlds->dev
and cxlds is embedded in mds.

So from a code point of view I can't see the restriction.
Is it more a semantic issue that it naturally feels better to use
the cxl_mdev?

Jonathan


>
Davidlohr Bueso Oct. 4, 2023, 4:21 p.m. UTC | #8
On Tue, 03 Oct 2023, Dan Williams wrote:

>Davidlohr Bueso wrote:
>> On Fri, 29 Sep 2023, Dan Williams wrote:
>>
>> >+static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
>> >+{
>> >+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
>> >+	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
>> >+	struct device *dev = cxlds->dev;
>>
>> This wants to be dev = &cxlmd->dev;
>
>No, the notifier needs to be torn down in the cxl_pci teardown path. If
>cxlmd->dev was the devm operations host then this notifier would need to
>be setup from the cxl_mem driver, not cxl_pci. The teardown order of
>cxl_pci ends with @cxlds->dev as the devm host ends up as:
>
>cxl_sanitize_teardown_notifier()
>cxl_memdev_unregister()
>
>...otherwise if the @cxlmd->dev is used then the devm callback may not
>fire until device_release() time since it is possible that the cxl_mem
>driver never attaches to trigger the typical devm action around
>->remove() time.

As is, the first sysfs_get_dirent() fails, fyi.
Dan Williams Oct. 4, 2023, 6:47 p.m. UTC | #9
Jonathan Cameron wrote:
> On Tue, 3 Oct 2023 17:59:46 -0700
> Dan Williams <dan.j.williams@intel.com> wrote:
> 
> > Jonathan Cameron wrote:
> > > On Fri, 29 Sep 2023 16:09:44 -0700
> > > Dan Williams <dan.j.williams@intel.com> wrote:
> > >   
> > > > 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.
> > > > 
> > > > This fix is also needed as a preparation fix for a memdev unregistration
> > > > crash.
> > > > 
> > > > Reported-by: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
> > > > Cc: Dave Jiang <dave.jiang@intel.com>
> > > > Cc: Davidlohr Bueso <dave@stgolabs.net>
> > > > Fixes: 0c36b6ad436a ("cxl/mbox: Add sanitization handling machinery")
> > > > Signed-off-by: Dan Williams <dan.j.williams@intel.com>  
> > > 
> > > One trivial question inline about which parameter to pass in from the
> > > many many interlocking state structures...
> > > 
> > > If you do make the suggested change, it's just complex enough I want another
> > > look so I'm not giving a tag for now.
> > >   
> > > > ---
> > > >  drivers/cxl/core/memdev.c |   42 ----------------------------------------
> > > >  drivers/cxl/pci.c         |   47 +++++++++++++++++++++++++++++++++++++++++++++
> > > >  2 files changed, 47 insertions(+), 42 deletions(-)
> > > > 
> > > > diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
> > > > index 2a7a07f6d165..a950091e5640 100644
> > > > --- a/drivers/cxl/core/memdev.c
> > > > +++ b/drivers/cxl/core/memdev.c
> > > > @@ -556,20 +556,11 @@ void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds,
> > > >  }
> > > >  EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL);
> > > >  
> > > > -static void cxl_memdev_security_shutdown(struct device *dev)
> > > > -{
> > > > -	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
> > > > -	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
> > > > -
> > > > -	cancel_delayed_work_sync(&mds->security.poll_dwork);
> > > > -}
> > > > -
> > > >  static void cxl_memdev_shutdown(struct device *dev)
> > > >  {
> > > >  	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
> > > >  
> > > >  	down_write(&cxl_memdev_rwsem);
> > > > -	cxl_memdev_security_shutdown(dev);
> > > >  	cxlmd->cxlds = NULL;
> > > >  	up_write(&cxl_memdev_rwsem);
> > > >  }
> > > > @@ -1001,35 +992,6 @@ static const struct file_operations cxl_memdev_fops = {
> > > >  	.llseek = noop_llseek,
> > > >  };
> > > >  
> > > > -static void put_sanitize(void *data)
> > > > -{
> > > > -	struct cxl_memdev_state *mds = data;
> > > > -
> > > > -	sysfs_put(mds->security.sanitize_node);
> > > > -}
> > > > -
> > > > -static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
> > > > -{
> > > > -	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> > > > -	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
> > > > -	struct device *dev = &cxlmd->dev;
> > > > -	struct kernfs_node *sec;
> > > > -
> > > > -	sec = sysfs_get_dirent(dev->kobj.sd, "security");
> > > > -	if (!sec) {
> > > > -		dev_err(dev, "sysfs_get_dirent 'security' failed\n");
> > > > -		return -ENODEV;
> > > > -	}
> > > > -	mds->security.sanitize_node = sysfs_get_dirent(sec, "state");
> > > > -	sysfs_put(sec);
> > > > -	if (!mds->security.sanitize_node) {
> > > > -		dev_err(dev, "sysfs_get_dirent 'state' failed\n");
> > > > -		return -ENODEV;
> > > > -	}
> > > > -
> > > > -	return devm_add_action_or_reset(cxlds->dev, put_sanitize, mds);
> > > > - }
> > > > -
> > > >  struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
> > > >  {
> > > >  	struct cxl_memdev *cxlmd;
> > > > @@ -1058,10 +1020,6 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
> > > >  	if (rc)
> > > >  		goto err;
> > > >  
> > > > -	rc = cxl_memdev_security_init(cxlmd);
> > > > -	if (rc)
> > > > -		goto err;
> > > > -
> > > >  	rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd);
> > > >  	if (rc)
> > > >  		return ERR_PTR(rc);
> > > > diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> > > > index ac4e434b0806..b0023e479315 100644
> > > > --- a/drivers/cxl/pci.c
> > > > +++ b/drivers/cxl/pci.c
> > > > @@ -165,6 +165,49 @@ static void cxl_mbox_sanitize_work(struct work_struct *work)
> > > >  	mutex_unlock(&mds->mbox_mutex);
> > > >  }
> > > >  
> > > > +static void cxl_sanitize_teardown_notifier(void *data)
> > > > +{
> > > > +	struct cxl_memdev_state *mds = data;
> > > > +	struct kernfs_node *state;
> > > > +
> > > > +	/*
> > > > +	 * Prevent new irq triggered invocations of the workqueue and
> > > > +	 * flush inflight invocations.
> > > > +	 */
> > > > +	mutex_lock(&mds->mbox_mutex);
> > > > +	state = mds->security.sanitize_node;
> > > > +	mds->security.sanitize_node = NULL;
> > > > +	mutex_unlock(&mds->mbox_mutex);
> > > > +
> > > > +	cancel_delayed_work_sync(&mds->security.poll_dwork);
> > > > +	sysfs_put(state);
> > > > +}
> > > > +
> > > > +static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
> > > > +{  
> > > 
> > > Almost everything in cxl_pci_probe() passes in the mds.
> > > Why not do the same here?  
> > 
> > Because this one really is built on top of a stack of things and needs
> > the 'device' because it is tying the device's sysfs attributes to the
> > completion notifications of the background workqueue.
> > 
> > I mentioned this in the cover, but failed to mention it again in this
> > changelog:
> > 
> > "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."
> > 
> > There are no sysfs attributes reachable from an @mds.
> 
> I'm confused.  This accesses the sysfs stuff via
> sec = sysfs_get_dirent(dev->kobj.sd, "security");
> where dev = cxlds->dev
> and cxlds is embedded in mds.

Ah, no that's a bug I introduced. The dev should be &cxlmd->dev and I
made this mistake when combining the code.

> So from a code point of view I can't see the restriction.
> Is it more a semantic issue that it naturally feels better to use
> the cxl_mdev?

This is also why I wanted a positive test result that I did not
introduce some silly bug, which I did. My typical capture of silly bugs
is cxl_test, but there is no cxl_test infrastructure for sanitize.
Dan Williams Oct. 4, 2023, 6:48 p.m. UTC | #10
Davidlohr Bueso wrote:
> On Tue, 03 Oct 2023, Dan Williams wrote:
> 
> >Davidlohr Bueso wrote:
> >> On Fri, 29 Sep 2023, Dan Williams wrote:
> >>
> >> >+static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
> >> >+{
> >> >+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> >> >+	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
> >> >+	struct device *dev = cxlds->dev;
> >>
> >> This wants to be dev = &cxlmd->dev;
> >
> >No, the notifier needs to be torn down in the cxl_pci teardown path. If
> >cxlmd->dev was the devm operations host then this notifier would need to
> >be setup from the cxl_mem driver, not cxl_pci. The teardown order of
> >cxl_pci ends with @cxlds->dev as the devm host ends up as:
> >
> >cxl_sanitize_teardown_notifier()
> >cxl_memdev_unregister()
> >
> >...otherwise if the @cxlmd->dev is used then the devm callback may not
> >fire until device_release() time since it is possible that the cxl_mem
> >driver never attaches to trigger the typical devm action around
> >->remove() time.
> 
> As is, the first sysfs_get_dirent() fails, fyi.

Yup, thanks for testing, I am using the wrong device to lookup the sysfs
entry.

What would it take to get your test scenario into cxl_test... or at
least a recipe for it in QEMU that can be checked into the cxl-cli
tests?
Dan Williams Oct. 4, 2023, 6:50 p.m. UTC | #11
Davidlohr Bueso wrote:
> On Tue, 03 Oct 2023, Dan Williams wrote:
> 
> >Davidlohr Bueso wrote:
> >> On Fri, 29 Sep 2023, Dan Williams wrote:
> >>
> >> >+static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
> >> >+{
> >> >+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> >> >+	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
> >> >+	struct device *dev = cxlds->dev;
> >>
> >> This wants to be dev = &cxlmd->dev;
> >
> >No, the notifier needs to be torn down in the cxl_pci teardown path. If
> >cxlmd->dev was the devm operations host then this notifier would need to
> >be setup from the cxl_mem driver, not cxl_pci. The teardown order of
> >cxl_pci ends with @cxlds->dev as the devm host ends up as:
> >
> >cxl_sanitize_teardown_notifier()
> >cxl_memdev_unregister()
> >
> >...otherwise if the @cxlmd->dev is used then the devm callback may not
> >fire until device_release() time since it is possible that the cxl_mem
> >driver never attaches to trigger the typical devm action around
> >->remove() time.
> 
> As is, the first sysfs_get_dirent() fails, fyi.

I should say that I misread your motivation for changing the dev because
that would also change the devm host, and now I see the bug.
Dan Williams Oct. 4, 2023, 6:54 p.m. UTC | #12
Davidlohr Bueso wrote:
> On Tue, 03 Oct 2023, Dan Williams wrote:
> 
> >Davidlohr Bueso wrote:
> >> On Fri, 29 Sep 2023, Dan Williams wrote:
> >>
> >> >+static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
> >> >+{
> >> >+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> >> >+	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
> >> >+	struct device *dev = cxlds->dev;
> >>
> >> This wants to be dev = &cxlmd->dev;
> >
> >No, the notifier needs to be torn down in the cxl_pci teardown path. If
> >cxlmd->dev was the devm operations host then this notifier would need to
> >be setup from the cxl_mem driver, not cxl_pci. The teardown order of
> >cxl_pci ends with @cxlds->dev as the devm host ends up as:
> >
> >cxl_sanitize_teardown_notifier()
> >cxl_memdev_unregister()
> >
> >...otherwise if the @cxlmd->dev is used then the devm callback may not
> >fire until device_release() time since it is possible that the cxl_mem
> >driver never attaches to trigger the typical devm action around
> >->remove() time.
> 
> As is, the first sysfs_get_dirent() fails, fyi.

Here is the full fix, apologies for misreading your fix earlier:

diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index f69f6195c465..a84932ad9392 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -187,25 +187,25 @@ static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
 {
        struct cxl_dev_state *cxlds = cxlmd->cxlds;
        struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
-       struct device *dev = cxlds->dev;
+       struct device *host = cxlds->dev;
        struct kernfs_node *sec;
 
        if (!test_bit(CXL_SEC_ENABLED_SANITIZE, mds->security.enabled_cmds))
                return 0;
 
-       sec = sysfs_get_dirent(dev->kobj.sd, "security");
+       sec = sysfs_get_dirent(cxlmd->dev.kobj.sd, "security");
        if (!sec) {
-               dev_err(dev, "sanitize notification setup failure\n");
+               dev_err(host, "sanitize notification setup failure\n");
                return -ENOENT;
        }
        mds->security.sanitize_node = sysfs_get_dirent(sec, "state");
        sysfs_put(sec);
        if (!mds->security.sanitize_node) {
-               dev_err(dev, "sanitize notification setup failure\n");
+               dev_err(host, "sanitize notification setup failure\n");
                return -ENOENT;
        }
 
-       return devm_add_action_or_reset(dev, cxl_sanitize_teardown_notifier, mds);
+       return devm_add_action_or_reset(host, cxl_sanitize_teardown_notifier, mds);
 }
 
 /**
Davidlohr Bueso Oct. 4, 2023, 7:23 p.m. UTC | #13
On Wed, 04 Oct 2023, Dan Williams wrote:

>Davidlohr Bueso wrote:
>> On Tue, 03 Oct 2023, Dan Williams wrote:
>>
>> >Davidlohr Bueso wrote:
>> >> On Fri, 29 Sep 2023, Dan Williams wrote:
>> >>
>> >> >+static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
>> >> >+{
>> >> >+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
>> >> >+	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
>> >> >+	struct device *dev = cxlds->dev;
>> >>
>> >> This wants to be dev = &cxlmd->dev;
>> >
>> >No, the notifier needs to be torn down in the cxl_pci teardown path. If
>> >cxlmd->dev was the devm operations host then this notifier would need to
>> >be setup from the cxl_mem driver, not cxl_pci. The teardown order of
>> >cxl_pci ends with @cxlds->dev as the devm host ends up as:
>> >
>> >cxl_sanitize_teardown_notifier()
>> >cxl_memdev_unregister()
>> >
>> >...otherwise if the @cxlmd->dev is used then the devm callback may not
>> >fire until device_release() time since it is possible that the cxl_mem
>> >driver never attaches to trigger the typical devm action around
>> >->remove() time.
>>
>> As is, the first sysfs_get_dirent() fails, fyi.
>
>Here is the full fix, apologies for misreading your fix earlier:

Yep, looks good (and tested).

>
>diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
>index f69f6195c465..a84932ad9392 100644
>--- a/drivers/cxl/pci.c
>+++ b/drivers/cxl/pci.c
>@@ -187,25 +187,25 @@ static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
> {
>        struct cxl_dev_state *cxlds = cxlmd->cxlds;
>        struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
>-       struct device *dev = cxlds->dev;
>+       struct device *host = cxlds->dev;
>        struct kernfs_node *sec;
>
>        if (!test_bit(CXL_SEC_ENABLED_SANITIZE, mds->security.enabled_cmds))
>                return 0;
>
>-       sec = sysfs_get_dirent(dev->kobj.sd, "security");
>+       sec = sysfs_get_dirent(cxlmd->dev.kobj.sd, "security");
>        if (!sec) {
>-               dev_err(dev, "sanitize notification setup failure\n");
>+               dev_err(host, "sanitize notification setup failure\n");
>                return -ENOENT;
>        }
>        mds->security.sanitize_node = sysfs_get_dirent(sec, "state");
>        sysfs_put(sec);
>        if (!mds->security.sanitize_node) {
>-               dev_err(dev, "sanitize notification setup failure\n");
>+               dev_err(host, "sanitize notification setup failure\n");
>                return -ENOENT;
>        }
>
>-       return devm_add_action_or_reset(dev, cxl_sanitize_teardown_notifier, mds);
>+       return devm_add_action_or_reset(host, cxl_sanitize_teardown_notifier, mds);
> }
>
> /**
>
diff mbox series

Patch

diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index 2a7a07f6d165..a950091e5640 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -556,20 +556,11 @@  void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds,
 }
 EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL);
 
-static void cxl_memdev_security_shutdown(struct device *dev)
-{
-	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
-	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
-
-	cancel_delayed_work_sync(&mds->security.poll_dwork);
-}
-
 static void cxl_memdev_shutdown(struct device *dev)
 {
 	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
 
 	down_write(&cxl_memdev_rwsem);
-	cxl_memdev_security_shutdown(dev);
 	cxlmd->cxlds = NULL;
 	up_write(&cxl_memdev_rwsem);
 }
@@ -1001,35 +992,6 @@  static const struct file_operations cxl_memdev_fops = {
 	.llseek = noop_llseek,
 };
 
-static void put_sanitize(void *data)
-{
-	struct cxl_memdev_state *mds = data;
-
-	sysfs_put(mds->security.sanitize_node);
-}
-
-static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
-{
-	struct cxl_dev_state *cxlds = cxlmd->cxlds;
-	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
-	struct device *dev = &cxlmd->dev;
-	struct kernfs_node *sec;
-
-	sec = sysfs_get_dirent(dev->kobj.sd, "security");
-	if (!sec) {
-		dev_err(dev, "sysfs_get_dirent 'security' failed\n");
-		return -ENODEV;
-	}
-	mds->security.sanitize_node = sysfs_get_dirent(sec, "state");
-	sysfs_put(sec);
-	if (!mds->security.sanitize_node) {
-		dev_err(dev, "sysfs_get_dirent 'state' failed\n");
-		return -ENODEV;
-	}
-
-	return devm_add_action_or_reset(cxlds->dev, put_sanitize, mds);
- }
-
 struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
 {
 	struct cxl_memdev *cxlmd;
@@ -1058,10 +1020,6 @@  struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
 	if (rc)
 		goto err;
 
-	rc = cxl_memdev_security_init(cxlmd);
-	if (rc)
-		goto err;
-
 	rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd);
 	if (rc)
 		return ERR_PTR(rc);
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index ac4e434b0806..b0023e479315 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -165,6 +165,49 @@  static void cxl_mbox_sanitize_work(struct work_struct *work)
 	mutex_unlock(&mds->mbox_mutex);
 }
 
+static void cxl_sanitize_teardown_notifier(void *data)
+{
+	struct cxl_memdev_state *mds = data;
+	struct kernfs_node *state;
+
+	/*
+	 * Prevent new irq triggered invocations of the workqueue and
+	 * flush inflight invocations.
+	 */
+	mutex_lock(&mds->mbox_mutex);
+	state = mds->security.sanitize_node;
+	mds->security.sanitize_node = NULL;
+	mutex_unlock(&mds->mbox_mutex);
+
+	cancel_delayed_work_sync(&mds->security.poll_dwork);
+	sysfs_put(state);
+}
+
+static int cxl_sanitize_setup_notifier(struct cxl_memdev *cxlmd)
+{
+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
+	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
+	struct device *dev = cxlds->dev;
+	struct kernfs_node *sec;
+
+	if (!test_bit(CXL_SEC_ENABLED_SANITIZE, mds->security.enabled_cmds))
+		return 0;
+
+	sec = sysfs_get_dirent(dev->kobj.sd, "security");
+	if (!sec) {
+		dev_err(dev, "sanitize notification setup failure\n");
+		return -ENOENT;
+	}
+	mds->security.sanitize_node = sysfs_get_dirent(sec, "state");
+	sysfs_put(sec);
+	if (!mds->security.sanitize_node) {
+		dev_err(dev, "sanitize notification setup failure\n");
+		return -ENOENT;
+	}
+
+	return devm_add_action_or_reset(dev, cxl_sanitize_teardown_notifier, mds);
+}
+
 /**
  * __cxl_pci_mbox_send_cmd() - Execute a mailbox command
  * @mds: The memory device driver data
@@ -875,6 +918,10 @@  static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (rc)
 		return rc;
 
+	rc = cxl_sanitize_setup_notifier(cxlmd);
+	if (rc)
+		return rc;
+
 	pmu_count = cxl_count_regblock(pdev, CXL_REGLOC_RBI_PMU);
 	for (i = 0; i < pmu_count; i++) {
 		struct cxl_pmu_regs pmu_regs;