svn commit: r278283 - in stable/10/sys: fs/devfs kern sys
Hans Petter Selasky
hselasky at FreeBSD.org
Thu Feb 5 20:49:15 UTC 2015
Author: hselasky
Date: Thu Feb 5 20:49:13 2015
New Revision: 278283
URL: https://svnweb.freebsd.org/changeset/base/278283
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/10/sys/fs/devfs/devfs_int.h
stable/10/sys/kern/kern_conf.c
stable/10/sys/sys/conf.h
Directory Properties:
stable/10/ (props changed)
Modified: stable/10/sys/fs/devfs/devfs_int.h
==============================================================================
--- stable/10/sys/fs/devfs/devfs_int.h Thu Feb 5 20:45:50 2015 (r278282)
+++ stable/10/sys/fs/devfs/devfs_int.h Thu Feb 5 20:49:13 2015 (r278283)
@@ -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/10/sys/kern/kern_conf.c
==============================================================================
--- stable/10/sys/kern/kern_conf.c Thu Feb 5 20:45:50 2015 (r278282)
+++ stable/10/sys/kern/kern_conf.c Thu Feb 5 20:49:13 2015 (r278283)
@@ -116,6 +116,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);
}
@@ -1035,6 +1037,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,
@@ -1043,13 +1046,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);
@@ -1105,13 +1117,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/10/sys/sys/conf.h
==============================================================================
--- stable/10/sys/sys/conf.h Thu Feb 5 20:45:50 2015 (r278282)
+++ stable/10/sys/sys/conf.h Thu Feb 5 20:49:13 2015 (r278283)
@@ -245,6 +245,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);
More information about the svn-src-all
mailing list