diff options
author | Ivo Sieben <meltedpianoman@gmail.com> | 2013-01-28 07:32:01 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-02-04 18:05:04 -0500 |
commit | 98001214c0436c2b697d696fde3696d32620d394 (patch) | |
tree | 281011943ccd3621272d7188e6a35c3118a7223e /drivers/tty/n_tty.c | |
parent | 183d95cdd834381c594d3aa801c1f9f9c0c54fa9 (diff) |
tty: Use raw spin lock to protect the TTY read section
The "normal" spin lock that guards the N_TTY line discipline read section
is replaced by a raw spin lock.
On a PREEMP_RT system this prevents unwanted scheduling overhead when data is
read at the same time as data is being received: while RX IRQ threaded handling
is busy a TTY read call is performed from a RT priority > threaded IRQ priority.
The read call tries to take the read section spin lock (held by the threaded
IRQ) which blocks and causes a context switch to/from the threaded IRQ handler
until the spin lock is unlocked.
Signed-off-by: Ivo Sieben <meltedpianoman@gmail.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/n_tty.c')
-rw-r--r-- | drivers/tty/n_tty.c | 56 |
1 files changed, 28 insertions, 28 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 19083efa2314..095072899b5e 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c | |||
@@ -100,7 +100,7 @@ struct n_tty_data { | |||
100 | struct mutex atomic_read_lock; | 100 | struct mutex atomic_read_lock; |
101 | struct mutex output_lock; | 101 | struct mutex output_lock; |
102 | struct mutex echo_lock; | 102 | struct mutex echo_lock; |
103 | spinlock_t read_lock; | 103 | raw_spinlock_t read_lock; |
104 | }; | 104 | }; |
105 | 105 | ||
106 | static inline int tty_put_user(struct tty_struct *tty, unsigned char x, | 106 | static inline int tty_put_user(struct tty_struct *tty, unsigned char x, |
@@ -182,9 +182,9 @@ static void put_tty_queue(unsigned char c, struct n_tty_data *ldata) | |||
182 | * The problem of stomping on the buffers ends here. | 182 | * The problem of stomping on the buffers ends here. |
183 | * Why didn't anyone see this one coming? --AJK | 183 | * Why didn't anyone see this one coming? --AJK |
184 | */ | 184 | */ |
185 | spin_lock_irqsave(&ldata->read_lock, flags); | 185 | raw_spin_lock_irqsave(&ldata->read_lock, flags); |
186 | put_tty_queue_nolock(c, ldata); | 186 | put_tty_queue_nolock(c, ldata); |
187 | spin_unlock_irqrestore(&ldata->read_lock, flags); | 187 | raw_spin_unlock_irqrestore(&ldata->read_lock, flags); |
188 | } | 188 | } |
189 | 189 | ||
190 | /** | 190 | /** |
@@ -218,9 +218,9 @@ static void reset_buffer_flags(struct tty_struct *tty) | |||
218 | struct n_tty_data *ldata = tty->disc_data; | 218 | struct n_tty_data *ldata = tty->disc_data; |
219 | unsigned long flags; | 219 | unsigned long flags; |
220 | 220 | ||
221 | spin_lock_irqsave(&ldata->read_lock, flags); | 221 | raw_spin_lock_irqsave(&ldata->read_lock, flags); |
222 | ldata->read_head = ldata->read_tail = ldata->read_cnt = 0; | 222 | ldata->read_head = ldata->read_tail = ldata->read_cnt = 0; |
223 | spin_unlock_irqrestore(&ldata->read_lock, flags); | 223 | raw_spin_unlock_irqrestore(&ldata->read_lock, flags); |
224 | 224 | ||
225 | mutex_lock(&ldata->echo_lock); | 225 | mutex_lock(&ldata->echo_lock); |
226 | ldata->echo_pos = ldata->echo_cnt = ldata->echo_overrun = 0; | 226 | ldata->echo_pos = ldata->echo_cnt = ldata->echo_overrun = 0; |
@@ -276,7 +276,7 @@ static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) | |||
276 | unsigned long flags; | 276 | unsigned long flags; |
277 | ssize_t n = 0; | 277 | ssize_t n = 0; |
278 | 278 | ||
279 | spin_lock_irqsave(&ldata->read_lock, flags); | 279 | raw_spin_lock_irqsave(&ldata->read_lock, flags); |
280 | if (!ldata->icanon) { | 280 | if (!ldata->icanon) { |
281 | n = ldata->read_cnt; | 281 | n = ldata->read_cnt; |
282 | } else if (ldata->canon_data) { | 282 | } else if (ldata->canon_data) { |
@@ -284,7 +284,7 @@ static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) | |||
284 | ldata->canon_head - ldata->read_tail : | 284 | ldata->canon_head - ldata->read_tail : |
285 | ldata->canon_head + (N_TTY_BUF_SIZE - ldata->read_tail); | 285 | ldata->canon_head + (N_TTY_BUF_SIZE - ldata->read_tail); |
286 | } | 286 | } |
287 | spin_unlock_irqrestore(&ldata->read_lock, flags); | 287 | raw_spin_unlock_irqrestore(&ldata->read_lock, flags); |
288 | return n; | 288 | return n; |
289 | } | 289 | } |
290 | 290 | ||
@@ -915,19 +915,19 @@ static void eraser(unsigned char c, struct tty_struct *tty) | |||
915 | kill_type = WERASE; | 915 | kill_type = WERASE; |
916 | else { | 916 | else { |
917 | if (!L_ECHO(tty)) { | 917 | if (!L_ECHO(tty)) { |
918 | spin_lock_irqsave(&ldata->read_lock, flags); | 918 | raw_spin_lock_irqsave(&ldata->read_lock, flags); |
919 | ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) & | 919 | ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) & |
920 | (N_TTY_BUF_SIZE - 1)); | 920 | (N_TTY_BUF_SIZE - 1)); |
921 | ldata->read_head = ldata->canon_head; | 921 | ldata->read_head = ldata->canon_head; |
922 | spin_unlock_irqrestore(&ldata->read_lock, flags); | 922 | raw_spin_unlock_irqrestore(&ldata->read_lock, flags); |
923 | return; | 923 | return; |
924 | } | 924 | } |
925 | if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) { | 925 | if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) { |
926 | spin_lock_irqsave(&ldata->read_lock, flags); | 926 | raw_spin_lock_irqsave(&ldata->read_lock, flags); |
927 | ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) & | 927 | ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) & |
928 | (N_TTY_BUF_SIZE - 1)); | 928 | (N_TTY_BUF_SIZE - 1)); |
929 | ldata->read_head = ldata->canon_head; | 929 | ldata->read_head = ldata->canon_head; |
930 | spin_unlock_irqrestore(&ldata->read_lock, flags); | 930 | raw_spin_unlock_irqrestore(&ldata->read_lock, flags); |
931 | finish_erasing(ldata); | 931 | finish_erasing(ldata); |
932 | echo_char(KILL_CHAR(tty), tty); | 932 | echo_char(KILL_CHAR(tty), tty); |
933 | /* Add a newline if ECHOK is on and ECHOKE is off. */ | 933 | /* Add a newline if ECHOK is on and ECHOKE is off. */ |
@@ -961,10 +961,10 @@ static void eraser(unsigned char c, struct tty_struct *tty) | |||
961 | break; | 961 | break; |
962 | } | 962 | } |
963 | cnt = (ldata->read_head - head) & (N_TTY_BUF_SIZE-1); | 963 | cnt = (ldata->read_head - head) & (N_TTY_BUF_SIZE-1); |
964 | spin_lock_irqsave(&ldata->read_lock, flags); | 964 | raw_spin_lock_irqsave(&ldata->read_lock, flags); |
965 | ldata->read_head = head; | 965 | ldata->read_head = head; |
966 | ldata->read_cnt -= cnt; | 966 | ldata->read_cnt -= cnt; |
967 | spin_unlock_irqrestore(&ldata->read_lock, flags); | 967 | raw_spin_unlock_irqrestore(&ldata->read_lock, flags); |
968 | if (L_ECHO(tty)) { | 968 | if (L_ECHO(tty)) { |
969 | if (L_ECHOPRT(tty)) { | 969 | if (L_ECHOPRT(tty)) { |
970 | if (!ldata->erasing) { | 970 | if (!ldata->erasing) { |
@@ -1344,12 +1344,12 @@ send_signal: | |||
1344 | put_tty_queue(c, ldata); | 1344 | put_tty_queue(c, ldata); |
1345 | 1345 | ||
1346 | handle_newline: | 1346 | handle_newline: |
1347 | spin_lock_irqsave(&ldata->read_lock, flags); | 1347 | raw_spin_lock_irqsave(&ldata->read_lock, flags); |
1348 | set_bit(ldata->read_head, ldata->read_flags); | 1348 | set_bit(ldata->read_head, ldata->read_flags); |
1349 | put_tty_queue_nolock(c, ldata); | 1349 | put_tty_queue_nolock(c, ldata); |
1350 | ldata->canon_head = ldata->read_head; | 1350 | ldata->canon_head = ldata->read_head; |
1351 | ldata->canon_data++; | 1351 | ldata->canon_data++; |
1352 | spin_unlock_irqrestore(&ldata->read_lock, flags); | 1352 | raw_spin_unlock_irqrestore(&ldata->read_lock, flags); |
1353 | kill_fasync(&tty->fasync, SIGIO, POLL_IN); | 1353 | kill_fasync(&tty->fasync, SIGIO, POLL_IN); |
1354 | if (waitqueue_active(&tty->read_wait)) | 1354 | if (waitqueue_active(&tty->read_wait)) |
1355 | wake_up_interruptible(&tty->read_wait); | 1355 | wake_up_interruptible(&tty->read_wait); |
@@ -1423,7 +1423,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, | |||
1423 | unsigned long cpuflags; | 1423 | unsigned long cpuflags; |
1424 | 1424 | ||
1425 | if (ldata->real_raw) { | 1425 | if (ldata->real_raw) { |
1426 | spin_lock_irqsave(&ldata->read_lock, cpuflags); | 1426 | raw_spin_lock_irqsave(&ldata->read_lock, cpuflags); |
1427 | i = min(N_TTY_BUF_SIZE - ldata->read_cnt, | 1427 | i = min(N_TTY_BUF_SIZE - ldata->read_cnt, |
1428 | N_TTY_BUF_SIZE - ldata->read_head); | 1428 | N_TTY_BUF_SIZE - ldata->read_head); |
1429 | i = min(count, i); | 1429 | i = min(count, i); |
@@ -1439,7 +1439,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, | |||
1439 | memcpy(ldata->read_buf + ldata->read_head, cp, i); | 1439 | memcpy(ldata->read_buf + ldata->read_head, cp, i); |
1440 | ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1); | 1440 | ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1); |
1441 | ldata->read_cnt += i; | 1441 | ldata->read_cnt += i; |
1442 | spin_unlock_irqrestore(&ldata->read_lock, cpuflags); | 1442 | raw_spin_unlock_irqrestore(&ldata->read_lock, cpuflags); |
1443 | } else { | 1443 | } else { |
1444 | for (i = count, p = cp, f = fp; i; i--, p++) { | 1444 | for (i = count, p = cp, f = fp; i; i--, p++) { |
1445 | if (f) | 1445 | if (f) |
@@ -1635,7 +1635,7 @@ static int n_tty_open(struct tty_struct *tty) | |||
1635 | mutex_init(&ldata->atomic_read_lock); | 1635 | mutex_init(&ldata->atomic_read_lock); |
1636 | mutex_init(&ldata->output_lock); | 1636 | mutex_init(&ldata->output_lock); |
1637 | mutex_init(&ldata->echo_lock); | 1637 | mutex_init(&ldata->echo_lock); |
1638 | spin_lock_init(&ldata->read_lock); | 1638 | raw_spin_lock_init(&ldata->read_lock); |
1639 | 1639 | ||
1640 | /* These are ugly. Currently a malloc failure here can panic */ | 1640 | /* These are ugly. Currently a malloc failure here can panic */ |
1641 | ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); | 1641 | ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); |
@@ -1703,10 +1703,10 @@ static int copy_from_read_buf(struct tty_struct *tty, | |||
1703 | bool is_eof; | 1703 | bool is_eof; |
1704 | 1704 | ||
1705 | retval = 0; | 1705 | retval = 0; |
1706 | spin_lock_irqsave(&ldata->read_lock, flags); | 1706 | raw_spin_lock_irqsave(&ldata->read_lock, flags); |
1707 | n = min(ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_tail); | 1707 | n = min(ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_tail); |
1708 | n = min(*nr, n); | 1708 | n = min(*nr, n); |
1709 | spin_unlock_irqrestore(&ldata->read_lock, flags); | 1709 | raw_spin_unlock_irqrestore(&ldata->read_lock, flags); |
1710 | if (n) { | 1710 | if (n) { |
1711 | retval = copy_to_user(*b, &ldata->read_buf[ldata->read_tail], n); | 1711 | retval = copy_to_user(*b, &ldata->read_buf[ldata->read_tail], n); |
1712 | n -= retval; | 1712 | n -= retval; |
@@ -1714,13 +1714,13 @@ static int copy_from_read_buf(struct tty_struct *tty, | |||
1714 | ldata->read_buf[ldata->read_tail] == EOF_CHAR(tty); | 1714 | ldata->read_buf[ldata->read_tail] == EOF_CHAR(tty); |
1715 | tty_audit_add_data(tty, &ldata->read_buf[ldata->read_tail], n, | 1715 | tty_audit_add_data(tty, &ldata->read_buf[ldata->read_tail], n, |
1716 | ldata->icanon); | 1716 | ldata->icanon); |
1717 | spin_lock_irqsave(&ldata->read_lock, flags); | 1717 | raw_spin_lock_irqsave(&ldata->read_lock, flags); |
1718 | ldata->read_tail = (ldata->read_tail + n) & (N_TTY_BUF_SIZE-1); | 1718 | ldata->read_tail = (ldata->read_tail + n) & (N_TTY_BUF_SIZE-1); |
1719 | ldata->read_cnt -= n; | 1719 | ldata->read_cnt -= n; |
1720 | /* Turn single EOF into zero-length read */ | 1720 | /* Turn single EOF into zero-length read */ |
1721 | if (L_EXTPROC(tty) && ldata->icanon && is_eof && !ldata->read_cnt) | 1721 | if (L_EXTPROC(tty) && ldata->icanon && is_eof && !ldata->read_cnt) |
1722 | n = 0; | 1722 | n = 0; |
1723 | spin_unlock_irqrestore(&ldata->read_lock, flags); | 1723 | raw_spin_unlock_irqrestore(&ldata->read_lock, flags); |
1724 | *b += n; | 1724 | *b += n; |
1725 | *nr -= n; | 1725 | *nr -= n; |
1726 | } | 1726 | } |
@@ -1900,7 +1900,7 @@ do_it_again: | |||
1900 | 1900 | ||
1901 | if (ldata->icanon && !L_EXTPROC(tty)) { | 1901 | if (ldata->icanon && !L_EXTPROC(tty)) { |
1902 | /* N.B. avoid overrun if nr == 0 */ | 1902 | /* N.B. avoid overrun if nr == 0 */ |
1903 | spin_lock_irqsave(&ldata->read_lock, flags); | 1903 | raw_spin_lock_irqsave(&ldata->read_lock, flags); |
1904 | while (nr && ldata->read_cnt) { | 1904 | while (nr && ldata->read_cnt) { |
1905 | int eol; | 1905 | int eol; |
1906 | 1906 | ||
@@ -1918,25 +1918,25 @@ do_it_again: | |||
1918 | if (--ldata->canon_data < 0) | 1918 | if (--ldata->canon_data < 0) |
1919 | ldata->canon_data = 0; | 1919 | ldata->canon_data = 0; |
1920 | } | 1920 | } |
1921 | spin_unlock_irqrestore(&ldata->read_lock, flags); | 1921 | raw_spin_unlock_irqrestore(&ldata->read_lock, flags); |
1922 | 1922 | ||
1923 | if (!eol || (c != __DISABLED_CHAR)) { | 1923 | if (!eol || (c != __DISABLED_CHAR)) { |
1924 | if (tty_put_user(tty, c, b++)) { | 1924 | if (tty_put_user(tty, c, b++)) { |
1925 | retval = -EFAULT; | 1925 | retval = -EFAULT; |
1926 | b--; | 1926 | b--; |
1927 | spin_lock_irqsave(&ldata->read_lock, flags); | 1927 | raw_spin_lock_irqsave(&ldata->read_lock, flags); |
1928 | break; | 1928 | break; |
1929 | } | 1929 | } |
1930 | nr--; | 1930 | nr--; |
1931 | } | 1931 | } |
1932 | if (eol) { | 1932 | if (eol) { |
1933 | tty_audit_push(tty); | 1933 | tty_audit_push(tty); |
1934 | spin_lock_irqsave(&ldata->read_lock, flags); | 1934 | raw_spin_lock_irqsave(&ldata->read_lock, flags); |
1935 | break; | 1935 | break; |
1936 | } | 1936 | } |
1937 | spin_lock_irqsave(&ldata->read_lock, flags); | 1937 | raw_spin_lock_irqsave(&ldata->read_lock, flags); |
1938 | } | 1938 | } |
1939 | spin_unlock_irqrestore(&ldata->read_lock, flags); | 1939 | raw_spin_unlock_irqrestore(&ldata->read_lock, flags); |
1940 | if (retval) | 1940 | if (retval) |
1941 | break; | 1941 | break; |
1942 | } else { | 1942 | } else { |