When trying to match the nomatch event passed to us, attempt to look

up the device described by the nomatch event in the device tree. If we
find it, then if the device is marked as have already attached to a
device once, then ignore the device.

This keeps us from reloading the device driver when it has just been
manually unloaded. All devies that have had a driver attach to them at
least once no longer participate in pnp-based autoloading.

Differential Revision: https://reviews.freebsd.org/D16735
This commit is contained in:
Warner Losh 2018-08-23 05:06:22 +00:00
parent d36967bd2b
commit ce1ba01c8a

View File

@ -65,6 +65,7 @@ static int verbose_flag;
static void *hints;
static void *hints_end;
static struct devinfo_dev *root;
static void *
read_hints(const char *fn, size_t *len)
@ -440,10 +441,50 @@ find_unmatched(struct devinfo_dev *dev, void *arg)
return (devinfo_foreach_device_child(dev, find_unmatched, arg));
}
struct exact_info
{
const char *bus;
const char *loc;
struct devinfo_dev *dev;
};
/*
* Look for the exact location specified by the nomatch event. The
* loc and pnpinfo run together to get the string we're looking for,
* so we have to synthesize the same thing that subr_bus.c is
* generating in devnomatch/devaddq to do the string comparison.
*/
static int
find_exact_dev(struct devinfo_dev *dev, void *arg)
{
struct devinfo_dev *parent;
char *loc;
struct exact_info *info;
info = arg;
do {
if (info->dev != NULL)
break;
if (!(dev->dd_flags & DF_ENABLED))
break;
parent = devinfo_handle_to_device(dev->dd_parent);
if (strcmp(info->bus, parent->dd_name) != 0)
break;
asprintf(&loc, "%s %s", parent->dd_pnpinfo,
parent->dd_location);
if (strcmp(loc, info->loc) == 0)
info->dev = dev;
free(loc);
} while (0);
return (devinfo_foreach_device_child(dev, find_exact_dev, arg));
}
static void
find_nomatch(char *nomatch)
{
char *bus, *pnpinfo, *tmp;
char *bus, *pnpinfo, *tmp, *busnameunit;
struct exact_info info;
/*
* Find our bus name. It will include the unit number. We have to search
@ -459,6 +500,9 @@ find_nomatch(char *nomatch)
errx(1, "No bus found in nomatch string: '%s'", nomatch);
bus = tmp + 4;
*tmp = '\0';
busnameunit = strdup(bus);
if (busnameunit == NULL)
errx(1, "Can't allocate memory for strings");
tmp = bus + strlen(bus) - 1;
while (tmp > bus && isdigit(*tmp))
tmp--;
@ -475,6 +519,17 @@ find_nomatch(char *nomatch)
errx(1, "Malformed NOMATCH string: '%s'", nomatch);
pnpinfo = nomatch + 4;
/*
* See if we can find the devinfo_dev for this device. If we
* can, and it's been attached before, we should filter it out
* so that a kldunload foo doesn't cause an immediate reload.
*/
info.loc = pnpinfo;
info.bus = busnameunit;
info.dev = NULL;
devinfo_foreach_device_child(root, find_exact_dev, (void *)&info);
if (info.dev != NULL && info.dev->dd_flags & DF_ATTACHED_ONCE)
exit(0);
search_hints(bus, "", pnpinfo);
exit(0);
@ -490,7 +545,6 @@ usage(void)
int
main(int argc, char **argv)
{
struct devinfo_dev *root;
int ch;
while ((ch = getopt_long(argc, argv, "adh:p:uv",
@ -530,12 +584,13 @@ main(int argc, char **argv)
exit(0);
}
if (nomatch_str != NULL)
find_nomatch(nomatch_str);
if (devinfo_init())
err(1, "devinfo_init");
if ((root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE)) == NULL)
errx(1, "can't find root device");
devinfo_foreach_device_child(root, find_unmatched, (void *)0);
if (nomatch_str != NULL)
find_nomatch(nomatch_str);
else
devinfo_foreach_device_child(root, find_unmatched, (void *)0);
devinfo_free();
}