From owner-freebsd-bugs@FreeBSD.ORG Wed Jul 19 07:20:19 2006 Return-Path: X-Original-To: freebsd-bugs@hub.freebsd.org Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 79E2316A4DD for ; Wed, 19 Jul 2006 07:20:19 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id D8F8643D49 for ; Wed, 19 Jul 2006 07:20:18 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.4/8.13.4) with ESMTP id k6J7KIHu019689 for ; Wed, 19 Jul 2006 07:20:18 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.4/8.13.4/Submit) id k6J7KItK019687; Wed, 19 Jul 2006 07:20:18 GMT (envelope-from gnats) Date: Wed, 19 Jul 2006 07:20:18 GMT Message-Id: <200607190720.k6J7KItK019687@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org From: Atsuo Ohki Cc: Subject: Re: kern/99758: chown/chmod pty slave side in kernel X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Atsuo Ohki List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 19 Jul 2006 07:20:19 -0000 The following reply was made to PR kern/99758; it has been noted by GNATS. From: Atsuo Ohki To: "Wojciech A. Koszek" , freebsd-gnats-submit@FreeBSD.org, freebsd-bugs@FreeBSD.org Cc: Subject: Re: kern/99758: chown/chmod pty slave side in kernel Date: Wed, 19 Jul 2006 16:12:27 +0900 Hi. I think I made it (but, still running stress2). (thanks to those who introduced `struct mtx devfs_de_interlock'!) following patch may make things running. I left many printf, counter variables for debugging :-) --- ./fs/devfs/devfs_devs.c-ORIG Wed Feb 22 18:05:40 2006 +++ ./fs/devfs/devfs_devs.c Wed Jul 19 15:51:49 2006 @@ -23,9 +23,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36 + + From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36 * - * $FreeBSD: src/sys/fs/devfs/devfs_devs.c,v 1.45 2006/02/22 09:05:40 jeff Exp $ + + $FreeBSD: src/sys/fs/devfs/devfs_devs.c,v 1.45 2006/02/22 09:05:40 jeff Exp $ */ #include "opt_devfs.h" @@ -93,9 +93,13 @@ ud ^ devfs_random(); */ dev_lock(); - TAILQ_FOREACH(cdp, &cdevp_list, cdp_list) + TAILQ_FOREACH(cdp, &cdevp_list, cdp_list) { + if (!(cdp->cdp_flags & CDP_ACTIVE) + || (cdp->cdp_flags & CDP_HID)) + continue; if (cdp->cdp_inode == ud) break; + } dev_unlock(); if (cdp == NULL) return(ENOENT); @@ -112,6 +116,9 @@ SYSCTL_INT(_debug_sizeof, OID_AUTO, cdev_priv, CTLFLAG_RD, 0, sizeof(struct cdev_priv), "sizeof(struct cdev_priv)"); +static int devfs_alloc_cnt = 0; +static int devfs_free_cnt = 0; + struct cdev * devfs_alloc(void) { @@ -129,6 +136,7 @@ cdev->si_name = cdev->__si_namebuf; LIST_INIT(&cdev->si_children); + devfs_alloc_cnt++; return (cdev); } @@ -136,8 +144,16 @@ devfs_free(struct cdev *cdev) { struct cdev_priv *cdp; + u_int i; + u_int p; cdp = cdev->si_priv; + + for (p=0, i=0; i <= cdp->cdp_maxdirent; i++) + p |= (u_int)cdp->cdp_dirents[i]; + KASSERT(cdp->cdp_inuse == 0, ("cdp_inuse != 0 @%p", cdev)); + KASSERT(p == 0, ("cdp_dirents[] != NULL @%p", cdev)); + if (cdev->si_cred != NULL) crfree(cdev->si_cred); if (cdp->cdp_inode > 0) @@ -145,6 +161,7 @@ if (cdp->cdp_maxdirent > 0) free(cdp->cdp_dirents, M_DEVFS2); free(cdp, M_CDEVP); + devfs_free_cnt++; } struct devfs_dirent * @@ -153,6 +170,9 @@ struct devfs_dirent *de; TAILQ_FOREACH(de, &dd->de_dlist, de_list) { + if (de->de_cdp && (!(de->de_cdp->cdp_flags & CDP_ACTIVE) || + (de->de_cdp->cdp_flags & CDP_HID))) + continue; if (namelen != de->de_dirent->d_namlen) continue; if (bcmp(name, de->de_dirent->d_name, namelen) != 0) @@ -233,18 +253,27 @@ void devfs_delete(struct devfs_mount *dm, struct devfs_dirent *de) { + struct vnode *vp; + sx_assert(&dm->dm_lock, SX_XLOCKED); if (de->de_symlink) { free(de->de_symlink, M_DEVFS); de->de_symlink = NULL; } - if (de->de_vnode != NULL) { - vhold(de->de_vnode); - de->de_vnode->v_data = NULL; - vgone(de->de_vnode); - vdrop(de->de_vnode); + devfs_de_lock(); + vp = de->de_vnode; + if (vp != NULL) { de->de_vnode = NULL; - } + vp->v_data = NULL; + if (vp->v_rdev) + dev_rel(vp->v_rdev); + vp->v_rdev = NULL; + devfs_de_unlock(); + vhold(vp); + vgone(vp); + vdrop(vp); + } else + devfs_de_unlock(); #ifdef MAC mac_destroy_devfsdirent(de); #endif @@ -314,6 +343,8 @@ dev_unlock(); } +static int devfs_populate_gc = 0; + static int devfs_populate_loop(struct devfs_mount *dm, int cleanup) { @@ -361,6 +392,7 @@ TAILQ_REMOVE(&cdevp_list, cdp, cdp_list); dev_unlock(); dev_rel(&cdp->cdp_c); + devfs_populate_gc++; return (1); } /* @@ -440,13 +472,21 @@ void devfs_populate(struct devfs_mount *dm) { + unsigned old_generation; sx_assert(&dm->dm_lock, SX_XLOCKED); - if (dm->dm_generation == devfs_generation) - return; - while (devfs_populate_loop(dm, 0)) - continue; - dm->dm_generation = devfs_generation; + while(1) { + dev_lock(); + if (dm->dm_generation == devfs_generation) { + dev_unlock(); + return; + } + old_generation = devfs_generation; + dev_unlock(); + while (devfs_populate_loop(dm, 0)) + continue; + dm->dm_generation = old_generation; + } } void @@ -487,6 +527,17 @@ mtx_assert(&devmtx, MA_OWNED); cdp = dev->si_priv; cdp->cdp_flags &= ~CDP_ACTIVE; + devfs_generation++; +} + +void +devfs_hide(struct cdev *dev) +{ + struct cdev_priv *cdp; + + mtx_assert(&devmtx, MA_OWNED); + cdp = dev->si_priv; + cdp->cdp_flags |= CDP_HID; devfs_generation++; } --- ./fs/devfs/devfs_vnops.c-ORIG Fri Jul 7 16:28:01 2006 +++ ./fs/devfs/devfs_vnops.c Wed Jul 19 15:51:55 2006 @@ -29,9 +29,9 @@ * SUCH DAMAGE. * * @(#)kernfs_vnops.c 8.15 (Berkeley) 5/21/95 - * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43 + + From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43 * - * $FreeBSD: src/sys/fs/devfs/devfs_vnops.c,v 1.131 2006/07/06 13:22:08 rwatson Exp $ + + $FreeBSD: src/sys/fs/devfs/devfs_vnops.c,v 1.131 2006/07/06 13:22:08 rwatson Exp $ */ /* @@ -72,6 +72,21 @@ #include #include +static struct mtx devfs_de_interlock; +MTX_SYSINIT(devfs_de_interlock, &devfs_de_interlock, "devfs interlock", MTX_DEF); + +void +devfs_de_lock(void) +{ + mtx_lock(&devfs_de_interlock); +} + +void +devfs_de_unlock(void) +{ + mtx_unlock(&devfs_de_interlock); +} + static int devfs_fp_check(struct file *fp, struct cdev **devp, struct cdevsw **dswp) { @@ -124,24 +139,52 @@ } int -devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td) +devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td, int lkflag) { int error; struct vnode *vp; struct cdev *dev; + struct devfs_mount *dmp; KASSERT(td == curthread, ("devfs_allocv: td != curthread")); + dmp = VFSTODEVFS(mp); + sx_assert(&dmp->dm_lock, SX_XLOCKED); + lkflag = LK_EXCLUSIVE; loop: + devfs_de_lock(); vp = de->de_vnode; if (vp != NULL) { - if (vget(vp, LK_EXCLUSIVE, td)) + VI_LOCK(vp); + devfs_de_unlock(); + sx_xunlock(&dmp->dm_lock); + error=vget(vp, lkflag|LK_INTERLOCK, td); + if (error) { + if (error == ENOENT) { + /* vnode has gone! */ + devfs_de_lock(); + de->de_vnode = NULL; + devfs_de_unlock(); + printf("devfs_allocv(): vnode %p error#%d\n", + vp, error); + } + sx_xlock(&dmp->dm_lock); goto loop; + } + sx_xlock(&dmp->dm_lock); + devfs_de_lock(); + KASSERT(vp == de->de_vnode, + ("devfs_allocv(): vp(%p) changed!", vp)); + devfs_de_unlock(); *vpp = vp; return (0); } + devfs_de_unlock(); if (de->de_dirent->d_type == DT_CHR) { - if (!(de->de_cdp->cdp_flags & CDP_ACTIVE)) + /* should not happen, but ... paranoia */ + if (!(de->de_cdp->cdp_flags & CDP_ACTIVE) || + (de->de_cdp->cdp_flags & CDP_HID)) { return (ENOENT); + } dev = &de->de_cdp->cdp_c; } else { dev = NULL; @@ -171,9 +214,20 @@ } else { vp->v_type = VBAD; } + devfs_de_lock(); + if (de->de_vnode != NULL) { + /* someone has allocated before us ! */ + VI_LOCK(vp); + vholdl(vp); + VI_UNLOCK(vp); + vgone(vp); + vdrop(vp); + vp = de->de_vnode; + } vp->v_data = de; de->de_vnode = vp; - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); + devfs_de_unlock(); + vn_lock(vp, lkflag | LK_RETRY, td); #ifdef MAC mac_associate_vnode_devfs(mp, de, vp); #endif @@ -498,7 +552,7 @@ de = TAILQ_FIRST(&dd->de_dlist); /* "." */ de = TAILQ_NEXT(de, de_list); /* ".." */ de = de->de_dir; - error = devfs_allocv(de, dvp->v_mount, vpp, td); + error = devfs_allocv(de, dvp->v_mount, vpp, td, cnp->cn_lkflags); vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); return (error); } @@ -506,7 +560,8 @@ devfs_populate(dmp); dd = dvp->v_data; de = devfs_find(dd, cnp->cn_nameptr, cnp->cn_namelen); - while (de == NULL) { /* While(...) so we can use break */ + if ((flags & (ISLASTCN|ISOPEN)) == (ISLASTCN|ISOPEN)) + while (de == NULL) { /* While(...) so we can use break */ if (nameiop == DELETE) return (ENOENT); @@ -555,7 +610,7 @@ return (0); } } - error = devfs_allocv(de, dvp->v_mount, vpp, td); + error = devfs_allocv(de, dvp->v_mount, vpp, td, cnp->cn_lkflags); return (error); } @@ -611,7 +666,7 @@ if (de == NULL) goto notfound; de->de_flags &= ~DE_WHITEOUT; - error = devfs_allocv(de, dvp->v_mount, vpp, td); + error = devfs_allocv(de, dvp->v_mount, vpp, td, cnp->cn_lkflags); notfound: sx_xunlock(&dmp->dm_lock); return (error); @@ -830,6 +885,10 @@ de = dd->de_dir; else de = dd; + if (de->de_cdp && (de->de_cdp->cdp_flags & CDP_HID)) { + /* printf("devfs_readdir(): skip hid dev\n"); */ + continue; + } dp = dd->de_dirent; if (dp->d_reclen > uio->uio_resid) break; @@ -870,17 +929,21 @@ struct devfs_dirent *de; struct cdev *dev; + devfs_de_lock(); de = vp->v_data; - if (de != NULL) + if (de != NULL) { de->de_vnode = NULL; - vp->v_data = NULL; + vp->v_data = NULL; + } + devfs_de_unlock(); vnode_destroy_vobject(vp); dev = vp->v_rdev; vp->v_rdev = NULL; - if (dev == NULL) + if (dev == NULL) { return (0); + } dev_lock(); dev->si_usecount -= vp->v_usecount; @@ -934,25 +997,32 @@ dev = vp->v_rdev; cdp = dev->si_priv; for (;;) { + devfs_de_lock(); dev_lock(); vp2 = NULL; for (i = 0; i <= cdp->cdp_maxdirent; i++) { de = cdp->cdp_dirents[i]; if (de == NULL) continue; + vp2 = de->de_vnode; - de->de_vnode = NULL; - if (vp2 != NULL) + if (vp2 != NULL) { + de->de_vnode = NULL; + dev_unlock(); + VI_LOCK(vp2); + devfs_de_unlock(); + vholdl(vp2); + VI_UNLOCK(vp2); + vgone(vp2); + vdrop(vp2); break; + } } - dev_unlock(); if (vp2 != NULL) { - /* XXX */ - vhold(vp2); - vgone(vp2); - vdrop(vp2); continue; } + dev_unlock(); + devfs_de_unlock(); break; } return (0); @@ -1120,7 +1190,7 @@ mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de); #endif TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); - devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, td); + devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, td, ap->a_cnp->cn_lkflags); sx_xunlock(&dmp->dm_lock); return (0); } --- ./fs/devfs/devfs_int.h-ORIG Tue Sep 20 04:56:48 2005 +++ ./fs/devfs/devfs_int.h Wed Jul 19 15:52:01 2006 @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/fs/devfs/devfs_int.h,v 1.2 2005/09/19 19:56:48 phk Exp $ + + $FreeBSD: src/sys/fs/devfs/devfs_int.h,v 1.2 2005/09/19 19:56:48 phk Exp $ */ /* @@ -47,6 +47,7 @@ u_int cdp_flags; #define CDP_ACTIVE (1 << 0) +#define CDP_HID (1 << 1) u_int cdp_inuse; u_int cdp_maxdirent; @@ -58,6 +59,10 @@ void devfs_free(struct cdev *); void devfs_create(struct cdev *dev); void devfs_destroy(struct cdev *dev); +void devfs_hide(struct cdev *dev); + +void devfs_de_lock(void); +void devfs_de_unlock(void); extern struct unrhdr *devfs_inos; extern struct mtx devmtx; --- ./fs/devfs/devfs_vfsops.c-ORIG Fri Jul 7 16:28:01 2006 +++ ./fs/devfs/devfs_vfsops.c Wed Jul 19 15:52:06 2006 @@ -29,9 +29,9 @@ * SUCH DAMAGE. * * @(#)kernfs_vfsops.c 8.10 (Berkeley) 5/14/95 - * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36 + + From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36 * - * $FreeBSD: src/sys/fs/devfs/devfs_vfsops.c,v 1.49 2006/07/06 13:24:22 rwatson Exp $ + + $FreeBSD: src/sys/fs/devfs/devfs_vfsops.c,v 1.49 2006/07/06 13:24:22 rwatson Exp $ */ #include "opt_devfs.h" @@ -139,10 +139,14 @@ struct devfs_mount *dmp; dmp = VFSTODEVFS(mp); - error = devfs_allocv(dmp->dm_rootdir, mp, &vp, td); + sx_xlock(&dmp->dm_lock); + error = devfs_allocv(dmp->dm_rootdir, mp, &vp, td, LK_EXCLUSIVE); + sx_xunlock(&dmp->dm_lock); if (error) return (error); vp->v_vflag |= VV_ROOT; + VREF(vp); + vhold(vp); *vpp = vp; return (0); } --- ./fs/devfs/devfs.h-ORIG Wed Apr 12 21:17:29 2006 +++ ./fs/devfs/devfs.h Wed Jul 19 15:52:14 2006 @@ -31,9 +31,9 @@ * SUCH DAMAGE. * * @(#)kernfs.h 8.6 (Berkeley) 3/29/95 - * From: FreeBSD: src/sys/miscfs/kernfs/kernfs.h 1.14 + + From: FreeBSD: src/sys/miscfs/kernfs/kernfs.h 1.14 * - * $FreeBSD: src/sys/fs/devfs/devfs.h,v 1.29 2006/04/12 12:17:29 pjd Exp $ + + $FreeBSD: src/sys/fs/devfs/devfs.h,v 1.29 2006/04/12 12:17:29 pjd Exp $ */ #ifndef _FS_DEVFS_DEVFS_H_ @@ -163,7 +163,7 @@ void devfs_rules_apply(struct devfs_mount *dm, struct devfs_dirent *de); void devfs_rules_cleanup (struct devfs_mount *dm); int devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct thread *td); -int devfs_allocv (struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td); +int devfs_allocv (struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td, int lkflag); void devfs_delete(struct devfs_mount *dm, struct devfs_dirent *de); void devfs_populate (struct devfs_mount *dm); void devfs_cleanup (struct devfs_mount *dm); --- ./kern/kern_conf.c-ORIG Wed May 17 15:37:14 2006 +++ ./kern/kern_conf.c Wed Jul 19 15:52:33 2006 @@ -25,7 +25,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/kern/kern_conf.c,v 1.198 2006/05/17 06:37:14 phk Exp $"); +__FBSDID("$FreeBSD: src/sys/kern/kern_conf.c,v 1.198-bis 2006/05/17 06:37:14 phk Exp $"); #include #include @@ -72,6 +72,10 @@ dev_ref(struct cdev *dev) { + KASSERT(dev != (void*)0xdeadc0de, + ("dev_ref(): dev:%p", dev)); + KASSERT(dev->si_refcount != 0xdeadc0de, + ("dev_ref(): si_refcount @%p", dev)); mtx_assert(&devmtx, MA_NOTOWNED); mtx_lock(&devmtx); dev->si_refcount++; @@ -82,6 +86,10 @@ dev_refl(struct cdev *dev) { + KASSERT(dev != (void*)0xdeadc0de, + ("dev_refl(): dev:%p", dev)); + KASSERT(dev->si_refcount != 0xdeadc0de, + ("dev_refl(): si_refcount @%p", dev)); mtx_assert(&devmtx, MA_OWNED); dev->si_refcount++; } @@ -91,6 +99,10 @@ { int flag = 0; + KASSERT(dev != (void*)0xdeadc0de, + ("dev_rel(): dev:%p", dev)); + KASSERT(dev->si_refcount != 0xdeadc0de, + ("dev_rel(): si_refcount @%p", dev)); mtx_assert(&devmtx, MA_NOTOWNED); dev_lock(); dev->si_refcount--; @@ -116,6 +128,10 @@ { struct cdevsw *csw; + KASSERT(dev != (void*)0xdeadc0de, + ("dev_refthread(): dev:%p", dev)); + KASSERT(dev->si_threadcount != 0xdeadc0de, + ("dev_refthread(): si_threadcount @%p", dev)); mtx_assert(&devmtx, MA_NOTOWNED); dev_lock(); csw = dev->si_devsw; @@ -129,6 +145,10 @@ dev_relthread(struct cdev *dev) { + KASSERT(dev != (void*)0xdeadc0de, + ("dev_relthread(): dev:%p", dev)); + KASSERT(dev->si_threadcount != 0xdeadc0de, + ("dev_relthread(): si_threadcount@%p", dev)); mtx_assert(&devmtx, MA_NOTOWNED); dev_lock(); dev->si_threadcount--; @@ -400,6 +420,7 @@ LIST_FOREACH(si2, &csw->d_devs, si_list) { if (si2->si_drv0 == udev) { devfs_free(si); + printf("newdev(): reuse %s:%d\n", csw->d_name, udev); return (si2); } } @@ -515,6 +536,11 @@ struct cdev *dev; int i; + if (devsw == NULL) printf("make_dev_credv(): NULL cdevsw\n"); + KASSERT(((devsw != (void*)0xdeadc0de) && + (*((u_int*)devsw) != 0xdeadc0de)), + ("Invalid devsw (%p) in make_dev", devsw)); + KASSERT((minornr & ~MAXMINOR) == 0, ("Invalid minor (0x%x) in make_dev", minornr)); @@ -633,12 +659,20 @@ { struct cdevsw *csw; + KASSERT(dev != (void*)0xdeadc0de, + ("destroy_dev(): dev:%p", dev)); + KASSERT(dev->si_refcount != 0xdeadc0de, + ("destroy_dev(): si_refcount @%p", dev)); + mtx_assert(&devmtx, MA_OWNED); KASSERT(dev->si_flags & SI_NAMED, ("WARNING: Driver mistake: destroy_dev on %d\n", minor(dev))); devfs_destroy(dev); + if (dev->si_refcount == 0) + printf("destroy_devl(): si_refcount == 0 @%p\n", dev); + /* Remove name marking */ dev->si_flags &= ~SI_NAMED; @@ -677,7 +711,7 @@ LIST_REMOVE(dev, si_list); /* If cdevsw has no more struct cdev *'s, clean it */ - if (LIST_EMPTY(&csw->d_devs)) + if (LIST_EMPTY(&csw->d_devs) && !(csw->d_flags & D_NO_FINI)) fini_cdevsw(csw); } dev->si_flags &= ~SI_ALIAS; @@ -685,16 +719,29 @@ if (dev->si_refcount > 0) { LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); } else { + printf("destroy_devl(%p)\n", dev); devfs_free(dev); } } +static int destroy_dev_cnt = 0; + void destroy_dev(struct cdev *dev) { dev_lock(); destroy_devl(dev); + dev_unlock(); + destroy_dev_cnt++; +} + +void +hide_dev(struct cdev *dev) +{ + + dev_lock(); + devfs_hide(dev); dev_unlock(); } --- ./kern/tty_pts.c-ORIG Sat Apr 29 06:39:57 2006 +++ ./kern/tty_pts.c Wed Jul 19 15:52:47 2006 @@ -40,7 +40,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/kern/tty_pts.c,v 1.8 2006/04/28 21:39:57 rwatson Exp $"); +__FBSDID("$FreeBSD: src/sys/kern/tty_pts.c,v 1.8-bis 2006/04/28 21:39:57 rwatson Exp $"); /* * Pseudo-teletype Driver @@ -96,7 +96,7 @@ .d_ioctl = ptsioctl, .d_poll = ttypoll, .d_name = "pts", - .d_flags = D_TTY | D_NEEDGIANT, + .d_flags = D_TTY | D_NEEDGIANT | D_NO_FINI, .d_kqfilter = ttykqfilter, }; @@ -109,7 +109,7 @@ .d_ioctl = ptcioctl, .d_poll = ptcpoll, .d_name = "ptc", - .d_flags = D_TTY | D_NEEDGIANT, + .d_flags = D_TTY | D_NEEDGIANT | D_NO_FINI, .d_kqfilter = ttykqfilter, }; @@ -135,7 +135,7 @@ */ struct pt_desc { int pt_num; /* (c) pty number */ - LIST_ENTRY(pt_desc) pt_list; /* (p) global pty list */ + TAILQ_ENTRY(pt_desc) pt_list; /* (p) global pty list */ int pt_flags; struct selinfo pt_selr, pt_selw; @@ -148,8 +148,8 @@ }; static struct mtx pt_mtx; -static LIST_HEAD(,pt_desc) pt_list; -static LIST_HEAD(,pt_desc) pt_free_list; +static TAILQ_HEAD(,pt_desc) pt_active_list; +static TAILQ_HEAD(,pt_desc) pt_free_list; #define PF_PKT 0x008 /* packet mode */ #define PF_STOPPED 0x010 /* user told stopped */ @@ -162,6 +162,10 @@ static unsigned int max_pts = 1000; +static int free_pts = 0; + +static int active_pts = 0; + static unsigned int nb_allocated; TUNABLE_INT("kern.pts.enable", &use_pts); @@ -173,6 +177,12 @@ SYSCTL_INT(_kern_pts, OID_AUTO, max, CTLFLAG_RW, &max_pts, 0, "max pts"); +SYSCTL_INT(_kern_pts, OID_AUTO, active, CTLFLAG_RD, &active_pts, 0, + "# of active pts"); + +SYSCTL_INT(_kern_pts, OID_AUTO, free, CTLFLAG_RD, &free_pts, 0, + "# of free pts"); + /* * If there's a free pty descriptor in the pty descriptor list, retrieve it. * Otherwise, allocate a new one, initialize it, and hook it up. If there's @@ -182,29 +192,47 @@ pty_new(void) { struct pt_desc *pt; - int nb; mtx_lock(&pt_mtx); if (nb_allocated >= max_pts || nb_allocated == 0xffffff) { mtx_unlock(&pt_mtx); + printf("pty_new(): too many pty allocation(%d)\n", + nb_allocated); return (NULL); } - pt = LIST_FIRST(&pt_free_list); - if (pt) { - LIST_REMOVE(pt, pt_list); - LIST_INSERT_HEAD(&pt_list, pt, pt_list); - mtx_unlock(&pt_mtx); - } else { - nb = next_avail_nb++; + nb_allocated++; + /* first free unused ptc/pty pairs */ + TAILQ_FOREACH(pt, &pt_free_list, pt_list) { + dev_lock(); + if (pt->pt_devc && pt->pt_devc->si_usecount == 0 && + pt->pt_devs && pt->pt_devs->si_usecount == 0) { + dev_unlock(); + destroy_dev(pt->pt_devc); + destroy_dev(pt->pt_devs); + pt->pt_devc = pt->pt_devs = NULL; + } else + dev_unlock(); + } + TAILQ_FOREACH(pt, &pt_free_list, pt_list) { + if (pt->pt_devc == NULL && pt->pt_devs == NULL) { + TAILQ_REMOVE(&pt_free_list, pt, pt_list); + free_pts--; + TAILQ_INSERT_TAIL(&pt_active_list, pt, pt_list); + active_pts++; + mtx_unlock(&pt_mtx); + break; + } + } + if (!pt) { mtx_unlock(&pt_mtx); pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO); mtx_lock(&pt_mtx); - pt->pt_num = nb; - LIST_INSERT_HEAD(&pt_list, pt, pt_list); + pt->pt_num = next_avail_nb++; + TAILQ_INSERT_TAIL(&pt_active_list, pt, pt_list); + active_pts++; mtx_unlock(&pt_mtx); pt->pt_tty = ttyalloc(); } - nb_allocated++; return (pt); } @@ -218,12 +246,16 @@ KASSERT(pt->pt_ptc_open == 0 && pt->pt_pts_open == 0, ("pty_release: pts/%d freed while open\n", pt->pt_num)); +#if 0 KASSERT(pt->pt_devs == NULL && pt->pt_devc == NULL, - ("pty_release: pts/%d freed whith non-null struct cdev\n", pt->pt_num)); + ("pty_release: pts/%d freed while non-null struct cdev\n", pt->pt_num)); +#endif mtx_assert(&pt_mtx, MA_OWNED); nb_allocated--; - LIST_REMOVE(pt, pt_list); - LIST_INSERT_HEAD(&pt_free_list, pt, pt_list); + TAILQ_REMOVE(&pt_active_list, pt, pt_list); + active_pts--; + TAILQ_INSERT_TAIL(&pt_free_list, pt, pt_list); + free_pts++; } /* @@ -238,6 +270,15 @@ if (pt->pt_ptc_open || pt->pt_pts_open) return; +#if 1 + pt->pt_tty->t_dev = NULL; + + hide_dev(pt->pt_devs); + hide_dev(pt->pt_devc); + mtx_lock(&pt_mtx); + pty_release(pt); + mtx_unlock(&pt_mtx); +#else if (bootverbose) printf("destroying pty %d\n", pt->pt_num); @@ -249,6 +290,8 @@ mtx_lock(&pt_mtx); pty_release(pt); mtx_unlock(&pt_mtx); +#endif + return; } /*ARGSUSED*/ @@ -857,9 +900,11 @@ NUM_TO_MINOR(pt->pt_num), cred, UID_ROOT, GID_WHEEL, 0666, "pty/%d", pt->pt_num); - dev_ref(devc); + dev_lock(); + dev_refl(devc); devc->si_drv1 = pt; devc->si_tty = pt->pt_tty; + dev_unlock(); *dev = devc; if (bootverbose) @@ -869,14 +914,28 @@ return; } +#if 0 +static struct cdev *dmyc; +static struct cdev *dmys; +#endif + static void pty_drvinit(void *unused) { mtx_init(&pt_mtx, "pt_mtx", NULL, MTX_DEF); - LIST_INIT(&pt_list); - LIST_INIT(&pt_free_list); + TAILQ_INIT(&pt_active_list); + TAILQ_INIT(&pt_free_list); EVENTHANDLER_REGISTER(dev_clone, pty_clone, 0, 1000); +#if 0 + dmyc = make_dev(&ptc_cdevsw, + MAXMINOR, UID_ROOT, GID_WHEEL, 0666, "pty/ptmx"); + make_dev_alias(dmyc, "ptmx"); + hide_dev(dmyc); + dmys = make_dev(&pts_cdevsw, + MAXMINOR, UID_ROOT, GID_WHEEL, 0666, "pts/d"); + hide_dev(dmys); +#endif } SYSINIT(ptydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,pty_drvinit,NULL) --- ./sys/conf.h-ORIG Sat May 13 04:40:54 2006 +++ ./sys/conf.h Wed Jul 19 15:52:54 2006 @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)conf.h 8.5 (Berkeley) 1/9/95 - * $FreeBSD: src/sys/sys/conf.h,v 1.229 2006/05/12 19:40:54 jmg Exp $ + + $FreeBSD: src/sys/sys/conf.h,v 1.229 2006/05/12 19:40:54 jmg Exp $ */ #ifndef _SYS_CONF_H_ @@ -169,6 +169,7 @@ #define D_MMAP_ANON 0x00100000 /* special treatment in vm_mmap.c */ #define D_PSEUDO 0x00200000 /* make_dev() can return NULL */ #define D_NEEDGIANT 0x00400000 /* driver want Giant */ +#define D_NO_FINI 0x00800000 /* do not call fini_cdevsw() */ /* * Version numbers. @@ -243,6 +244,7 @@ int count_dev(struct cdev *_dev); void destroy_dev(struct cdev *_dev); +void hide_dev(struct cdev *_dev); struct cdevsw *dev_refthread(struct cdev *_dev); void dev_relthread(struct cdev *_dev); void dev_depends(struct cdev *_pdev, struct cdev *_cdev);