Commit 89a7a45d authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Pavel Emelyanov

tty: Add checkpoint/restore for unix terminals v6

Usually the PTYs represent a pair of links -- master peer and slave
peer. Master peer must be opened before slave. Internally, when kernel
creates master peer it also generates a slave interface in a form of
/dev/pts/N, where N is that named pty "index". Master/slave connection
unambiguously identified by this index.

Still, one master can carry multiple slaves -- for example a user opens
one master via /dev/ptmx and appropriate /dev/pts/N in sequence.
The result will be the following

master
`- slave 1
`- slave 2

both slave will have same master index but different file descriptors.
Still inside the kernel pty parameters are same for both slaves. Thus
only one slave parameters should be restored, there is no need to carry
all parameters for every slave peer we've found.

Not yet addressed problems:

- At moment of restore the master peer might be already closed for
  any reason so to resolve such problem we need to open a fake master
  peer with proper index and hook a slave on it, then we close
  master peer.

- Need to figure out how to deal with ttys which have some
  data in buffers not yet flushed, at moment this data will
  be simply lost during c/r

- Need to restore control terminals

- Need to fetch tty flags such as exclusive/packet-mode,
  this can't be done without kernel patching

[ avagin@:
   - ideas on contol terminals restore
   - overall code redesign and simplification
]

v4:
 - drop redundant pid from dump_chrdev
 - make sure optional fown is passed on regular ptys
 - add a comments about zeroifying termios
 - get rid of redundant empty line in files.c

v5 (by avagin@):
 - complete rework of tty image format, now we have
   two files -- tty.img and tty-info.img. The idea
   behind to reduce data being stored.

v6 (by xemul@):
 - packet mode should be set to true in image,
   until properly fetched from the kernel
 - verify image data on retrieval
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
CC: Andrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 5340807b
......@@ -42,6 +42,7 @@ OBJS += inotify.o
OBJS += signalfd.o
OBJS += pstree.o
OBJS += protobuf.o
OBJS += tty.o
PROTOBUF-LIB := protobuf/protobuf-lib.o
......
......@@ -47,6 +47,7 @@
#include "signalfd.h"
#include "pstree.h"
#include "mount.h"
#include "tty.h"
#include "protobuf.h"
#include "protobuf/fdinfo.pb-c.h"
......@@ -235,12 +236,10 @@ static int dump_chrdev(struct fd_parms *p, int lfd, const struct cr_fdset *set)
switch (maj) {
case MEM_MAJOR:
return dump_reg_file(p, lfd, set);
case TTY_MAJOR:
case TTYAUX_MAJOR:
case UNIX98_PTY_MASTER_MAJOR ... (UNIX98_PTY_MASTER_MAJOR + UNIX98_PTY_MAJOR_COUNT - 1):
case UNIX98_PTY_SLAVE_MAJOR:
if (p->fd < 3) {
pr_info("... Skipping tty ... %d\n", p->fd);
return 0;
}
return dump_tty(p, lfd, set);
}
return dump_unsupp_fd(p);
......
......@@ -51,6 +51,7 @@
#include "inotify.h"
#include "pstree.h"
#include "net.h"
#include "tty.h"
#include "protobuf.h"
#include "protobuf/sa.pb-c.h"
......@@ -119,6 +120,9 @@ static int prepare_shared(void)
if (collect_inotify())
return -1;
if (collect_tty())
return -1;
for_each_pstree_item(pi) {
if (pi->state == TASK_HELPER)
continue;
......@@ -133,6 +137,11 @@ static int prepare_shared(void)
}
mark_pipe_master();
ret = tty_prepare_shared();
if (ret)
goto err;
ret = resolve_unix_peers();
if (!ret) {
......@@ -140,6 +149,7 @@ static int prepare_shared(void)
show_saved_files();
}
err:
return ret;
}
......
......@@ -23,6 +23,7 @@
#include "lock.h"
#include "sockets.h"
#include "pstree.h"
#include "tty.h"
#include "protobuf.h"
#include "protobuf/fs.pb-c.h"
......@@ -152,6 +153,10 @@ static struct list_head *select_ps_list(int type, struct fdinfo_list_entry *le,
switch (type) {
case FD_TYPES__EVENTPOLL:
return &ri->eventpoll;
case FD_TYPES__TTY:
if (!tty_is_master(le))
return &ri->tty_slaves;
/* Fall through */
default:
return &ri->fds;
}
......
......@@ -128,6 +128,8 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = {
FD_ENTRY(IFADDR, "ifaddr-%d", show_raw_image),
FD_ENTRY(ROUTE, "route-%d", show_raw_image),
FD_ENTRY(TMPFS, "tmpfs-%d.tar.gz", show_raw_image),
FD_ENTRY(TTY, "tty", NULL),
FD_ENTRY(TTY_INFO, "tty-info", NULL),
};
static struct cr_fdset *alloc_cr_fdset(int nr)
......
......@@ -66,6 +66,8 @@ enum {
CR_FD_PIPES_DATA,
CR_FD_FIFO,
CR_FD_FIFO_DATA,
CR_FD_TTY,
CR_FD_TTY_INFO,
CR_FD_REMAP_FPATH,
CR_FD_EVENTFD,
CR_FD_EVENTPOLL,
......
......@@ -59,6 +59,8 @@
#define INOTIFY_WD_MAGIC 0x54562009 /* Svetlogorsk (Rauschen) */
#define MOUNTPOINTS_MAGIC 0x55563928 /* Petushki */
#define NETDEV_MAGIC 0x57373951 /* Yaroslavl */
#define TTY_MAGIC 0x59433025 /* Pushkin */
#define TTY_INFO_MAGIC 0x59453036 /* Kolpino */
#define IFADDR_MAGIC RAW_IMAGE_MAGIC
#define ROUTE_MAGIC RAW_IMAGE_MAGIC
......
......@@ -41,6 +41,8 @@ enum {
PB_SIGNALFD,
PB_INOTIFY,
PB_INOTIFY_WD,
PB_TTY,
PB_TTY_INFO,
PB_MAX
};
......
#ifndef CR_TTY_H__
#define CR_TTY_H__
#include "files.h"
#include "crtools.h"
/* Kernel's limit */
#define TERMIOS_NCC 19
#define PTMX_PATH "/dev/ptmx"
#ifndef PTMX_MINOR
# define PTMX_MINOR 2
#endif
#define PTS_FMT "/dev/pts/%d"
#define TTY_LOCKED (1 << 0)
#define TTY_EXCLUSIVE (1 << 1)
extern int dump_tty(struct fd_parms *p, int lfd, const struct cr_fdset *set);
extern int collect_tty(void);
extern int tty_is_master(struct fdinfo_list_entry *le);
extern int tty_prepare_shared(void);
#endif /* CR_TTY_H__ */
......@@ -48,6 +48,7 @@
#include "protobuf/mnt.pb-c.h"
#include "protobuf/netdev.pb-c.h"
#include "protobuf/tcp-stream.pb-c.h"
#include "protobuf/tty.pb-c.h"
typedef size_t (*pb_getpksize_t)(void *obj);
typedef size_t (*pb_pack_t)(void *obj, void *where);
......@@ -122,6 +123,8 @@ void cr_pb_init(void)
CR_PB_DESC(MOUNTPOINTS, Mnt, mnt);
CR_PB_DESC(NETDEV, NetDevice, net_device);
CR_PB_DESC(PACKETSK, PacketSock, packet_sock);
CR_PB_DESC(TTY, TtyFile, tty_file);
CR_PB_DESC(TTY_INFO, TtyInfo, tty_info);
}
/*
......
......@@ -38,6 +38,7 @@ PROTO_FILES += creds.proto
PROTO_FILES += vma.proto
PROTO_FILES += core.proto
PROTO_FILES += netdev.proto
PROTO_FILES += tty.proto
PROTO_HDRS := $(patsubst %.proto,%.pb-c.h,$(PROTO_FILES))
PROTO_SRCS := $(patsubst %.proto,%.pb-c.c,$(PROTO_FILES))
......
......@@ -10,6 +10,7 @@ enum fd_types {
INOTIFY = 8;
SIGNALFD = 9;
PACKETSK = 10;
TTY = 11;
}
message fdinfo_entry {
......
import "fown.proto";
message winsize_entry {
required uint32 ws_row = 1;
required uint32 ws_col = 2;
required uint32 ws_xpixel = 3;
required uint32 ws_ypixel = 4;
};
message termios_entry {
required uint32 c_iflag = 1;
required uint32 c_oflag = 2;
required uint32 c_cflag = 3;
required uint32 c_lflag = 4;
required uint32 c_line = 5;
required uint32 c_ispeed = 6;
required uint32 c_ospeed = 7;
repeated uint32 c_cc = 8;
}
message tty_pty_entry {
required uint32 index = 1;
}
enum TtyType {
UNKNOWN = 0;
PTY = 1;
}
message tty_info_entry {
required uint32 id = 1;
required TtyType type = 2;
required bool locked = 3;
required bool exclusive = 4;
required bool packet_mode = 5;
required uint32 sid = 6;
required uint32 pgrp = 7;
/*
* Convenient for printing errors and such, with this
* device encoded we can figure out major and minor
* numbers.
*/
required uint32 rdev = 8;
required termios_entry termios = 9;
required termios_entry termios_locked = 10;
required winsize_entry winsize = 11;
/*
* These are optional fields which presense depends on
* TTY type.
*/
optional tty_pty_entry pty = 12;
};
message tty_file_entry {
required uint32 id = 1;
required uint32 tty_info_id = 2;
required uint32 flags = 3;
required fown_entry fown = 4;
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment