diff mbox series

[1/1] scsi: target: Fix unmap setup during configuration

Message ID 20240207021919.7989-1-michael.christie@oracle.com (mailing list archive)
State Superseded
Headers show
Series [1/1] scsi: target: Fix unmap setup during configuration | expand

Commit Message

Mike Christie Feb. 7, 2024, 2:19 a.m. UTC
This issue was found and also debugged by Carl Lei <me@xecycle.info>.

If the device is not enabled, iblock/file will have not setup their
se_device to bdev/file mappings. If a user tries to config the unmap
settings at this time, we will then crash trying to access a NULL
pointer where the bdev/file should be.

This patch adds a check to make sure the device is configured before
we try to call the configure_unmap callout.

Fixes: 34bd1dcacf0d ("scsi: target: Detect UNMAP support post configuration")
Reported-by: Carl Lei <me@xecycle.info>
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/target/target_core_configfs.c | 46 +++++++++++++++++----------
 1 file changed, 30 insertions(+), 16 deletions(-)

Comments

Dmitry Bogdanov Feb. 7, 2024, 7:33 a.m. UTC | #1
Hi Mike,

On Tue, Feb 06, 2024 at 08:19:19PM -0600, Mike Christie wrote:
 
> +static int target_try_configure_unmap(struct se_device *dev,
> +                                     const char *config_opt)
> +{
> +       if (!dev->transport->configure_unmap)
> +               return 0;
> +
> +       if (!target_dev_configured(dev)) {
> +               pr_err("Generic Block Discard setup for %s requires device to be configured\n",
> +                      config_opt);
> +               return -ENODEV;
> +       }
> +
> +       if (!dev->transport->configure_unmap(dev)) {
> +               pr_err("Generic Block Discard setup for %s failed\n",
> +                      config_opt);
> +               return -ENOSYS;
> +       }
> +
> +       return 0;
> +}
> +
>  static ssize_t emulate_tpu_store(struct config_item *item,
>                 const char *page, size_t count)
>  {
> @@ -776,11 +797,9 @@ static ssize_t emulate_tpu_store(struct config_item *item,
>          * Discard supported is detected iblock_create_virtdevice().
>          */
>         if (flag && !da->max_unmap_block_desc_count) {
> -               if (!dev->transport->configure_unmap ||
You removed this check but that callout is not mandatory and exists just in
2 backstore modules.

BR,
 Dmitry
Dmitry Bogdanov Feb. 7, 2024, 7:49 a.m. UTC | #2
On Wed, Feb 07, 2024 at 10:33:36AM +0300, Dmitry Bogdanov wrote:
> Hi Mike,
> 
> On Tue, Feb 06, 2024 at 08:19:19PM -0600, Mike Christie wrote:
>  
> > +static int target_try_configure_unmap(struct se_device *dev,
> > +                                     const char *config_opt)
> > +{
> > +       if (!dev->transport->configure_unmap)
> > +               return 0;
Oh, sorry, here it is :)

> > +
> > +       if (!target_dev_configured(dev)) {
> > +               pr_err("Generic Block Discard setup for %s requires device to be configured\n",
> > +                      config_opt);
> > +               return -ENODEV;
> > +       }
> > +
> > +       if (!dev->transport->configure_unmap(dev)) {
> > +               pr_err("Generic Block Discard setup for %s failed\n",
> > +                      config_opt);
> > +               return -ENOSYS;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> >  static ssize_t emulate_tpu_store(struct config_item *item,
> >                 const char *page, size_t count)
> >  {
> > @@ -776,11 +797,9 @@ static ssize_t emulate_tpu_store(struct config_item *item,
> >          * Discard supported is detected iblock_create_virtdevice().
> >          */
> >         if (flag && !da->max_unmap_block_desc_count) {
> > -               if (!dev->transport->configure_unmap ||
> You removed this check but that callout is not mandatory and exists just in
> 2 backstore modules.
>
Maurizio Lombardi Feb. 7, 2024, 10:40 a.m. UTC | #3
st 7. 2. 2024 v 3:19 odesílatel Mike Christie
<michael.christie@oracle.com> napsal:
>
> +static int target_try_configure_unmap(struct se_device *dev,
> +                                     const char *config_opt)
> +{
> +       if (!dev->transport->configure_unmap)
> +               return 0;

With this patch, if the configure_unmap callback is NULL then we
return 0, implying that discard is supported.

Before, a NULL configure_unmap callback triggered an error:

        if (flag && !da->max_unmap_block_desc_count) {
                if (!dev->transport->configure_unmap ||   <<------
                    !dev->transport->configure_unmap(dev)) {
                        pr_err("Generic Block Discard not supported\n");
                        return -ENOSYS;
                }
        }

Shouldn't you return -ENOSYS in target_try_configure_unmap() if
configure_unmap is NULL?

Maurizio
Mike Christie Feb. 7, 2024, 3:35 p.m. UTC | #4
On 2/7/24 4:40 AM, Maurizio Lombardi wrote:
> st 7. 2. 2024 v 3:19 odesílatel Mike Christie
> <michael.christie@oracle.com> napsal:
>>
>> +static int target_try_configure_unmap(struct se_device *dev,
>> +                                     const char *config_opt)
>> +{
>> +       if (!dev->transport->configure_unmap)
>> +               return 0;
> 
> With this patch, if the configure_unmap callback is NULL then we
> return 0, implying that discard is supported.
> 
> Before, a NULL configure_unmap callback triggered an error:
> 
>         if (flag && !da->max_unmap_block_desc_count) {
>                 if (!dev->transport->configure_unmap ||   <<------
>                     !dev->transport->configure_unmap(dev)) {
>                         pr_err("Generic Block Discard not supported\n");
>                         return -ENOSYS;
>                 }
>         }
> 
> Shouldn't you return -ENOSYS in target_try_configure_unmap() if
> configure_unmap is NULL?
> 

You are right. Will fix.
diff mbox series

Patch

diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index a5f58988130a..d87f6eba4eda 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -759,6 +759,27 @@  static ssize_t emulate_tas_store(struct config_item *item,
 	return count;
 }
 
+static int target_try_configure_unmap(struct se_device *dev,
+				      const char *config_opt)
+{
+	if (!dev->transport->configure_unmap)
+		return 0;
+
+	if (!target_dev_configured(dev)) {
+		pr_err("Generic Block Discard setup for %s requires device to be configured\n",
+		       config_opt);
+		return -ENODEV;
+	}
+
+	if (!dev->transport->configure_unmap(dev)) {
+		pr_err("Generic Block Discard setup for %s failed\n",
+		       config_opt);
+		return -ENOSYS;
+	}
+
+	return 0;
+}
+
 static ssize_t emulate_tpu_store(struct config_item *item,
 		const char *page, size_t count)
 {
@@ -776,11 +797,9 @@  static ssize_t emulate_tpu_store(struct config_item *item,
 	 * Discard supported is detected iblock_create_virtdevice().
 	 */
 	if (flag && !da->max_unmap_block_desc_count) {
-		if (!dev->transport->configure_unmap ||
-		    !dev->transport->configure_unmap(dev)) {
-			pr_err("Generic Block Discard not supported\n");
-			return -ENOSYS;
-		}
+		ret = target_try_configure_unmap(dev, "emulate_tpu");
+		if (ret)
+			return ret;
 	}
 
 	da->emulate_tpu = flag;
@@ -806,11 +825,9 @@  static ssize_t emulate_tpws_store(struct config_item *item,
 	 * Discard supported is detected iblock_create_virtdevice().
 	 */
 	if (flag && !da->max_unmap_block_desc_count) {
-		if (!dev->transport->configure_unmap ||
-		    !dev->transport->configure_unmap(dev)) {
-			pr_err("Generic Block Discard not supported\n");
-			return -ENOSYS;
-		}
+		ret = target_try_configure_unmap(dev, "emulate_tpws");
+		if (ret)
+			return ret;
 	}
 
 	da->emulate_tpws = flag;
@@ -1022,12 +1039,9 @@  static ssize_t unmap_zeroes_data_store(struct config_item *item,
 	 * Discard supported is detected iblock_configure_device().
 	 */
 	if (flag && !da->max_unmap_block_desc_count) {
-		if (!dev->transport->configure_unmap ||
-		    !dev->transport->configure_unmap(dev)) {
-			pr_err("dev[%p]: Thin Provisioning LBPRZ will not be set because max_unmap_block_desc_count is zero\n",
-			       da->da_dev);
-			return -ENOSYS;
-		}
+		ret = target_try_configure_unmap(dev, "unmap_zeroes_data");
+		if (ret)
+			return ret;
 	}
 	da->unmap_zeroes_data = flag;
 	pr_debug("dev[%p]: SE Device Thin Provisioning LBPRZ bit: %d\n",