[CRIU] [PATCH cr 3/8] tcp: unset TCP_REPAIR at the last moment after unlocking network

Andrey Vagin avagin at openvz.org
Fri Sep 14 06:25:27 EDT 2012


TCP_REPAIR should be droppet when a network is unlocked.
A network should be unlocked at the last moment, because
after this moment restore must not failed, otherwise a state of
a tcp connection can be changed and a state of one side in our image
will be invalid.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 cr-restore.c       |    9 ++++++-
 include/restorer.h |    3 ++
 include/sk-inet.h  |   17 +++++++++++++
 restorer.c         |    7 ++++-
 sk-tcp.c           |   64 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 97 insertions(+), 3 deletions(-)

diff --git a/cr-restore.c b/cr-restore.c
index 0e3f948..9fee16f 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -1280,7 +1280,8 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core, struct list_head *tgt_v
 					      restore_task_vma_len +
 					      restore_thread_vma_len +
 					      self_vmas_len +
-					      SHMEMS_SIZE + TASK_ENTRIES_SIZE);
+					      SHMEMS_SIZE + TASK_ENTRIES_SIZE +
+					      rst_tcp_socks_size);
 	if (exec_mem_hint == -1) {
 		pr_err("No suitable area for task_restore bootstrap (%ldK)\n",
 		       restore_task_vma_len + restore_thread_vma_len);
@@ -1356,6 +1357,12 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core, struct list_head *tgt_v
 	if (!task_args->tgt_vmas)
 		goto err;
 
+	mem += vmas_len;
+	if (rst_tcp_socks_remap(mem))
+		goto err;
+	task_args->rst_tcp_socks = mem;
+	task_args->rst_tcp_socks_size = rst_tcp_socks_size;
+
 	/*
 	 * Arguments for task restoration.
 	 */
diff --git a/include/restorer.h b/include/restorer.h
index 274459b..3b9fbcf 100644
--- a/include/restorer.h
+++ b/include/restorer.h
@@ -110,6 +110,9 @@ struct task_restore_core_args {
 	bool				has_futex;
 	u64				futex_rla;
 	u32				futex_rla_len;
+
+	int				*rst_tcp_socks;
+	int				rst_tcp_socks_size;
 } __aligned(sizeof(long));
 
 struct pt_regs {
diff --git a/include/sk-inet.h b/include/sk-inet.h
index 0fe550c..18c8cdb 100644
--- a/include/sk-inet.h
+++ b/include/sk-inet.h
@@ -3,6 +3,9 @@
 
 #include <netinet/tcp.h>
 
+#include "sockets.h"
+#include "files.h"
+#include "list.h"
 #include "protobuf.h"
 #include "../protobuf/sk-inet.pb-c.h"
 
@@ -62,4 +65,18 @@ struct cr_options;
 void show_tcp_stream(int fd, struct cr_options *);
 
 int check_tcp_repair(void);
+
+extern int rst_tcp_socks_size;
+extern int rst_tcp_socks_remap(void *addr);
+
+static inline void rst_tcp_socks_all(int *arr, int size)
+{
+	int i;
+
+	for (i =0; i < size / sizeof(int) && arr[i] >= 0; i++)
+		tcp_repair_off(arr[i]);
+
+	sys_munmap(arr, size);
+}
+
 #endif
diff --git a/restorer.c b/restorer.c
index 5cee0b1..f6c780d 100644
--- a/restorer.c
+++ b/restorer.c
@@ -18,6 +18,7 @@
 #include "restorer-log.h"
 #include "util.h"
 #include "image.h"
+#include "sk-inet.h"
 
 #include "crtools.h"
 #include "lock.h"
@@ -631,10 +632,12 @@ long __export_restore_task(struct task_restore_core_args *args)
 
 	futex_dec_and_wake(&args->task_entries->nr_in_progress);
 
-	sys_close(args->logfd);
-
 	futex_wait_while(&args->task_entries->start, CR_STATE_RESTORE_SIGCHLD);
 
+	rst_tcp_socks_all(args->rst_tcp_socks, args->rst_tcp_socks_size);
+
+	sys_close(args->logfd);
+
 	/*
 	 * The code that prepared the itimers makes shure the
 	 * code below doesn't fail due to bad timing values.
diff --git a/sk-tcp.c b/sk-tcp.c
index 4a9cf73..65c0e21 100644
--- a/sk-tcp.c
+++ b/sk-tcp.c
@@ -3,6 +3,7 @@
 #include <linux/sockios.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <sys/mman.h>
 
 #include "crtools.h"
 #include "util.h"
@@ -473,6 +474,66 @@ err:
 	return -1;
 }
 
+/*
+ * rst_tcp_socks contains sockets in repair mode,
+ * which will be off in restorer before resuming.
+ */
+static int *rst_tcp_socks = NULL;
+static int rst_tcp_socks_num = 0;
+int rst_tcp_socks_size = 0;
+
+int rst_tcp_socks_remap(void *addr)
+{
+	if (!rst_tcp_socks) {
+		BUG_ON(rst_tcp_socks_size);
+		return 0;
+	}
+
+	if (rst_tcp_socks_num * sizeof(int) < rst_tcp_socks_size)
+		rst_tcp_socks[rst_tcp_socks_num] = -1;
+
+	rst_tcp_socks = mremap(rst_tcp_socks,
+					rst_tcp_socks_size,
+					rst_tcp_socks_size,
+					MREMAP_MAYMOVE | MREMAP_FIXED,
+					addr);
+
+	if (rst_tcp_socks == MAP_FAILED) {
+		pr_perror("mremap failed\n");
+		return -1;
+	}
+
+	BUG_ON(rst_tcp_socks != addr);
+
+	return 0;
+}
+
+static int rst_tcp_socks_add(int fd)
+{
+	if (rst_tcp_socks == NULL) {
+		rst_tcp_socks_size += PAGE_SIZE;
+		rst_tcp_socks = mmap(NULL, rst_tcp_socks_size,
+					    PROT_WRITE | PROT_READ,
+					    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	}
+
+	if ((rst_tcp_socks_num + 1) * sizeof(int) > rst_tcp_socks_size) {
+		rst_tcp_socks = mremap(rst_tcp_socks,
+						rst_tcp_socks_size,
+						rst_tcp_socks_size + PAGE_SIZE,
+						MREMAP_MAYMOVE);
+		rst_tcp_socks_size += PAGE_SIZE;
+	}
+
+	if (rst_tcp_socks == MAP_FAILED) {
+		pr_perror("Can't allocate memory\n");
+		return -1;
+	}
+
+	rst_tcp_socks[rst_tcp_socks_num++] = fd;
+	return 0;
+}
+
 int restore_one_tcp(int fd, struct inet_sk_info *ii)
 {
 	pr_info("Restoring TCP connection\n");
@@ -480,6 +541,9 @@ int restore_one_tcp(int fd, struct inet_sk_info *ii)
 	if (tcp_repair_on(fd))
 		return -1;
 
+	if (rst_tcp_socks_add(fd))
+		return -1;
+
 	nf_unlock_connection_info(ii);
 
 	if (restore_tcp_conn_state(fd, ii))
-- 
1.7.1



More information about the CRIU mailing list