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
This commit is contained in:
parent
8cf783bde3
commit
555a861d68
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user