aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/n_tty.c
diff options
context:
space:
mode:
authorIvo Sieben <meltedpianoman@gmail.com>2013-01-28 07:32:01 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-02-04 18:05:04 -0500
commit98001214c0436c2b697d696fde3696d32620d394 (patch)
tree281011943ccd3621272d7188e6a35c3118a7223e /drivers/tty/n_tty.c
parent183d95cdd834381c594d3aa801c1f9f9c0c54fa9 (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.c56
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
106static inline int tty_put_user(struct tty_struct *tty, unsigned char x, 106static 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
1346handle_newline: 1346handle_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 {