The branch main has been updated by kib:

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

commit 555a861d6826eca8710e361ee4d0ef29b28f39d2
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2022-10-08 00:08:14 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2022-10-19 16:39:40 +0000

    device_get_path(): take sbuf directly
    
    This allows to fix a bug where sbuf allocation done in the context of
    dev_wired_cache_match() must use non-sleepable allocations.
    
    Suggested by:   jhb
    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 | 73 +++++++++++++++++++++++++----------------------------
 1 file changed, 35 insertions(+), 38 deletions(-)

diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index 74bc47174d8d..5c165419af2d 100644
--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -5305,37 +5305,24 @@ device_do_deferred_actions(void)
 }
 
 static int
-device_get_path(device_t dev, const char *locator, char **rvp)
+device_get_path(device_t dev, const char *locator, struct sbuf *sb)
 {
-       struct sbuf *sb;
-       char *s;
        device_t parent;
-       ssize_t len;
        int error;
 
+       sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND | SBUF_INCLUDENUL);
        parent = device_get_parent(dev);
        if (parent == NULL) {
-               *rvp = strdup_flags("/", M_BUS, M_NOWAIT);
-               return (*rvp == NULL ? ENOMEM : 0);
-       }
-       sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND | SBUF_INCLUDENUL);
-       error = BUS_GET_DEVICE_PATH(parent, dev, locator, sb);
-       sbuf_finish(sb);        /* Note: errors checked with sbuf_len() below */
-       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;
-                       }
+               error = sbuf_printf(sb, "/");
+       } else {
+               error = BUS_GET_DEVICE_PATH(parent, dev, locator, sb);
+               if (error == 0) {
+                       error = sbuf_error(sb);
+                       if (error == 0 && sbuf_len(sb) <= 1)
+                               error = EIO;
                }
        }
-       sbuf_delete(sb);
+       sbuf_finish(sb);
        return (error);
 }
 
@@ -5599,25 +5586,28 @@ devctl2_ioctl(struct cdev *cdev, u_long cmd, caddr_t 
data, int fflag,
                    req->dr_flags);
                break;
        case DEV_GET_PATH: {
+               struct sbuf *sb;
                char locator[64];
-               char *path;
                ssize_t len;
 
                error = copyinstr(req->dr_buffer.buffer, locator,
                    sizeof(locator), NULL);
                if (error != 0)
                        break;
-               error = device_get_path(dev, locator, &path);
-               if (error != 0)
-                       break;
-               len = strlen(path) + 1;
-               if (req->dr_buffer.length < len) {
-                       error = ENAMETOOLONG;
-               } else {
-                       error = copyout(path, req->dr_buffer.buffer, len);
+               sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND |
+                   SBUF_INCLUDENUL /* | SBUF_WAITOK */);
+               error = device_get_path(dev, locator, sb);
+               if (error == 0) {
+                       len = sbuf_len(sb);
+                       if (req->dr_buffer.length < len) {
+                               error = ENAMETOOLONG;
+                       } else {
+                               error = copyout(sbuf_data(sb),
+                                   req->dr_buffer.buffer, len);
+                       }
+                       req->dr_buffer.length = len;
                }
-               req->dr_buffer.length = len;
-               free(path, M_BUS);
+               sbuf_delete(sb);
                break;
        }
        }
@@ -5712,8 +5702,8 @@ bool
 dev_wired_cache_match(device_location_cache_t *dcp, device_t dev,
     const char *at)
 {
+       struct sbuf *sb;
        const char *cp;
-       char *path;
        char locator[32];
        int error, len;
        struct device_location_node *res;
@@ -5732,9 +5722,16 @@ dev_wired_cache_match(device_location_cache_t *dcp, 
device_t dev,
        /* maybe cache this inside device_t and look that up, but not yet */
        res = dev_wired_cache_lookup(dcp, locator);
        if (res == NULL) {
-               error = device_get_path(dev, locator, &path);
-               if (error == 0)
-                       res = dev_wired_cache_add(dcp, locator, path);
+               sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND |
+                   SBUF_INCLUDENUL | SBUF_NOWAIT);
+               if (sb != NULL) {
+                       error = device_get_path(dev, locator, sb);
+                       if (error == 0) {
+                               res = dev_wired_cache_add(dcp, locator,
+                                   sbuf_data(sb));
+                       }
+                       sbuf_delete(sb);
+               }
        }
        if (error != 0 || res == NULL || res->dln_path == NULL)
                return (false);

Reply via email to