summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/tty.c32
-rw-r--r--sys/kern/tty_inq.c65
-rw-r--r--sys/kern/tty_outq.c71
-rw-r--r--sys/sys/ttyqueue.h18
4 files changed, 80 insertions, 106 deletions
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index df781e8d033b..1c3791663d08 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -112,23 +112,6 @@ tty_watermarks(struct tty *tp)
tp->t_outlow = (ttyoutq_getsize(&tp->t_outq) * 9) / 10;
}
-static void
-tty_freebuffers(struct tty *tp)
-{
-
- /* Destroy input buffers. */
- ttyinq_flush(&tp->t_inq);
- ttyinq_setsize(&tp->t_inq, NULL, 0);
- MPASS(ttyinq_getsize(&tp->t_inq) == 0);
- tp->t_inlow = 0;
-
- /* Destroy output buffers. */
- ttyoutq_flush(&tp->t_outq);
- ttyoutq_setsize(&tp->t_outq, NULL, 0);
- MPASS(ttyoutq_getsize(&tp->t_outq) == 0);
- tp->t_outlow = 0;
-}
-
static int
tty_drain(struct tty *tp)
{
@@ -199,7 +182,10 @@ ttydev_leave(struct tty *tp)
ttydisc_close(tp);
/* Destroy associated buffers already. */
- tty_freebuffers(tp);
+ ttyinq_free(&tp->t_inq);
+ tp->t_inlow = 0;
+ ttyoutq_free(&tp->t_outq);
+ tp->t_outlow = 0;
knlist_clear(&tp->t_inpoll.si_note, 1);
knlist_clear(&tp->t_outpoll.si_note, 1);
@@ -875,8 +861,8 @@ tty_alloc(struct ttydevsw *tsw, void *sc, struct mtx *mutex)
cv_init(&tp->t_bgwait, "tty background");
cv_init(&tp->t_dcdwait, "tty dcd");
- TAILQ_INIT(&tp->t_inq.ti_list);
- STAILQ_INIT(&tp->t_outq.to_list);
+ ttyinq_init(&tp->t_inq);
+ ttyoutq_init(&tp->t_outq);
/* Allow drivers to use a custom mutex to lock the TTY. */
if (mutex != NULL) {
@@ -907,6 +893,10 @@ tty_dealloc(void *arg)
tty_list_count--;
sx_xunlock(&tty_list_sx);
+ /* Make sure we haven't leaked buffers. */
+ MPASS(ttyinq_getsize(&tp->t_inq) == 0);
+ MPASS(ttyoutq_getsize(&tp->t_outq) == 0);
+
knlist_destroy(&tp->t_inpoll.si_note);
knlist_destroy(&tp->t_outpoll.si_note);
@@ -935,8 +925,6 @@ tty_rel_free(struct tty *tp)
return;
}
- tty_freebuffers(tp);
-
/* TTY can be deallocated. */
dev = tp->t_dev;
tp->t_dev = NULL;
diff --git a/sys/kern/tty_inq.c b/sys/kern/tty_inq.c
index b93dde6fe83c..fc99729fe4ec 100644
--- a/sys/kern/tty_inq.c
+++ b/sys/kern/tty_inq.c
@@ -89,12 +89,11 @@ static uma_zone_t ttyinq_zone;
void
ttyinq_setsize(struct ttyinq *ti, struct tty *tp, size_t size)
{
- unsigned int nblocks;
struct ttyinq_block *tib;
- nblocks = howmany(size, TTYINQ_DATASIZE);
+ ti->ti_quota = howmany(size, TTYINQ_DATASIZE);
- while (nblocks > ti->ti_nblocks) {
+ while (ti->ti_quota > ti->ti_nblocks) {
/*
* List is getting bigger.
* Add new blocks to the tail of the list.
@@ -109,36 +108,26 @@ ttyinq_setsize(struct ttyinq *ti, struct tty *tp, size_t size)
tib = uma_zalloc(ttyinq_zone, M_WAITOK);
tty_lock(tp);
- if (tty_gone(tp))
- return;
-
TAILQ_INSERT_TAIL(&ti->ti_list, tib, tib_list);
ti->ti_nblocks++;
}
+}
- while (nblocks < ti->ti_nblocks) {
- /*
- * List is getting smaller. Remove unused blocks at the
- * end. This means we cannot guarantee this routine
- * shrinks buffers properly, when we need to reclaim
- * more space than there is available.
- *
- * XXX TODO: Two solutions here:
- * - Throw data away
- * - Temporarily hit the watermark until enough data has
- * been flushed, so we can remove the blocks.
- */
+void
+ttyinq_free(struct ttyinq *ti)
+{
+ struct ttyinq_block *tib;
+
+ ttyinq_flush(ti);
+ ti->ti_quota = 0;
- if (ti->ti_end == 0)
- tib = TAILQ_FIRST(&ti->ti_list);
- else
- tib = TAILQ_NEXT(ti->ti_lastblock, tib_list);
- if (tib == NULL)
- break;
+ while ((tib = TAILQ_FIRST(&ti->ti_list)) != NULL) {
TAILQ_REMOVE(&ti->ti_list, tib, tib_list);
uma_zfree(ttyinq_zone, tib);
ti->ti_nblocks--;
}
+
+ MPASS(ti->ti_nblocks == 0);
}
int
@@ -217,21 +206,13 @@ ttyinq_read_uio(struct ttyinq *ti, struct tty *tp, struct uio *uio,
clen - flen, uio);
tty_lock(tp);
- if (tty_gone(tp)) {
- /* Something went bad - discard this block. */
+ /* Block can now be readded to the list. */
+ if (ti->ti_quota <= ti->ti_nblocks) {
uma_zfree(ttyinq_zone, tib);
- return (ENXIO);
+ } else {
+ TAILQ_INSERT_TAIL(&ti->ti_list, tib, tib_list);
+ ti->ti_nblocks++;
}
- /* Block can now be readded to the list. */
- /*
- * XXX: we could remove the blocks here when the
- * queue was shrunk, but still in use. See
- * ttyinq_setsize().
- */
- TAILQ_INSERT_TAIL(&ti->ti_list, tib, tib_list);
- ti->ti_nblocks++;
- if (error != 0)
- return (error);
} else {
char ob[TTYINQ_DATASIZE - 1];
atomic_add_long(&ttyinq_nslow, 1);
@@ -247,12 +228,12 @@ ttyinq_read_uio(struct ttyinq *ti, struct tty *tp, struct uio *uio,
tty_unlock(tp);
error = uiomove(ob, clen - flen, uio);
tty_lock(tp);
-
- if (error != 0)
- return (error);
- if (tty_gone(tp))
- return (ENXIO);
}
+
+ if (error != 0)
+ return (error);
+ if (tty_gone(tp))
+ return (ENXIO);
}
return (0);
diff --git a/sys/kern/tty_outq.c b/sys/kern/tty_outq.c
index 30df4eb8bdde..d55ec1509af9 100644
--- a/sys/kern/tty_outq.c
+++ b/sys/kern/tty_outq.c
@@ -78,12 +78,11 @@ ttyoutq_flush(struct ttyoutq *to)
void
ttyoutq_setsize(struct ttyoutq *to, struct tty *tp, size_t size)
{
- unsigned int nblocks;
struct ttyoutq_block *tob;
- nblocks = howmany(size, TTYOUTQ_DATASIZE);
+ to->to_quota = howmany(size, TTYOUTQ_DATASIZE);
- while (nblocks > to->to_nblocks) {
+ while (to->to_quota > to->to_nblocks) {
/*
* List is getting bigger.
* Add new blocks to the tail of the list.
@@ -98,40 +97,26 @@ ttyoutq_setsize(struct ttyoutq *to, struct tty *tp, size_t size)
tob = uma_zalloc(ttyoutq_zone, M_WAITOK);
tty_lock(tp);
- if (tty_gone(tp))
- return;
-
STAILQ_INSERT_TAIL(&to->to_list, tob, tob_list);
to->to_nblocks++;
}
+}
- while (nblocks < to->to_nblocks) {
- /*
- * List is getting smaller. Remove unused blocks at the
- * end. This means we cannot guarantee this routine
- * shrinks buffers properly, when we need to reclaim
- * more space than there is available.
- *
- * XXX TODO: Two solutions here:
- * - Throw data away
- * - Temporarily hit the watermark until enough data has
- * been flushed, so we can remove the blocks.
- */
+void
+ttyoutq_free(struct ttyoutq *to)
+{
+ struct ttyoutq_block *tob;
+
+ ttyoutq_flush(to);
+ to->to_quota = 0;
- if (to->to_end == 0) {
- tob = STAILQ_FIRST(&to->to_list);
- if (tob == NULL)
- break;
- STAILQ_REMOVE_HEAD(&to->to_list, tob_list);
- } else {
- tob = STAILQ_NEXT(to->to_lastblock, tob_list);
- if (tob == NULL)
- break;
- STAILQ_REMOVE_NEXT(&to->to_list, to->to_lastblock, tob_list);
- }
+ while ((tob = STAILQ_FIRST(&to->to_list)) != NULL) {
+ STAILQ_REMOVE_HEAD(&to->to_list, tob_list);
uma_zfree(ttyoutq_zone, tob);
to->to_nblocks--;
}
+
+ MPASS(to->to_nblocks == 0);
}
size_t
@@ -164,7 +149,12 @@ ttyoutq_read(struct ttyoutq *to, void *buf, size_t len)
if (cend == TTYOUTQ_DATASIZE || cend == to->to_end) {
/* Read the block until the end. */
STAILQ_REMOVE_HEAD(&to->to_list, tob_list);
- STAILQ_INSERT_TAIL(&to->to_list, tob, tob_list);
+ if (to->to_quota < to->to_nblocks) {
+ uma_zfree(ttyoutq_zone, tob);
+ to->to_nblocks--;
+ } else {
+ STAILQ_INSERT_TAIL(&to->to_list, tob, tob_list);
+ }
to->to_begin = 0;
if (to->to_end <= TTYOUTQ_DATASIZE) {
to->to_end = 0;
@@ -251,15 +241,12 @@ ttyoutq_read_uio(struct ttyoutq *to, struct tty *tp, struct uio *uio)
tty_lock(tp);
/* Block can now be readded to the list. */
- /*
- * XXX: we could remove the blocks here when the
- * queue was shrunk, but still in use. See
- * ttyoutq_setsize().
- */
- STAILQ_INSERT_TAIL(&to->to_list, tob, tob_list);
- to->to_nblocks++;
- if (error != 0)
- return (error);
+ if (to->to_quota <= to->to_nblocks) {
+ uma_zfree(ttyoutq_zone, tob);
+ } else {
+ STAILQ_INSERT_TAIL(&to->to_list, tob, tob_list);
+ to->to_nblocks++;
+ }
} else {
char ob[TTYOUTQ_DATASIZE - 1];
atomic_add_long(&ttyoutq_nslow, 1);
@@ -275,10 +262,10 @@ ttyoutq_read_uio(struct ttyoutq *to, struct tty *tp, struct uio *uio)
tty_unlock(tp);
error = uiomove(ob, clen, uio);
tty_lock(tp);
-
- if (error != 0)
- return (error);
}
+
+ if (error != 0)
+ return (error);
}
return (0);
diff --git a/sys/sys/ttyqueue.h b/sys/sys/ttyqueue.h
index 3e72fefb0c97..24e1187636ea 100644
--- a/sys/sys/ttyqueue.h
+++ b/sys/sys/ttyqueue.h
@@ -52,6 +52,7 @@ struct ttyinq {
unsigned int ti_reprint;
unsigned int ti_end;
unsigned int ti_nblocks;
+ unsigned int ti_quota;
};
#define TTYINQ_DATASIZE 128
@@ -62,12 +63,14 @@ struct ttyoutq {
unsigned int to_begin;
unsigned int to_end;
unsigned int to_nblocks;
+ unsigned int to_quota;
};
#define TTYOUTQ_DATASIZE (256 - sizeof(STAILQ_ENTRY(ttyoutq_block)))
#ifdef _KERNEL
/* Input queue handling routines. */
void ttyinq_setsize(struct ttyinq *, struct tty *, size_t);
+void ttyinq_free(struct ttyinq *);
int ttyinq_read_uio(struct ttyinq *, struct tty *, struct uio *,
size_t, size_t);
size_t ttyinq_write(struct ttyinq *, const void *, size_t, int);
@@ -80,6 +83,13 @@ void ttyinq_unputchar(struct ttyinq *);
void ttyinq_reprintpos_set(struct ttyinq *);
void ttyinq_reprintpos_reset(struct ttyinq *);
+static __inline void
+ttyinq_init(struct ttyinq *ti)
+{
+
+ TAILQ_INIT(&ti->ti_list);
+}
+
static __inline size_t
ttyinq_getsize(struct ttyinq *ti)
{
@@ -124,11 +134,19 @@ void ttyinq_line_iterate_from_reprintpos(struct ttyinq *,
/* Output queue handling routines. */
void ttyoutq_flush(struct ttyoutq *);
void ttyoutq_setsize(struct ttyoutq *, struct tty *, size_t);
+void ttyoutq_free(struct ttyoutq *);
size_t ttyoutq_read(struct ttyoutq *, void *, size_t);
int ttyoutq_read_uio(struct ttyoutq *, struct tty *, struct uio *);
size_t ttyoutq_write(struct ttyoutq *, const void *, size_t);
int ttyoutq_write_nofrag(struct ttyoutq *, const void *, size_t);
+static __inline void
+ttyoutq_init(struct ttyoutq *to)
+{
+
+ STAILQ_INIT(&to->to_list);
+}
+
static __inline size_t
ttyoutq_getsize(struct ttyoutq *to)
{