Author: hselasky
Date: Thu Feb  5 21:25:11 2015
New Revision: 278290
URL: https://svnweb.freebsd.org/changeset/base/278290

Log:
  MFC r277179, r277199 and r277391:
  Add a kernel function to delist our kernel character devices, so that
  the device name can be re-used right away in case we are destroying
  the character devices in the background.

Modified:
  stable/9/sys/fs/devfs/devfs_int.h
  stable/9/sys/kern/kern_conf.c
  stable/9/sys/sys/conf.h
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/dev/   (props changed)
  stable/9/sys/fs/   (props changed)
  stable/9/sys/sys/   (props changed)

Modified: stable/9/sys/fs/devfs/devfs_int.h
==============================================================================
--- stable/9/sys/fs/devfs/devfs_int.h   Thu Feb  5 21:18:44 2015        
(r278289)
+++ stable/9/sys/fs/devfs/devfs_int.h   Thu Feb  5 21:25:11 2015        
(r278290)
@@ -56,6 +56,7 @@ struct cdev_priv {
        u_int                   cdp_flags;
 #define CDP_ACTIVE             (1 << 0)
 #define CDP_SCHED_DTR          (1 << 1)
+#define        CDP_UNREF_DTR           (1 << 2)
 
        u_int                   cdp_inuse;
        u_int                   cdp_maxdirent;

Modified: stable/9/sys/kern/kern_conf.c
==============================================================================
--- stable/9/sys/kern/kern_conf.c       Thu Feb  5 21:18:44 2015        
(r278289)
+++ stable/9/sys/kern/kern_conf.c       Thu Feb  5 21:25:11 2015        
(r278290)
@@ -115,6 +115,8 @@ dev_free_devlocked(struct cdev *cdev)
 
        mtx_assert(&devmtx, MA_OWNED);
        cdp = cdev2priv(cdev);
+       KASSERT((cdp->cdp_flags & CDP_UNREF_DTR) == 0,
+           ("destroy_dev() was not called after delist_dev(%p)", cdev));
        TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list);
 }
 
@@ -1030,6 +1032,7 @@ destroy_devl(struct cdev *dev)
 {
        struct cdevsw *csw;
        struct cdev_privdata *p;
+       struct cdev_priv *cdp;
 
        mtx_assert(&devmtx, MA_OWNED);
        KASSERT(dev->si_flags & SI_NAMED,
@@ -1038,13 +1041,22 @@ destroy_devl(struct cdev *dev)
            ("WARNING: Driver mistake: destroy_dev on eternal %d\n",
             dev2unit(dev)));
 
-       devfs_destroy(dev);
+       cdp = cdev2priv(dev);
+       if ((cdp->cdp_flags & CDP_UNREF_DTR) == 0) {
+               /*
+                * Avoid race with dev_rel(), e.g. from the populate
+                * loop.  If CDP_UNREF_DTR flag is set, the reference
+                * to be dropped at the end of destroy_devl() was
+                * already taken by delist_dev_locked().
+                */
+               dev_refl(dev);
+
+               devfs_destroy(dev);
+       }
 
        /* Remove name marking */
        dev->si_flags &= ~SI_NAMED;
 
-       dev->si_refcount++;     /* Avoid race with dev_rel() */
-
        /* If we are a child, remove us from the parents list */
        if (dev->si_flags & SI_CHILD) {
                LIST_REMOVE(dev, si_siblings);
@@ -1100,13 +1112,39 @@ destroy_devl(struct cdev *dev)
                }
        }
        dev->si_flags &= ~SI_ALIAS;
-       dev->si_refcount--;     /* Avoid race with dev_rel() */
+       cdp->cdp_flags &= ~CDP_UNREF_DTR;
+       dev->si_refcount--;
 
-       if (dev->si_refcount > 0) {
+       if (dev->si_refcount > 0)
                LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
-       } else {
+       else
                dev_free_devlocked(dev);
-       }
+}
+
+static void
+delist_dev_locked(struct cdev *dev)
+{
+       struct cdev_priv *cdp;
+       struct cdev *child;
+
+       mtx_assert(&devmtx, MA_OWNED);
+       cdp = cdev2priv(dev);
+       if ((cdp->cdp_flags & CDP_UNREF_DTR) != 0)
+               return;
+       cdp->cdp_flags |= CDP_UNREF_DTR;
+       dev_refl(dev);
+       devfs_destroy(dev);
+       LIST_FOREACH(child, &dev->si_children, si_siblings)
+               delist_dev_locked(child);
+}
+
+void
+delist_dev(struct cdev *dev)
+{
+
+       dev_lock();
+       delist_dev_locked(dev);
+       dev_unlock();
 }
 
 void

Modified: stable/9/sys/sys/conf.h
==============================================================================
--- stable/9/sys/sys/conf.h     Thu Feb  5 21:18:44 2015        (r278289)
+++ stable/9/sys/sys/conf.h     Thu Feb  5 21:25:11 2015        (r278290)
@@ -247,6 +247,7 @@ void clone_cleanup(struct clonedevs **);
 int clone_create(struct clonedevs **, struct cdevsw *, int *unit, struct cdev 
**dev, int extra);
 
 int    count_dev(struct cdev *_dev);
+void   delist_dev(struct cdev *_dev);
 void   destroy_dev(struct cdev *_dev);
 int    destroy_dev_sched(struct cdev *dev);
 int    destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg);
_______________________________________________
svn-src-stable-9@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-stable-9
To unsubscribe, send any mail to "svn-src-stable-9-unsubscr...@freebsd.org"

Reply via email to