[RHEL7,COMMIT] ve/tty: Provide interface for current tty inheritance

Submitted by Konstantin Khorenko on Feb. 19, 2018, 4:16 p.m.

Details

Message ID 201802191616.w1JGGD94001791@finist_ce7.work
State New
Series ": ve: Provide interface for current tty inheritance"
Headers show

Commit Message

Konstantin Khorenko Feb. 19, 2018, 4:16 p.m.
The commit is pushed to "branch-rh7-3.10.0-693.17.1.vz7.45.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-693.17.1.vz7.45.3
------>
commit 098099f6daaf49d7fd06ea2aada56ead7958e8d1
Author: Cyrill Gorcunov <gorcunov@virtuozzo.com>
Date:   Mon Feb 19 19:16:13 2018 +0300

    ve/tty: Provide interface for current tty inheritance
    
    When fork() is called the current controlling terminal is inherited
    by a child process. But in criu we fork all process first and then
    restore their files, thus if terminal is opened in some children
    its reference get lost. We refuse to checkpoint such configurations
    at the moment in criu itself.
    
    So to be able to restore this kind of container we need a way to
    propagate controlling terminal to children processes, and here
    is an interface "ve.ctty" entry on toplevel ve cgroup. One have
    to pass pid of the donor task in first position followed by a series
    of recipient pids.
    
    https://jira.sw.ru/browse/PSBM-76490
    
    CC: Andrey Vagin <avagin@virtuozzo.com>
    CC: Andrey Ryabinin <aryabinin@virtuozzo.com>
    CC: Konstantin Khorenko <khorenko@virtuozzo.com>
    CC: "Denis V. Lunev" <den@virtuozzo.com>
    Signed-off-by: Cyrill Gorcunov <gorcunov@virtuozzo.com>
    
    khorenko@: we'll try to push the interface for ctty set up to mainstream.
    May be it will be another interface like ioctl/netlink/etc, whatever.
    
    This work (interface to mainstream) will be done in the scope of
    https://jira.sw.ru/browse/PSBM-81687
---
 kernel/ve/ve.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)

Patch hide | download patch | download mbox

diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
index ef615caa3398..ee043483c7e7 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -37,6 +37,7 @@ 
 #include <linux/fs_struct.h>
 #include <linux/task_work.h>
 #include <linux/ctype.h>
+#include <linux/tty.h>
 
 #include <uapi/linux/vzcalluser.h>
 #include <linux/vziptable_defs.h>
@@ -1214,6 +1215,7 @@  enum {
 	VE_CF_NETNS_NR,
 	VE_CF_NETIF_MAX_NR,
 	VE_CF_NETIF_NR,
+	VE_CF_CTTY,
 };
 
 static int ve_ts_read(struct cgroup *cg, struct cftype *cft, struct seq_file *m)
@@ -1393,6 +1395,94 @@  static int ve_write_running_u64(struct cgroup *cg, struct cftype *cft, u64 value
 	return _ve_write_u64(cg, cft, value, 1);
 }
 
+static int ve_write_ctty(struct cgroup *cg, struct cftype *cft, const char *buffer)
+{
+	struct task_struct *tsk_from, *tsk_to;
+	struct tty_struct *tty_from, *tty_to;
+	pid_t pid_from, pid_to;
+	unsigned long flags;
+	char *pids;
+	int ret;
+
+	/*
+	 * Buffer format is the following
+	 *
+	 * 	pid_from pid_to pid_to ...
+	 *
+	 * where pid_to are pids to propagate
+	 * current terminal into.
+	 */
+
+	pids = skip_spaces(buffer);
+	if (sscanf(pids, "%d", &pid_from) != 1)
+		return -EINVAL;
+	pids = strchr(pids, ' ');
+	if (!pids)
+		return -EINVAL;
+	pids = skip_spaces(pids);
+
+	rcu_read_lock();
+	tsk_from = find_task_by_vpid(pid_from);
+	if (tsk_from)
+		get_task_struct(tsk_from);
+	rcu_read_unlock();
+
+	if (!tsk_from)
+		return -ESRCH;
+
+	spin_lock_irqsave(&tsk_from->sighand->siglock, flags);
+	tty_from = tty_kref_get(tsk_from->signal->tty);
+	spin_unlock_irqrestore(&tsk_from->sighand->siglock, flags);
+
+	if (!tty_from) {
+		ret = -ENOTTY;
+		goto out;
+	}
+
+	ret = 0;
+	while (pids && *pids) {
+		if (sscanf(pids, "%d", &pid_to) != 1) {
+			ret = -EINVAL;
+			goto out;
+		}
+		pids = strchr(pids, ' ');
+		if (pids)
+			pids = skip_spaces(pids);
+
+		rcu_read_lock();
+		tsk_to = find_task_by_vpid(pid_to);
+		if (tsk_to)
+			get_task_struct(tsk_to);
+		rcu_read_unlock();
+
+		if (!tsk_to) {
+			ret = -ESRCH;
+			goto out;
+		}
+
+		if (tsk_from->task_ve == tsk_to->task_ve) {
+			spin_lock_irqsave(&tsk_to->sighand->siglock, flags);
+			tty_to = tsk_to->signal->tty;
+			if (!tty_to)
+				tsk_to->signal->tty = tty_kref_get(tty_from);
+			else
+				ret = -EBUSY;
+			spin_unlock_irqrestore(&tsk_to->sighand->siglock, flags);
+		} else
+			ret = -EINVAL;
+
+		put_task_struct(tsk_to);
+
+		if (ret)
+			goto out;
+	}
+
+out:
+	tty_kref_put(tty_from);
+	put_task_struct(tsk_from);
+	return ret;
+}
+
 static struct cftype ve_cftypes[] = {
 	{
 		.name			= "state",
@@ -1496,6 +1586,12 @@  static struct cftype ve_cftypes[] = {
 		.read_u64		= ve_read_u64,
 		.private		= VE_CF_NETIF_NR,
 	},
+	{
+		.name			= "ctty",
+		.flags			= CFTYPE_ONLY_ON_ROOT,
+		.write_string		= ve_write_ctty,
+		.private		= VE_CF_CTTY,
+	},
 	{ }
 };