Skip to contentSkip to conversation

FAILED: patch "[PATCH] scsi: sd: fix missing put_disk() when device_add(&disk_dev)" failed to apply to 5.15-stable tree

PATCH New [email protected] 2 participants 5 messages May 4 – May 9

Subsystems (2)
lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

The patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.

To reproduce the conflict and resubmit, you may use the following commands:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x 1e111c4b3a726df1254670a5cc4868cedb946d37
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026050456-overview-shaking-6135@gregkh' --subject-prefix 'PATCH 5.15.y' HEAD^..

Possible dependencies:

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From 1e111c4b3a726df1254670a5cc4868cedb946d37 Mon Sep 17 00:00:00 2001
From: Yang Xiuwei <[email protected]>
Date: Mon, 30 Mar 2026 09:49:52 +0800
Subject: [PATCH] scsi: sd: fix missing put_disk() when device_add(&disk_dev)
fails

If device_add(&sdkp->disk_dev) fails, put_device() runs scsi_disk_release(), which frees the scsi_disk but leaves the gendisk referenced. The device_add_disk() error path in sd_probe() calls put_disk(gd); call put_disk(gd) here to mirror that cleanup.

Fixes 265dfe8ebbab ("scsi: sd: Free scsi_disk device via put_device()")
drivers/scsi/sd.c +1 -0
index 205877b1f8aa..adc3fa55ca2c 100644
@@ -4061,6 +4061,7 @@ static int sd_probe(struct scsi_device *sdp)
 	error = device_add(&sdkp->disk_dev);
 	if (error) {
 		put_device(&sdkp->disk_dev);
+		put_disk(gd);
 		goto out;
 	}
 
maintainer
#1 lore raw

PATCH 1/4 scsi: core: pm: Rely on the device driver core for async power management

From: Bart Van Assche <[email protected]>

[ Upstream commit a19a93e4c6a98c9c0f2f5a6db76846f10d7d1f85 ]

Instead of implementing asynchronous resume support in the SCSI core, rely on the device driver core for resuming SCSI devices asynchronously. Instead of only supporting asynchronous resumes, also support asynchronous suspends.

Stable-dep-of: 1e111c4b3a72 ("scsi: sd: fix missing put_disk() when device_add(&disk_dev) fails")

---
 drivers/scsi/hosts.c      |  1 +
 drivers/scsi/scsi.c       |  8 -------
 drivers/scsi/scsi_pm.c    | 44 ++-------------------------------------
 drivers/scsi/scsi_priv.h  |  4 +---
 drivers/scsi/scsi_scan.c  | 17 +++++++++++++++
 drivers/scsi/scsi_sysfs.c |  1 +
 drivers/scsi/sd.c         |  1 -
 7 files changed, 22 insertions(+), 54 deletions(-)
drivers/scsi/hosts.c +1 -0
index cf842c97639a7..c7d85591a192f 100644
@@ -487,6 +487,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
 	dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
 	shost->shost_gendev.bus = &scsi_bus_type;
 	shost->shost_gendev.type = &scsi_host_type;
+	scsi_enable_async_suspend(&shost->shost_gendev);
 
 	device_initialize(&shost->shost_dev);
 	shost->shost_dev.parent = &shost->shost_gendev;
drivers/scsi/scsi.c +0 -8
index a499a57150720..d031c577d5d32 100644
@@ -86,14 +86,6 @@ unsigned int scsi_logging_level;
 EXPORT_SYMBOL(scsi_logging_level);
 #endif
 
-/*
- * Domain for asynchronous system resume operations.  It is marked 'exclusive'
- * to avoid being included in the async_synchronize_full() that is invoked by
- * dpm_resume().
- */
-ASYNC_DOMAIN_EXCLUSIVE(scsi_sd_pm_domain);
-EXPORT_SYMBOL(scsi_sd_pm_domain);
-
 #ifdef CONFIG_SCSI_LOGGING
 void scsi_log_send(struct scsi_cmnd *cmd)
 {
drivers/scsi/scsi_pm.c +2 -42

59 lines not on this page · raw message

drivers/scsi/scsi_priv.h +1 -3
index b531dec3d4206..2032db81897be 100644
@@ -117,7 +117,7 @@ extern void scsi_exit_procfs(void);
 #endif /* CONFIG_PROC_FS */
 
 /* scsi_scan.c */
-extern char scsi_scan_type[];
+void scsi_enable_async_suspend(struct device *dev);
 extern int scsi_complete_async_scans(void);
 extern int scsi_scan_host_selected(struct Scsi_Host *, unsigned int,
 				   unsigned int, u64, enum scsi_scan_mode);
@@ -171,8 +171,6 @@ static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; }
 static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
 #endif /* CONFIG_PM */
 
-extern struct async_domain scsi_sd_pm_domain;
-
 /* scsi_dh.c */
 #ifdef CONFIG_SCSI_DH
 void scsi_dh_add_device(struct scsi_device *sdev);
drivers/scsi/scsi_scan.c +17 -0
index 518aa152849ef..b80dd68d79e9d 100644
@@ -122,6 +122,22 @@ struct async_scan_data {
 	struct completion prev_finished;
 };
 
+/**
+ * scsi_enable_async_suspend - Enable async suspend and resume
+ */
+void scsi_enable_async_suspend(struct device *dev)
+{
+	/*
+	 * If a user has disabled async probing a likely reason is due to a
+	 * storage enclosure that does not inject staggered spin-ups. For
+	 * safety, make resume synchronous as well in that case.
+	 */
+	if (strncmp(scsi_scan_type, "async", 5) != 0)
+		return;
+	/* Enable asynchronous suspend and resume. */
+	device_enable_async_suspend(dev);
+}
+
 /**
  * scsi_complete_async_scans - Wait for asynchronous scans to complete
  *
@@ -499,6 +515,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
 	dev_set_name(dev, "target%d:%d:%d", shost->host_no, channel, id);
 	dev->bus = &scsi_bus_type;
 	dev->type = &scsi_target_type;
+	scsi_enable_async_suspend(dev);
 	starget->id = id;
 	starget->channel = channel;
 	starget->can_queue = 0;
drivers/scsi/scsi_sysfs.c +1 -0
index 7d3cbf4e6bc6e..b761c88f32dfe 100644
@@ -1643,6 +1643,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
 	device_initialize(&sdev->sdev_gendev);
 	sdev->sdev_gendev.bus = &scsi_bus_type;
 	sdev->sdev_gendev.type = &scsi_dev_type;
+	scsi_enable_async_suspend(&sdev->sdev_gendev);
 	dev_set_name(&sdev->sdev_gendev, "%d:%d:%d:%llu",
 		     sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
 
drivers/scsi/sd.c +0 -1
index 1e887c11e83d0..f06cb6c5615a7 100644
@@ -3505,7 +3505,6 @@ static int sd_remove(struct device *dev)
 	sdkp = dev_get_drvdata(dev);
 	scsi_autopm_get_device(sdkp->device);
 
-	async_synchronize_full_domain(&scsi_sd_pm_domain);
 	device_del(&sdkp->dev);
 	del_gendisk(sdkp->disk);
 	sd_shutdown(dev);
Signature · 1 line
2.53.0
maintainer
#2 lore raw

PATCH 2/4 scsi: sd: Add error handling support for add_disk()

From: Luis Chamberlain <[email protected]>

[ Upstream commit 2a7a891f4c406822801ecd676b076c64de072c9e ]

We never checked for errors on add_disk() as this function returned void. Now that this is fixed, use the shiny new error handling.

As with the error handling for device_add() we follow the same logic and just put the device so that cleanup is done via the scsi_disk_release().

Stable-dep-of: 1e111c4b3a72 ("scsi: sd: fix missing put_disk() when device_add(&disk_dev) fails")

---
 drivers/scsi/sd.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/scsi/sd.c +7 -1
index f06cb6c5615a7..91cbe7d569c05 100644
@@ -3458,7 +3458,13 @@ static int sd_probe(struct device *dev)
 		pm_runtime_set_autosuspend_delay(dev,
 			sdp->host->hostt->rpm_autosuspend_delay);
 	}
-	device_add_disk(dev, gd, NULL);
+
+	error = device_add_disk(dev, gd, NULL);
+	if (error) {
+		put_device(&sdkp->dev);
+		goto out;
+	}
+
 	if (sdkp->capacity)
 		sd_dif_config_host(sdkp);
 
Signature · 1 line
2.53.0
maintainer
#3 lore raw

PATCH 3/4 sd: rename the scsi_disk.dev field

In reply to Sasha Levin

From: Christoph Hellwig <[email protected]>

[ Upstream commit fad45c3007a18064da759b4dba35eb722bc64e97 ]

dev is very hard to grep for. Give the field a more descriptive name and documents its purpose.

Stable-dep-of: 1e111c4b3a72 ("scsi: sd: fix missing put_disk() when device_add(&disk_dev) fails")

---
 drivers/scsi/sd.c | 22 +++++++++++-----------
 drivers/scsi/sd.h |  9 +++++++--
 2 files changed, 18 insertions(+), 13 deletions(-)
drivers/scsi/sd.c +11 -11
index 91cbe7d569c05..6c6cca6664c94 100644
@@ -674,7 +674,7 @@ static struct scsi_disk *scsi_disk_get(struct gendisk *disk)
 	if (disk->private_data) {
 		sdkp = scsi_disk(disk);
 		if (scsi_device_get(sdkp->device) == 0)
-			get_device(&sdkp->dev);
+			get_device(&sdkp->disk_dev);
 		else
 			sdkp = NULL;
 	}
@@ -687,7 +687,7 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
 	struct scsi_device *sdev = sdkp->device;
 
 	mutex_lock(&sd_ref_mutex);
-	put_device(&sdkp->dev);
+	put_device(&sdkp->disk_dev);
 	scsi_device_put(sdev);
 	mutex_unlock(&sd_ref_mutex);
 }
@@ -3412,14 +3412,14 @@ static int sd_probe(struct device *dev)
 					     SD_MOD_TIMEOUT);
 	}
 
-	device_initialize(&sdkp->dev);
-	sdkp->dev.parent = get_device(dev);
-	sdkp->dev.class = &sd_disk_class;
-	dev_set_name(&sdkp->dev, "%s", dev_name(dev));
+	device_initialize(&sdkp->disk_dev);
+	sdkp->disk_dev.parent = get_device(dev);
+	sdkp->disk_dev.class = &sd_disk_class;
+	dev_set_name(&sdkp->disk_dev, "%s", dev_name(dev));
 
-	error = device_add(&sdkp->dev);
+	error = device_add(&sdkp->disk_dev);
 	if (error) {
-		put_device(&sdkp->dev);
+		put_device(&sdkp->disk_dev);
 		goto out;
 	}
 
@@ -3461,7 +3461,7 @@ static int sd_probe(struct device *dev)
 
 	error = device_add_disk(dev, gd, NULL);
 	if (error) {
-		put_device(&sdkp->dev);
+		put_device(&sdkp->disk_dev);
 		goto out;
 	}
 
@@ -3511,7 +3511,7 @@ static int sd_remove(struct device *dev)
 	sdkp = dev_get_drvdata(dev);
 	scsi_autopm_get_device(sdkp->device);
 
-	device_del(&sdkp->dev);
+	device_del(&sdkp->disk_dev);
 	del_gendisk(sdkp->disk);
 	sd_shutdown(dev);
 
@@ -3519,7 +3519,7 @@ static int sd_remove(struct device *dev)
 
 	mutex_lock(&sd_ref_mutex);
 	dev_set_drvdata(dev, NULL);
-	put_device(&sdkp->dev);
+	put_device(&sdkp->disk_dev);
 	mutex_unlock(&sd_ref_mutex);
 
 	return 0;
drivers/scsi/sd.h +7 -2
index b59136c4125ba..f97eb3fe045b9 100644
@@ -70,7 +70,12 @@ enum {
 struct scsi_disk {
 	struct scsi_driver *driver;	/* always &sd_template */
 	struct scsi_device *device;
-	struct device	dev;
+
+	/*
+	 * disk_dev is used to show attributes in /sys/class/scsi_disk/,
+	 * but otherwise not really needed.  Do not use for refcounting.
+	 */
+	struct device	disk_dev;
 	struct gendisk	*disk;
 	struct opal_dev *opal_dev;
 #ifdef CONFIG_BLK_DEV_ZONED
@@ -126,7 +131,7 @@ struct scsi_disk {
 	unsigned	security : 1;
 	unsigned	ignore_medium_access_errors : 1;
 };
-#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
+#define to_scsi_disk(obj) container_of(obj, struct scsi_disk, disk_dev)
 
 static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
 {
Signature · 1 line
2.53.0
maintainer
#4 lore raw

PATCH 4/4 scsi: sd: fix missing put_disk() when device_add(&disk_dev) fails

In reply to Sasha Levin

From: Yang Xiuwei <[email protected]>

[ Upstream commit 1e111c4b3a726df1254670a5cc4868cedb946d37 ]

If device_add(&sdkp->disk_dev) fails, put_device() runs scsi_disk_release(), which frees the scsi_disk but leaves the gendisk referenced. The device_add_disk() error path in sd_probe() calls put_disk(gd); call put_disk(gd) here to mirror that cleanup.

---
 drivers/scsi/sd.c | 1 +
 1 file changed, 1 insertion(+)
drivers/scsi/sd.c +1 -0
index 6c6cca6664c94..358354fe6c76f 100644
@@ -3420,6 +3420,7 @@ static int sd_probe(struct device *dev)
 	error = device_add(&sdkp->disk_dev);
 	if (error) {
 		put_device(&sdkp->disk_dev);
+		put_disk(gd);
 		goto out;
 	}
 
Signature · 1 line
2.53.0