diff options
Diffstat (limited to 'drivers/tty/n_tty.c')
-rw-r--r-- | drivers/tty/n_tty.c | 75 |
1 files changed, 28 insertions, 47 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 8406a23ee920..3b499451b7ed 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c | |||
@@ -106,10 +106,10 @@ struct n_tty_data { | |||
106 | /* consumer-published */ | 106 | /* consumer-published */ |
107 | size_t read_tail; | 107 | size_t read_tail; |
108 | 108 | ||
109 | /* protected by echo_lock */ | ||
110 | unsigned char *echo_buf; | 109 | unsigned char *echo_buf; |
111 | size_t echo_head; | 110 | size_t echo_head; |
112 | size_t echo_tail; | 111 | size_t echo_tail; |
112 | size_t echo_commit; | ||
113 | 113 | ||
114 | /* protected by output lock */ | 114 | /* protected by output lock */ |
115 | unsigned int column; | 115 | unsigned int column; |
@@ -117,7 +117,6 @@ struct n_tty_data { | |||
117 | 117 | ||
118 | struct mutex atomic_read_lock; | 118 | struct mutex atomic_read_lock; |
119 | struct mutex output_lock; | 119 | struct mutex output_lock; |
120 | struct mutex echo_lock; | ||
121 | }; | 120 | }; |
122 | 121 | ||
123 | static inline size_t read_cnt(struct n_tty_data *ldata) | 122 | static inline size_t read_cnt(struct n_tty_data *ldata) |
@@ -333,10 +332,7 @@ static void put_tty_queue(unsigned char c, struct n_tty_data *ldata) | |||
333 | static void reset_buffer_flags(struct n_tty_data *ldata) | 332 | static void reset_buffer_flags(struct n_tty_data *ldata) |
334 | { | 333 | { |
335 | ldata->read_head = ldata->canon_head = ldata->read_tail = 0; | 334 | ldata->read_head = ldata->canon_head = ldata->read_tail = 0; |
336 | 335 | ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0; | |
337 | mutex_lock(&ldata->echo_lock); | ||
338 | ldata->echo_head = ldata->echo_tail = 0; | ||
339 | mutex_unlock(&ldata->echo_lock); | ||
340 | 336 | ||
341 | ldata->erasing = 0; | 337 | ldata->erasing = 0; |
342 | bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); | 338 | bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); |
@@ -642,8 +638,7 @@ break_out: | |||
642 | * are prioritized. Also, when control characters are echoed with a | 638 | * are prioritized. Also, when control characters are echoed with a |
643 | * prefixed "^", the pair is treated atomically and thus not separated. | 639 | * prefixed "^", the pair is treated atomically and thus not separated. |
644 | * | 640 | * |
645 | * Locking: output_lock to protect column state and space left, | 641 | * Locking: output_lock to protect column state and space left |
646 | * echo_lock to protect the echo buffer | ||
647 | */ | 642 | */ |
648 | 643 | ||
649 | static void process_echoes(struct tty_struct *tty) | 644 | static void process_echoes(struct tty_struct *tty) |
@@ -653,16 +648,15 @@ static void process_echoes(struct tty_struct *tty) | |||
653 | size_t tail; | 648 | size_t tail; |
654 | unsigned char c; | 649 | unsigned char c; |
655 | 650 | ||
656 | if (ldata->echo_head == ldata->echo_tail) | 651 | if (ldata->echo_commit == ldata->echo_tail) |
657 | return; | 652 | return; |
658 | 653 | ||
659 | mutex_lock(&ldata->output_lock); | 654 | mutex_lock(&ldata->output_lock); |
660 | mutex_lock(&ldata->echo_lock); | ||
661 | 655 | ||
662 | space = tty_write_room(tty); | 656 | space = tty_write_room(tty); |
663 | 657 | ||
664 | tail = ldata->echo_tail; | 658 | tail = ldata->echo_tail; |
665 | nr = ldata->echo_head - ldata->echo_tail; | 659 | nr = ldata->echo_commit - ldata->echo_tail; |
666 | while (nr > 0) { | 660 | while (nr > 0) { |
667 | c = echo_buf(ldata, tail); | 661 | c = echo_buf(ldata, tail); |
668 | if (c == ECHO_OP_START) { | 662 | if (c == ECHO_OP_START) { |
@@ -779,13 +773,21 @@ static void process_echoes(struct tty_struct *tty) | |||
779 | 773 | ||
780 | ldata->echo_tail = tail; | 774 | ldata->echo_tail = tail; |
781 | 775 | ||
782 | mutex_unlock(&ldata->echo_lock); | ||
783 | mutex_unlock(&ldata->output_lock); | 776 | mutex_unlock(&ldata->output_lock); |
784 | 777 | ||
785 | if (tty->ops->flush_chars) | 778 | if (tty->ops->flush_chars) |
786 | tty->ops->flush_chars(tty); | 779 | tty->ops->flush_chars(tty); |
787 | } | 780 | } |
788 | 781 | ||
782 | static void commit_echoes(struct tty_struct *tty) | ||
783 | { | ||
784 | struct n_tty_data *ldata = tty->disc_data; | ||
785 | |||
786 | smp_mb(); | ||
787 | ldata->echo_commit = ldata->echo_head; | ||
788 | process_echoes(tty); | ||
789 | } | ||
790 | |||
789 | /** | 791 | /** |
790 | * add_echo_byte - add a byte to the echo buffer | 792 | * add_echo_byte - add a byte to the echo buffer |
791 | * @c: unicode byte to echo | 793 | * @c: unicode byte to echo |
@@ -793,13 +795,16 @@ static void process_echoes(struct tty_struct *tty) | |||
793 | * | 795 | * |
794 | * Add a character or operation byte to the echo buffer. | 796 | * Add a character or operation byte to the echo buffer. |
795 | * | 797 | * |
796 | * Should be called under the echo lock to protect the echo buffer. | 798 | * Locks: may claim output_lock to prevent concurrent modify of |
799 | * echo_tail by process_echoes(). | ||
797 | */ | 800 | */ |
798 | 801 | ||
799 | static void add_echo_byte(unsigned char c, struct n_tty_data *ldata) | 802 | static void add_echo_byte(unsigned char c, struct n_tty_data *ldata) |
800 | { | 803 | { |
801 | if (ldata->echo_head - ldata->echo_tail == N_TTY_BUF_SIZE) { | 804 | if (ldata->echo_head - ldata->echo_tail == N_TTY_BUF_SIZE) { |
802 | size_t head = ldata->echo_head; | 805 | size_t head = ldata->echo_head; |
806 | |||
807 | mutex_lock(&ldata->output_lock); | ||
803 | /* | 808 | /* |
804 | * Since the buffer start position needs to be advanced, | 809 | * Since the buffer start position needs to be advanced, |
805 | * be sure to step by a whole operation byte group. | 810 | * be sure to step by a whole operation byte group. |
@@ -811,6 +816,7 @@ static void add_echo_byte(unsigned char c, struct n_tty_data *ldata) | |||
811 | ldata->echo_tail += 2; | 816 | ldata->echo_tail += 2; |
812 | } else | 817 | } else |
813 | ldata->echo_tail++; | 818 | ldata->echo_tail++; |
819 | mutex_unlock(&ldata->output_lock); | ||
814 | } | 820 | } |
815 | 821 | ||
816 | *echo_buf_addr(ldata, ldata->echo_head++) = c; | 822 | *echo_buf_addr(ldata, ldata->echo_head++) = c; |
@@ -821,16 +827,12 @@ static void add_echo_byte(unsigned char c, struct n_tty_data *ldata) | |||
821 | * @ldata: n_tty data | 827 | * @ldata: n_tty data |
822 | * | 828 | * |
823 | * Add an operation to the echo buffer to move back one column. | 829 | * Add an operation to the echo buffer to move back one column. |
824 | * | ||
825 | * Locking: echo_lock to protect the echo buffer | ||
826 | */ | 830 | */ |
827 | 831 | ||
828 | static void echo_move_back_col(struct n_tty_data *ldata) | 832 | static void echo_move_back_col(struct n_tty_data *ldata) |
829 | { | 833 | { |
830 | mutex_lock(&ldata->echo_lock); | ||
831 | add_echo_byte(ECHO_OP_START, ldata); | 834 | add_echo_byte(ECHO_OP_START, ldata); |
832 | add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata); | 835 | add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata); |
833 | mutex_unlock(&ldata->echo_lock); | ||
834 | } | 836 | } |
835 | 837 | ||
836 | /** | 838 | /** |
@@ -839,16 +841,12 @@ static void echo_move_back_col(struct n_tty_data *ldata) | |||
839 | * | 841 | * |
840 | * Add an operation to the echo buffer to set the canon column | 842 | * Add an operation to the echo buffer to set the canon column |
841 | * to the current column. | 843 | * to the current column. |
842 | * | ||
843 | * Locking: echo_lock to protect the echo buffer | ||
844 | */ | 844 | */ |
845 | 845 | ||
846 | static void echo_set_canon_col(struct n_tty_data *ldata) | 846 | static void echo_set_canon_col(struct n_tty_data *ldata) |
847 | { | 847 | { |
848 | mutex_lock(&ldata->echo_lock); | ||
849 | add_echo_byte(ECHO_OP_START, ldata); | 848 | add_echo_byte(ECHO_OP_START, ldata); |
850 | add_echo_byte(ECHO_OP_SET_CANON_COL, ldata); | 849 | add_echo_byte(ECHO_OP_SET_CANON_COL, ldata); |
851 | mutex_unlock(&ldata->echo_lock); | ||
852 | } | 850 | } |
853 | 851 | ||
854 | /** | 852 | /** |
@@ -864,15 +862,11 @@ static void echo_set_canon_col(struct n_tty_data *ldata) | |||
864 | * of input. This information will be used later, along with | 862 | * of input. This information will be used later, along with |
865 | * canon column (if applicable), to go back the correct number | 863 | * canon column (if applicable), to go back the correct number |
866 | * of columns. | 864 | * of columns. |
867 | * | ||
868 | * Locking: echo_lock to protect the echo buffer | ||
869 | */ | 865 | */ |
870 | 866 | ||
871 | static void echo_erase_tab(unsigned int num_chars, int after_tab, | 867 | static void echo_erase_tab(unsigned int num_chars, int after_tab, |
872 | struct n_tty_data *ldata) | 868 | struct n_tty_data *ldata) |
873 | { | 869 | { |
874 | mutex_lock(&ldata->echo_lock); | ||
875 | |||
876 | add_echo_byte(ECHO_OP_START, ldata); | 870 | add_echo_byte(ECHO_OP_START, ldata); |
877 | add_echo_byte(ECHO_OP_ERASE_TAB, ldata); | 871 | add_echo_byte(ECHO_OP_ERASE_TAB, ldata); |
878 | 872 | ||
@@ -884,8 +878,6 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab, | |||
884 | num_chars |= 0x80; | 878 | num_chars |= 0x80; |
885 | 879 | ||
886 | add_echo_byte(num_chars, ldata); | 880 | add_echo_byte(num_chars, ldata); |
887 | |||
888 | mutex_unlock(&ldata->echo_lock); | ||
889 | } | 881 | } |
890 | 882 | ||
891 | /** | 883 | /** |
@@ -897,20 +889,16 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab, | |||
897 | * L_ECHO(tty) is true. Called from the driver receive_buf path. | 889 | * L_ECHO(tty) is true. Called from the driver receive_buf path. |
898 | * | 890 | * |
899 | * This variant does not treat control characters specially. | 891 | * This variant does not treat control characters specially. |
900 | * | ||
901 | * Locking: echo_lock to protect the echo buffer | ||
902 | */ | 892 | */ |
903 | 893 | ||
904 | static void echo_char_raw(unsigned char c, struct n_tty_data *ldata) | 894 | static void echo_char_raw(unsigned char c, struct n_tty_data *ldata) |
905 | { | 895 | { |
906 | mutex_lock(&ldata->echo_lock); | ||
907 | if (c == ECHO_OP_START) { | 896 | if (c == ECHO_OP_START) { |
908 | add_echo_byte(ECHO_OP_START, ldata); | 897 | add_echo_byte(ECHO_OP_START, ldata); |
909 | add_echo_byte(ECHO_OP_START, ldata); | 898 | add_echo_byte(ECHO_OP_START, ldata); |
910 | } else { | 899 | } else { |
911 | add_echo_byte(c, ldata); | 900 | add_echo_byte(c, ldata); |
912 | } | 901 | } |
913 | mutex_unlock(&ldata->echo_lock); | ||
914 | } | 902 | } |
915 | 903 | ||
916 | /** | 904 | /** |
@@ -923,16 +911,12 @@ static void echo_char_raw(unsigned char c, struct n_tty_data *ldata) | |||
923 | * | 911 | * |
924 | * This variant tags control characters to be echoed as "^X" | 912 | * This variant tags control characters to be echoed as "^X" |
925 | * (where X is the letter representing the control char). | 913 | * (where X is the letter representing the control char). |
926 | * | ||
927 | * Locking: echo_lock to protect the echo buffer | ||
928 | */ | 914 | */ |
929 | 915 | ||
930 | static void echo_char(unsigned char c, struct tty_struct *tty) | 916 | static void echo_char(unsigned char c, struct tty_struct *tty) |
931 | { | 917 | { |
932 | struct n_tty_data *ldata = tty->disc_data; | 918 | struct n_tty_data *ldata = tty->disc_data; |
933 | 919 | ||
934 | mutex_lock(&ldata->echo_lock); | ||
935 | |||
936 | if (c == ECHO_OP_START) { | 920 | if (c == ECHO_OP_START) { |
937 | add_echo_byte(ECHO_OP_START, ldata); | 921 | add_echo_byte(ECHO_OP_START, ldata); |
938 | add_echo_byte(ECHO_OP_START, ldata); | 922 | add_echo_byte(ECHO_OP_START, ldata); |
@@ -941,8 +925,6 @@ static void echo_char(unsigned char c, struct tty_struct *tty) | |||
941 | add_echo_byte(ECHO_OP_START, ldata); | 925 | add_echo_byte(ECHO_OP_START, ldata); |
942 | add_echo_byte(c, ldata); | 926 | add_echo_byte(c, ldata); |
943 | } | 927 | } |
944 | |||
945 | mutex_unlock(&ldata->echo_lock); | ||
946 | } | 928 | } |
947 | 929 | ||
948 | /** | 930 | /** |
@@ -1284,7 +1266,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) | |||
1284 | if (ldata->canon_head == ldata->read_head) | 1266 | if (ldata->canon_head == ldata->read_head) |
1285 | echo_set_canon_col(ldata); | 1267 | echo_set_canon_col(ldata); |
1286 | echo_char(c, tty); | 1268 | echo_char(c, tty); |
1287 | process_echoes(tty); | 1269 | commit_echoes(tty); |
1288 | } | 1270 | } |
1289 | if (parmrk) | 1271 | if (parmrk) |
1290 | put_tty_queue(c, ldata); | 1272 | put_tty_queue(c, ldata); |
@@ -1295,7 +1277,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) | |||
1295 | if (I_IXON(tty)) { | 1277 | if (I_IXON(tty)) { |
1296 | if (c == START_CHAR(tty)) { | 1278 | if (c == START_CHAR(tty)) { |
1297 | start_tty(tty); | 1279 | start_tty(tty); |
1298 | process_echoes(tty); | 1280 | commit_echoes(tty); |
1299 | return; | 1281 | return; |
1300 | } | 1282 | } |
1301 | if (c == STOP_CHAR(tty)) { | 1283 | if (c == STOP_CHAR(tty)) { |
@@ -1326,7 +1308,7 @@ send_signal: | |||
1326 | start_tty(tty); | 1308 | start_tty(tty); |
1327 | if (L_ECHO(tty)) { | 1309 | if (L_ECHO(tty)) { |
1328 | echo_char(c, tty); | 1310 | echo_char(c, tty); |
1329 | process_echoes(tty); | 1311 | commit_echoes(tty); |
1330 | } | 1312 | } |
1331 | isig(signal, tty); | 1313 | isig(signal, tty); |
1332 | return; | 1314 | return; |
@@ -1345,7 +1327,7 @@ send_signal: | |||
1345 | if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || | 1327 | if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || |
1346 | (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { | 1328 | (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { |
1347 | eraser(c, tty); | 1329 | eraser(c, tty); |
1348 | process_echoes(tty); | 1330 | commit_echoes(tty); |
1349 | return; | 1331 | return; |
1350 | } | 1332 | } |
1351 | if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { | 1333 | if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { |
@@ -1355,7 +1337,7 @@ send_signal: | |||
1355 | if (L_ECHOCTL(tty)) { | 1337 | if (L_ECHOCTL(tty)) { |
1356 | echo_char_raw('^', ldata); | 1338 | echo_char_raw('^', ldata); |
1357 | echo_char_raw('\b', ldata); | 1339 | echo_char_raw('\b', ldata); |
1358 | process_echoes(tty); | 1340 | commit_echoes(tty); |
1359 | } | 1341 | } |
1360 | } | 1342 | } |
1361 | return; | 1343 | return; |
@@ -1371,7 +1353,7 @@ send_signal: | |||
1371 | echo_char(read_buf(ldata, tail), tty); | 1353 | echo_char(read_buf(ldata, tail), tty); |
1372 | tail++; | 1354 | tail++; |
1373 | } | 1355 | } |
1374 | process_echoes(tty); | 1356 | commit_echoes(tty); |
1375 | return; | 1357 | return; |
1376 | } | 1358 | } |
1377 | if (c == '\n') { | 1359 | if (c == '\n') { |
@@ -1382,7 +1364,7 @@ send_signal: | |||
1382 | } | 1364 | } |
1383 | if (L_ECHO(tty) || L_ECHONL(tty)) { | 1365 | if (L_ECHO(tty) || L_ECHONL(tty)) { |
1384 | echo_char_raw('\n', ldata); | 1366 | echo_char_raw('\n', ldata); |
1385 | process_echoes(tty); | 1367 | commit_echoes(tty); |
1386 | } | 1368 | } |
1387 | goto handle_newline; | 1369 | goto handle_newline; |
1388 | } | 1370 | } |
@@ -1411,7 +1393,7 @@ send_signal: | |||
1411 | if (ldata->canon_head == ldata->read_head) | 1393 | if (ldata->canon_head == ldata->read_head) |
1412 | echo_set_canon_col(ldata); | 1394 | echo_set_canon_col(ldata); |
1413 | echo_char(c, tty); | 1395 | echo_char(c, tty); |
1414 | process_echoes(tty); | 1396 | commit_echoes(tty); |
1415 | } | 1397 | } |
1416 | /* | 1398 | /* |
1417 | * XXX does PARMRK doubling happen for | 1399 | * XXX does PARMRK doubling happen for |
@@ -1448,7 +1430,7 @@ handle_newline: | |||
1448 | echo_set_canon_col(ldata); | 1430 | echo_set_canon_col(ldata); |
1449 | echo_char(c, tty); | 1431 | echo_char(c, tty); |
1450 | } | 1432 | } |
1451 | process_echoes(tty); | 1433 | commit_echoes(tty); |
1452 | } | 1434 | } |
1453 | 1435 | ||
1454 | if (parmrk) | 1436 | if (parmrk) |
@@ -1713,7 +1695,6 @@ static int n_tty_open(struct tty_struct *tty) | |||
1713 | ldata->overrun_time = jiffies; | 1695 | ldata->overrun_time = jiffies; |
1714 | mutex_init(&ldata->atomic_read_lock); | 1696 | mutex_init(&ldata->atomic_read_lock); |
1715 | mutex_init(&ldata->output_lock); | 1697 | mutex_init(&ldata->output_lock); |
1716 | mutex_init(&ldata->echo_lock); | ||
1717 | 1698 | ||
1718 | /* These are ugly. Currently a malloc failure here can panic */ | 1699 | /* These are ugly. Currently a malloc failure here can panic */ |
1719 | ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); | 1700 | ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); |