Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F133646072
D16735.id46920.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D16735.id46920.diff
View Options
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
@@ -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, "", 0));
+}
+
+int
+devctl_thaw(void)
+{
+
+ return (devctl_simple_request(DEV_THAW, "", 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;
@@ -71,6 +65,7 @@
static void *hints;
static void *hints_end;
+static struct devinfo_dev *root;
static void *
read_hints(const char *fn, size_t *len)
@@ -240,35 +235,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 +383,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 +401,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("------------------------- ");
@@ -480,6 +423,8 @@
break;
if (!(dev->dd_flags & DF_ENABLED))
break;
+ if (dev->dd_flags & DF_ATTACHED_ONCE)
+ break;
parent = devinfo_handle_to_device(dev->dd_parent);
bus = strdup(parent->dd_name);
p = bus + strlen(bus) - 1;
@@ -496,10 +441,50 @@
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
@@ -515,6 +500,9 @@
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--;
@@ -531,6 +519,17 @@
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);
@@ -546,7 +545,6 @@
int
main(int argc, char **argv)
{
- struct devinfo_dev *root;
int ch;
while ((ch = getopt_long(argc, argv, "adh:p:uv",
@@ -586,12 +584,13 @@
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();
}
Index: sbin/init/rc.conf
===================================================================
--- sbin/init/rc.conf
+++ sbin/init/rc.conf
@@ -42,6 +42,7 @@
devd_enable="YES" # Run devd, to trigger programs on device tree changes.
devd_flags="" # Additional flags for devd(8).
devmatch_enable="YES" # Demand load kernel modules based on device ids.
+devmatch_blacklist="" # List of modules (w/o .ko) to exclude from devmatch.
#kld_list="" # Kernel modules to load after local disks are mounted
kldxref_enable="YES" # Build linker.hints files with kldxref(8).
kldxref_clobber="NO" # Overwrite old linker.hints at boot.
Index: sbin/init/rc.d/devmatch
===================================================================
--- sbin/init/rc.d/devmatch
+++ sbin/init/rc.d/devmatch
@@ -41,15 +41,15 @@
devmatch_start()
{
- local x
+ local x m list
if [ -n "$one_nomatch" ]; then
- x=$(devmatch -p "${one_nomatch}")
+ list=$(devmatch -p "${one_nomatch}" | sort -u)
else
- x=$(devmatch)
+ list=$(devmatch | sort -u)
fi
- [ -n "$x" ] || return
+ [ -n "$list" ] || return
# While kldload can accept multiple modules
# on the line at once, we loop here in case
@@ -57,10 +57,18 @@
# We also optimize against the false positives
# or drivers that have symbolic links that
# confuse devmatch by running it -n.
- for m in ${x}; do
+ # Finally, we filter out all items in the
+ # devmactch_blacklist.
+ devctl freeze
+ x=$(echo ${devmatch_blacklist} | tr ' ' '#')
+ for m in ${list}; do
+ case "#${x}#" in
+ *"#${m}#"*) continue ;;
+ esac
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);
}
@@ -1208,6 +1217,9 @@
* Note that since a driver can be in multiple devclasses, we
* should not detach devices which are not children of devices in
* the affected devclass.
+ *
+ * If we're frozen, we don't generate NOMATCH events. We assume
+ * something later will scan them.
*/
for (i = 0; i < dc->maxunit; i++) {
if (dc->devices[i]) {
@@ -1216,9 +1228,13 @@
dev->parent->devclass == busclass) {
if ((error = device_detach(dev)) != 0)
return (error);
- BUS_PROBE_NOMATCH(dev->parent, dev);
- devnomatch(dev);
- dev->flags |= DF_DONENOMATCH;
+ if (device_frozen) {
+ dev->flags &= ~DF_DONENOMATCH;
+ } else {
+ BUS_PROBE_NOMATCH(dev->parent, dev);
+ devnomatch(dev);
+ dev->flags |= DF_DONENOMATCH;
+ }
}
}
}
@@ -2935,6 +2951,7 @@
dev->state = DS_NOTPRESENT;
return (error);
}
+ dev->flags |= DF_ATTACHED_ONCE;
attachtime = get_cyclecount() - attachtime;
/*
* 4 bits per device is a reasonable value for desktop and server
@@ -5406,6 +5423,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 +5469,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 +5676,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
@@ -92,7 +92,8 @@
#define DF_EXTERNALSOFTC 0x40 /* softc not allocated by us */
#define DF_REBID 0x80 /* Can rebid after attach */
#define DF_SUSPENDED 0x100 /* Device is suspended. */
-#define DF_QUIET_CHILDREN 0x200 /* Default to quiet for all my children */
+#define DF_QUIET_CHILDREN 0x200 /* Default to quiet for all my children */
+#define DF_ATTACHED_ONCE 0x400 /* Has been attached at least once */
/**
* @brief Device request structure used for ioctl's.
@@ -126,6 +127,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[])
{
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Oct 28, 6:15 AM (5 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24297168
Default Alt Text
D16735.id46920.diff (15 KB)
Attached To
Mode
D16735: Create devctl freeze/thaw.
Attached
Detach File
Event Timeline
Log In to Comment