summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2002-09-27 19:47:59 +0000
committerphk <phk@FreeBSD.org>2002-09-27 19:47:59 +0000
commit5031f247a0bdcfd0f9eccc36050f2a0ff31dfed6 (patch)
treedb5b956045623504e7b7b670b1b8f0ff9eaf85bf
parent3fbb04e11fad39e7044e9e0dab9ffdf3bdc89e44 (diff)
downloadFreeBSD-src-5031f247a0bdcfd0f9eccc36050f2a0ff31dfed6.zip
FreeBSD-src-5031f247a0bdcfd0f9eccc36050f2a0ff31dfed6.tar.gz
Add a D_NOGIANT flag which can be set in a struct cdevsw to indicate
that a particular device driver is not Giant-challenged. SPECFS will DROP_GIANT() ... PICKUP_GIANT() around calls to the driver in question. Notice that the interrupt path is not affected by this! This does _NOT_ work for drivers accessed through cdevsw->d_strategy() ie drivers for disk(-like), some tapes, maybe others.
-rw-r--r--sys/fs/specfs/spec_vnops.c89
-rw-r--r--sys/sys/conf.h1
-rw-r--r--sys/sys/linedisc.h1
3 files changed, 78 insertions, 13 deletions
diff --git a/sys/fs/specfs/spec_vnops.c b/sys/fs/specfs/spec_vnops.c
index 0f2f161..e2f5cdf 100644
--- a/sys/fs/specfs/spec_vnops.c
+++ b/sys/fs/specfs/spec_vnops.c
@@ -198,7 +198,12 @@ spec_open(ap)
vp->v_vflag |= VV_ISTTY;
VOP_UNLOCK(vp, 0, td);
- error = (*dsw->d_open)(dev, ap->a_mode, S_IFCHR, td);
+ if(dsw->d_flags & D_NOGIANT) {
+ DROP_GIANT();
+ error = dsw->d_open(dev, ap->a_mode, S_IFCHR, td);
+ PICKUP_GIANT();
+ } else
+ error = dsw->d_open(dev, ap->a_mode, S_IFCHR, td);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
if (error)
@@ -254,12 +259,19 @@ spec_read(ap)
uio = ap->a_uio;
td = uio->uio_td;
resid = uio->uio_resid;
+ struct cdevsw *dsw;
if (resid == 0)
return (0);
+ dsw = devsw(dev);
VOP_UNLOCK(vp, 0, td);
- error = (*devsw(dev)->d_read)(dev, uio, ap->a_ioflag);
+ if (dsw->d_flags & D_NOGIANT) {
+ DROP_GIANT();
+ error = dsw->d_read(dev, uio, ap->a_ioflag);
+ PICKUP_GIANT();
+ } else
+ error = dsw->d_read(dev, uio, ap->a_ioflag);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
if (uio->uio_resid != resid || (error == 0 && resid != 0))
vfs_timestamp(&dev->si_atime);
@@ -284,15 +296,22 @@ spec_write(ap)
struct uio *uio;
dev_t dev;
int error, resid;
+ struct cdevsw *dsw;
vp = ap->a_vp;
dev = vp->v_rdev;
+ dsw = devsw(dev);
uio = ap->a_uio;
td = uio->uio_td;
resid = uio->uio_resid;
VOP_UNLOCK(vp, 0, td);
- error = (*devsw(dev)->d_write) (dev, uio, ap->a_ioflag);
+ if (dsw->d_flags & D_NOGIANT) {
+ DROP_GIANT();
+ error = dsw->d_write(dev, uio, ap->a_ioflag);
+ PICKUP_GIANT();
+ } else
+ error = dsw->d_write(dev, uio, ap->a_ioflag);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
if (uio->uio_resid != resid || (error == 0 && resid != 0)) {
vfs_timestamp(&dev->si_ctime);
@@ -318,10 +337,18 @@ spec_ioctl(ap)
{
dev_t dev;
int error;
+ struct cdevsw *dsw;
dev = ap->a_vp->v_rdev;
- error = (*devsw(dev)->d_ioctl)(dev, ap->a_command,
- ap->a_data, ap->a_fflag, ap->a_td);
+ dsw = devsw(dev);
+ if (dsw->d_flags & D_NOGIANT) {
+ DROP_GIANT();
+ error = dsw->d_ioctl(dev, ap->a_command,
+ ap->a_data, ap->a_fflag, ap->a_td);
+ PICKUP_GIANT();
+ } else
+ error = dsw->d_ioctl(dev, ap->a_command,
+ ap->a_data, ap->a_fflag, ap->a_td);
if (error == ENOIOCTL)
error = ENOTTY;
return (error);
@@ -338,9 +365,18 @@ spec_poll(ap)
} */ *ap;
{
dev_t dev;
+ struct cdevsw *dsw;
+ int error;
dev = ap->a_vp->v_rdev;
- return (*devsw(dev)->d_poll)(dev, ap->a_events, ap->a_td);
+ dsw = devsw(dev);
+ if (dsw->d_flags & D_NOGIANT) {
+ 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);
+ return(error);
}
/* ARGSUSED */
@@ -352,11 +388,20 @@ spec_kqfilter(ap)
} */ *ap;
{
dev_t dev;
+ struct cdevsw *dsw;
+ int error;
dev = ap->a_vp->v_rdev;
- if (devsw(dev)->d_flags & D_KQFILTER)
- return (*devsw(dev)->d_kqfilter)(dev, ap->a_kn);
- return (1);
+ dsw = devsw(dev);
+ if (!(dsw->d_flags & D_KQFILTER))
+ return (1);
+ if (dsw->d_flags & D_NOGIANT) {
+ DROP_GIANT();
+ error = dsw->d_kqfilter(dev, ap->a_kn);
+ PICKUP_GIANT();
+ } else
+ error = dsw->d_kqfilter(dev, ap->a_kn);
+ return (error);
}
/*
@@ -461,6 +506,7 @@ spec_strategy(ap)
struct vnode *vp;
struct mount *mp;
int error;
+ struct cdevsw *dsw;
bp = ap->a_bp;
vp = ap->a_vp;
@@ -506,10 +552,18 @@ spec_strategy(ap)
biodone(&bp->b_io);
return (0);
}
- KASSERT(devsw(bp->b_dev)->d_strategy != NULL,
+ dsw = devsw(bp->b_dev);
+ KASSERT(dsw->d_strategy != NULL,
("No strategy on dev %s responsible for buffer %p\n",
devtoname(bp->b_dev), bp));
- DEV_STRATEGY(bp, 0);
+
+ if (dsw->d_flags & D_NOGIANT) {
+ DROP_GIANT();
+ DEV_STRATEGY(bp, 0);
+ PICKUP_GIANT();
+ } else
+ DEV_STRATEGY(bp, 0);
+
return (0);
}
@@ -591,6 +645,8 @@ spec_close(ap)
struct vnode *vp = ap->a_vp, *oldvp;
struct thread *td = ap->a_td;
dev_t dev = vp->v_rdev;
+ struct cdevsw *dsw;
+ int error;
/*
* Hack: a tty device that is a controlling terminal
@@ -607,6 +663,7 @@ spec_close(ap)
* consideration.
*/
+ dsw = devsw(dev);
oldvp = NULL;
sx_xlock(&proctree_lock);
if (td && vp == td->td_proc->p_session->s_ttyvp) {
@@ -634,14 +691,20 @@ spec_close(ap)
VI_LOCK(vp);
if (vp->v_iflag & VI_XLOCK) {
/* Forced close. */
- } else if (devsw(dev)->d_flags & D_TRACKCLOSE) {
+ } else if (dsw->d_flags & D_TRACKCLOSE) {
/* Keep device updated on status. */
} else if (vcount(vp) > 1) {
VI_UNLOCK(vp);
return (0);
}
VI_UNLOCK(vp);
- return (devsw(dev)->d_close(dev, ap->a_fflag, S_IFCHR, td));
+ if (dsw->d_flags & D_NOGIANT) {
+ 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);
+ return (error);
}
/*
diff --git a/sys/sys/conf.h b/sys/sys/conf.h
index 35ac4c2..b49f490 100644
--- a/sys/sys/conf.h
+++ b/sys/sys/conf.h
@@ -208,6 +208,7 @@ typedef int l_modem_t(struct tty *tp, int flag);
#define D_TRACKCLOSE 0x00080000 /* track all closes */
#define D_MMAP_ANON 0x00100000 /* special treatment in vm_mmap.c */
#define D_KQFILTER 0x00200000 /* has kqfilter entry */
+#define D_NOGIANT 0x00400000 /* Doesn't want Giant */
/*
* Character device switch table
diff --git a/sys/sys/linedisc.h b/sys/sys/linedisc.h
index 35ac4c2..b49f490 100644
--- a/sys/sys/linedisc.h
+++ b/sys/sys/linedisc.h
@@ -208,6 +208,7 @@ typedef int l_modem_t(struct tty *tp, int flag);
#define D_TRACKCLOSE 0x00080000 /* track all closes */
#define D_MMAP_ANON 0x00100000 /* special treatment in vm_mmap.c */
#define D_KQFILTER 0x00200000 /* has kqfilter entry */
+#define D_NOGIANT 0x00400000 /* Doesn't want Giant */
/*
* Character device switch table
OpenPOWER on IntegriCloud