git: 555a861d6826 - main - device_get_path(): take sbuf directly
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 19 Oct 2022 16:40:03 UTC
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=555a861d6826eca8710e361ee4d0ef29b28f39d2
commit 555a861d6826eca8710e361ee4d0ef29b28f39d2
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2022-10-08 00:08:14 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
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);