aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/tty_buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/tty_buffer.c')
-rw-r--r--drivers/tty/tty_buffer.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 5a3fa8913880..a660ab181cca 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -242,7 +242,10 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)
242 atomic_inc(&buf->priority); 242 atomic_inc(&buf->priority);
243 243
244 mutex_lock(&buf->lock); 244 mutex_lock(&buf->lock);
245 while ((next = buf->head->next) != NULL) { 245 /* paired w/ release in __tty_buffer_request_room; ensures there are
246 * no pending memory accesses to the freed buffer
247 */
248 while ((next = smp_load_acquire(&buf->head->next)) != NULL) {
246 tty_buffer_free(port, buf->head); 249 tty_buffer_free(port, buf->head);
247 buf->head = next; 250 buf->head = next;
248 } 251 }
@@ -290,7 +293,10 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size,
290 if (n != NULL) { 293 if (n != NULL) {
291 n->flags = flags; 294 n->flags = flags;
292 buf->tail = n; 295 buf->tail = n;
293 b->commit = b->used; 296 /* paired w/ acquire in flush_to_ldisc(); ensures
297 * flush_to_ldisc() sees buffer data.
298 */
299 smp_store_release(&b->commit, b->used);
294 /* paired w/ acquire in flush_to_ldisc(); ensures the 300 /* paired w/ acquire in flush_to_ldisc(); ensures the
295 * latest commit value can be read before the head is 301 * latest commit value can be read before the head is
296 * advanced to the next buffer 302 * advanced to the next buffer
@@ -393,7 +399,10 @@ void tty_schedule_flip(struct tty_port *port)
393{ 399{
394 struct tty_bufhead *buf = &port->buf; 400 struct tty_bufhead *buf = &port->buf;
395 401
396 buf->tail->commit = buf->tail->used; 402 /* paired w/ acquire in flush_to_ldisc(); ensures
403 * flush_to_ldisc() sees buffer data.
404 */
405 smp_store_release(&buf->tail->commit, buf->tail->used);
397 schedule_work(&buf->work); 406 schedule_work(&buf->work);
398} 407}
399EXPORT_SYMBOL(tty_schedule_flip); 408EXPORT_SYMBOL(tty_schedule_flip);
@@ -467,7 +476,7 @@ static void flush_to_ldisc(struct work_struct *work)
467 struct tty_struct *tty; 476 struct tty_struct *tty;
468 struct tty_ldisc *disc; 477 struct tty_ldisc *disc;
469 478
470 tty = port->itty; 479 tty = READ_ONCE(port->itty);
471 if (tty == NULL) 480 if (tty == NULL)
472 return; 481 return;
473 482
@@ -491,7 +500,10 @@ static void flush_to_ldisc(struct work_struct *work)
491 * is advancing to the next buffer 500 * is advancing to the next buffer
492 */ 501 */
493 next = smp_load_acquire(&head->next); 502 next = smp_load_acquire(&head->next);
494 count = head->commit - head->read; 503 /* paired w/ release in __tty_buffer_request_room() or in
504 * tty_buffer_flush(); ensures we see the committed buffer data
505 */
506 count = smp_load_acquire(&head->commit) - head->read;
495 if (!count) { 507 if (!count) {
496 if (next == NULL) { 508 if (next == NULL) {
497 check_other_closed(tty); 509 check_other_closed(tty);