[Devel] [PATCH RHEL7 COMMIT] tty: Fix task hang if one of peers is sitting in read

Konstantin Khorenko khorenko at virtuozzo.com
Thu Jan 28 11:02:43 PST 2016


The commit is pushed to "branch-rh7-3.10.0-327.3.1-vz7.10.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-327.3.1.vz7.10.7
------>
commit d7a8b04ecac8408598a9b3aa4aa0f4957796bdde
Author: Cyrill Gorcunov <gorcunov at virtuozzo.com>
Date:   Thu Jan 28 23:02:43 2016 +0400

    tty: Fix task hang if one of peers is sitting in read
    
    The locking scheme has been reworked significantly on current
    vanilla kernel, so here is a minimal patch which eliminate
    task hanging waiting for tty lock.
    
    We've noticed this issue during our vtty console testing:
    when we're entering into console the container spawns
    "login" which calls vhangup and close all fds immediately,
    so the "vzctl console" code continue hanging inside loop
    
     | vzctl waiting for password:
     |
     | [root at pcs7 ~]# cat /proc/2482/stack
     | [<ffffffff814b1935>] n_tty_read+0x336/0x721
     | [<ffffffff814accb4>] tty_read+0x89/0xcb
     | [<ffffffff81183651>] vfs_read+0xaf/0xf3
     | [<ffffffff81183d5f>] SyS_read+0x50/0x79
     | [<ffffffff817991b2>] system_call_fastpath+0x16/0x1b
     | [<ffffffffffffffff>] 0xffffffffffffffff
     |
     | login calls for vhangup
     |
     | [root at pcs7 ~]# cat /proc/2314/stack
     | [<ffffffff814b51ae>] __ldsem_down_write_nested+0xf7/0x1c6
     | [<ffffffff814b54cd>] ldsem_down_write_nested+0x38/0x3f
     | [<ffffffff814b37a4>] tty_ldisc_hangup+0xd1/0x1b9
     | [<ffffffff814aca10>] __tty_hangup+0x2d3/0x3a3
     | [<ffffffff814acaf0>] tty_vhangup+0x10/0x12
     | [<ffffffff814acd15>] tty_vhangup_self+0x1f/0x2a
     | [<ffffffff81182cf4>] sys_vhangup+0x20/0x27
     | [<ffffffff817991b2>] system_call_fastpath+0x16/0x1b
     | [<ffffffffffffffff>] 0xffffffffffffffff
    
    The primary commit in vanilla kernel which address this
    
     | commit fae76e9adfa450f4c2dd5773265eb3c811a9c484
     | Author: Peter Hurley <peter at hurleysoftware.com>
     | Date:   Wed Nov 5 12:13:07 2014 -0500
     |
     |     tty: Fix hung task on pty hangup
    
    Ufortunately it's not suitable to cherry-picking
    because of related changes done in tty layer. So
    I made kind of minimal fix which treats the issue
    
     - drop tty_ldisc_lock_pair and tty_unlock/tty_lock
       calls from tty_ldisc_hangup: sole locking of
       @ldisc_sem should be safe
     - same with tty_ldisc_release: no need for
       tty_lock_pair, plain @ldisc_sem taken on
       both ends with tty_ldisc_lock_pair help
       should order locking.
    
    The tests in the bug are passed and "console"
    action works as expected but better continue
    wathing over tty layer.
    
    https://jira.sw.ru/browse/PSBM-43454
    
    Signed-off-by: Cyrill Gorcunov <gorcunov at virtuozzo.com>
    
    CC: Vladimir Davydov <vdavydov at virtuozzo.com>
    CC: Konstantin Khorenko <khorenko at virtuozzo.com>
---
 drivers/tty/tty_ldisc.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index b7b8048..d389c82 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -679,16 +679,13 @@ void tty_ldisc_hangup(struct tty_struct *tty)
 	wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
 	wake_up_interruptible_poll(&tty->read_wait, POLLIN);
 
-	tty_unlock(tty);
-
 	/*
 	 * Shutdown the current line discipline, and reset it to
 	 * N_TTY if need be.
 	 *
 	 * Avoid racing set_ldisc or tty_ldisc_release
 	 */
-	tty_ldisc_lock_pair(tty, tty->link);
-	tty_lock(tty);
+	tty_ldisc_lock(tty, MAX_SCHEDULE_TIMEOUT);
 
 	if (tty->ldisc) {
 
@@ -710,7 +707,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
 			WARN_ON(tty_ldisc_open(tty, tty->ldisc));
 		}
 	}
-	tty_ldisc_enable_pair(tty, tty->link);
+	tty_ldisc_unlock(tty);
 	if (reset)
 		tty_reset_termios(tty);
 
@@ -780,13 +777,11 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
 	tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
 
 	tty_ldisc_lock_pair(tty, o_tty);
-	tty_lock_pair(tty, o_tty);
 
 	tty_ldisc_kill(tty);
 	if (o_tty)
 		tty_ldisc_kill(o_tty);
 
-	tty_unlock_pair(tty, o_tty);
 	tty_ldisc_unlock_pair(tty, o_tty);
 
 	/* And the memory resources remaining (buffers, termios) will be


More information about the Devel mailing list