From: Hendrik Brueckner <hidden> Date: 2013-07-02 15:07:38
Hi folks,
this series resolves an issue for hvc back-ends that transfer
terminal data over an established communication path.
The current implementation of the hvc_console layer notifies its
back-ends for tty open, close, and hangups. However, there are
conditions where the hangup-on-close (HUPCL) termios flag must be
considered, for example, when doing a vhangup().
For the hvc_iucv back-end, users perceives disconnects at their
login which are triggered by a modified vhangup() invocation as
described in https://lkml.org/lkml/2012/6/5/145.
(The kernel change implied also a change in the login program).
However, this also necessitates to inform back-ends about changes
in the DTR/RTS control lines which actually depend on the setting
of the HUPCL termios flag. Like in the old days for modems,
network-based back-ends need to know when to hang-up and drop off
an established communication path. Without this new notification,
back-ends can only use the tty open, close, hangup notifiers to
decide whether to disconnect. This is not sufficient because the
HUPCL flag can be cleared (i.e. not to hang-up a connection) when
last tty file descriptor is closed.
This series adds the dtr_rts() callback to the hvc_console layer
and modifies the hvc_iucv device driver to disconnect an established
IUCV connection only when the DTR/RTS is lowered.
Feedback is very welcome. Thanks in advance!
Kind regards,
Hendrik
From: Hendrik Brueckner <hidden> Date: 2013-07-02 15:07:37
Introduce a new callback to explicitly handle the HUPCL termios control flag.
This prepares for a follow-up commit for the hvc_iucv device driver to
improve handling when to drop an established network connection.
The callback naming is based on the recently added tty_port interface to
facilitate a potential refactoring of the hvc_console to use tty_port
functions.
Signed-off-by: Hendrik Brueckner <redacted>
---
drivers/tty/hvc/hvc_console.c | 11 ++++++++++-
drivers/tty/hvc/hvc_console.h | 3 +++
2 files changed, 13 insertions(+), 1 deletions(-)
@@ -361,7 +361,12 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)tty->driver_data=NULL;tty_port_put(&hp->port);printk(KERN_ERR"hvc_open: request_irq failed with rc %d.\n",rc);-}+}else+/* We are ready... raise DTR/RTS */+if(C_BAUD(tty))+if(hp->ops->dtr_rts)+hp->ops->dtr_rts(hp,1);+/* Force wakeup of the polling thread */hvc_kick();
@@ -393,6 +398,10 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)/* We are done with the tty pointer now. */tty_port_tty_set(&hp->port,NULL);+if(C_HUPCL(tty))+if(hp->ops->dtr_rts)+hp->ops->dtr_rts(hp,0);+if(hp->ops->notifier_del)hp->ops->notifier_del(hp,hp->data);
@@ -75,6 +75,9 @@ struct hv_ops {/* tiocmget/set implementation */int(*tiocmget)(structhvc_struct*hp);int(*tiocmset)(structhvc_struct*hp,unsignedintset,unsignedintclear);++/* Callbacks to handle tty ports */+void(*dtr_rts)(structhvc_struct*hp,intraise);};/* Register a vterm and a slot index for use as a console (console_init) */
From: Hendrik Brueckner <hidden> Date: 2013-07-02 15:07:39
Implement the dtr_rts() hvc console callback to improve control when to
disconnect the IUCV connection. Previously, the IUCV connection was
disconnected during the notifier_del() callback, i.e., when the last file
descriptor to the hvc terminal device was closed.
Recent changes in login programs caused undesired disconnects during the
login phase. To prevent these kind of disconnects, implement the dtr_rts
callback to implicitly handle the HUPCL termios control via the hvc_console
driver.
Signed-off-by: Hendrik Brueckner <redacted>
---
drivers/tty/hvc/hvc_iucv.c | 64 +++++++++++++++++++++++++++++++++++---------
1 files changed, 51 insertions(+), 13 deletions(-)
@@ -656,21 +656,64 @@ static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id)}/**+*hvc_iucv_dtr_rts()-HVCnotifierforhandlingDTR/RTS+*@hp:PointertheHVCdevice(structhvc_struct)+*@raise:Non-zerotoraiseorzerotolowerDTR/RTSlines+*+*ThisroutinenotifiestheHVCback-endtoraiseorlowerDTR/RTS+*lines.RaisingDTR/RTSisignored.LoweringDTR/RTSindicatesto+*droptheIUCVconnection(similartohangupthemodem).+*/+staticvoidhvc_iucv_dtr_rts(structhvc_struct*hp,intraise)+{+structhvc_iucv_private*priv;+structiucv_path*path;++/* Raising the DTR/RTS is ignored as IUCV connections can be+*establishedatanytimes.+*/+if(raise)+return;++priv=hvc_iucv_get_private(hp->vtermno);+if(!priv)+return;++/* Lowering the DTR/RTS lines disconnects an established IUCV+*connection.+*/+flush_sndbuf_sync(priv);++spin_lock_bh(&priv->lock);+path=priv->path;/* save reference to IUCV path */+priv->path=NULL;+priv->iucv_state=IUCV_DISCONN;+spin_unlock_bh(&priv->lock);++/* Sever IUCV path outside of priv->lock due to lock ordering of:+*priv->lock<-->iucv_table_lock*/+if(path){+iucv_path_sever(path,NULL);+iucv_path_free(path);+}+}++/***hvc_iucv_notifier_del()-HVCnotifierforclosingaTTYforthelasttime.*@hp:PointertotheHVCdevice(structhvc_struct)*@id:Additionaldata(originallypassedtohvc_alloc):*theindexofanstructhvc_iucv_privateinstance.**ThisroutinenotifiestheHVCback-endthatthelastttydevicefdhasbeen-*closed.Thefunctioncallshvc_iucv_cleanup()tocleanupthestruct-*hvc_iucv_privateinstance.+*closed.Thefunctioncleansupttyresources.Theclean-upoftheIUCV+*connectionisdoneinhvc_iucv_dtr_rts()anddependsontheHUPCLtermios+*controlsetting.**Locking:structhvc_iucv_private->lock*/staticvoidhvc_iucv_notifier_del(structhvc_struct*hp,intid){structhvc_iucv_private*priv;-structiucv_path*path;priv=hvc_iucv_get_private(id);if(!priv)
@@ -679,17 +722,11 @@ static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id)flush_sndbuf_sync(priv);spin_lock_bh(&priv->lock);-path=priv->path;/* save reference to IUCV path */-priv->path=NULL;-hvc_iucv_cleanup(priv);+destroy_tty_buffer_list(&priv->tty_outqueue);+destroy_tty_buffer_list(&priv->tty_inqueue);+priv->tty_state=TTY_CLOSED;+priv->sndbuf_len=0;spin_unlock_bh(&priv->lock);--/* sever IUCV path outside of priv->lock due to lock ordering of:-*priv->lock<-->iucv_table_lock*/-if(path){-iucv_path_sever(path,NULL);-iucv_path_free(path);-}}/**
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2013-10-11 07:15:44
On Tue, 2013-07-02 at 17:07 +0200, Hendrik Brueckner wrote:
Introduce a new callback to explicitly handle the HUPCL termios control flag.
This prepares for a follow-up commit for the hvc_iucv device driver to
improve handling when to drop an established network connection.
The callback naming is based on the recently added tty_port interface to
facilitate a potential refactoring of the hvc_console to use tty_port
functions.
I only just noticed that ... oops. Why add those dtr_rts() calls ? We
already have tiocmset in there which is used to set DTR on HVSI consoles
such as hvc_opal when using hvsi_lib...
Any reason why a separate callback was needed ?
Cheers,
Ben.
@@ -361,7 +361,12 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)tty->driver_data=NULL;tty_port_put(&hp->port);printk(KERN_ERR"hvc_open: request_irq failed with rc %d.\n",rc);-}+}else+/* We are ready... raise DTR/RTS */+if(C_BAUD(tty))+if(hp->ops->dtr_rts)+hp->ops->dtr_rts(hp,1);+/* Force wakeup of the polling thread */hvc_kick();
@@ -393,6 +398,10 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)/* We are done with the tty pointer now. */tty_port_tty_set(&hp->port,NULL);+if(C_HUPCL(tty))+if(hp->ops->dtr_rts)+hp->ops->dtr_rts(hp,0);+if(hp->ops->notifier_del)hp->ops->notifier_del(hp,hp->data);
@@ -75,6 +75,9 @@ struct hv_ops {/* tiocmget/set implementation */int(*tiocmget)(structhvc_struct*hp);int(*tiocmset)(structhvc_struct*hp,unsignedintset,unsignedintclear);++/* Callbacks to handle tty ports */+void(*dtr_rts)(structhvc_struct*hp,intraise);};/* Register a vterm and a slot index for use as a console (console_init) */
From: Hendrik Brueckner <hidden> Date: 2013-10-11 12:48:32
Hi Benjamin,
On Fri, Oct 11, 2013 at 06:15:11PM +1100, Benjamin Herrenschmidt wrote:
On Tue, 2013-07-02 at 17:07 +0200, Hendrik Brueckner wrote:
quoted
Introduce a new callback to explicitly handle the HUPCL termios control flag.
This prepares for a follow-up commit for the hvc_iucv device driver to
improve handling when to drop an established network connection.
The callback naming is based on the recently added tty_port interface to
facilitate a potential refactoring of the hvc_console to use tty_port
functions.
I only just noticed that ... oops. Why add those dtr_rts() calls ? We
already have tiocmset in there which is used to set DTR on HVSI consoles
such as hvc_opal when using hvsi_lib...
Any reason why a separate callback was needed ?
The tiocmget/tiocmset callbacks are used to set and get modem status and
triggered through an tty ioctl.
The dtr_rts() callback is different and it is used for DTS/RTS handshaking
between the hvc_console (or any other tty_port) and the tty layer. The tty
port layer uses this callback to signal the hvc_console whether to raise or
lower the DTR/RTS lines. This is different than the ioctl interface to
controls the modem status.
Thanks and kind regards,
Hendrik
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2013-10-11 20:43:57
On Fri, 2013-10-11 at 14:47 +0200, Hendrik Brueckner wrote:
The tiocmget/tiocmset callbacks are used to set and get modem status and
triggered through an tty ioctl.
The dtr_rts() callback is different and it is used for DTS/RTS handshaking
between the hvc_console (or any other tty_port) and the tty layer. The tty
port layer uses this callback to signal the hvc_console whether to raise or
lower the DTR/RTS lines. This is different than the ioctl interface to
controls the modem status.
Well, DTR at least is the same via both callbacks... Also normal handshaking
is normally RTS/CTS, only some HW setups "hijacks" DTR for RTS (old Macs come
to mind).
Cheers,
Ben.
From: Hendrik Brueckner <hidden> Date: 2013-10-15 15:40:50
Hi Benjamin,
On Sat, Oct 12, 2013 at 07:43:24AM +1100, Benjamin Herrenschmidt wrote:
On Fri, 2013-10-11 at 14:47 +0200, Hendrik Brueckner wrote:
quoted
The tiocmget/tiocmset callbacks are used to set and get modem status and
triggered through an tty ioctl.
The dtr_rts() callback is different and it is used for DTS/RTS handshaking
between the hvc_console (or any other tty_port) and the tty layer. The tty
port layer uses this callback to signal the hvc_console whether to raise or
lower the DTR/RTS lines. This is different than the ioctl interface to
controls the modem status.
Well, DTR at least is the same via both callbacks... Also normal handshaking
is normally RTS/CTS, only some HW setups "hijacks" DTR for RTS (old Macs come
to mind).
Yep. DTR is changed in both callbacks but from different layers. The
tiocmget/tiocmset are triggered through the ioctl. The dtr_rts() callback is
called in hvc_close() to properly handle HUPCL to lower modem control lines
after last process closes the device (hang up).
This is also done in the hvsilib_close() in hvsi_lib.c:
/* Clear our own DTR */
if (!pv->tty || (pv->tty->termios.c_cflag & HUPCL))
hvsilib_write_mctrl(pv, 0);
This is actually what the dtr_rts() callback should trigger and I wonder
whether it would be worth to introduce the dtr_rts() callback to encapsulate
the "hvsilib_write_mctrl(pv, 0);" call from above.
On the other hand, the dtr_rts() callback is a good encapsulation to not
directly access the hp->tty to potentially prevent a layering violation. At
least for the hvc_iucv() I do not want to deal with the "underlying" tty layer
and introduce additional reference accounting.
I hope this helps you to understand my rational for introducing the dtr_rts()
callback.
Thanks and kind regards,
Hendrik
From: Benjamin Herrenschmidt <hidden> Date: 2013-10-15 20:48:07
On Tue, 2013-10-15 at 17:36 +0200, Hendrik Brueckner wrote:
Hi Benjamin,
On Sat, Oct 12, 2013 at 07:43:24AM +1100, Benjamin Herrenschmidt wrote:
quoted
On Fri, 2013-10-11 at 14:47 +0200, Hendrik Brueckner wrote:
quoted
The tiocmget/tiocmset callbacks are used to set and get modem status and
triggered through an tty ioctl.
The dtr_rts() callback is different and it is used for DTS/RTS handshaking
between the hvc_console (or any other tty_port) and the tty layer. The tty
port layer uses this callback to signal the hvc_console whether to raise or
lower the DTR/RTS lines. This is different than the ioctl interface to
controls the modem status.
Well, DTR at least is the same via both callbacks... Also normal handshaking
is normally RTS/CTS, only some HW setups "hijacks" DTR for RTS (old Macs come
to mind).
Yep. DTR is changed in both callbacks but from different layers. The
tiocmget/tiocmset are triggered through the ioctl. The dtr_rts() callback is
called in hvc_close() to properly handle HUPCL to lower modem control lines
after last process closes the device (hang up).
This is also done in the hvsilib_close() in hvsi_lib.c:
/* Clear our own DTR */
if (!pv->tty || (pv->tty->termios.c_cflag & HUPCL))
hvsilib_write_mctrl(pv, 0);
This is actually what the dtr_rts() callback should trigger and I wonder
whether it would be worth to introduce the dtr_rts() callback to encapsulate
the "hvsilib_write_mctrl(pv, 0);" call from above.
On the other hand, the dtr_rts() callback is a good encapsulation to not
directly access the hp->tty to potentially prevent a layering violation. At
least for the hvc_iucv() I do not want to deal with the "underlying" tty layer
and introduce additional reference accounting.
I hope this helps you to understand my rational for introducing the dtr_rts()
callback.
I'm not sure :) We still end up basically with 2 callbacks to do the
same thing ... change the DTR line. It's odd at best, I still don't
quite see why hvc_console couldn't just use mctrl...
Cheers,
Ben.
From: Hendrik Brueckner <hidden> Date: 2013-10-16 09:04:49
On Tue, Oct 15, 2013 at 03:47:50PM -0500, Benjamin Herrenschmidt wrote:
On Tue, 2013-10-15 at 17:36 +0200, Hendrik Brueckner wrote:
quoted
On Sat, Oct 12, 2013 at 07:43:24AM +1100, Benjamin Herrenschmidt wrote:
quoted
On Fri, 2013-10-11 at 14:47 +0200, Hendrik Brueckner wrote:
quoted
The tiocmget/tiocmset callbacks are used to set and get modem status and
triggered through an tty ioctl.
The dtr_rts() callback is different and it is used for DTS/RTS handshaking
between the hvc_console (or any other tty_port) and the tty layer. The tty
port layer uses this callback to signal the hvc_console whether to raise or
lower the DTR/RTS lines. This is different than the ioctl interface to
controls the modem status.
Well, DTR at least is the same via both callbacks... Also normal handshaking
is normally RTS/CTS, only some HW setups "hijacks" DTR for RTS (old Macs come
to mind).
Yep. DTR is changed in both callbacks but from different layers. The
tiocmget/tiocmset are triggered through the ioctl. The dtr_rts() callback is
called in hvc_close() to properly handle HUPCL to lower modem control lines
after last process closes the device (hang up).
This is also done in the hvsilib_close() in hvsi_lib.c:
/* Clear our own DTR */
if (!pv->tty || (pv->tty->termios.c_cflag & HUPCL))
hvsilib_write_mctrl(pv, 0);
This is actually what the dtr_rts() callback should trigger and I wonder
whether it would be worth to introduce the dtr_rts() callback to encapsulate
the "hvsilib_write_mctrl(pv, 0);" call from above.
On the other hand, the dtr_rts() callback is a good encapsulation to not
directly access the hp->tty to potentially prevent a layering violation. At
least for the hvc_iucv() I do not want to deal with the "underlying" tty layer
and introduce additional reference accounting.
I hope this helps you to understand my rational for introducing the dtr_rts()
callback.
I'm not sure :) We still end up basically with 2 callbacks to do the
same thing ... change the DTR line. It's odd at best, I still don't
quite see why hvc_console couldn't just use mctrl...
Indeed, two callbacks change the DTR line. The main difference is that
tiocmget/tiocmset can be called from user space by ioctl. That's not the case
for the dtr_cts callback. Also, tiocmget/tiocmset provide more flags that can
be changed (ST, SR, CTS, CD, RNG, RI, ...)
Assume we would like to unify them have a single callback to change DTR, then
we have to take care of these differences. So the question to you now is
whether you plan for a) other modem flags to be changed and b) if changing the
DTR line (or other control flags) through an ioctl?
Depending on your results, I could work on sth that helps us both and reduces
the callbacks.
Thanks and kind regards,
Hendrik
From: Benjamin Herrenschmidt <hidden> Date: 2013-10-16 23:21:29
On Wed, 2013-10-16 at 11:04 +0200, Hendrik Brueckner wrote:
Indeed, two callbacks change the DTR line. The main difference is that
tiocmget/tiocmset can be called from user space by ioctl. That's not the case
for the dtr_cts callback. Also, tiocmget/tiocmset provide more flags that can
be changed (ST, SR, CTS, CD, RNG, RI, ...)
Assume we would like to unify them have a single callback to change DTR, then
we have to take care of these differences. So the question to you now is
whether you plan for a) other modem flags to be changed and b) if changing the
DTR line (or other control flags) through an ioctl?
Depending on your results, I could work on sth that helps us both and reduces
the callbacks.
Can we not just have the users of dtr_cts just call the backend's tiocmset ?
If they need to filter or clamp bits, we could handle all that in hvc_console
by caching the user intended value and passing a cooked value down to the backend..
None of that is urgent or anything, it's just odd and would be nice to cleanup.
Cheers,
Ben.
From: Hendrik Brueckner <hidden> Date: 2013-10-17 08:16:55
On Wed, Oct 16, 2013 at 06:21:12PM -0500, Benjamin Herrenschmidt wrote:
On Wed, 2013-10-16 at 11:04 +0200, Hendrik Brueckner wrote:
quoted
Indeed, two callbacks change the DTR line. The main difference is that
tiocmget/tiocmset can be called from user space by ioctl. That's not the case
for the dtr_cts callback. Also, tiocmget/tiocmset provide more flags that can
be changed (ST, SR, CTS, CD, RNG, RI, ...)
Assume we would like to unify them have a single callback to change DTR, then
we have to take care of these differences. So the question to you now is
whether you plan for a) other modem flags to be changed and b) if changing the
DTR line (or other control flags) through an ioctl?
Depending on your results, I could work on sth that helps us both and reduces
the callbacks.
Can we not just have the users of dtr_cts just call the backend's tiocmset ?
That's possible. The only concern is that the tiocmset() callback could be
triggered from within the hvc_console() layer as well as from user space via
ioctl. For the hvc_iucv driver, I do not want to introduce this ioctl.
One option would be to add parameter to the hvc_callbacks that indicate the
origin so that a backend could filter.
If they need to filter or clamp bits, we could handle all that in hvc_console
by caching the user intended value and passing a cooked value down to the backend..
Sure the hvc_console layer could do as much as possible.
None of that is urgent or anything, it's just odd and would be nice to cleanup.