Index: lib/libdevctl/devctl.h =================================================================== --- lib/libdevctl/devctl.h +++ lib/libdevctl/devctl.h @@ -41,5 +41,7 @@ int devctl_clear_driver(const char *device, bool force); int devctl_rescan(const char *device); int devctl_delete(const char *device, bool force); +int devctl_freeze(void); +int devctl_thaw(void); #endif /* !__DEVCTL_H__ */ Index: lib/libdevctl/devctl.3 =================================================================== --- lib/libdevctl/devctl.3 +++ lib/libdevctl/devctl.3 @@ -36,10 +36,12 @@ .Nm devctl_detach , .Nm devctl_disable , .Nm devctl_enable , +.Nm devctl_freeze , .Nm devctl_rescan , .Nm devctl_resume , .Nm devctl_set_driver , -.Nm devctl_suspend +.Nm devctl_suspend , +.Nm devctl_thaw .Nd device control library .Sh LIBRARY .Lb libdevctl @@ -58,6 +60,8 @@ .Ft int .Fn devctl_enable "const char *device" .Ft int +.Fn devctl_freeze "void" +.Ft int .Fn devctl_rescan "const char *device" .Ft int .Fn devctl_resume "const char *device" @@ -65,6 +69,8 @@ .Fn devctl_set_driver "const char *device" "const char *driver" "bool force" .Ft int .Fn devctl_suspend "const char *device" +.Ft int +.Fn devctl_thaw "void" .Sh DESCRIPTION The .Nm @@ -189,6 +195,16 @@ .Fn devctl_rescan function rescans a bus device checking for devices that have been added or removed. +.Pp +The +.Fn devctl_freeze +function freezes probe and attach processing initiated in response to +drivers being loaded. +.Pp +The +.Fn devctl_thaw +function resumes (thaws the freeze) probe and attach processing +initiated in response to drivers being loaded. .Sh RETURN VALUES .Rv -std devctl_attach devctl_clear_driver devctl_delete devctl_detach \ devctl_disable devctl_enable devctl_suspend devctl_rescan devctl_resume \ Index: lib/libdevctl/devctl.c =================================================================== --- lib/libdevctl/devctl.c +++ lib/libdevctl/devctl.c @@ -53,7 +53,7 @@ struct devreq req; memset(&req, 0, sizeof(req)); - if (strlcpy(req.dr_name, name, sizeof(req.dr_name)) >= + if (name != NULL && strlcpy(req.dr_name, name, sizeof(req.dr_name)) >= sizeof(req.dr_name)) { errno = EINVAL; return (-1); @@ -145,3 +145,17 @@ return (devctl_simple_request(DEV_DELETE, device, force ? DEVF_FORCE_DELETE : 0)); } + +int +devctl_freeze(void) +{ + + return (devctl_simple_request(DEV_FREEZE, NULL, 0)); +} + +int +devctl_thaw(void) +{ + + return (devctl_simple_request(DEV_THAW, NULL, 0)); +} Index: sbin/devmatch/devmatch.c =================================================================== --- sbin/devmatch/devmatch.c +++ sbin/devmatch/devmatch.c @@ -56,12 +56,6 @@ #define DEVMATCH_MAX_HITS 256 -static struct match_data { - char *descr; - int priority; -} match_data[DEVMATCH_MAX_HITS]; - -static int hit_index; static int all_flag; static int dump_flag; static char *linker_hints; @@ -240,35 +234,6 @@ return retval; } -static int -match_data_compare(const void *_pa, const void *_pb) -{ - const struct match_data *pa = _pa; - const struct match_data *pb = _pb; - - /* biggest value first */ - if (pa->priority > pb->priority) - return (-1); - else if (pa->priority < pb->priority) - return (1); - - /* then sort by string */ - return (strcmp(pa->descr, pb->descr)); -} - -static int -bitrev16(int input) -{ - int retval = 0; - int x; - - for (x = 0; x != 16; x++) { - if ((input >> x) & 1) - retval |= (0x8000 >> x); - } - return (retval); -} - static void search_hints(const char *bus, const char *dev, const char *pnpinfo) { @@ -417,22 +382,12 @@ printf("\n"); else if (!notme) { if (!unbound_flag) { - char *descr = NULL; - if (all_flag) - asprintf(&descr, "%s: %s", *dev ? dev : "unattached", lastmod); + printf("%s: %s", *dev ? dev : "unattached", lastmod); else - asprintf(&descr, "%s", lastmod); + printf("%s", lastmod); if (verbose_flag) printf("Matches --- %s ---\n", lastmod); - - if (descr != NULL && hit_index < DEVMATCH_MAX_HITS) { - match_data[hit_index].descr = descr; - match_data[hit_index].priority = bitrev16(mask); - hit_index++; - } else { - free(descr); - } } found++; } @@ -445,19 +400,6 @@ } walker = (void *)(len - sizeof(int) + (intptr_t)walker); } - if (hit_index != 0) { - /* sort hits by priority */ - mergesort(match_data, hit_index, sizeof(match_data[0]), &match_data_compare); - - /* printout */ - for (i = 0; i != hit_index; i++) { - puts(match_data[i].descr); - free(match_data[i].descr); - } - - /* reset hit_index */ - hit_index = 0; - } if (unbound_flag && found == 0 && *pnpinfo) { if (verbose_flag) printf("------------------------- "); Index: sbin/init/rc.d/devmatch =================================================================== --- sbin/init/rc.d/devmatch +++ sbin/init/rc.d/devmatch @@ -44,9 +44,9 @@ local x if [ -n "$one_nomatch" ]; then - x=$(devmatch -p "${one_nomatch}") + x=$(devmatch -p "${one_nomatch}" | sort -u) else - x=$(devmatch) + x=$(devmatch | sort -u) fi [ -n "$x" ] || return @@ -57,10 +57,12 @@ # We also optimize against the false positives # or drivers that have symbolic links that # confuse devmatch by running it -n. + devctl freeze for m in ${x}; do echo "Autoloading module: ${m}" kldload -n ${m} done + devctl thaw } load_rc_config $name Index: sys/kern/subr_bus.c =================================================================== --- sys/kern/subr_bus.c +++ sys/kern/subr_bus.c @@ -82,6 +82,8 @@ kobj_class_t driver; TAILQ_ENTRY(driverlink) link; /* list of drivers in devclass */ int pass; + int flags; +#define DL_DEFERRED_PROBE 1 /* Probe deferred on this */ TAILQ_ENTRY(driverlink) passlink; }; @@ -101,6 +103,7 @@ int maxunit; /* size of devices array */ int flags; #define DC_HAS_CHILDREN 1 +#define DC_DEFERRED_PROBE 2 /* Driver loaded during freeze */ struct sysctl_ctx_list sysctl_ctx; struct sysctl_oid *sysctl_tree; @@ -152,6 +155,7 @@ EVENTHANDLER_LIST_DEFINE(dev_lookup); static void devctl2_init(void); +static bool device_frozen; #define DRIVERNAME(d) ((d)? d->name : "no driver") #define DEVCLANAME(d) ((d)? d->name : "no devclass") @@ -1168,7 +1172,12 @@ dl->pass = pass; driver_register_pass(dl); - devclass_driver_added(dc, driver); + if (device_frozen) { + dc->flags |= DC_DEFERRED_PROBE; + dl->flags |= DL_DEFERRED_PROBE; + } else { + devclass_driver_added(dc, driver); + } bus_data_generation_update(); return (0); } @@ -5406,6 +5415,26 @@ return (false); } +static void +device_do_deferred_probes(void) +{ + devclass_t dc; + driverlink_t dl; + + TAILQ_FOREACH(dc, &devclasses, link) { + if ((dc->flags & DC_DEFERRED_PROBE) == 0) + continue; + TAILQ_FOREACH(dl, &dc->drivers, link) { + if ((dl->flags & DL_DEFERRED_PROBE) == 0) + continue; + devclass_driver_added(dc, dl->driver); + dl->flags &= ~DL_DEFERRED_PROBE; + } + dc->flags &= ~DC_DEFERRED_PROBE; + } + bus_data_generation_update(); +} + static int devctl2_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, struct thread *td) @@ -5432,6 +5461,10 @@ if (error == 0) error = find_device(req, &dev); break; + case DEV_FREEZE: + case DEV_THAW: + error = priv_check(td, PRIV_DRIVER); + break; default: error = ENOTTY; break; @@ -5635,6 +5668,24 @@ error = device_delete_child(parent, dev); break; } + case DEV_FREEZE: + printf("Freeze: %d -- ", device_frozen); + if (device_frozen) + error = EBUSY; + else + device_frozen = true; + printf("%d (%d)\n", device_frozen, error); + break; + case DEV_THAW: + printf("Thaw: %d -- ", device_frozen); + if (!device_frozen) + error = EBUSY; + else { + device_do_deferred_probes(); + device_frozen = false; + } + printf("%d (%d)\n", device_frozen, error); + break; } mtx_unlock(&Giant); return (error); Index: sys/sys/bus.h =================================================================== --- sys/sys/bus.h +++ sys/sys/bus.h @@ -126,6 +126,8 @@ #define DEV_CLEAR_DRIVER _IOW('D', 8, struct devreq) #define DEV_RESCAN _IOW('D', 9, struct devreq) #define DEV_DELETE _IOW('D', 10, struct devreq) +#define DEV_FREEZE _IOW('D', 11, struct devreq) +#define DEV_THAW _IOW('D', 12, struct devreq) /* Flags for DEV_DETACH and DEV_DISABLE. */ #define DEVF_FORCE_DETACH 0x0000001 Index: usr.sbin/devctl/devctl.c =================================================================== --- usr.sbin/devctl/devctl.c +++ usr.sbin/devctl/devctl.c @@ -71,17 +71,19 @@ static void usage(void) { - fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", - "usage: devctl attach device", - " devctl detach [-f] device", - " devctl disable [-f] device", - " devctl enable device", - " devctl suspend device", - " devctl resume device", - " devctl set driver [-f] device driver", - " devctl clear driver [-f] device", - " devctl rescan device", - " devctl delete [-f] device"); + fprintf(stderr, + "usage: devctl attach device\n" + " devctl detach [-f] device\n" + " devctl disable [-f] device\n" + " devctl enable device\n" + " devctl suspend device\n" + " devctl resume device\n" + " devctl set driver [-f] device driver\n" + " devctl clear driver [-f] device\n" + " devctl rescan device\n" + " devctl delete [-f] device\n" + " devctl freeze\n" + " devctl thaw\n"); exit(1); } @@ -343,6 +345,46 @@ } DEVCTL_COMMAND(top, delete, delete); +static void +freeze_usage(void) +{ + + fprintf(stderr, "usage: devctl freeze\n"); + exit(1); +} + +static int +freeze(int ac, char **av __unused) +{ + + if (ac != 1) + freeze_usage(); + if (devctl_freeze() < 0) + err(1, "Failed to freeze probe/attach"); + return (0); +} +DEVCTL_COMMAND(top, freeze, freeze); + +static void +thaw_usage(void) +{ + + fprintf(stderr, "usage: devctl thaw\n"); + exit(1); +} + +static int +thaw(int ac, char **av __unused) +{ + + if (ac != 1) + thaw_usage(); + if (devctl_thaw() < 0) + err(1, "Failed to thaw probe/attach"); + return (0); +} +DEVCTL_COMMAND(top, thaw, thaw); + int main(int ac, char *av[]) {