summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2004-02-10 01:19:48 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2004-02-10 01:19:48 +0000
commit6887a1953f21ae450e97fe8085e3d6e972a2dda6 (patch)
tree5de9e1ab9422a6352423ec5446e0109a82b59795 /sys
parent178138fbd46c0e9d1ba58e9dbaffc20e2960f1b6 (diff)
Dynamically allocate space for ptys; adapted from NetBSD by beck@
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/tty.c8
-rw-r--r--sys/kern/tty_pty.c176
-rw-r--r--sys/sys/tty.h11
3 files changed, 162 insertions, 33 deletions
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index 10e99856386..3b14f4c01ad 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty.c,v 1.62 2003/10/03 16:44:51 miod Exp $ */
+/* $OpenBSD: tty.c,v 1.63 2004/02/10 01:19:47 millert Exp $ */
/* $NetBSD: tty.c,v 1.68.4.2 1996/06/06 16:04:52 thorpej Exp $ */
/*-
@@ -63,6 +63,8 @@
#include <uvm/uvm_extern.h>
#include <dev/rndvar.h>
+#include "pty.h"
+
static int ttnread(struct tty *);
static void ttyblock(struct tty *);
void ttyunblock(struct tty *);
@@ -2370,7 +2372,11 @@ sysctl_tty(name, namelen, oldp, oldlenp, newp, newlen)
free(ttystats, M_SYSCTL);
return (err);
default:
+#if NPTY > 0
+ return (sysctl_pty(name, namelen, oldp, oldlenp, newp, newlen));
+#else
return (EOPNOTSUPP);
+#endif
}
/* NOTREACHED */
}
diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c
index a77c60c108f..c3dd4252e77 100644
--- a/sys/kern/tty_pty.c
+++ b/sys/kern/tty_pty.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty_pty.c,v 1.16 2003/10/03 16:44:51 miod Exp $ */
+/* $OpenBSD: tty_pty.c,v 1.17 2004/02/10 01:19:47 millert Exp $ */
/* $NetBSD: tty_pty.c,v 1.33.4.1 1996/06/02 09:08:11 mrg Exp $ */
/*
@@ -50,7 +50,9 @@
#include <sys/signalvar.h>
#include <sys/uio.h>
#include <sys/conf.h>
+#include <sys/sysctl.h>
#include <sys/poll.h>
+#include <sys/rwlock.h>
#define BUFSIZ 100 /* Chunk size iomoved to/from user */
@@ -64,8 +66,15 @@ struct pt_softc {
struct selinfo pt_selr, pt_selw;
u_char pt_send;
u_char pt_ucntl;
-} *pt_softc;
-int npty;
+};
+
+#define DEFAULT_NPTYS 8 /* default number of initial ptys */
+#define DEFAULT_MAXPTYS 256 /* default maximum number of ptys */
+
+static struct pt_softc **pt_softc = NULL; /* pty array */
+static int npty = 0; /* size of pty array */
+static int maxptys = DEFAULT_MAXPTYS; /* maximum number of ptys */
+struct rwlock pt_softc_lock = RWLOCK_INITIALIZER; /* for pty array */
#define PF_PKT 0x08 /* packet mode */
#define PF_STOPPED 0x10 /* user told stopped */
@@ -77,26 +86,93 @@ void ptyattach(int);
void ptcwakeup(struct tty *, int);
struct tty *ptytty(dev_t);
void ptsstart(struct tty *);
+int sysctl_pty(int *, u_int, void *, size_t *, void *, size_t);
void filt_ptcrdetach(struct knote *);
int filt_ptcread(struct knote *, long);
void filt_ptcwdetach(struct knote *);
int filt_ptcwrite(struct knote *, long);
+static struct pt_softc **ptyarralloc(int);
+static int check_pty(int);
+
+/*
+ * Allocate and zero array of nelem elements.
+ */
+static struct pt_softc **
+ptyarralloc(int nelem)
+{
+ struct pt_softc **pt;
+
+ pt = malloc(nelem * sizeof(struct pt_softc *), M_DEVBUF, M_WAITOK);
+ bzero(pt, nelem * sizeof(struct pt_softc *));
+ return pt;
+}
+
+/*
+ * Check if the minor is correct and ensure necessary structures
+ * are properly allocated.
+ */
+static int
+check_pty(int minor)
+{
+ struct pt_softc *pti;
+
+ rw_enter_write(&pt_softc_lock, curproc);
+ if (minor >= npty) {
+ struct pt_softc **newpt;
+ int newnpty;
+
+ /* check if the requested pty can be granted */
+ if (minor >= maxptys)
+ goto limit_reached;
+
+ /* grow pty array by powers of two, up to maxptys */
+ for (newnpty = npty; newnpty <= minor; newnpty *= 2)
+ ;
+
+ if (newnpty > maxptys)
+ newnpty = maxptys;
+ newpt = ptyarralloc(newnpty);
+
+ if (maxptys == npty) {
+ goto limit_reached;
+ }
+
+ memcpy(newpt, pt_softc, npty * sizeof(struct pt_softc *));
+ free(pt_softc, M_DEVBUF);
+ pt_softc = newpt;
+ npty = newnpty;
+ }
+
+ /*
+ * If the entry is not yet allocated, allocate one.
+ */
+ if (!pt_softc[minor]) {
+ MALLOC(pti, struct pt_softc *, sizeof(struct pt_softc),
+ M_DEVBUF, M_WAITOK);
+ bzero(pti, sizeof(struct pt_softc));
+ pti->pt_tty = ttymalloc();
+ pt_softc[minor] = pti;
+ }
+ rw_exit_write(&pt_softc_lock);
+ return (0);
+limit_reached:
+ rw_exit_write(&pt_softc_lock);
+ tablefull("pty");
+ return (ENXIO);
+}
+
/*
* Establish n (or default if n is 1) ptys in the system.
*/
void
-ptyattach(n)
- int n;
+ptyattach(int n)
{
-#define DEFAULT_NPTY 32
-
/* maybe should allow 0 => none? */
if (n <= 1)
- n = DEFAULT_NPTY;
- pt_softc = malloc(n * sizeof(struct pt_softc), M_DEVBUF, M_WAITOK);
- bzero(pt_softc, n * sizeof(struct pt_softc));
+ n = DEFAULT_NPTYS;
+ pt_softc = ptyarralloc(n);
npty = n;
}
@@ -111,9 +187,10 @@ ptsopen(dev, flag, devtype, p)
register struct tty *tp;
int error;
- if (minor(dev) >= npty)
- return (ENXIO);
- pti = &pt_softc[minor(dev)];
+ if ((error = check_pty(minor(dev))))
+ return (error);
+
+ pti = pt_softc[minor(dev)];
if (!pti->pt_tty) {
tp = pti->pt_tty = ttymalloc();
} else
@@ -151,7 +228,7 @@ ptsclose(dev, flag, mode, p)
int flag, mode;
struct proc *p;
{
- register struct pt_softc *pti = &pt_softc[minor(dev)];
+ register struct pt_softc *pti = pt_softc[minor(dev)];
register struct tty *tp = pti->pt_tty;
int error;
@@ -168,7 +245,7 @@ ptsread(dev, uio, flag)
int flag;
{
struct proc *p = curproc;
- register struct pt_softc *pti = &pt_softc[minor(dev)];
+ register struct pt_softc *pti = pt_softc[minor(dev)];
register struct tty *tp = pti->pt_tty;
int error = 0;
@@ -222,7 +299,7 @@ ptswrite(dev, uio, flag)
struct uio *uio;
int flag;
{
- register struct pt_softc *pti = &pt_softc[minor(dev)];
+ register struct pt_softc *pti = pt_softc[minor(dev)];
register struct tty *tp = pti->pt_tty;
if (tp->t_oproc == 0)
@@ -238,7 +315,7 @@ void
ptsstart(tp)
struct tty *tp;
{
- register struct pt_softc *pti = &pt_softc[minor(tp->t_dev)];
+ register struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
if (tp->t_state & TS_TTSTOP)
return;
@@ -254,7 +331,7 @@ ptsstop(tp, flush)
register struct tty *tp;
int flush;
{
- struct pt_softc *pti = &pt_softc[minor(tp->t_dev)];
+ struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
int flag;
/* note: FLUSHREAD and FLUSHWRITE already ok */
@@ -279,7 +356,7 @@ ptcwakeup(tp, flag)
struct tty *tp;
int flag;
{
- struct pt_softc *pti = &pt_softc[minor(tp->t_dev)];
+ struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
if (flag & FREAD) {
selwakeup(&pti->pt_selr);
@@ -304,10 +381,12 @@ ptcopen(dev, flag, devtype, p)
{
struct pt_softc *pti;
register struct tty *tp;
+ int error;
+
+ if ((error = check_pty(minor(dev))))
+ return (error);
- if (minor(dev) >= npty)
- return (ENXIO);
- pti = &pt_softc[minor(dev)];
+ pti = pt_softc[minor(dev)];
if (!pti->pt_tty) {
tp = pti->pt_tty = ttymalloc();
} else
@@ -330,7 +409,7 @@ ptcclose(dev, flag, devtype, p)
int flag, devtype;
struct proc *p;
{
- register struct pt_softc *pti = &pt_softc[minor(dev)];
+ register struct pt_softc *pti = pt_softc[minor(dev)];
register struct tty *tp = pti->pt_tty;
(void)(*linesw[tp->t_line].l_modem)(tp, 0);
@@ -345,7 +424,7 @@ ptcread(dev, uio, flag)
struct uio *uio;
int flag;
{
- register struct pt_softc *pti = &pt_softc[minor(dev)];
+ register struct pt_softc *pti = pt_softc[minor(dev)];
register struct tty *tp = pti->pt_tty;
char buf[BUFSIZ];
int error = 0, cc;
@@ -414,7 +493,7 @@ ptcwrite(dev, uio, flag)
register struct uio *uio;
int flag;
{
- register struct pt_softc *pti = &pt_softc[minor(dev)];
+ register struct pt_softc *pti = pt_softc[minor(dev)];
register struct tty *tp = pti->pt_tty;
register u_char *cp = NULL;
register int cc = 0;
@@ -500,7 +579,7 @@ block:
int
ptcpoll(dev_t dev, int events, struct proc *p)
{
- struct pt_softc *pti = &pt_softc[minor(dev)];
+ struct pt_softc *pti = pt_softc[minor(dev)];
struct tty *tp = pti->pt_tty;
int revents = 0, s;
@@ -616,7 +695,7 @@ struct filterops ptcwrite_filtops =
int
ptckqfilter(dev_t dev, struct knote *kn)
{
- struct pt_softc *pti = &pt_softc[minor(dev)];
+ struct pt_softc *pti = pt_softc[minor(dev)];
struct klist *klist;
int s;
@@ -646,7 +725,7 @@ struct tty *
ptytty(dev)
dev_t dev;
{
- register struct pt_softc *pti = &pt_softc[minor(dev)];
+ register struct pt_softc *pti = pt_softc[minor(dev)];
register struct tty *tp = pti->pt_tty;
return (tp);
@@ -661,7 +740,7 @@ ptyioctl(dev, cmd, data, flag, p)
int flag;
struct proc *p;
{
- register struct pt_softc *pti = &pt_softc[minor(dev)];
+ register struct pt_softc *pti = pt_softc[minor(dev)];
register struct tty *tp = pti->pt_tty;
register u_char *cc = tp->t_cc;
int stop, error;
@@ -820,3 +899,42 @@ ptyioctl(dev, cmd, data, flag, p)
}
return (error);
}
+
+/*
+ * Return pty-related information.
+ */
+int
+sysctl_pty(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
+ size_t newlen)
+{
+ int err;
+ int newmax;
+
+ if (namelen != 1)
+ return (ENOTDIR);
+
+ switch (name[0]) {
+ case KERN_TTY_MAXPTYS:
+ if (!newp)
+ return (sysctl_rdint(oldp, oldlenp, newp, maxptys));
+ err = sysctl_int(oldp, oldlenp, newp, newlen, &newmax);
+ if (err)
+ return (err);
+ rw_enter_write(&pt_softc_lock, curproc);
+ /*
+ * We can't set the max lower than the current
+ * active value or to a value bigger than a dev_t minor
+ */
+ if (newmax <= USHRT_MAX && newmax > npty)
+ maxptys = newmax;
+ else
+ err = EINVAL;
+ rw_exit_write(&pt_softc_lock);
+ return(err);
+ case KERN_TTY_NPTYS:
+ return (sysctl_rdint(oldp, oldlenp, newp, npty));
+ default:
+ return (EOPNOTSUPP);
+ }
+ /* NOTREACHED */
+}
diff --git a/sys/sys/tty.h b/sys/sys/tty.h
index 7a4b7efe7b2..d5b2bdf30e0 100644
--- a/sys/sys/tty.h
+++ b/sys/sys/tty.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty.h,v 1.16 2003/10/03 16:44:51 miod Exp $ */
+/* $OpenBSD: tty.h,v 1.17 2004/02/10 01:19:47 millert Exp $ */
/* $NetBSD: tty.h,v 1.30.4.1 1996/06/02 09:08:13 mrg Exp $ */
/*-
@@ -46,8 +46,10 @@
#define KERN_TTY_TKNOUT 2 /* quad: output chars */
#define KERN_TTY_TKRAWCC 3 /* quad: input chars, raw mode */
#define KERN_TTY_TKCANCC 4 /* quad: input char, cooked mode */
-#define KERN_TTY_INFO 5
-#define KERN_TTY_MAXID 6
+#define KERN_TTY_INFO 5 /* struct: tty stats */
+#define KERN_TTY_MAXPTYS 6 /* int: max ptys */
+#define KERN_TTY_NPTYS 7 /* int: number of allocated ptys */
+#define KERN_TTY_MAXID 8
#define CTL_KERN_TTY_NAMES { \
{ 0, 0 }, \
@@ -56,6 +58,8 @@
{ "tk_rawcc", CTLTYPE_QUAD }, \
{ "tk_cancc", CTLTYPE_QUAD }, \
{ "ttyinfo", CTLTYPE_STRUCT }, \
+ { "maxptys", CTLTYPE_INT }, \
+ { "nptys", CTLTYPE_INT }, \
}
/*
@@ -227,6 +231,7 @@ extern struct ttychars ttydefaults;
extern char ttyin[], ttyout[], ttopen[], ttclos[], ttybg[], ttybuf[];
int sysctl_tty(int *, u_int, void *, size_t *, void *, size_t);
+int sysctl_pty(int *, u_int, void *, size_t *, void *, size_t);
int b_to_q(u_char *cp, int cc, struct clist *q);
void catq(struct clist *from, struct clist *to);