kern/99758: chown/chmod pty slave side in kernel
Atsuo Ohki
ohki at gssm.otsuka.tsukuba.ac.jp
Wed Jul 19 07:20:19 UTC 2006
The following reply was made to PR kern/99758; it has been noted by GNATS.
From: Atsuo Ohki <ohki at gssm.otsuka.tsukuba.ac.jp>
To: "Wojciech A. Koszek" <wkoszek at FreeBSD.org>,
freebsd-gnats-submit at FreeBSD.org, freebsd-bugs at 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 <fs/devfs/devfs.h>
#include <fs/devfs/devfs_int.h>
+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 <sys/cdefs.h>
-__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 <sys/param.h>
#include <sys/kernel.h>
@@ -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 <sys/cdefs.h>
-__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);
More information about the freebsd-bugs
mailing list