diff options
author | Alan Cox <alan@redhat.com> | 2007-07-16 02:39:43 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-16 12:05:41 -0400 |
commit | 9c1729db3e6d738f872bcb090212af00473bf666 (patch) | |
tree | be68b99784607953fb50d9330d34c2728215be57 /drivers/char/n_hdlc.c | |
parent | c9c64155f5a81b4b41e98f9fb9c464a565c1bf72 (diff) |
Prevent an O_NDELAY writer from blocking when a tty write is blocked by the tty atomic writer mutex
Without this a tty write could block if a previous blocking tty write was
in progress on the same tty and blocked by a line discipline or hardware
event. Originally found and reported by Dave Johnson.
Signed-off-by: Alan Cox <alan@redhat.com>
Acked-by: Dave Johnson <djohnson+linux-kernel@sw.starentnetworks.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/n_hdlc.c')
-rw-r--r-- | drivers/char/n_hdlc.c | 9 |
1 files changed, 5 insertions, 4 deletions
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index 337a87f86a3b..37f7d3403040 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c | |||
@@ -780,13 +780,14 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, | |||
780 | poll_wait(filp, &tty->write_wait, wait); | 780 | poll_wait(filp, &tty->write_wait, wait); |
781 | 781 | ||
782 | /* set bits for operations that won't block */ | 782 | /* set bits for operations that won't block */ |
783 | if(n_hdlc->rx_buf_list.head) | 783 | if (n_hdlc->rx_buf_list.head) |
784 | mask |= POLLIN | POLLRDNORM; /* readable */ | 784 | mask |= POLLIN | POLLRDNORM; /* readable */ |
785 | if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) | 785 | if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) |
786 | mask |= POLLHUP; | 786 | mask |= POLLHUP; |
787 | if(tty_hung_up_p(filp)) | 787 | if (tty_hung_up_p(filp)) |
788 | mask |= POLLHUP; | 788 | mask |= POLLHUP; |
789 | if(n_hdlc->tx_free_buf_list.head) | 789 | if (!tty_is_writelocked(tty) && |
790 | n_hdlc->tx_free_buf_list.head) | ||
790 | mask |= POLLOUT | POLLWRNORM; /* writable */ | 791 | mask |= POLLOUT | POLLWRNORM; /* writable */ |
791 | } | 792 | } |
792 | return mask; | 793 | return mask; |
@@ -861,7 +862,7 @@ static void n_hdlc_buf_put(struct n_hdlc_buf_list *list, | |||
861 | spin_lock_irqsave(&list->spinlock,flags); | 862 | spin_lock_irqsave(&list->spinlock,flags); |
862 | 863 | ||
863 | buf->link=NULL; | 864 | buf->link=NULL; |
864 | if(list->tail) | 865 | if (list->tail) |
865 | list->tail->link = buf; | 866 | list->tail->link = buf; |
866 | else | 867 | else |
867 | list->head = buf; | 868 | list->head = buf; |