diff options
Diffstat (limited to 'drivers/tty/n_tty.c')
-rw-r--r-- | drivers/tty/n_tty.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index cf6e0f2e1331..cc57a3a6b02b 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c | |||
@@ -1949,6 +1949,18 @@ static inline int input_available_p(struct tty_struct *tty, int poll) | |||
1949 | return ldata->commit_head - ldata->read_tail >= amt; | 1949 | return ldata->commit_head - ldata->read_tail >= amt; |
1950 | } | 1950 | } |
1951 | 1951 | ||
1952 | static inline int check_other_done(struct tty_struct *tty) | ||
1953 | { | ||
1954 | int done = test_bit(TTY_OTHER_DONE, &tty->flags); | ||
1955 | if (done) { | ||
1956 | /* paired with cmpxchg() in check_other_closed(); ensures | ||
1957 | * read buffer head index is not stale | ||
1958 | */ | ||
1959 | smp_mb__after_atomic(); | ||
1960 | } | ||
1961 | return done; | ||
1962 | } | ||
1963 | |||
1952 | /** | 1964 | /** |
1953 | * copy_from_read_buf - copy read data directly | 1965 | * copy_from_read_buf - copy read data directly |
1954 | * @tty: terminal device | 1966 | * @tty: terminal device |
@@ -2167,7 +2179,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, | |||
2167 | struct n_tty_data *ldata = tty->disc_data; | 2179 | struct n_tty_data *ldata = tty->disc_data; |
2168 | unsigned char __user *b = buf; | 2180 | unsigned char __user *b = buf; |
2169 | DEFINE_WAIT_FUNC(wait, woken_wake_function); | 2181 | DEFINE_WAIT_FUNC(wait, woken_wake_function); |
2170 | int c; | 2182 | int c, done; |
2171 | int minimum, time; | 2183 | int minimum, time; |
2172 | ssize_t retval = 0; | 2184 | ssize_t retval = 0; |
2173 | long timeout; | 2185 | long timeout; |
@@ -2235,8 +2247,10 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, | |||
2235 | ((minimum - (b - buf)) >= 1)) | 2247 | ((minimum - (b - buf)) >= 1)) |
2236 | ldata->minimum_to_wake = (minimum - (b - buf)); | 2248 | ldata->minimum_to_wake = (minimum - (b - buf)); |
2237 | 2249 | ||
2250 | done = check_other_done(tty); | ||
2251 | |||
2238 | if (!input_available_p(tty, 0)) { | 2252 | if (!input_available_p(tty, 0)) { |
2239 | if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { | 2253 | if (done) { |
2240 | retval = -EIO; | 2254 | retval = -EIO; |
2241 | break; | 2255 | break; |
2242 | } | 2256 | } |
@@ -2443,12 +2457,12 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, | |||
2443 | 2457 | ||
2444 | poll_wait(file, &tty->read_wait, wait); | 2458 | poll_wait(file, &tty->read_wait, wait); |
2445 | poll_wait(file, &tty->write_wait, wait); | 2459 | poll_wait(file, &tty->write_wait, wait); |
2460 | if (check_other_done(tty)) | ||
2461 | mask |= POLLHUP; | ||
2446 | if (input_available_p(tty, 1)) | 2462 | if (input_available_p(tty, 1)) |
2447 | mask |= POLLIN | POLLRDNORM; | 2463 | mask |= POLLIN | POLLRDNORM; |
2448 | if (tty->packet && tty->link->ctrl_status) | 2464 | if (tty->packet && tty->link->ctrl_status) |
2449 | mask |= POLLPRI | POLLIN | POLLRDNORM; | 2465 | mask |= POLLPRI | POLLIN | POLLRDNORM; |
2450 | if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) | ||
2451 | mask |= POLLHUP; | ||
2452 | if (tty_hung_up_p(file)) | 2466 | if (tty_hung_up_p(file)) |
2453 | mask |= POLLHUP; | 2467 | mask |= POLLHUP; |
2454 | if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) { | 2468 | if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) { |