diff options
Diffstat (limited to 'drivers/tty/tty_buffer.c')
| -rw-r--r-- | drivers/tty/tty_buffer.c | 40 |
1 files changed, 19 insertions, 21 deletions
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 685757c6ce87..c3c606c52722 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c | |||
| @@ -157,8 +157,6 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b) | |||
| 157 | * flush all the buffers containing receive data. Caller must | 157 | * flush all the buffers containing receive data. Caller must |
| 158 | * hold the buffer lock and must have ensured no parallel flush to | 158 | * hold the buffer lock and must have ensured no parallel flush to |
| 159 | * ldisc is running. | 159 | * ldisc is running. |
| 160 | * | ||
| 161 | * Locking: Caller must hold tty->buf.lock | ||
| 162 | */ | 160 | */ |
| 163 | 161 | ||
| 164 | static void __tty_buffer_flush(struct tty_port *port) | 162 | static void __tty_buffer_flush(struct tty_port *port) |
| @@ -182,29 +180,29 @@ static void __tty_buffer_flush(struct tty_port *port) | |||
| 182 | * being processed by flush_to_ldisc then we defer the processing | 180 | * being processed by flush_to_ldisc then we defer the processing |
| 183 | * to that function | 181 | * to that function |
| 184 | * | 182 | * |
| 185 | * Locking: none | 183 | * Locking: takes flush_mutex to ensure single-threaded flip buffer |
| 184 | * 'consumer' | ||
| 186 | */ | 185 | */ |
| 187 | 186 | ||
| 188 | void tty_buffer_flush(struct tty_struct *tty) | 187 | void tty_buffer_flush(struct tty_struct *tty) |
| 189 | { | 188 | { |
| 190 | struct tty_port *port = tty->port; | 189 | struct tty_port *port = tty->port; |
| 191 | struct tty_bufhead *buf = &port->buf; | 190 | struct tty_bufhead *buf = &port->buf; |
| 192 | unsigned long flags; | ||
| 193 | |||
| 194 | spin_lock_irqsave(&buf->lock, flags); | ||
| 195 | 191 | ||
| 192 | mutex_lock(&buf->flush_mutex); | ||
| 196 | /* If the data is being pushed to the tty layer then we can't | 193 | /* If the data is being pushed to the tty layer then we can't |
| 197 | process it here. Instead set a flag and the flush_to_ldisc | 194 | process it here. Instead set a flag and the flush_to_ldisc |
| 198 | path will process the flush request before it exits */ | 195 | path will process the flush request before it exits */ |
| 199 | if (test_bit(TTYP_FLUSHING, &port->iflags)) { | 196 | if (test_bit(TTYP_FLUSHING, &port->iflags)) { |
| 200 | set_bit(TTYP_FLUSHPENDING, &port->iflags); | 197 | set_bit(TTYP_FLUSHPENDING, &port->iflags); |
| 201 | spin_unlock_irqrestore(&buf->lock, flags); | 198 | mutex_unlock(&buf->flush_mutex); |
| 202 | wait_event(tty->read_wait, | 199 | wait_event(tty->read_wait, |
| 203 | test_bit(TTYP_FLUSHPENDING, &port->iflags) == 0); | 200 | test_bit(TTYP_FLUSHPENDING, &port->iflags) == 0); |
| 204 | return; | 201 | return; |
| 205 | } else | 202 | } |
| 206 | __tty_buffer_flush(port); | 203 | |
| 207 | spin_unlock_irqrestore(&buf->lock, flags); | 204 | __tty_buffer_flush(port); |
| 205 | mutex_unlock(&buf->flush_mutex); | ||
| 208 | } | 206 | } |
| 209 | 207 | ||
| 210 | /** | 208 | /** |
| @@ -408,9 +406,10 @@ receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count) | |||
| 408 | * This routine is called out of the software interrupt to flush data | 406 | * This routine is called out of the software interrupt to flush data |
| 409 | * from the buffer chain to the line discipline. | 407 | * from the buffer chain to the line discipline. |
| 410 | * | 408 | * |
| 411 | * Locking: holds tty->buf.lock to guard buffer list. Drops the lock | 409 | * The receive_buf method is single threaded for each tty instance. |
| 412 | * while invoking the line discipline receive_buf method. The | 410 | * |
| 413 | * receive_buf method is single threaded for each tty instance. | 411 | * Locking: takes flush_mutex to ensure single-threaded flip buffer |
| 412 | * 'consumer' | ||
| 414 | */ | 413 | */ |
| 415 | 414 | ||
| 416 | static void flush_to_ldisc(struct work_struct *work) | 415 | static void flush_to_ldisc(struct work_struct *work) |
| @@ -418,7 +417,6 @@ static void flush_to_ldisc(struct work_struct *work) | |||
| 418 | struct tty_port *port = container_of(work, struct tty_port, buf.work); | 417 | struct tty_port *port = container_of(work, struct tty_port, buf.work); |
| 419 | struct tty_bufhead *buf = &port->buf; | 418 | struct tty_bufhead *buf = &port->buf; |
| 420 | struct tty_struct *tty; | 419 | struct tty_struct *tty; |
| 421 | unsigned long flags; | ||
| 422 | struct tty_ldisc *disc; | 420 | struct tty_ldisc *disc; |
| 423 | 421 | ||
| 424 | tty = port->itty; | 422 | tty = port->itty; |
| @@ -429,7 +427,7 @@ static void flush_to_ldisc(struct work_struct *work) | |||
| 429 | if (disc == NULL) | 427 | if (disc == NULL) |
| 430 | return; | 428 | return; |
| 431 | 429 | ||
| 432 | spin_lock_irqsave(&buf->lock, flags); | 430 | mutex_lock(&buf->flush_mutex); |
| 433 | 431 | ||
| 434 | if (!test_and_set_bit(TTYP_FLUSHING, &port->iflags)) { | 432 | if (!test_and_set_bit(TTYP_FLUSHING, &port->iflags)) { |
| 435 | while (1) { | 433 | while (1) { |
| @@ -444,11 +442,13 @@ static void flush_to_ldisc(struct work_struct *work) | |||
| 444 | tty_buffer_free(port, head); | 442 | tty_buffer_free(port, head); |
| 445 | continue; | 443 | continue; |
| 446 | } | 444 | } |
| 447 | spin_unlock_irqrestore(&buf->lock, flags); | 445 | |
| 446 | mutex_unlock(&buf->flush_mutex); | ||
| 448 | 447 | ||
| 449 | count = receive_buf(tty, head, count); | 448 | count = receive_buf(tty, head, count); |
| 450 | 449 | ||
| 451 | spin_lock_irqsave(&buf->lock, flags); | 450 | mutex_lock(&buf->flush_mutex); |
| 451 | |||
| 452 | /* Ldisc or user is trying to flush the buffers. | 452 | /* Ldisc or user is trying to flush the buffers. |
| 453 | We may have a deferred request to flush the | 453 | We may have a deferred request to flush the |
| 454 | input buffer, if so pull the chain under the lock | 454 | input buffer, if so pull the chain under the lock |
| @@ -464,7 +464,7 @@ static void flush_to_ldisc(struct work_struct *work) | |||
| 464 | clear_bit(TTYP_FLUSHING, &port->iflags); | 464 | clear_bit(TTYP_FLUSHING, &port->iflags); |
| 465 | } | 465 | } |
| 466 | 466 | ||
| 467 | spin_unlock_irqrestore(&buf->lock, flags); | 467 | mutex_unlock(&buf->flush_mutex); |
| 468 | 468 | ||
| 469 | tty_ldisc_deref(disc); | 469 | tty_ldisc_deref(disc); |
| 470 | } | 470 | } |
| @@ -514,15 +514,13 @@ EXPORT_SYMBOL(tty_flip_buffer_push); | |||
| 514 | * | 514 | * |
| 515 | * Set up the initial state of the buffer management for a tty device. | 515 | * Set up the initial state of the buffer management for a tty device. |
| 516 | * Must be called before the other tty buffer functions are used. | 516 | * Must be called before the other tty buffer functions are used. |
| 517 | * | ||
| 518 | * Locking: none | ||
| 519 | */ | 517 | */ |
| 520 | 518 | ||
| 521 | void tty_buffer_init(struct tty_port *port) | 519 | void tty_buffer_init(struct tty_port *port) |
| 522 | { | 520 | { |
| 523 | struct tty_bufhead *buf = &port->buf; | 521 | struct tty_bufhead *buf = &port->buf; |
| 524 | 522 | ||
| 525 | spin_lock_init(&buf->lock); | 523 | mutex_init(&buf->flush_mutex); |
| 526 | tty_buffer_reset(&buf->sentinel, 0); | 524 | tty_buffer_reset(&buf->sentinel, 0); |
| 527 | buf->head = &buf->sentinel; | 525 | buf->head = &buf->sentinel; |
| 528 | buf->tail = &buf->sentinel; | 526 | buf->tail = &buf->sentinel; |
