[PATCH 29/30] cr: tty/pty

Alexey Dobriyan adobriyan at gmail.com
Thu Apr 9 19:40:50 PDT 2009


FIXME: opened tty won't passed ->checkpoint check.

currently in desperate need on how to test it.

Signed-off-by: Alexey Dobriyan <adobriyan at gmail.com>
---

 include/linux/cr.h  |   37 ++++++++++++
 kernel/cr/Kconfig   |    1 
 kernel/cr/Makefile  |    1 
 kernel/cr/cpt-sys.c |    6 +
 kernel/cr/cr-pid.c  |   14 ++++
 kernel/cr/cr-tty.c  |  160 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 kernel/cr/cr.h      |    4 +
 7 files changed, 223 insertions(+)

--- a/include/linux/cr.h
+++ b/include/linux/cr.h
@@ -51,6 +51,7 @@ struct cr_object_header {
 #define CR_OBJ_MNT_NS		20
 #define CR_OBJ_NET_NS		21
 #define CR_OBJ_SOCK		22
+#define CR_OBJ_TTY		23
 	__u32	cr_type;	/* object type */
 	__u32	cr_len;		/* object length in bytes including header */
 } __packed;
@@ -381,4 +382,40 @@ struct cr_image_sock {
 	cr_pos_t	cr_pos_sk_net;
 	__u16		cr_sk_family;
 } __packed;
+
+struct cr_image_tty {
+	struct cr_object_header cr_hdr;
+
+	__u16		cr_driver_type;
+	__u16		cr_driver_subtype;
+	__u32		cr_driver_flags;
+	__u32		cr_index;
+	__u32		cr_link_index;
+	struct {
+		__u32	cr_c_iflag;
+		__u32	cr_c_oflag;
+		__u32	cr_c_cflag;
+		__u32	cr_c_lflag;
+		__u8	cr_c_line;
+		__u8	cr_c_cc[23];
+		__u32	cr_c_ispeed;
+		__u32	cr_c_ospeed;
+	} cr_termios;
+	__u8		cr_name[64];
+	cr_pos_t	cr_pos_pgrp;	/* CR_POS_UNDEF if tty->pgrp == NULL */
+	cr_pos_t	cr_pos_session;	/* CR_POS_UNDEF if tty->session == NULL */
+	__u64		cr_flags;
+	struct {
+		__u16	cr_ws_row;
+		__u16	cr_ws_col;
+		__u16	cr_ws_xpixel;
+		__u16	cr_ws_ypixel;
+	} cr_winsize;
+	__u8		cr_stopped;
+	__u8		cr_hw_stopped;
+	__u8		cr_flow_stopped;
+	__u8		cr_packet;
+	__u8		cr_low_latency;
+	__u8		cr_ctrl_status;
+} __packed;
 #endif
--- a/kernel/cr/Kconfig
+++ b/kernel/cr/Kconfig
@@ -1,5 +1,6 @@
 config CR
 	bool "Container checkpoint/restart"
+	depends on DEVPTS_MULTIPLE_INSTANCES
 	depends on NET_NS || (NET = n)
 	depends on PID_NS
 	depends on USER_NS
--- a/kernel/cr/Makefile
+++ b/kernel/cr/Makefile
@@ -12,6 +12,7 @@ cr-y += cr-pid.o
 cr-y += cr-signal.o
 cr-$(CONFIG_NET) += cr-socket.o
 cr-y += cr-task.o
+cr-y += cr-tty.o
 cr-y += cr-uts.o
 cr-$(CONFIG_X86_32) += cr-x86_32.o
 cr-$(CONFIG_X86_64) += cr-x86_64.o
--- a/kernel/cr/cpt-sys.c
+++ b/kernel/cr/cpt-sys.c
@@ -101,6 +101,9 @@ static int cr_collect(struct cr_context *ctx)
 	rv = cr_collect_all_sighand_struct(ctx);
 	if (rv < 0)
 		return rv;
+	rv = cr_collect_all_tty_struct(ctx);
+	if (rv < 0)
+		return rv;
 	rv = cr_collect_all_cred(ctx);
 	if (rv < 0)
 		return rv;
@@ -179,6 +182,9 @@ static int cr_dump(struct cr_context *ctx)
 	rv = cr_dump_all_fs_struct(ctx);
 	if (rv < 0)
 		return rv;
+	rv = cr_dump_all_tty(ctx);
+	if (rv < 0)
+		return rv;
 	rv = cr_dump_all_uts_ns(ctx);
 	if (rv < 0)
 		return rv;
--- a/kernel/cr/cr-pid.c
+++ b/kernel/cr/cr-pid.c
@@ -226,6 +226,20 @@ int cr_collect_all_pid(struct cr_context *ctx)
 				return rv;
 		}
 	}
+	for_each_cr_object(ctx, obj, CR_CTX_TTY) {
+		struct tty_struct *tty = obj->o_obj;
+
+		if (tty->pgrp) {
+			rv = cr_collect_pid(ctx, tty->pgrp);
+			if (rv < 0)
+				return rv;
+		}
+		if (tty->session) {
+			rv = cr_collect_pid(ctx, tty->session);
+			if (rv < 0)
+				return rv;
+		}
+	}
 	/* FIXME pid refcount check should account references from proc inodes */
 	return 0;
 }
new file mode 100644
--- /dev/null
+++ b/kernel/cr/cr-tty.c
@@ -0,0 +1,160 @@
+/* Copyright (C) 2000-2009 Parallels Holdings, Ltd. */
+#include <linux/tty.h>
+
+#include <linux/cr.h>
+#include "cr.h"
+
+static int cr_check_tty(struct tty_struct *tty)
+{
+	if (!tty->link) {
+		WARN(1, "tty %p, tty->link %p\n", tty, tty->link);
+		return -EINVAL;
+	}
+	if (tty->link->link != tty) {
+		WARN(1, "tty %p, tty->link %p, tty->link->link %p\n", tty, tty->link, tty->link->link);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int __cr_collect_tty(struct cr_context *ctx, struct tty_struct *tty)
+{
+	int rv;
+
+	rv = cr_collect_object(ctx, tty, CR_CTX_TTY);
+	printk("collect tty %p: rv %d\n", tty, rv);
+	return rv;
+}
+
+static int cr_collect_tty(struct cr_context *ctx, struct tty_struct *tty)
+{
+	int rv;
+
+	rv = cr_check_tty(tty);
+	if (rv < 0)
+		return rv;
+	rv = __cr_collect_tty(ctx, tty);
+	if (rv < 0)
+		return rv;
+	if (tty->link) {
+		rv = cr_check_tty(tty->link);
+		if (rv < 0)
+			return rv;
+		rv = __cr_collect_tty(ctx, tty->link);
+		if (rv < 0)
+			return rv;
+	}
+	return 0;
+}
+
+int cr_collect_all_tty_struct(struct cr_context *ctx)
+{
+	struct cr_object *obj;
+	int rv;
+
+	for_each_cr_object(ctx, obj, CR_CTX_FILE) {
+		struct file *file = obj->o_obj;
+		struct inode *inode = file->f_path.dentry->d_inode;
+
+		if (!S_ISCHR(inode->i_mode))
+			continue;
+
+		switch (imajor(inode)) {
+		case UNIX98_PTY_SLAVE_MAJOR:
+			rv = cr_collect_tty(ctx, file->private_data);
+			if (rv < 0)
+				return rv;
+			break;
+		}
+	}
+	for_each_cr_object(ctx, obj, CR_CTX_TTY) {
+		struct tty_struct *tty = obj->o_obj;
+
+		if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_SLAVE) {
+			if (tty->link && tty->link->count)
+				obj->o_count++;
+		}
+	}
+	for_each_cr_object(ctx, obj, CR_CTX_TTY) {
+		struct tty_struct *tty = obj->o_obj;
+		unsigned int cnt = tty->count;
+
+		if (obj->o_count != cnt) {
+			printk("%s: tty %p has external references %lu:%u\n", __func__, tty, obj->o_count, cnt);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static int cr_dump_tty(struct cr_context *ctx, struct cr_object *obj)
+{
+	struct tty_struct *tty = obj->o_obj;
+	struct cr_image_tty *i;
+	struct cr_object *tmp;
+	int n;
+	int rv;
+
+	printk("dump tty = %p, type = %d, subtype = %d\n", tty, tty->driver->type, tty->driver->subtype);
+
+	i = cr_prepare_image(CR_OBJ_TTY, sizeof(*i));
+	if (!i)
+		return -ENOMEM;
+
+	i->cr_driver_type = tty->driver->type;
+	i->cr_driver_subtype = tty->driver->subtype;
+	i->cr_driver_flags = tty->driver->flags;
+	i->cr_index = tty->index;
+	i->cr_link_index = tty->link->index;
+	i->cr_termios.cr_c_iflag = tty->termios->c_iflag;
+	i->cr_termios.cr_c_oflag = tty->termios->c_oflag;
+	i->cr_termios.cr_c_cflag = tty->termios->c_cflag;
+	i->cr_termios.cr_c_lflag = tty->termios->c_lflag;
+	i->cr_termios.cr_c_line = tty->termios->c_line;
+	BUILD_BUG_ON(NCCS > 23);
+	for (n = 0; n < NCCS; n++)
+		i->cr_termios.cr_c_cc[n] = tty->termios->c_cc[n];
+	i->cr_termios.cr_c_ispeed = tty->termios->c_ispeed;
+	i->cr_termios.cr_c_ospeed = tty->termios->c_ospeed;
+	BUILD_BUG_ON(sizeof(tty->name) > 64);
+	strlcpy(i->cr_name, tty->name, 64);
+	if (tty->pgrp) {
+		tmp = cr_find_obj_by_ptr(ctx, tty->pgrp, CR_CTX_PID);
+		i->cr_pos_pgrp = tmp->o_pos;
+	} else
+		i->cr_pos_pgrp = CR_POS_UNDEF;
+	if (tty->session) {
+		tmp = cr_find_obj_by_ptr(ctx, tty->session, CR_CTX_PID);
+		i->cr_pos_session = tmp->o_pos;
+	} else
+		i->cr_pos_session = CR_POS_UNDEF;
+	i->cr_flags = tty->flags;
+	i->cr_winsize.cr_ws_row = tty->winsize.ws_row;
+	i->cr_winsize.cr_ws_col = tty->winsize.ws_col;
+	i->cr_winsize.cr_ws_xpixel = tty->winsize.ws_xpixel;
+	i->cr_winsize.cr_ws_ypixel = tty->winsize.ws_ypixel;
+	i->cr_stopped = tty->stopped;
+	i->cr_hw_stopped = tty->hw_stopped;
+	i->cr_flow_stopped = tty->flow_stopped;
+	i->cr_packet = tty->packet;
+	i->cr_low_latency = tty->low_latency;
+	i->cr_ctrl_status = tty->ctrl_status;
+
+	obj->o_pos = ctx->cr_dump_file->f_pos;
+	rv = cr_write(ctx, i, sizeof(*i));
+	kfree(i);
+	return rv;
+}
+
+int cr_dump_all_tty(struct cr_context *ctx)
+{
+	struct cr_object *obj;
+	int rv;
+
+	for_each_cr_object(ctx, obj, CR_CTX_TTY) {
+		rv = cr_dump_tty(ctx, obj);
+		if (rv < 0)
+			return rv;
+	}
+	return 0;
+}
--- a/kernel/cr/cr.h
+++ b/kernel/cr/cr.h
@@ -3,6 +3,7 @@
 #define __KERNEL_CR_CR_H
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <asm/signal.h>
 
 #include <linux/cr.h>
 
@@ -41,6 +42,7 @@ enum cr_context_obj_type {
 	CR_CTX_SOCK,
 #endif
 	CR_CTX_TASK_STRUCT,
+	CR_CTX_TTY,
 	CR_CTX_USER_NS,
 	CR_CTX_USER_STRUCT,
 	CR_CTX_UTS_NS,
@@ -125,6 +127,7 @@ static inline int cr_collect_all_sock(struct cr_context *ctx)
 }
 #endif
 int cr_collect_all_task_struct(struct cr_context *ctx);
+int cr_collect_all_tty_struct(struct cr_context *ctx);
 int cr_collect_all_user_ns(struct cr_context *ctx);
 int cr_collect_all_user_struct(struct cr_context *ctx);
 int cr_collect_all_uts_ns(struct cr_context *ctx);
@@ -158,6 +161,7 @@ static inline int cr_dump_all_sock(struct cr_context *ctx)
 }
 #endif
 int cr_dump_all_task_struct(struct cr_context *ctx);
+int cr_dump_all_tty(struct cr_context *ctx);
 int cr_dump_all_user_ns(struct cr_context *ctx);
 int cr_dump_all_user_struct(struct cr_context *ctx);
 int cr_dump_all_uts_ns(struct cr_context *ctx);


More information about the Containers mailing list