[Concept,02/17] blk: Return error from blk_get_devnum_by_uclass_idname()

Message ID 20260316183050.3855921-3-sjg@u-boot.org
State New
Headers
Series Add automatic memory-leak detection to U-Boot tests |

Commit Message

Simon Glass March 16, 2026, 6:30 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

blk_get_devnum_by_uclass_idname() returns a struct blk_desc pointer,
discarding the error code from device_probe(). When probe fails due
to out-of-memory or other errors, callers see NULL and report a
generic 'device not found' instead of the actual cause.

Change the function to return int and pass back the block device via
a struct udevice ** parameter. This propagates the actual error from
device_probe() through to callers.

Rename the legacy version to blk_get_desc_by_uclass_idname() since it
has no struct udevice to return, and use CONFIG_IS_ENABLED(BLK) in
disk/part.c to select the right function.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 cmd/blkmap.c               |  8 ++++----
 disk/part.c                | 23 ++++++++++++++++++-----
 drivers/block/blk-uclass.c | 19 +++++++++++--------
 drivers/block/blk_legacy.c |  3 ++-
 include/blk.h              | 24 +++++++++++++++++++-----
 test/boot/luks.c           | 15 +++++++++------
 6 files changed, 63 insertions(+), 29 deletions(-)
  

Patch

diff --git a/cmd/blkmap.c b/cmd/blkmap.c
index 65edec899e2..2dc516e2ca4 100644
--- a/cmd/blkmap.c
+++ b/cmd/blkmap.c
@@ -28,7 +28,7 @@  struct map_handler {
 static int do_blkmap_map_linear(struct map_ctx *ctx, int argc,
 				char *const argv[])
 {
-	struct blk_desc *lbd;
+	struct udevice *ldev;
 	int err, ldevnum;
 	lbaint_t lblknr;
 
@@ -38,15 +38,15 @@  static int do_blkmap_map_linear(struct map_ctx *ctx, int argc,
 	ldevnum = dectoul(argv[2], NULL);
 	lblknr = dectoul(argv[3], NULL);
 
-	lbd = blk_get_devnum_by_uclass_idname(argv[1], ldevnum);
-	if (!lbd) {
+	err = blk_get_devnum_by_uclass_idname(argv[1], ldevnum, &ldev);
+	if (err) {
 		printf("Found no device matching \"%s %d\"\n",
 		       argv[1], ldevnum);
 		return CMD_RET_FAILURE;
 	}
 
 	err = blkmap_map_linear(ctx->dev, ctx->blknr, ctx->blkcnt,
-				lbd->bdev, lblknr);
+				ldev, lblknr);
 	if (err) {
 		printf("Unable to map \"%s %d\" at block 0x" LBAF ": %d\n",
 		       argv[1], ldevnum, ctx->blknr, err);
diff --git a/disk/part.c b/disk/part.c
index b6dd3598c0f..d5ebdb037a6 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -8,6 +8,7 @@ 
 
 #include <blk.h>
 #include <command.h>
+#include <dm.h>
 #include <env.h>
 #include <errno.h>
 #include <log.h>
@@ -124,11 +125,23 @@  static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
 
 	if (!blk_enabled())
 		return NULL;
-	desc = blk_get_devnum_by_uclass_idname(ifname, dev);
-	if (!desc) {
-		debug("%s: No device for iface '%s', dev %d\n", __func__,
-		      ifname, dev);
-		return NULL;
+	if (CONFIG_IS_ENABLED(BLK)) {
+		struct udevice *blk;
+
+		ret = blk_get_devnum_by_uclass_idname(ifname, dev, &blk);
+		if (ret) {
+			log_debug("No device for iface '%s', dev %d: err=%d\n",
+				  ifname, dev, ret);
+			return NULL;
+		}
+		desc = dev_get_uclass_plat(blk);
+	} else {
+		desc = blk_get_desc_by_uclass_idname(ifname, dev);
+		if (!desc) {
+			log_debug("No device for iface '%s', dev %d\n",
+				  ifname, dev);
+			return NULL;
+		}
 	}
 	ret = blk_dselect_hwpart(desc, hwpart);
 	if (ret) {
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
index a6ef34c2d5f..9c9169d6ac8 100644
--- a/drivers/block/blk-uclass.c
+++ b/drivers/block/blk-uclass.c
@@ -107,7 +107,8 @@  struct blk_desc *blk_get_devnum_by_uclass_id(enum uclass_id uclass_id, int devnu
  * name in a local table. This gives us an interface type which we can match
  * against the uclass of the block device's parent.
  */
-struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum)
+int blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum,
+				    struct udevice **blkp)
 {
 	enum uclass_id uclass_id;
 	enum uclass_id type;
@@ -119,18 +120,18 @@  struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int
 	if (type == UCLASS_INVALID) {
 		debug("%s: Unknown interface type '%s'\n", __func__,
 		      uclass_idname);
-		return NULL;
+		return -ENODEV;
 	}
 	uclass_id = conv_uclass_id(type);
 	if (uclass_id == UCLASS_INVALID) {
 		debug("%s: Unknown uclass for interface type'\n",
 		      blk_get_uclass_name(type));
-		return NULL;
+		return -ENODEV;
 	}
 
 	ret = uclass_get(UCLASS_BLK, &uc);
 	if (ret)
-		return NULL;
+		return ret;
 	uclass_foreach_dev(dev, uc) {
 		struct blk_desc *desc = dev_get_uclass_plat(dev);
 
@@ -146,15 +147,17 @@  struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int
 			continue;
 		}
 
-		if (device_probe(dev))
-			return NULL;
+		ret = device_probe(dev);
+		if (ret)
+			return ret;
 
 		debug("%s: Device desc %p\n", __func__, desc);
-		return desc;
+		*blkp = dev;
+		return 0;
 	}
 	debug("%s: No device found\n", __func__);
 
-	return NULL;
+	return -ENXIO;
 }
 
 /**
diff --git a/drivers/block/blk_legacy.c b/drivers/block/blk_legacy.c
index f36932183d1..28e40d23c71 100644
--- a/drivers/block/blk_legacy.c
+++ b/drivers/block/blk_legacy.c
@@ -199,7 +199,8 @@  int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
 	return 0;
 }
 
-struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum)
+struct blk_desc *blk_get_desc_by_uclass_idname(const char *uclass_idname,
+					       int devnum)
 {
 	struct blk_driver *drv = blk_driver_lookup_typename(uclass_idname);
 	struct blk_desc *desc;
diff --git a/include/blk.h b/include/blk.h
index 877876cb622..14ab77f7c51 100644
--- a/include/blk.h
+++ b/include/blk.h
@@ -642,15 +642,29 @@  struct blk_desc *blk_get_devnum_by_uclass_id(enum uclass_id uclass_id, int devnu
 /**
  * blk_get_devnum_by_uclass_idname() - Get block device by type name and number
  *
- * This looks up the block device type based on @uclass_idname, then calls
- * blk_get_devnum_by_uclass_id().
+ * This looks up the block device type based on @uclass_idname, then probes
+ * the device.
+ *
+ * @uclass_idname:	Block device type name (e.g. "mmc")
+ * @devnum:		Device number
+ * @blkp:		Returns the block device
+ * Return: 0 if OK, -ENODEV if the uclass is not known, -ENXIO if the
+ *	device is not found, or other -ve on probe error
+ */
+int blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum,
+				    struct udevice **blkp);
+
+/**
+ * blk_get_desc_by_uclass_idname() - Get block descriptor by type name/number
+ *
+ * Legacy version for non-DM block devices.
  *
  * @uclass_idname:	Block device type name
  * @devnum:		Device number
- * Return: point to block device descriptor, or NULL if not found
+ * Return: pointer to block device descriptor, or NULL if not found
  */
-struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname,
-						 int devnum);
+struct blk_desc *blk_get_desc_by_uclass_idname(const char *uclass_idname,
+					       int devnum);
 
 /**
  * blk_dselect_hwpart() - select a hardware partition
diff --git a/test/boot/luks.c b/test/boot/luks.c
index 339c7d7fc94..f6d0d951fee 100644
--- a/test/boot/luks.c
+++ b/test/boot/luks.c
@@ -220,6 +220,7 @@  BOOTSTD_TEST(bootstd_test_luks2_info, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
 static int bootstd_test_luks_unlock(struct unit_test_state *uts)
 {
 	struct blk_desc *desc;
+	struct udevice *blk;
 	struct udevice *mmc;
 	loff_t file_size;
 
@@ -242,8 +243,8 @@  static int bootstd_test_luks_unlock(struct unit_test_state *uts)
 	ut_assert_console_end();
 
 	/* Verify that a file can be read from the decrypted filesystem */
-	desc = blk_get_devnum_by_uclass_idname("blkmap", 0);
-	ut_assertnonnull(desc);
+	ut_assertok(blk_get_devnum_by_uclass_idname("blkmap", 0, &blk));
+	desc = dev_get_uclass_plat(blk);
 
 	ut_assertok(fs_set_blk_dev_with_part(desc, 0));
 	ut_assertok(fs_size("/bin/bash", &file_size));
@@ -262,6 +263,7 @@  static int bootstd_test_luks2_unlock(struct unit_test_state *uts)
 {
 	struct disk_partition info;
 	struct blk_desc *desc;
+	struct udevice *blk;
 	struct udevice *mmc;
 	u8 master_key[512];
 	loff_t file_size;
@@ -284,8 +286,8 @@  static int bootstd_test_luks2_unlock(struct unit_test_state *uts)
 	ut_assert_console_end();
 
 	/* Verify that a file can be read from the decrypted filesystem */
-	desc = blk_get_devnum_by_uclass_idname("blkmap", 0);
-	ut_assertnonnull(desc);
+	ut_assertok(blk_get_devnum_by_uclass_idname("blkmap", 0, &blk));
+	desc = dev_get_uclass_plat(blk);
 
 	ut_assertok(fs_set_blk_dev_with_part(desc, 0));
 	ut_assertok(fs_size("/bin/bash", &file_size));
@@ -312,6 +314,7 @@  static int setup_mmc14(struct unit_test_state *uts, struct udevice **mmcp)
 static int bootstd_test_luks2_unlock_prederived(struct unit_test_state *uts)
 {
 	struct blk_desc *desc;
+	struct udevice *blk;
 	struct udevice *mmc;
 	loff_t file_size;
 
@@ -333,8 +336,8 @@  static int bootstd_test_luks2_unlock_prederived(struct unit_test_state *uts)
 	ut_assert_console_end();
 
 	/* Verify that a file can be read from the decrypted filesystem */
-	desc = blk_get_devnum_by_uclass_idname("blkmap", 0);
-	ut_assertnonnull(desc);
+	ut_assertok(blk_get_devnum_by_uclass_idname("blkmap", 0, &blk));
+	desc = dev_get_uclass_plat(blk);
 
 	ut_assertok(fs_set_blk_dev_with_part(desc, 0));
 	ut_assertok(fs_size("/bin/bash", &file_size));