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[])
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to