aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2014-05-02 10:56:11 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-05-03 18:14:28 -0400
commit5fbf1a65dd53ef313783c34a0e93a6e29def6136 (patch)
treee4631779d08d03cd27d0b4a5546e4a5768a77ead
parent501fed45b7e8836ee9373f4d31e2d85e3db6103a (diff)
Revert "tty: Fix race condition between __tty_buffer_request_room and flush_to_ldisc"
This reverts commit 6a20dbd6caa2358716136144bf524331d70b1e03. Although the commit correctly identifies an unsafe race condition between __tty_buffer_request_room() and flush_to_ldisc(), the commit fixes the race with an unnecessary spinlock in a lockless algorithm. The follow-on commit, "tty: Fix lockless tty buffer race" fixes the race locklessly. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/tty_buffer.c16
-rw-r--r--include/linux/tty.h1
2 files changed, 2 insertions, 15 deletions
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index f1d30f6945af..8ebd9f88a6f6 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -255,16 +255,11 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size,
255 if (change || left < size) { 255 if (change || left < size) {
256 /* This is the slow path - looking for new buffers to use */ 256 /* This is the slow path - looking for new buffers to use */
257 if ((n = tty_buffer_alloc(port, size)) != NULL) { 257 if ((n = tty_buffer_alloc(port, size)) != NULL) {
258 unsigned long iflags;
259
260 n->flags = flags; 258 n->flags = flags;
261 buf->tail = n; 259 buf->tail = n;
262
263 spin_lock_irqsave(&buf->flush_lock, iflags);
264 b->commit = b->used; 260 b->commit = b->used;
261 smp_mb();
265 b->next = n; 262 b->next = n;
266 spin_unlock_irqrestore(&buf->flush_lock, iflags);
267
268 } else if (change) 263 } else if (change)
269 size = 0; 264 size = 0;
270 else 265 else
@@ -448,7 +443,6 @@ static void flush_to_ldisc(struct work_struct *work)
448 mutex_lock(&buf->lock); 443 mutex_lock(&buf->lock);
449 444
450 while (1) { 445 while (1) {
451 unsigned long flags;
452 struct tty_buffer *head = buf->head; 446 struct tty_buffer *head = buf->head;
453 int count; 447 int count;
454 448
@@ -456,19 +450,14 @@ static void flush_to_ldisc(struct work_struct *work)
456 if (atomic_read(&buf->priority)) 450 if (atomic_read(&buf->priority))
457 break; 451 break;
458 452
459 spin_lock_irqsave(&buf->flush_lock, flags);
460 count = head->commit - head->read; 453 count = head->commit - head->read;
461 if (!count) { 454 if (!count) {
462 if (head->next == NULL) { 455 if (head->next == NULL)
463 spin_unlock_irqrestore(&buf->flush_lock, flags);
464 break; 456 break;
465 }
466 buf->head = head->next; 457 buf->head = head->next;
467 spin_unlock_irqrestore(&buf->flush_lock, flags);
468 tty_buffer_free(port, head); 458 tty_buffer_free(port, head);
469 continue; 459 continue;
470 } 460 }
471 spin_unlock_irqrestore(&buf->flush_lock, flags);
472 461
473 count = receive_buf(tty, head, count); 462 count = receive_buf(tty, head, count);
474 if (!count) 463 if (!count)
@@ -523,7 +512,6 @@ void tty_buffer_init(struct tty_port *port)
523 struct tty_bufhead *buf = &port->buf; 512 struct tty_bufhead *buf = &port->buf;
524 513
525 mutex_init(&buf->lock); 514 mutex_init(&buf->lock);
526 spin_lock_init(&buf->flush_lock);
527 tty_buffer_reset(&buf->sentinel, 0); 515 tty_buffer_reset(&buf->sentinel, 0);
528 buf->head = &buf->sentinel; 516 buf->head = &buf->sentinel;
529 buf->tail = &buf->sentinel; 517 buf->tail = &buf->sentinel;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 036cccd80d9f..1c3316a47d7e 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -61,7 +61,6 @@ struct tty_bufhead {
61 struct tty_buffer *head; /* Queue head */ 61 struct tty_buffer *head; /* Queue head */
62 struct work_struct work; 62 struct work_struct work;
63 struct mutex lock; 63 struct mutex lock;
64 spinlock_t flush_lock;
65 atomic_t priority; 64 atomic_t priority;
66 struct tty_buffer sentinel; 65 struct tty_buffer sentinel;
67 struct llist_head free; /* Free queue head */ 66 struct llist_head free; /* Free queue head */