From 227434f8986c3827a1faedd1feb437acd6285315 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 3 Jan 2013 15:53:01 +0100 Subject: TTY: switch tty_buffer_request_room to tty_port Now, we start converting tty buffer functions to actually use tty_port. This will allow us to get rid of the need of tty pointer in many call sites. Only tty_port will be needed and hence no more tty_port_tty_get calls in those paths. Here we start with tty_buffer_request_room. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/tty/tty_buffer.c') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 45d916198f78..f897332fb4ee 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -235,7 +235,7 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size) /** * tty_buffer_request_room - grow tty buffer if needed - * @tty: tty structure + * @port: tty port structure * @size: size desired * * Make at least size bytes of linear space available for the tty @@ -243,9 +243,8 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size) * * Locking: Takes port->buf.lock */ -int tty_buffer_request_room(struct tty_struct *tty, size_t size) +int tty_buffer_request_room(struct tty_port *port, size_t size) { - struct tty_port *port = tty->port; unsigned long flags; int length; -- cgit v1.2.3 From 2f69335710884ae6112fc8196ebe29b5cda7b79b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 3 Jan 2013 15:53:02 +0100 Subject: TTY: convert more flipping functions Now, we start converting tty buffer functions to actually use tty_port. This will allow us to get rid of the need of tty pointer in many call sites. Only tty_port will be needed and hence no more tty_port_tty_get calls in those paths. Now 4 string flipping ones are on turn: * tty_insert_flip_string_flags * tty_insert_flip_string_fixed_flag * tty_prepare_flip_string * tty_prepare_flip_string_flags Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/tty/tty_buffer.c') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index f897332fb4ee..31873e42602a 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -257,7 +257,7 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room); /** * tty_insert_flip_string_fixed_flag - Add characters to the tty buffer - * @tty: tty structure + * @port: tty port * @chars: characters * @flag: flag value for each character * @size: size @@ -268,10 +268,10 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room); * Locking: Called functions may take port->buf.lock */ -int tty_insert_flip_string_fixed_flag(struct tty_struct *tty, +int tty_insert_flip_string_fixed_flag(struct tty_port *port, const unsigned char *chars, char flag, size_t size) { - struct tty_bufhead *buf = &tty->port->buf; + struct tty_bufhead *buf = &port->buf; int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); @@ -280,7 +280,7 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty, struct tty_buffer *tb; spin_lock_irqsave(&buf->lock, flags); - space = __tty_buffer_request_room(tty->port, goal); + space = __tty_buffer_request_room(port, goal); tb = buf->tail; /* If there is no space then tb may be NULL */ if (unlikely(space == 0)) { @@ -302,7 +302,7 @@ EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag); /** * tty_insert_flip_string_flags - Add characters to the tty buffer - * @tty: tty structure + * @port: tty port * @chars: characters * @flags: flag bytes * @size: size @@ -314,10 +314,10 @@ EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag); * Locking: Called functions may take port->buf.lock */ -int tty_insert_flip_string_flags(struct tty_struct *tty, +int tty_insert_flip_string_flags(struct tty_port *port, const unsigned char *chars, const char *flags, size_t size) { - struct tty_bufhead *buf = &tty->port->buf; + struct tty_bufhead *buf = &port->buf; int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); @@ -326,7 +326,7 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, struct tty_buffer *tb; spin_lock_irqsave(&buf->lock, __flags); - space = __tty_buffer_request_room(tty->port, goal); + space = __tty_buffer_request_room(port, goal); tb = buf->tail; /* If there is no space then tb may be NULL */ if (unlikely(space == 0)) { @@ -376,7 +376,7 @@ EXPORT_SYMBOL(tty_schedule_flip); /** * tty_prepare_flip_string - make room for characters - * @tty: tty + * @port: tty port * @chars: return pointer for character write area * @size: desired size * @@ -389,16 +389,16 @@ EXPORT_SYMBOL(tty_schedule_flip); * Locking: May call functions taking port->buf.lock */ -int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, +int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, size_t size) { - struct tty_bufhead *buf = &tty->port->buf; + struct tty_bufhead *buf = &port->buf; int space; unsigned long flags; struct tty_buffer *tb; spin_lock_irqsave(&buf->lock, flags); - space = __tty_buffer_request_room(tty->port, size); + space = __tty_buffer_request_room(port, size); tb = buf->tail; if (likely(space)) { @@ -413,7 +413,7 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); /** * tty_prepare_flip_string_flags - make room for characters - * @tty: tty + * @port: tty port * @chars: return pointer for character write area * @flags: return pointer for status flag write area * @size: desired size @@ -427,16 +427,16 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); * Locking: May call functions taking port->buf.lock */ -int tty_prepare_flip_string_flags(struct tty_struct *tty, +int tty_prepare_flip_string_flags(struct tty_port *port, unsigned char **chars, char **flags, size_t size) { - struct tty_bufhead *buf = &tty->port->buf; + struct tty_bufhead *buf = &port->buf; int space; unsigned long __flags; struct tty_buffer *tb; spin_lock_irqsave(&buf->lock, __flags); - space = __tty_buffer_request_room(tty->port, size); + space = __tty_buffer_request_room(port, size); tb = buf->tail; if (likely(space)) { -- cgit v1.2.3 From d6c53c0e9bd0a83f9f9ddbc9fd80141a54d83896 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 3 Jan 2013 15:53:05 +0100 Subject: TTY: move low_latency to tty_port One point is to have less places where we actually need tty pointer. The other is that low_latency is bound to buffer processing and buffers are now in tty_port. So it makes sense to move low_latency to tty_port too. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/tty/tty_buffer.c') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 31873e42602a..1bfe97a8e2eb 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -364,7 +364,7 @@ void tty_schedule_flip(struct tty_struct *tty) { struct tty_bufhead *buf = &tty->port->buf; unsigned long flags; - WARN_ON(tty->low_latency); + WARN_ON(tty->port->low_latency); spin_lock_irqsave(&buf->lock, flags); if (buf->tail != NULL) @@ -538,7 +538,7 @@ static void flush_to_ldisc(struct work_struct *work) */ void tty_flush_to_ldisc(struct tty_struct *tty) { - if (!tty->low_latency) + if (!tty->port->low_latency) flush_work(&tty->port->buf.work); } @@ -547,7 +547,8 @@ void tty_flush_to_ldisc(struct tty_struct *tty) * @tty: tty to push * * Queue a push of the terminal flip buffers to the line discipline. This - * function must not be called from IRQ context if tty->low_latency is set. + * function must not be called from IRQ context if port->low_latency is + * set. * * In the event of the queue being busy for flipping the work will be * held off and retried later. @@ -565,7 +566,7 @@ void tty_flip_buffer_push(struct tty_struct *tty) buf->tail->commit = buf->tail->used; spin_unlock_irqrestore(&buf->lock, flags); - if (tty->low_latency) + if (tty->port->low_latency) flush_to_ldisc(&buf->work); else schedule_work(&buf->work); -- cgit v1.2.3 From 2e124b4a390ca85325fae75764bef92f0547fa25 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 3 Jan 2013 15:53:06 +0100 Subject: TTY: switch tty_flip_buffer_push Now, we start converting tty buffer functions to actually use tty_port. This will allow us to get rid of the need of tty in many call sites. Only tty_port will needed and hence no more tty_port_tty_get in those paths. Now, the one where most of tty_port_tty_get gets removed: tty_flip_buffer_push. IOW we also closed all the races in drivers not using tty_port_tty_get at all yet. Also we move tty_flip_buffer_push declaration from include/linux/tty.h to include/linux/tty_flip.h to all others while we are changing it anyway. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/tty/tty_buffer.c') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 1bfe97a8e2eb..b6efacadf23b 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -544,7 +544,7 @@ void tty_flush_to_ldisc(struct tty_struct *tty) /** * tty_flip_buffer_push - terminal - * @tty: tty to push + * @port: tty port to push * * Queue a push of the terminal flip buffers to the line discipline. This * function must not be called from IRQ context if port->low_latency is @@ -556,9 +556,9 @@ void tty_flush_to_ldisc(struct tty_struct *tty) * Locking: tty buffer lock. Driver locks in low latency mode. */ -void tty_flip_buffer_push(struct tty_struct *tty) +void tty_flip_buffer_push(struct tty_port *port) { - struct tty_bufhead *buf = &tty->port->buf; + struct tty_bufhead *buf = &port->buf; unsigned long flags; spin_lock_irqsave(&buf->lock, flags); @@ -566,7 +566,7 @@ void tty_flip_buffer_push(struct tty_struct *tty) buf->tail->commit = buf->tail->used; spin_unlock_irqrestore(&buf->lock, flags); - if (tty->port->low_latency) + if (port->low_latency) flush_to_ldisc(&buf->work); else schedule_work(&buf->work); -- cgit v1.2.3 From 6732c8bb8671acbdac6cdc93dd72ddd581dd5e25 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 3 Jan 2013 15:53:07 +0100 Subject: TTY: switch tty_schedule_flip Now, we start converting tty buffer functions to actually use tty_port. This will allow us to get rid of the need of tty in many call sites. Only tty_port will needed and hence no more tty_port_tty_get in those paths. This is the last one: tty_schedule_flip Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/tty/tty_buffer.c') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index b6efacadf23b..d6969f6e4c43 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -349,7 +349,7 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags); /** * tty_schedule_flip - push characters to ldisc - * @tty: tty to push from + * @port: tty port to push from * * Takes any pending buffers and transfers their ownership to the * ldisc side of the queue. It then schedules those characters for @@ -360,11 +360,11 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags); * Locking: Takes port->buf.lock */ -void tty_schedule_flip(struct tty_struct *tty) +void tty_schedule_flip(struct tty_port *port) { - struct tty_bufhead *buf = &tty->port->buf; + struct tty_bufhead *buf = &port->buf; unsigned long flags; - WARN_ON(tty->port->low_latency); + WARN_ON(port->low_latency); spin_lock_irqsave(&buf->lock, flags); if (buf->tail != NULL) -- cgit v1.2.3 From 64325a3be08d364a62ee8f84b2cf86934bc2544a Mon Sep 17 00:00:00 2001 From: Ilya Zykov Date: Sat, 19 Jan 2013 18:16:20 +0400 Subject: tty: Correct tty buffer flush. The root of problem is carelessly zeroing pointer(in function __tty_buffer_flush()), when another thread can use it. It can be cause of "NULL pointer dereference". Main idea of the patch, this is never free last (struct tty_buffer) in the active buffer. Only flush the data for ldisc(buf->head->read = buf->head->commit). At that moment driver can collect(write) data in buffer without conflict. It is repeat behavior of flush_to_ldisc(), only without feeding data to ldisc. Also revert: commit c56a00a165712fd73081f40044b1e64407bb1875 tty: hold lock across tty buffer finding and buffer filling In order to delete the unneeded locks any more. Signed-off-by: Ilya Zykov CC: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 92 ++++++++++++------------------------------------ 1 file changed, 22 insertions(+), 70 deletions(-) (limited to 'drivers/tty/tty_buffer.c') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index d6969f6e4c43..61ec4ddf47e0 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -119,11 +119,14 @@ static void __tty_buffer_flush(struct tty_port *port) struct tty_bufhead *buf = &port->buf; struct tty_buffer *thead; - while ((thead = buf->head) != NULL) { - buf->head = thead->next; - tty_buffer_free(port, thead); + if (unlikely(buf->head == NULL)) + return; + while ((thead = buf->head->next) != NULL) { + tty_buffer_free(port, buf->head); + buf->head = thead; } - buf->tail = NULL; + WARN_ON(buf->head != buf->tail); + buf->head->read = buf->head->commit; } /** @@ -194,19 +197,22 @@ static struct tty_buffer *tty_buffer_find(struct tty_port *port, size_t size) have queued and recycle that ? */ } /** - * __tty_buffer_request_room - grow tty buffer if needed + * tty_buffer_request_room - grow tty buffer if needed * @tty: tty structure * @size: size desired * * Make at least size bytes of linear space available for the tty * buffer. If we fail return the size we managed to find. - * Locking: Caller must hold port->buf.lock + * + * Locking: Takes port->buf.lock */ -static int __tty_buffer_request_room(struct tty_port *port, size_t size) +int tty_buffer_request_room(struct tty_port *port, size_t size) { struct tty_bufhead *buf = &port->buf; struct tty_buffer *b, *n; int left; + unsigned long flags; + spin_lock_irqsave(&buf->lock, flags); /* OPTIMISATION: We could keep a per tty "zero" sized buffer to remove this conditional if its worth it. This would be invisible to the callers */ @@ -228,31 +234,9 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size) } else size = left; } - + spin_unlock_irqrestore(&buf->lock, flags); return size; } - - -/** - * tty_buffer_request_room - grow tty buffer if needed - * @port: tty port structure - * @size: size desired - * - * Make at least size bytes of linear space available for the tty - * buffer. If we fail return the size we managed to find. - * - * Locking: Takes port->buf.lock - */ -int tty_buffer_request_room(struct tty_port *port, size_t size) -{ - unsigned long flags; - int length; - - spin_lock_irqsave(&port->buf.lock, flags); - length = __tty_buffer_request_room(port, size); - spin_unlock_irqrestore(&port->buf.lock, flags); - return length; -} EXPORT_SYMBOL_GPL(tty_buffer_request_room); /** @@ -271,26 +255,18 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room); int tty_insert_flip_string_fixed_flag(struct tty_port *port, const unsigned char *chars, char flag, size_t size) { - struct tty_bufhead *buf = &port->buf; int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); - int space; - unsigned long flags; - struct tty_buffer *tb; - - spin_lock_irqsave(&buf->lock, flags); - space = __tty_buffer_request_room(port, goal); - tb = buf->tail; + int space = tty_buffer_request_room(port, goal); + struct tty_buffer *tb = port->buf.tail; /* If there is no space then tb may be NULL */ if (unlikely(space == 0)) { - spin_unlock_irqrestore(&buf->lock, flags); break; } memcpy(tb->char_buf_ptr + tb->used, chars, space); memset(tb->flag_buf_ptr + tb->used, flag, space); tb->used += space; - spin_unlock_irqrestore(&buf->lock, flags); copied += space; chars += space; /* There is a small chance that we need to split the data over @@ -317,26 +293,18 @@ EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag); int tty_insert_flip_string_flags(struct tty_port *port, const unsigned char *chars, const char *flags, size_t size) { - struct tty_bufhead *buf = &port->buf; int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); - int space; - unsigned long __flags; - struct tty_buffer *tb; - - spin_lock_irqsave(&buf->lock, __flags); - space = __tty_buffer_request_room(port, goal); - tb = buf->tail; + int space = tty_buffer_request_room(port, goal); + struct tty_buffer *tb = port->buf.tail; /* If there is no space then tb may be NULL */ if (unlikely(space == 0)) { - spin_unlock_irqrestore(&buf->lock, __flags); break; } memcpy(tb->char_buf_ptr + tb->used, chars, space); memcpy(tb->flag_buf_ptr + tb->used, flags, space); tb->used += space; - spin_unlock_irqrestore(&buf->lock, __flags); copied += space; chars += space; flags += space; @@ -392,21 +360,13 @@ EXPORT_SYMBOL(tty_schedule_flip); int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, size_t size) { - struct tty_bufhead *buf = &port->buf; - int space; - unsigned long flags; - struct tty_buffer *tb; - - spin_lock_irqsave(&buf->lock, flags); - space = __tty_buffer_request_room(port, size); - - tb = buf->tail; + int space = tty_buffer_request_room(port, size); if (likely(space)) { + struct tty_buffer *tb = port->buf.tail; *chars = tb->char_buf_ptr + tb->used; memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); tb->used += space; } - spin_unlock_irqrestore(&buf->lock, flags); return space; } EXPORT_SYMBOL_GPL(tty_prepare_flip_string); @@ -430,21 +390,13 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); int tty_prepare_flip_string_flags(struct tty_port *port, unsigned char **chars, char **flags, size_t size) { - struct tty_bufhead *buf = &port->buf; - int space; - unsigned long __flags; - struct tty_buffer *tb; - - spin_lock_irqsave(&buf->lock, __flags); - space = __tty_buffer_request_room(port, size); - - tb = buf->tail; + int space = tty_buffer_request_room(port, size); if (likely(space)) { + struct tty_buffer *tb = port->buf.tail; *chars = tb->char_buf_ptr + tb->used; *flags = tb->flag_buf_ptr + tb->used; tb->used += space; } - spin_unlock_irqrestore(&buf->lock, __flags); return space; } EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); -- cgit v1.2.3 From 593fb1ae457aab28b392ac114f6e3358788da985 Mon Sep 17 00:00:00 2001 From: George Spelvin Date: Tue, 12 Feb 2013 02:00:43 -0500 Subject: pps: Move timestamp read into PPS code proper The PPS (Pulse-Per-Second) line discipline has developed a number of unhealthy attachments to core tty data and functions, ultimately leading to its breakage. The previous patches fixed the crashing. This one reduces coupling further by eliminating the timestamp parameter from the dcd_change ldisc method. This reduces header file linkage and makes the extension more generic, and the timestamp read is delayed only slightly, from just before the ldisc->ops->dcd_change method call to just after. Fix attendant build breakage in drivers/tty/n_tty.c drivers/tty/tty_buffer.c drivers/staging/speakup/selection.c drivers/staging/dgrp/dgrp_*.c Cc: William Hubbs Cc: Chris Brannon Cc: Kirk Reiser Cc: Samuel Thibault Signed-off-by: Peter Hurley Signed-off-by: George Spelvin Acked-by: Rodolfo Giometti Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/tty/tty_buffer.c') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 61ec4ddf47e0..bb119934e76c 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -16,6 +16,7 @@ #include #include #include +#include /** * tty_buffer_free_all - free buffers used by a tty -- cgit v1.2.3 From 34dcfb8479ab3c3669561eb9279284cb0eda2572 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 27 Feb 2013 22:30:24 +0100 Subject: TTY: disable debugging warning We added a warning to flush_to_ldisc to report cases when it is called with a NULL tty. It was for debugging purposes and it lead to a patchset from Peter Hurley. The patchset however did not make it to 3.9, so disable the warning now to not disturb people. We can re-add it when the series is in and we are hunting for another bugs. Reported-by: David Miller Cc: stable # 3.8 Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty/tty_buffer.c') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index bb119934e76c..578aa7594b11 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -425,7 +425,7 @@ static void flush_to_ldisc(struct work_struct *work) struct tty_ldisc *disc; tty = port->itty; - if (WARN_RATELIMIT(tty == NULL, "tty is NULL\n")) + if (tty == NULL) return; disc = tty_ldisc_ref(tty); -- cgit v1.2.3