diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-06-16 20:24:53 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-06-16 20:24:53 -0400 |
commit | 492b057c426e4aa747484958e18e9da29003985d (patch) | |
tree | 34e08c24618688d8bcc190523028b5f94cce0c0b /drivers/char | |
parent | 313485175da221c388f6a8ecf4c30062ba9bea17 (diff) | |
parent | 300df7dc89cc276377fc020704e34875d5c473b6 (diff) |
Merge commit 'origin/master' into next
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/hvc_iucv.c | 204 | ||||
-rw-r--r-- | drivers/char/pty.c | 53 | ||||
-rw-r--r-- | drivers/char/tty_io.c | 2 | ||||
-rw-r--r-- | drivers/char/tty_ioctl.c | 5 | ||||
-rw-r--r-- | drivers/char/tty_ldisc.c | 9 |
5 files changed, 213 insertions, 60 deletions
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index 54481a887769..86105efb4eb6 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * This HVC device driver provides terminal access using | 4 | * This HVC device driver provides terminal access using |
5 | * z/VM IUCV communication paths. | 5 | * z/VM IUCV communication paths. |
6 | * | 6 | * |
7 | * Copyright IBM Corp. 2008 | 7 | * Copyright IBM Corp. 2008, 2009 |
8 | * | 8 | * |
9 | * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> | 9 | * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> |
10 | */ | 10 | */ |
@@ -15,6 +15,7 @@ | |||
15 | #include <asm/ebcdic.h> | 15 | #include <asm/ebcdic.h> |
16 | #include <linux/ctype.h> | 16 | #include <linux/ctype.h> |
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/device.h> | ||
18 | #include <linux/init.h> | 19 | #include <linux/init.h> |
19 | #include <linux/mempool.h> | 20 | #include <linux/mempool.h> |
20 | #include <linux/moduleparam.h> | 21 | #include <linux/moduleparam.h> |
@@ -74,6 +75,7 @@ struct hvc_iucv_private { | |||
74 | wait_queue_head_t sndbuf_waitq; /* wait for send completion */ | 75 | wait_queue_head_t sndbuf_waitq; /* wait for send completion */ |
75 | struct list_head tty_outqueue; /* outgoing IUCV messages */ | 76 | struct list_head tty_outqueue; /* outgoing IUCV messages */ |
76 | struct list_head tty_inqueue; /* incoming IUCV messages */ | 77 | struct list_head tty_inqueue; /* incoming IUCV messages */ |
78 | struct device *dev; /* device structure */ | ||
77 | }; | 79 | }; |
78 | 80 | ||
79 | struct iucv_tty_buffer { | 81 | struct iucv_tty_buffer { |
@@ -542,7 +544,68 @@ static void flush_sndbuf_sync(struct hvc_iucv_private *priv) | |||
542 | 544 | ||
543 | if (sync_wait) | 545 | if (sync_wait) |
544 | wait_event_timeout(priv->sndbuf_waitq, | 546 | wait_event_timeout(priv->sndbuf_waitq, |
545 | tty_outqueue_empty(priv), HZ); | 547 | tty_outqueue_empty(priv), HZ/10); |
548 | } | ||
549 | |||
550 | /** | ||
551 | * hvc_iucv_hangup() - Sever IUCV path and schedule hvc tty hang up | ||
552 | * @priv: Pointer to hvc_iucv_private structure | ||
553 | * | ||
554 | * This routine severs an existing IUCV communication path and hangs | ||
555 | * up the underlying HVC terminal device. | ||
556 | * The hang-up occurs only if an IUCV communication path is established; | ||
557 | * otherwise there is no need to hang up the terminal device. | ||
558 | * | ||
559 | * The IUCV HVC hang-up is separated into two steps: | ||
560 | * 1. After the IUCV path has been severed, the iucv_state is set to | ||
561 | * IUCV_SEVERED. | ||
562 | * 2. Later, when the HVC thread calls hvc_iucv_get_chars(), the | ||
563 | * IUCV_SEVERED state causes the tty hang-up in the HVC layer. | ||
564 | * | ||
565 | * If the tty has not yet been opened, clean up the hvc_iucv_private | ||
566 | * structure to allow re-connects. | ||
567 | * If the tty has been opened, let get_chars() return -EPIPE to signal | ||
568 | * the HVC layer to hang up the tty and, if so, wake up the HVC thread | ||
569 | * to call get_chars()... | ||
570 | * | ||
571 | * Special notes on hanging up a HVC terminal instantiated as console: | ||
572 | * Hang-up: 1. do_tty_hangup() replaces file ops (= hung_up_tty_fops) | ||
573 | * 2. do_tty_hangup() calls tty->ops->close() for console_filp | ||
574 | * => no hangup notifier is called by HVC (default) | ||
575 | * 2. hvc_close() returns because of tty_hung_up_p(filp) | ||
576 | * => no delete notifier is called! | ||
577 | * Finally, the back-end is not being notified, thus, the tty session is | ||
578 | * kept active (TTY_OPEN) to be ready for re-connects. | ||
579 | * | ||
580 | * Locking: spin_lock(&priv->lock) w/o disabling bh | ||
581 | */ | ||
582 | static void hvc_iucv_hangup(struct hvc_iucv_private *priv) | ||
583 | { | ||
584 | struct iucv_path *path; | ||
585 | |||
586 | path = NULL; | ||
587 | spin_lock(&priv->lock); | ||
588 | if (priv->iucv_state == IUCV_CONNECTED) { | ||
589 | path = priv->path; | ||
590 | priv->path = NULL; | ||
591 | priv->iucv_state = IUCV_SEVERED; | ||
592 | if (priv->tty_state == TTY_CLOSED) | ||
593 | hvc_iucv_cleanup(priv); | ||
594 | else | ||
595 | /* console is special (see above) */ | ||
596 | if (priv->is_console) { | ||
597 | hvc_iucv_cleanup(priv); | ||
598 | priv->tty_state = TTY_OPENED; | ||
599 | } else | ||
600 | hvc_kick(); | ||
601 | } | ||
602 | spin_unlock(&priv->lock); | ||
603 | |||
604 | /* finally sever path (outside of priv->lock due to lock ordering) */ | ||
605 | if (path) { | ||
606 | iucv_path_sever(path, NULL); | ||
607 | iucv_path_free(path); | ||
608 | } | ||
546 | } | 609 | } |
547 | 610 | ||
548 | /** | 611 | /** |
@@ -735,11 +798,8 @@ out_path_handled: | |||
735 | * @ipuser: User specified data for this path | 798 | * @ipuser: User specified data for this path |
736 | * (AF_IUCV: port/service name and originator port) | 799 | * (AF_IUCV: port/service name and originator port) |
737 | * | 800 | * |
738 | * The function also severs the path (as required by the IUCV protocol) and | 801 | * This function calls the hvc_iucv_hangup() function for the |
739 | * sets the iucv state to IUCV_SEVERED for the associated struct | 802 | * respective IUCV HVC terminal. |
740 | * hvc_iucv_private instance. Later, the IUCV_SEVERED state triggers a tty | ||
741 | * hangup (hvc_iucv_get_chars() / hvc_iucv_write()). | ||
742 | * If tty portion of the HVC is closed, clean up the outqueue. | ||
743 | * | 803 | * |
744 | * Locking: struct hvc_iucv_private->lock | 804 | * Locking: struct hvc_iucv_private->lock |
745 | */ | 805 | */ |
@@ -747,33 +807,7 @@ static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) | |||
747 | { | 807 | { |
748 | struct hvc_iucv_private *priv = path->private; | 808 | struct hvc_iucv_private *priv = path->private; |
749 | 809 | ||
750 | spin_lock(&priv->lock); | 810 | hvc_iucv_hangup(priv); |
751 | priv->iucv_state = IUCV_SEVERED; | ||
752 | |||
753 | /* If the tty has not yet been opened, clean up the hvc_iucv_private | ||
754 | * structure to allow re-connects. | ||
755 | * This is also done for our console device because console hangups | ||
756 | * are handled specially and no notifier is called by HVC. | ||
757 | * The tty session is active (TTY_OPEN) and ready for re-connects... | ||
758 | * | ||
759 | * If it has been opened, let get_chars() return -EPIPE to signal the | ||
760 | * HVC layer to hang up the tty. | ||
761 | * If so, we need to wake up the HVC thread to call get_chars()... | ||
762 | */ | ||
763 | priv->path = NULL; | ||
764 | if (priv->tty_state == TTY_CLOSED) | ||
765 | hvc_iucv_cleanup(priv); | ||
766 | else | ||
767 | if (priv->is_console) { | ||
768 | hvc_iucv_cleanup(priv); | ||
769 | priv->tty_state = TTY_OPENED; | ||
770 | } else | ||
771 | hvc_kick(); | ||
772 | spin_unlock(&priv->lock); | ||
773 | |||
774 | /* finally sever path (outside of priv->lock due to lock ordering) */ | ||
775 | iucv_path_sever(path, ipuser); | ||
776 | iucv_path_free(path); | ||
777 | } | 811 | } |
778 | 812 | ||
779 | /** | 813 | /** |
@@ -853,6 +887,37 @@ static void hvc_iucv_msg_complete(struct iucv_path *path, | |||
853 | destroy_tty_buffer_list(&list_remove); | 887 | destroy_tty_buffer_list(&list_remove); |
854 | } | 888 | } |
855 | 889 | ||
890 | /** | ||
891 | * hvc_iucv_pm_freeze() - Freeze PM callback | ||
892 | * @dev: IUVC HVC terminal device | ||
893 | * | ||
894 | * Sever an established IUCV communication path and | ||
895 | * trigger a hang-up of the underlying HVC terminal. | ||
896 | */ | ||
897 | static int hvc_iucv_pm_freeze(struct device *dev) | ||
898 | { | ||
899 | struct hvc_iucv_private *priv = dev_get_drvdata(dev); | ||
900 | |||
901 | local_bh_disable(); | ||
902 | hvc_iucv_hangup(priv); | ||
903 | local_bh_enable(); | ||
904 | |||
905 | return 0; | ||
906 | } | ||
907 | |||
908 | /** | ||
909 | * hvc_iucv_pm_restore_thaw() - Thaw and restore PM callback | ||
910 | * @dev: IUVC HVC terminal device | ||
911 | * | ||
912 | * Wake up the HVC thread to trigger hang-up and respective | ||
913 | * HVC back-end notifier invocations. | ||
914 | */ | ||
915 | static int hvc_iucv_pm_restore_thaw(struct device *dev) | ||
916 | { | ||
917 | hvc_kick(); | ||
918 | return 0; | ||
919 | } | ||
920 | |||
856 | 921 | ||
857 | /* HVC operations */ | 922 | /* HVC operations */ |
858 | static struct hv_ops hvc_iucv_ops = { | 923 | static struct hv_ops hvc_iucv_ops = { |
@@ -863,6 +928,20 @@ static struct hv_ops hvc_iucv_ops = { | |||
863 | .notifier_hangup = hvc_iucv_notifier_hangup, | 928 | .notifier_hangup = hvc_iucv_notifier_hangup, |
864 | }; | 929 | }; |
865 | 930 | ||
931 | /* Suspend / resume device operations */ | ||
932 | static struct dev_pm_ops hvc_iucv_pm_ops = { | ||
933 | .freeze = hvc_iucv_pm_freeze, | ||
934 | .thaw = hvc_iucv_pm_restore_thaw, | ||
935 | .restore = hvc_iucv_pm_restore_thaw, | ||
936 | }; | ||
937 | |||
938 | /* IUCV HVC device driver */ | ||
939 | static struct device_driver hvc_iucv_driver = { | ||
940 | .name = KMSG_COMPONENT, | ||
941 | .bus = &iucv_bus, | ||
942 | .pm = &hvc_iucv_pm_ops, | ||
943 | }; | ||
944 | |||
866 | /** | 945 | /** |
867 | * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance | 946 | * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance |
868 | * @id: hvc_iucv_table index | 947 | * @id: hvc_iucv_table index |
@@ -897,14 +976,12 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) | |||
897 | /* set console flag */ | 976 | /* set console flag */ |
898 | priv->is_console = is_console; | 977 | priv->is_console = is_console; |
899 | 978 | ||
900 | /* finally allocate hvc */ | 979 | /* allocate hvc device */ |
901 | priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */ | 980 | priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */ |
902 | HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256); | 981 | HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256); |
903 | if (IS_ERR(priv->hvc)) { | 982 | if (IS_ERR(priv->hvc)) { |
904 | rc = PTR_ERR(priv->hvc); | 983 | rc = PTR_ERR(priv->hvc); |
905 | free_page((unsigned long) priv->sndbuf); | 984 | goto out_error_hvc; |
906 | kfree(priv); | ||
907 | return rc; | ||
908 | } | 985 | } |
909 | 986 | ||
910 | /* notify HVC thread instead of using polling */ | 987 | /* notify HVC thread instead of using polling */ |
@@ -915,8 +992,45 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) | |||
915 | memcpy(priv->srv_name, name, 8); | 992 | memcpy(priv->srv_name, name, 8); |
916 | ASCEBC(priv->srv_name, 8); | 993 | ASCEBC(priv->srv_name, 8); |
917 | 994 | ||
995 | /* create and setup device */ | ||
996 | priv->dev = kzalloc(sizeof(*priv->dev), GFP_KERNEL); | ||
997 | if (!priv->dev) { | ||
998 | rc = -ENOMEM; | ||
999 | goto out_error_dev; | ||
1000 | } | ||
1001 | dev_set_name(priv->dev, "hvc_iucv%d", id); | ||
1002 | dev_set_drvdata(priv->dev, priv); | ||
1003 | priv->dev->bus = &iucv_bus; | ||
1004 | priv->dev->parent = iucv_root; | ||
1005 | priv->dev->driver = &hvc_iucv_driver; | ||
1006 | priv->dev->release = (void (*)(struct device *)) kfree; | ||
1007 | rc = device_register(priv->dev); | ||
1008 | if (rc) { | ||
1009 | kfree(priv->dev); | ||
1010 | goto out_error_dev; | ||
1011 | } | ||
1012 | |||
918 | hvc_iucv_table[id] = priv; | 1013 | hvc_iucv_table[id] = priv; |
919 | return 0; | 1014 | return 0; |
1015 | |||
1016 | out_error_dev: | ||
1017 | hvc_remove(priv->hvc); | ||
1018 | out_error_hvc: | ||
1019 | free_page((unsigned long) priv->sndbuf); | ||
1020 | kfree(priv); | ||
1021 | |||
1022 | return rc; | ||
1023 | } | ||
1024 | |||
1025 | /** | ||
1026 | * hvc_iucv_destroy() - Destroy and free hvc_iucv_private instances | ||
1027 | */ | ||
1028 | static void __init hvc_iucv_destroy(struct hvc_iucv_private *priv) | ||
1029 | { | ||
1030 | hvc_remove(priv->hvc); | ||
1031 | device_unregister(priv->dev); | ||
1032 | free_page((unsigned long) priv->sndbuf); | ||
1033 | kfree(priv); | ||
920 | } | 1034 | } |
921 | 1035 | ||
922 | /** | 1036 | /** |
@@ -1109,6 +1223,11 @@ static int __init hvc_iucv_init(void) | |||
1109 | goto out_error; | 1223 | goto out_error; |
1110 | } | 1224 | } |
1111 | 1225 | ||
1226 | /* register IUCV HVC device driver */ | ||
1227 | rc = driver_register(&hvc_iucv_driver); | ||
1228 | if (rc) | ||
1229 | goto out_error; | ||
1230 | |||
1112 | /* parse hvc_iucv_allow string and create z/VM user ID filter list */ | 1231 | /* parse hvc_iucv_allow string and create z/VM user ID filter list */ |
1113 | if (hvc_iucv_filter_string) { | 1232 | if (hvc_iucv_filter_string) { |
1114 | rc = hvc_iucv_setup_filter(hvc_iucv_filter_string); | 1233 | rc = hvc_iucv_setup_filter(hvc_iucv_filter_string); |
@@ -1183,15 +1302,14 @@ out_error_iucv: | |||
1183 | iucv_unregister(&hvc_iucv_handler, 0); | 1302 | iucv_unregister(&hvc_iucv_handler, 0); |
1184 | out_error_hvc: | 1303 | out_error_hvc: |
1185 | for (i = 0; i < hvc_iucv_devices; i++) | 1304 | for (i = 0; i < hvc_iucv_devices; i++) |
1186 | if (hvc_iucv_table[i]) { | 1305 | if (hvc_iucv_table[i]) |
1187 | if (hvc_iucv_table[i]->hvc) | 1306 | hvc_iucv_destroy(hvc_iucv_table[i]); |
1188 | hvc_remove(hvc_iucv_table[i]->hvc); | ||
1189 | kfree(hvc_iucv_table[i]); | ||
1190 | } | ||
1191 | out_error_memory: | 1307 | out_error_memory: |
1192 | mempool_destroy(hvc_iucv_mempool); | 1308 | mempool_destroy(hvc_iucv_mempool); |
1193 | kmem_cache_destroy(hvc_iucv_buffer_cache); | 1309 | kmem_cache_destroy(hvc_iucv_buffer_cache); |
1194 | out_error: | 1310 | out_error: |
1311 | if (hvc_iucv_filter) | ||
1312 | kfree(hvc_iucv_filter); | ||
1195 | hvc_iucv_devices = 0; /* ensure that we do not provide any device */ | 1313 | hvc_iucv_devices = 0; /* ensure that we do not provide any device */ |
1196 | return rc; | 1314 | return rc; |
1197 | } | 1315 | } |
diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 5acd29e6e043..daebe1ba43d4 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c | |||
@@ -95,23 +95,34 @@ static void pty_unthrottle(struct tty_struct *tty) | |||
95 | * a count. | 95 | * a count. |
96 | * | 96 | * |
97 | * FIXME: Our pty_write method is called with our ldisc lock held but | 97 | * FIXME: Our pty_write method is called with our ldisc lock held but |
98 | * not our partners. We can't just take the other one blindly without | 98 | * not our partners. We can't just wait on the other one blindly without |
99 | * risking deadlocks. | 99 | * risking deadlocks. At some point when everything has settled down we need |
100 | * to look into making pty_write at least able to sleep over an ldisc change. | ||
101 | * | ||
102 | * The return on no ldisc is a bit counter intuitive but the logic works | ||
103 | * like this. During an ldisc change the other end will flush its buffers. We | ||
104 | * thus return the full length which is identical to the case where we had | ||
105 | * proper locking and happened to queue the bytes just before the flush during | ||
106 | * the ldisc change. | ||
100 | */ | 107 | */ |
101 | static int pty_write(struct tty_struct *tty, const unsigned char *buf, | 108 | static int pty_write(struct tty_struct *tty, const unsigned char *buf, |
102 | int count) | 109 | int count) |
103 | { | 110 | { |
104 | struct tty_struct *to = tty->link; | 111 | struct tty_struct *to = tty->link; |
105 | int c; | 112 | struct tty_ldisc *ld; |
113 | int c = count; | ||
106 | 114 | ||
107 | if (!to || tty->stopped) | 115 | if (!to || tty->stopped) |
108 | return 0; | 116 | return 0; |
109 | 117 | ld = tty_ldisc_ref(to); | |
110 | c = to->receive_room; | 118 | |
111 | if (c > count) | 119 | if (ld) { |
112 | c = count; | 120 | c = to->receive_room; |
113 | to->ldisc->ops->receive_buf(to, buf, NULL, c); | 121 | if (c > count) |
114 | 122 | c = count; | |
123 | ld->ops->receive_buf(to, buf, NULL, c); | ||
124 | tty_ldisc_deref(ld); | ||
125 | } | ||
115 | return c; | 126 | return c; |
116 | } | 127 | } |
117 | 128 | ||
@@ -145,14 +156,23 @@ static int pty_write_room(struct tty_struct *tty) | |||
145 | static int pty_chars_in_buffer(struct tty_struct *tty) | 156 | static int pty_chars_in_buffer(struct tty_struct *tty) |
146 | { | 157 | { |
147 | struct tty_struct *to = tty->link; | 158 | struct tty_struct *to = tty->link; |
148 | int count; | 159 | struct tty_ldisc *ld; |
160 | int count = 0; | ||
149 | 161 | ||
150 | /* We should get the line discipline lock for "tty->link" */ | 162 | /* We should get the line discipline lock for "tty->link" */ |
151 | if (!to || !to->ldisc->ops->chars_in_buffer) | 163 | if (!to) |
164 | return 0; | ||
165 | /* We cannot take a sleeping reference here without deadlocking with | ||
166 | an ldisc change - but it doesn't really matter */ | ||
167 | ld = tty_ldisc_ref(to); | ||
168 | if (ld == NULL) | ||
152 | return 0; | 169 | return 0; |
153 | 170 | ||
154 | /* The ldisc must report 0 if no characters available to be read */ | 171 | /* The ldisc must report 0 if no characters available to be read */ |
155 | count = to->ldisc->ops->chars_in_buffer(to); | 172 | if (ld->ops->chars_in_buffer) |
173 | count = ld->ops->chars_in_buffer(to); | ||
174 | |||
175 | tty_ldisc_deref(ld); | ||
156 | 176 | ||
157 | if (tty->driver->subtype == PTY_TYPE_SLAVE) | 177 | if (tty->driver->subtype == PTY_TYPE_SLAVE) |
158 | return count; | 178 | return count; |
@@ -182,12 +202,19 @@ static void pty_flush_buffer(struct tty_struct *tty) | |||
182 | { | 202 | { |
183 | struct tty_struct *to = tty->link; | 203 | struct tty_struct *to = tty->link; |
184 | unsigned long flags; | 204 | unsigned long flags; |
205 | struct tty_ldisc *ld; | ||
185 | 206 | ||
186 | if (!to) | 207 | if (!to) |
187 | return; | 208 | return; |
209 | ld = tty_ldisc_ref(to); | ||
210 | |||
211 | /* The other end is changing discipline */ | ||
212 | if (!ld) | ||
213 | return; | ||
188 | 214 | ||
189 | if (to->ldisc->ops->flush_buffer) | 215 | if (ld->ops->flush_buffer) |
190 | to->ldisc->ops->flush_buffer(to); | 216 | to->ldisc->ops->flush_buffer(to); |
217 | tty_ldisc_deref(ld); | ||
191 | 218 | ||
192 | if (to->packet) { | 219 | if (to->packet) { |
193 | spin_lock_irqsave(&tty->ctrl_lock, flags); | 220 | spin_lock_irqsave(&tty->ctrl_lock, flags); |
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 939e198d7670..a3afa0c387cd 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -1263,7 +1263,9 @@ static int tty_reopen(struct tty_struct *tty) | |||
1263 | tty->count++; | 1263 | tty->count++; |
1264 | tty->driver = driver; /* N.B. why do this every time?? */ | 1264 | tty->driver = driver; /* N.B. why do this every time?? */ |
1265 | 1265 | ||
1266 | mutex_lock(&tty->ldisc_mutex); | ||
1266 | WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); | 1267 | WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); |
1268 | mutex_unlock(&tty->ldisc_mutex); | ||
1267 | 1269 | ||
1268 | return 0; | 1270 | return 0; |
1269 | } | 1271 | } |
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 8116bb1c8f80..b24f6c6a1ea3 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c | |||
@@ -947,7 +947,6 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
947 | void __user *p = (void __user *)arg; | 947 | void __user *p = (void __user *)arg; |
948 | int ret = 0; | 948 | int ret = 0; |
949 | struct ktermios kterm; | 949 | struct ktermios kterm; |
950 | struct termiox ktermx; | ||
951 | 950 | ||
952 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 951 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
953 | tty->driver->subtype == PTY_TYPE_MASTER) | 952 | tty->driver->subtype == PTY_TYPE_MASTER) |
@@ -1049,7 +1048,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
1049 | return ret; | 1048 | return ret; |
1050 | #endif | 1049 | #endif |
1051 | #ifdef TCGETX | 1050 | #ifdef TCGETX |
1052 | case TCGETX: | 1051 | case TCGETX: { |
1052 | struct termiox ktermx; | ||
1053 | if (real_tty->termiox == NULL) | 1053 | if (real_tty->termiox == NULL) |
1054 | return -EINVAL; | 1054 | return -EINVAL; |
1055 | mutex_lock(&real_tty->termios_mutex); | 1055 | mutex_lock(&real_tty->termios_mutex); |
@@ -1058,6 +1058,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
1058 | if (copy_to_user(p, &ktermx, sizeof(struct termiox))) | 1058 | if (copy_to_user(p, &ktermx, sizeof(struct termiox))) |
1059 | ret = -EFAULT; | 1059 | ret = -EFAULT; |
1060 | return ret; | 1060 | return ret; |
1061 | } | ||
1061 | case TCSETX: | 1062 | case TCSETX: |
1062 | return set_termiox(real_tty, p, 0); | 1063 | return set_termiox(real_tty, p, 0); |
1063 | case TCSETXW: | 1064 | case TCSETXW: |
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index 39c8f86dedd4..a19e935847b0 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c | |||
@@ -148,8 +148,10 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc) | |||
148 | } | 148 | } |
149 | } | 149 | } |
150 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 150 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
151 | if (err) | 151 | if (err) { |
152 | kfree(ld); | ||
152 | return ERR_PTR(err); | 153 | return ERR_PTR(err); |
154 | } | ||
153 | return ld; | 155 | return ld; |
154 | } | 156 | } |
155 | 157 | ||
@@ -205,6 +207,7 @@ static void tty_ldisc_put(struct tty_ldisc *ld) | |||
205 | ldo->refcount--; | 207 | ldo->refcount--; |
206 | module_put(ldo->owner); | 208 | module_put(ldo->owner); |
207 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 209 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
210 | WARN_ON(ld->refcount); | ||
208 | kfree(ld); | 211 | kfree(ld); |
209 | } | 212 | } |
210 | 213 | ||
@@ -262,7 +265,7 @@ const struct file_operations tty_ldiscs_proc_fops = { | |||
262 | * @ld: line discipline | 265 | * @ld: line discipline |
263 | * | 266 | * |
264 | * Install an instance of a line discipline into a tty structure. The | 267 | * Install an instance of a line discipline into a tty structure. The |
265 | * ldisc must have a reference count above zero to ensure it remains/ | 268 | * ldisc must have a reference count above zero to ensure it remains. |
266 | * The tty instance refcount starts at zero. | 269 | * The tty instance refcount starts at zero. |
267 | * | 270 | * |
268 | * Locking: | 271 | * Locking: |
@@ -791,6 +794,8 @@ void tty_ldisc_hangup(struct tty_struct *tty) | |||
791 | /* Avoid racing set_ldisc */ | 794 | /* Avoid racing set_ldisc */ |
792 | mutex_lock(&tty->ldisc_mutex); | 795 | mutex_lock(&tty->ldisc_mutex); |
793 | /* Switch back to N_TTY */ | 796 | /* Switch back to N_TTY */ |
797 | tty_ldisc_halt(tty); | ||
798 | tty_ldisc_wait_idle(tty); | ||
794 | tty_ldisc_reinit(tty); | 799 | tty_ldisc_reinit(tty); |
795 | /* At this point we have a closed ldisc and we want to | 800 | /* At this point we have a closed ldisc and we want to |
796 | reopen it. We could defer this to the next open but | 801 | reopen it. We could defer this to the next open but |