summaryrefslogtreecommitdiffstats
path: root/sys/fs
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2004-02-21 21:57:26 +0000
committerphk <phk@FreeBSD.org>2004-02-21 21:57:26 +0000
commit5551e292d8b6185cfd720b86e124a883103cfc15 (patch)
treed076858b5e5f94786b0a38e000ef6c98a01e7a00 /sys/fs
parent39fb4aef3d058a6d6726a689f365d2c8a3333178 (diff)
downloadFreeBSD-src-5551e292d8b6185cfd720b86e124a883103cfc15.zip
FreeBSD-src-5551e292d8b6185cfd720b86e124a883103cfc15.tar.gz
Device megapatch 6/6:
This is what we came here for: Hang dev_t's from their cdevsw, refcount cdevsw and dev_t and generally keep track of things a lot better than we used to: Hold a cdevsw reference around all entrances into the device driver, this will be necessary to safely determine when we can unload driver code. Hold a dev_t reference while the device is open. KASSERT that we do not enter the driver on a non-referenced dev_t. Remove old D_NAG code, anonymous dev_t's are not a problem now. When destroy_dev() is called on a referenced dev_t, move it to dead_cdevsw's list. When the refcount drops, free it. Check that cdevsw->d_version is correct. If not, set all methods to the dead_*() methods to prevent entrance into driver. Print warning on console to this effect. The device driver may still explode if it is also incompatible with newbus, but in that case we probably didn't get this far in the first place.
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/specfs/spec_vnops.c39
1 files changed, 30 insertions, 9 deletions
diff --git a/sys/fs/specfs/spec_vnops.c b/sys/fs/specfs/spec_vnops.c
index 4682b5d..ab9ce7f 100644
--- a/sys/fs/specfs/spec_vnops.c
+++ b/sys/fs/specfs/spec_vnops.c
@@ -140,7 +140,6 @@ spec_open(ap)
dev_t dev = vp->v_rdev;
int error;
struct cdevsw *dsw;
- const char *cp;
if (vp->v_type == VBLK)
return (ENXIO);
@@ -194,6 +193,8 @@ spec_open(ap)
vp->v_vflag |= VV_ISTTY;
VOP_UNLOCK(vp, 0, td);
+ dev_ref(dev);
+ cdevsw_ref(dsw);
if(!(dsw->d_flags & D_NEEDGIANT)) {
DROP_GIANT();
if (dsw->d_fdopen != NULL)
@@ -205,6 +206,9 @@ spec_open(ap)
error = dsw->d_fdopen(dev, ap->a_mode, td, ap->a_fdidx);
else
error = dsw->d_open(dev, ap->a_mode, S_IFCHR, td);
+ cdevsw_rel(dsw);
+ if (error != 0)
+ dev_rel(dev);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
if (error)
@@ -225,14 +229,6 @@ spec_open(ap)
if (!dev->si_bsize_phys)
dev->si_bsize_phys = DEV_BSIZE;
}
- if ((dsw->d_flags & D_DISK) == 0) {
- cp = devtoname(dev);
- if (*cp == '#' && (dsw->d_flags & D_NAGGED) == 0) {
- printf("WARNING: driver %s should register devices with make_dev() (dev_t = \"%s\")\n",
- dsw->d_name, cp);
- dsw->d_flags |= D_NAGGED;
- }
- }
return (error);
}
@@ -267,12 +263,16 @@ spec_read(ap)
dsw = devsw(dev);
VOP_UNLOCK(vp, 0, td);
+ KASSERT(dev->si_refcount > 0,
+ ("specread() on un-referenced dev_t (%s)", devtoname(dev)));
+ cdevsw_ref(dsw);
if (!(dsw->d_flags & D_NEEDGIANT)) {
DROP_GIANT();
error = dsw->d_read(dev, uio, ap->a_ioflag);
PICKUP_GIANT();
} else
error = dsw->d_read(dev, uio, ap->a_ioflag);
+ cdevsw_rel(dsw);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
if (uio->uio_resid != resid || (error == 0 && resid != 0))
vfs_timestamp(&dev->si_atime);
@@ -307,12 +307,16 @@ spec_write(ap)
resid = uio->uio_resid;
VOP_UNLOCK(vp, 0, td);
+ KASSERT(dev->si_refcount > 0,
+ ("spec_write() on un-referenced dev_t (%s)", devtoname(dev)));
+ cdevsw_ref(dsw);
if (!(dsw->d_flags & D_NEEDGIANT)) {
DROP_GIANT();
error = dsw->d_write(dev, uio, ap->a_ioflag);
PICKUP_GIANT();
} else
error = dsw->d_write(dev, uio, ap->a_ioflag);
+ cdevsw_rel(dsw);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
if (uio->uio_resid != resid || (error == 0 && resid != 0)) {
vfs_timestamp(&dev->si_ctime);
@@ -342,6 +346,9 @@ spec_ioctl(ap)
dev = ap->a_vp->v_rdev;
dsw = devsw(dev);
+ KASSERT(dev->si_refcount > 0,
+ ("spec_ioctl() on un-referenced dev_t (%s)", devtoname(dev)));
+ cdevsw_ref(dsw);
if (!(dsw->d_flags & D_NEEDGIANT)) {
DROP_GIANT();
error = dsw->d_ioctl(dev, ap->a_command,
@@ -350,6 +357,7 @@ spec_ioctl(ap)
} else
error = dsw->d_ioctl(dev, ap->a_command,
ap->a_data, ap->a_fflag, ap->a_td);
+ cdevsw_rel(dsw);
if (error == ENOIOCTL)
error = ENOTTY;
return (error);
@@ -371,12 +379,16 @@ spec_poll(ap)
dev = ap->a_vp->v_rdev;
dsw = devsw(dev);
+ KASSERT(dev->si_refcount > 0,
+ ("spec_poll() on un-referenced dev_t (%s)", devtoname(dev)));
+ cdevsw_ref(dsw);
if (!(dsw->d_flags & D_NEEDGIANT)) {
DROP_GIANT();
error = dsw->d_poll(dev, ap->a_events, ap->a_td);
PICKUP_GIANT();
} else
error = dsw->d_poll(dev, ap->a_events, ap->a_td);
+ cdevsw_rel(dsw);
return(error);
}
@@ -394,12 +406,16 @@ spec_kqfilter(ap)
dev = ap->a_vp->v_rdev;
dsw = devsw(dev);
+ KASSERT(dev->si_refcount > 0,
+ ("spec_kqfilter() on un-referenced dev_t (%s)", devtoname(dev)));
+ cdevsw_ref(dsw);
if (!(dsw->d_flags & D_NEEDGIANT)) {
DROP_GIANT();
error = dsw->d_kqfilter(dev, ap->a_kn);
PICKUP_GIANT();
} else
error = dsw->d_kqfilter(dev, ap->a_kn);
+ cdevsw_rel(dsw);
return (error);
}
@@ -631,12 +647,17 @@ spec_close(ap)
return (0);
}
VI_UNLOCK(vp);
+ KASSERT(dev->si_refcount > 0,
+ ("spec_close() on un-referenced dev_t (%s)", devtoname(dev)));
+ cdevsw_ref(dsw);
if (!(dsw->d_flags & D_NEEDGIANT)) {
DROP_GIANT();
error = dsw->d_close(dev, ap->a_fflag, S_IFCHR, td);
PICKUP_GIANT();
} else
error = dsw->d_close(dev, ap->a_fflag, S_IFCHR, td);
+ cdevsw_rel(dsw);
+ dev_rel(dev);
return (error);
}
OpenPOWER on IntegriCloud