diff options
author | phk <phk@FreeBSD.org> | 2002-09-27 19:47:59 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2002-09-27 19:47:59 +0000 |
commit | 5031f247a0bdcfd0f9eccc36050f2a0ff31dfed6 (patch) | |
tree | db5b956045623504e7b7b670b1b8f0ff9eaf85bf | |
parent | 3fbb04e11fad39e7044e9e0dab9ffdf3bdc89e44 (diff) | |
download | FreeBSD-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.c | 89 | ||||
-rw-r--r-- | sys/sys/conf.h | 1 | ||||
-rw-r--r-- | sys/sys/linedisc.h | 1 |
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 |