git: d97bfe3ff840 - stable/13 - bus: Cleanup device_probe_child()

From: Alexander Motin <mav_at_FreeBSD.org>
Date: Tue, 04 Jan 2022 17:18:20 UTC
The branch stable/13 has been updated by mav:

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

commit d97bfe3ff8404e04dada9d7b86d8379d4713c2e8
Author:     Alexander Motin <mav@FreeBSD.org>
AuthorDate: 2021-09-25 00:27:10 +0000
Commit:     Alexander Motin <mav@FreeBSD.org>
CommitDate: 2022-01-04 17:10:55 +0000

    bus: Cleanup device_probe_child()
    
    When device driver probe method returns 0, i.e. absolute priority, do
    not remove its class from the device just to set it back few lines
    later, that may change the device unit number, etc. and after which
    we'd better call the probe again.
    
    If during search we found some driver with absolute priority, we do
    not need to set device driver and class since we haven't removed them
    before.
    
    It should not happen, but if second probe method call failed, remove
    the driver and possibly the class from the device as it was when we
    started.
    
    Reviewed by:    imp, jhb
    Differential Revision:  https://reviews.freebsd.org/D32125
    
    (cherry picked from commit f73c2bbf811ba77b2fe91b5bc0cbe19e9f7eb6c4)
---
 sys/kern/subr_bus.c | 50 +++++++++++++++++++++++++++++---------------------
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index a7c09f6e9374..185a39cdb0ef 100644
--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -2076,6 +2076,7 @@ device_probe_child(device_t dev, device_t child)
 	driverlink_t best = NULL;
 	driverlink_t dl;
 	int result, pri = 0;
+	/* We should preserve the devclass (or lack of) set by the bus. */
 	int hasclass = (child->devclass != NULL);
 
 	GIANT_REQUIRED;
@@ -2127,11 +2128,6 @@ device_probe_child(device_t dev, device_t child)
 
 			result = DEVICE_PROBE(child);
 
-			/* Reset flags and devclass before the next probe. */
-			child->devflags = 0;
-			if (!hasclass)
-				(void)device_set_devclass(child, NULL);
-
 			/*
 			 * If the driver returns SUCCESS, there can be
 			 * no higher match for this device.
@@ -2142,6 +2138,11 @@ device_probe_child(device_t dev, device_t child)
 				break;
 			}
 
+			/* Reset flags and devclass before the next probe. */
+			child->devflags = 0;
+			if (!hasclass)
+				(void)device_set_devclass(child, NULL);
+
 			/*
 			 * Reset DF_QUIET in case this driver doesn't
 			 * end up as the best driver.
@@ -2186,36 +2187,43 @@ device_probe_child(device_t dev, device_t child)
 			break;
 	}
 
+	if (best == NULL)
+		return (ENXIO);
+
 	/*
 	 * If we found a driver, change state and initialise the devclass.
 	 */
-	if (best) {
+	if (pri < 0) {
 		/* Set the winning driver, devclass, and flags. */
+		result = device_set_driver(child, best->driver);
+		if (result != 0)
+			return (result);
 		if (!child->devclass) {
 			result = device_set_devclass(child, best->driver->name);
-			if (result != 0)
+			if (result != 0) {
+				(void)device_set_driver(child, NULL);
 				return (result);
+			}
 		}
-		result = device_set_driver(child, best->driver);
-		if (result != 0)
-			return (result);
 		resource_int_value(best->driver->name, child->unit,
 		    "flags", &child->devflags);
 
-		if (pri < 0) {
-			/*
-			 * A bit bogus. Call the probe method again to make
-			 * sure that we have the right description.
-			 */
-			DEVICE_PROBE(child);
+		/*
+		 * A bit bogus. Call the probe method again to make sure
+		 * that we have the right description.
+		 */
+		result = DEVICE_PROBE(child);
+		if (result > 0) {
+			if (!hasclass)
+				(void)device_set_devclass(child, NULL);
+			(void)device_set_driver(child, NULL);
+			return (result);
 		}
-		child->state = DS_ALIVE;
-
-		bus_data_generation_update();
-		return (0);
 	}
 
-	return (ENXIO);
+	child->state = DS_ALIVE;
+	bus_data_generation_update();
+	return (0);
 }
 
 /**