Date: Thu, 5 Feb 2015 20:49:14 +0000 (UTC) From: Hans Petter Selasky <hselasky@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r278283 - in stable/10/sys: fs/devfs kern sys Message-ID: <201502052049.t15KnEHv038772@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201502052049.t15KnEHv038772>