summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_conf.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2010-08-06 09:42:15 +0000
committerkib <kib@FreeBSD.org>2010-08-06 09:42:15 +0000
commitba7ee96f4acc27c8c70a4af6c81be42c4856619f (patch)
tree7da521a717547b550e58c94609d3078b5dd9e826 /sys/kern/kern_conf.c
parentc3d4f0835cad384499298be886c0a8afc90d5822 (diff)
downloadFreeBSD-src-ba7ee96f4acc27c8c70a4af6c81be42c4856619f.zip
FreeBSD-src-ba7ee96f4acc27c8c70a4af6c81be42c4856619f.tar.gz
Add new make_dev_p(9) flag MAKEDEV_ETERNAL to inform devfs that created
cdev will never be destroyed. Propagate the flag to devfs vnodes as VV_ETERNVALDEV. Use the flags to avoid acquiring devmtx and taking a thread reference on such nodes. In collaboration with: pho MFC after: 1 month
Diffstat (limited to 'sys/kern/kern_conf.c')
-rw-r--r--sys/kern/kern_conf.c119
1 files changed, 76 insertions, 43 deletions
diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c
index 7e4e677..9ef49af 100644
--- a/sys/kern/kern_conf.c
+++ b/sys/kern/kern_conf.c
@@ -177,12 +177,16 @@ dev_rel(struct cdev *dev)
}
struct cdevsw *
-dev_refthread(struct cdev *dev)
+dev_refthread(struct cdev *dev, int *ref)
{
struct cdevsw *csw;
struct cdev_priv *cdp;
mtx_assert(&devmtx, MA_NOTOWNED);
+ if ((dev->si_flags & SI_ETERNAL) != 0) {
+ *ref = 0;
+ return (dev->si_devsw);
+ }
dev_lock();
csw = dev->si_devsw;
if (csw != NULL) {
@@ -193,36 +197,59 @@ dev_refthread(struct cdev *dev)
csw = NULL;
}
dev_unlock();
+ *ref = 1;
return (csw);
}
struct cdevsw *
-devvn_refthread(struct vnode *vp, struct cdev **devp)
+devvn_refthread(struct vnode *vp, struct cdev **devp, int *ref)
{
struct cdevsw *csw;
struct cdev_priv *cdp;
+ struct cdev *dev;
mtx_assert(&devmtx, MA_NOTOWNED);
+ if ((vp->v_vflag & VV_ETERNALDEV) != 0) {
+ dev = vp->v_rdev;
+ if (dev == NULL)
+ return (NULL);
+ KASSERT((dev->si_flags & SI_ETERNAL) != 0,
+ ("Not eternal cdev"));
+ *ref = 0;
+ csw = dev->si_devsw;
+ KASSERT(csw != NULL, ("Eternal cdev is destroyed"));
+ *devp = dev;
+ return (csw);
+ }
+
csw = NULL;
dev_lock();
- *devp = vp->v_rdev;
- if (*devp != NULL) {
- cdp = cdev2priv(*devp);
- if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) {
- csw = (*devp)->si_devsw;
- if (csw != NULL)
- (*devp)->si_threadcount++;
- }
+ dev = vp->v_rdev;
+ if (dev == NULL) {
+ dev_unlock();
+ return (NULL);
+ }
+ cdp = cdev2priv(dev);
+ if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) {
+ csw = dev->si_devsw;
+ if (csw != NULL)
+ dev->si_threadcount++;
}
dev_unlock();
+ if (csw != NULL) {
+ *devp = dev;
+ *ref = 1;
+ }
return (csw);
}
void
-dev_relthread(struct cdev *dev)
+dev_relthread(struct cdev *dev, int ref)
{
mtx_assert(&devmtx, MA_NOTOWNED);
+ if (!ref)
+ return;
dev_lock();
KASSERT(dev->si_threadcount > 0,
("%s threadcount is wrong", dev->si_name));
@@ -325,15 +352,15 @@ static int
giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
{
struct cdevsw *dsw;
- int retval;
+ int ref, retval;
- dsw = dev_refthread(dev);
+ dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td);
mtx_unlock(&Giant);
- dev_relthread(dev);
+ dev_relthread(dev, ref);
return (retval);
}
@@ -341,15 +368,15 @@ static int
giant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp)
{
struct cdevsw *dsw;
- int retval;
+ int ref, retval;
- dsw = dev_refthread(dev);
+ dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp);
mtx_unlock(&Giant);
- dev_relthread(dev);
+ dev_relthread(dev, ref);
return (retval);
}
@@ -357,15 +384,15 @@ static int
giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
{
struct cdevsw *dsw;
- int retval;
+ int ref, retval;
- dsw = dev_refthread(dev);
+ dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td);
mtx_unlock(&Giant);
- dev_relthread(dev);
+ dev_relthread(dev, ref);
return (retval);
}
@@ -374,9 +401,10 @@ giant_strategy(struct bio *bp)
{
struct cdevsw *dsw;
struct cdev *dev;
+ int ref;
dev = bp->bio_dev;
- dsw = dev_refthread(dev);
+ dsw = dev_refthread(dev, &ref);
if (dsw == NULL) {
biofinish(bp, NULL, ENXIO);
return;
@@ -384,22 +412,22 @@ giant_strategy(struct bio *bp)
mtx_lock(&Giant);
dsw->d_gianttrick->d_strategy(bp);
mtx_unlock(&Giant);
- dev_relthread(dev);
+ dev_relthread(dev, ref);
}
static int
giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
{
struct cdevsw *dsw;
- int retval;
+ int ref, retval;
- dsw = dev_refthread(dev);
+ dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td);
mtx_unlock(&Giant);
- dev_relthread(dev);
+ dev_relthread(dev, ref);
return (retval);
}
@@ -407,15 +435,15 @@ static int
giant_read(struct cdev *dev, struct uio *uio, int ioflag)
{
struct cdevsw *dsw;
- int retval;
+ int ref, retval;
- dsw = dev_refthread(dev);
+ dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_read(dev, uio, ioflag);
mtx_unlock(&Giant);
- dev_relthread(dev);
+ dev_relthread(dev, ref);
return (retval);
}
@@ -423,15 +451,15 @@ static int
giant_write(struct cdev *dev, struct uio *uio, int ioflag)
{
struct cdevsw *dsw;
- int retval;
+ int ref, retval;
- dsw = dev_refthread(dev);
+ dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_write(dev, uio, ioflag);
mtx_unlock(&Giant);
- dev_relthread(dev);
+ dev_relthread(dev, ref);
return (retval);
}
@@ -439,15 +467,15 @@ static int
giant_poll(struct cdev *dev, int events, struct thread *td)
{
struct cdevsw *dsw;
- int retval;
+ int ref, retval;
- dsw = dev_refthread(dev);
+ dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_poll(dev, events, td);
mtx_unlock(&Giant);
- dev_relthread(dev);
+ dev_relthread(dev, ref);
return (retval);
}
@@ -455,15 +483,15 @@ static int
giant_kqfilter(struct cdev *dev, struct knote *kn)
{
struct cdevsw *dsw;
- int retval;
+ int ref, retval;
- dsw = dev_refthread(dev);
+ dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_kqfilter(dev, kn);
mtx_unlock(&Giant);
- dev_relthread(dev);
+ dev_relthread(dev, ref);
return (retval);
}
@@ -472,16 +500,16 @@ giant_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot,
vm_memattr_t *memattr)
{
struct cdevsw *dsw;
- int retval;
+ int ref, retval;
- dsw = dev_refthread(dev);
+ dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot,
memattr);
mtx_unlock(&Giant);
- dev_relthread(dev);
+ dev_relthread(dev, ref);
return (retval);
}
@@ -490,16 +518,16 @@ giant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size,
vm_object_t *object, int nprot)
{
struct cdevsw *dsw;
- int retval;
+ int ref, retval;
- dsw = dev_refthread(dev);
+ dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object,
nprot);
mtx_unlock(&Giant);
- dev_relthread(dev);
+ dev_relthread(dev, ref);
return (retval);
}
@@ -676,6 +704,8 @@ make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, int unit,
dev = newdev(devsw, unit, dev);
if (flags & MAKEDEV_REF)
dev_refl(dev);
+ if (flags & MAKEDEV_ETERNAL)
+ dev->si_flags |= SI_ETERNAL;
if (dev->si_flags & SI_CHEAPCLONE &&
dev->si_flags & SI_NAMED) {
/*
@@ -840,6 +870,9 @@ destroy_devl(struct cdev *dev)
mtx_assert(&devmtx, MA_OWNED);
KASSERT(dev->si_flags & SI_NAMED,
("WARNING: Driver mistake: destroy_dev on %d\n", dev2unit(dev)));
+ KASSERT((dev->si_flags & SI_ETERNAL) == 0,
+ ("WARNING: Driver mistake: destroy_dev on eternal %d\n",
+ dev2unit(dev)));
devfs_destroy(dev);
OpenPOWER on IntegriCloud