Date: Thu, 23 Aug 2018 05:05:47 +0000 (UTC) From: Warner Losh <imp@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r338233 - in head: lib/libdevctl sys/kern sys/sys usr.sbin/devctl Message-ID: <201808230505.w7N55lsc062765@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: imp Date: Thu Aug 23 05:05:47 2018 New Revision: 338233 URL: https://svnweb.freebsd.org/changeset/base/338233 Log: Create devctl freeze/thaw. This adds it to devctl, libdevctl, defines the two IOCTLs and implements the kernel bits. causes any new drivers that are added via kldload to be deferred until a 'thaw' comes in. These do not stack: it is an error to freeze while frozen, or thaw while thawed. Differential Revision: https://reviews.freebsd.org/D16735 Modified: head/lib/libdevctl/devctl.3 head/lib/libdevctl/devctl.c head/lib/libdevctl/devctl.h head/sys/kern/subr_bus.c head/sys/sys/bus.h head/usr.sbin/devctl/devctl.c Modified: head/lib/libdevctl/devctl.3 ============================================================================== --- head/lib/libdevctl/devctl.3 Thu Aug 23 02:26:40 2018 (r338232) +++ head/lib/libdevctl/devctl.3 Thu Aug 23 05:05:47 2018 (r338233) @@ -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 @@ The .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 \ Modified: head/lib/libdevctl/devctl.c ============================================================================== --- head/lib/libdevctl/devctl.c Thu Aug 23 02:26:40 2018 (r338232) +++ head/lib/libdevctl/devctl.c Thu Aug 23 05:05:47 2018 (r338233) @@ -145,3 +145,17 @@ devctl_delete(const char *device, bool force) 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)); +} Modified: head/lib/libdevctl/devctl.h ============================================================================== --- head/lib/libdevctl/devctl.h Thu Aug 23 02:26:40 2018 (r338232) +++ head/lib/libdevctl/devctl.h Thu Aug 23 05:05:47 2018 (r338233) @@ -41,5 +41,7 @@ int devctl_set_driver(const char *device, const char * 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__ */ Modified: head/sys/kern/subr_bus.c ============================================================================== --- head/sys/kern/subr_bus.c Thu Aug 23 02:26:40 2018 (r338232) +++ head/sys/kern/subr_bus.c Thu Aug 23 05:05:47 2018 (r338233) @@ -82,6 +82,8 @@ struct driverlink { 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; }; @@ -152,6 +154,7 @@ EVENTHANDLER_LIST_DEFINE(device_detach); 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 +1171,11 @@ devclass_add_driver(devclass_t dc, driver_t *driver, i dl->pass = pass; driver_register_pass(dl); - devclass_driver_added(dc, driver); + if (device_frozen) { + dl->flags |= DL_DEFERRED_PROBE; + } else { + devclass_driver_added(dc, driver); + } bus_data_generation_update(); return (0); } @@ -1208,6 +1215,9 @@ devclass_driver_deleted(devclass_t busclass, devclass_ * 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. Mark to + * generate later. */ for (i = 0; i < dc->maxunit; i++) { if (dc->devices[i]) { @@ -1216,9 +1226,14 @@ devclass_driver_deleted(devclass_t busclass, devclass_ 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; + dev->flags |= DF_NEEDNOMATCH; + } else { + BUS_PROBE_NOMATCH(dev->parent, dev); + devnomatch(dev); + dev->flags |= DF_DONENOMATCH; + } } } } @@ -5406,6 +5421,53 @@ driver_exists(device_t bus, const char *driver) return (false); } +static void +device_gen_nomatch(device_t dev) +{ + device_t child; + + if (dev->flags & DF_NEEDNOMATCH && + dev->state == DS_NOTPRESENT) { + BUS_PROBE_NOMATCH(dev->parent, dev); + devnomatch(dev); + dev->flags |= DF_DONENOMATCH; + } + dev->flags &= ~DF_NEEDNOMATCH; + TAILQ_FOREACH(child, &dev->children, link) { + device_gen_nomatch(child); + } +} + +static void +device_do_deferred_actions(void) +{ + devclass_t dc; + driverlink_t dl; + + /* + * Walk through the devclasses to find all the drivers we've tagged as + * deferred during the freeze and call the driver added routines. They + * have already been added to the lists in the background, so the driver + * added routines that trigger a probe will have all the right bidders + * for the probe auction. + */ + TAILQ_FOREACH(dc, &devclasses, link) { + TAILQ_FOREACH(dl, &dc->drivers, link) { + if (dl->flags & DL_DEFERRED_PROBE) { + devclass_driver_added(dc, dl->driver); + dl->flags &= ~DL_DEFERRED_PROBE; + } + } + } + + /* + * We also defer no-match events during a freeze. Walk the tree and + * generate all the pent-up events that are still relevant. + */ + device_gen_nomatch(root_bus); + bus_data_generation_update(); +} + static int devctl2_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, struct thread *td) @@ -5432,6 +5494,10 @@ devctl2_ioctl(struct cdev *cdev, u_long cmd, caddr_t d 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 +5701,20 @@ devctl2_ioctl(struct cdev *cdev, u_long cmd, caddr_t d error = device_delete_child(parent, dev); break; } + case DEV_FREEZE: + if (device_frozen) + error = EBUSY; + else + device_frozen = true; + break; + case DEV_THAW: + if (!device_frozen) + error = EBUSY; + else { + device_do_deferred_actions(); + device_frozen = false; + } + break; } mtx_unlock(&Giant); return (error); Modified: head/sys/sys/bus.h ============================================================================== --- head/sys/sys/bus.h Thu Aug 23 02:26:40 2018 (r338232) +++ head/sys/sys/bus.h Thu Aug 23 05:05:47 2018 (r338233) @@ -92,7 +92,8 @@ struct u_device { #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_NEEDNOMATCH 0x800 /* Has a pending NOMATCH event */ /** * @brief Device request structure used for ioctl's. @@ -126,6 +127,8 @@ struct devreq { #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 Modified: head/usr.sbin/devctl/devctl.c ============================================================================== --- head/usr.sbin/devctl/devctl.c Thu Aug 23 02:26:40 2018 (r338232) +++ head/usr.sbin/devctl/devctl.c Thu Aug 23 05:05:47 2018 (r338233) @@ -71,17 +71,19 @@ DEVCTL_TABLE(top, set); 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); } @@ -342,6 +344,46 @@ delete(int ac, char **av) return (0); } 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[])
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201808230505.w7N55lsc062765>