[PATCH 29/30] cr: tty/pty

From: Alexey Dobriyan
Date: Thu Apr 09 2009 - 22:48:14 EST


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

currently in desperate need on how to test it.

Signed-off-by: Alexey Dobriyan <adobriyan@xxxxxxxxx>
---

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);
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/