[PATCH 06/13] usb: storage: tear the disk down properly on disconnect

Sascha Hauer s.hauer at pengutronix.de
Mon Aug 31 06:20:13 PDT 2026


usb_stor_disconnect() unregistered the block device and freed it right
away, no matter whether the removal actually worked. With a filesystem
mounted from the stick it does not: the partition cdev is still open, so
the disk cannot go away and the cdevs would be left pointing into freed
memory.

Use blockdevice_unregister_removed(), which drops the filesystems that
were mounted from the stick before removing it. They are stale anyway,
the medium they live on is gone.

Should something else still hold the disk open we now keep it around
instead of freeing it. That leaks the disk and the us_data it refers to,
but a leak is preferable to handing out a cdev that points at freed
memory. barebox has no refcounting on devices, so there is no way to do
better than that here.

While at it, free the cdev name, which nobody did so far.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Assisted-by: Claude:claude-opus-5
---
 drivers/usb/storage/usb.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 39c4695b0a..7c19207a8d 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -608,16 +608,34 @@ static void usb_stor_disconnect(struct usb_device *usbdev)
 {
 	struct us_data *us = (struct us_data *)usbdev->drv_data;
 	struct us_blk_dev *bdev, *bdev_tmp;
+	bool busy = false;
+	int ret;
 
 	list_for_each_entry_safe(bdev, bdev_tmp, &us->blk_dev_list, list) {
+		ret = blockdevice_unregister_removed(&bdev->blk);
+		if (ret) {
+			/*
+			 * Something still holds the disk open. Leaking it is
+			 * not nice, but freeing it would leave the cdev that
+			 * is still in use pointing at freed memory.
+			 */
+			dev_err(&usbdev->dev, "%s is still in use, leaking it: %pe\n",
+				bdev->blk.cdev.name, ERR_PTR(ret));
+			busy = true;
+			continue;
+		}
+
 		list_del(&bdev->list);
-		blockdevice_unregister(&bdev->blk);
+		free(bdev->blk.cdev.name);
 		free(bdev);
 	}
 
 	/* release device's private data */
-	usbdev->drv_data = 0;
-	free(us);
+	usbdev->drv_data = NULL;
+
+	/* a leaked disk still refers to us, so that has to stay as well */
+	if (!busy)
+		free(us);
 }
 
 #define USUAL_DEV(use_proto, use_trans, drv_info) \

-- 
2.47.3




More information about the barebox mailing list