git: d9c5a9ea498a - main - device_get_path(): do not drop the error from BUS_GET_DEVICE_PATH()

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Wed, 19 Oct 2022 16:40:01 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=d9c5a9ea498aa1872b909fae16babf4b292d4e70

commit d9c5a9ea498aa1872b909fae16babf4b292d4e70
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2022-10-07 01:25:37 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2022-10-19 16:39:26 +0000

    device_get_path(): do not drop the error from BUS_GET_DEVICE_PATH()
    
    Later it would silently converted to ENOMEM always, because any error
    was reported as NULL return path.
    
    Reviewed by:    jhb, takawata
    Discussed with: imp
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D36899
---
 sys/kern/subr_bus.c | 49 ++++++++++++++++++++++++++++---------------------
 1 file changed, 28 insertions(+), 21 deletions(-)

diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index 3ba68ba78781..b083411f9876 100644
--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -5304,27 +5304,33 @@ device_do_deferred_actions(void)
 	bus_data_generation_update();
 }
 
-static char *
-device_get_path(device_t dev, const char *locator)
+static int
+device_get_path(device_t dev, const char *locator, char **rvp)
 {
 	struct sbuf *sb;
+	char *s;
 	ssize_t len;
-	char *rv = NULL;
 	int error;
 
 	sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND | SBUF_INCLUDENUL);
 	error = BUS_GET_DEVICE_PATH(device_get_parent(dev), dev, locator, sb);
 	sbuf_finish(sb);	/* Note: errors checked with sbuf_len() below */
-	if (error != 0)
-		goto out;
-	len = sbuf_len(sb);
-	if (len <= 1)
-		goto out;
-	rv = malloc(len, M_BUS, M_NOWAIT);
-	memcpy(rv, sbuf_data(sb), len);
-out:
+	if (error == 0) {
+		len = sbuf_len(sb);
+		if (len <= 1) {
+			error = EIO;
+		} else {
+			s = malloc(len, M_BUS, M_NOWAIT);
+			if (s == NULL) {
+				error = ENOMEM;
+			} else {
+				memcpy(s, sbuf_data(sb), len);
+				*rvp = s;
+			}
+		}
+	}
 	sbuf_delete(sb);
-	return (rv);
+	return (error);
 }
 
 static int
@@ -5595,11 +5601,9 @@ devctl2_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
 		    sizeof(locator), NULL);
 		if (error != 0)
 			break;
-		path = device_get_path(dev, locator);
-		if (path == NULL) {
-			error = ENOMEM;
+		error = device_get_path(dev, locator, &path);
+		if (error != 0)
 			break;
-		}
 		len = strlen(path) + 1;
 		if (req->dr_buffer.length < len) {
 			error = ENAMETOOLONG;
@@ -5702,9 +5706,10 @@ bool
 dev_wired_cache_match(device_location_cache_t *dcp, device_t dev,
     const char *at)
 {
-	const char *cp, *path;
+	const char *cp;
+	char *path;
 	char locator[32];
-	int len;
+	int error, len;
 	struct device_location_node *res;
 
 	cp = strchr(at, ':');
@@ -5717,13 +5722,15 @@ dev_wired_cache_match(device_location_cache_t *dcp, device_t dev,
 	locator[len] = '\0';
 	cp++;
 
+	error = 0;
 	/* maybe cache this inside device_t and look that up, but not yet */
 	res = dev_wired_cache_lookup(dcp, locator);
 	if (res == NULL) {
-		path = device_get_path(dev, locator);
-		res = dev_wired_cache_add(dcp, locator, path);
+		error = device_get_path(dev, locator, &path);
+		if (error == 0)
+			res = dev_wired_cache_add(dcp, locator, path);
 	}
-	if (res == NULL || res->dln_path == NULL)
+	if (error != 0 || res == NULL || res->dln_path == NULL)
 		return (false);
 
 	return (strcmp(res->dln_path, cp) == 0);