[CRIU] [crtools-bot for Kinsbursky Stanislav ] dump: socket queues support

Cyrill Gorcunov gorcunov at openvz.org
Wed Feb 29 08:42:30 EST 2012


The commit is pushed to "master" and will appear on git://github.com/cyrillos/crtools.git
------>
commit c19012326d155c22f28b5aec614e1f312b7bc87a
Author: Kinsbursky Stanislav <skinsbursky at openvz.org>
Date:   Wed Feb 29 16:06:48 2012 +0300

    dump: socket queues support
    
    This patch was designed to be generic and thus usable for all kinds of
    sockets. Not sure, thah this goal has been reached, but at least I tried.
    
    Key ideas:
    1) On-stack structure for collecting sockets queues and then passing them to
       parasite code.
    2) Singly linked list is used for collecting structures, representing sockets
       of any kind (!) with queues.
    
    Based on xemul@ patches.
    
    Signed-off-by: Stanislav Kinsbursky <skinsbursky at openvz.org>
    Acked-by: Pavel Emelyanov <xemul at parallels.com>
    Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 cr-dump.c                  |   40 +++++++++++++++++++++++-------
 crtools.c                  |    5 ++++
 include/crtools.h          |    3 ++
 include/image.h            |    1 +
 include/parasite-syscall.h |    1 +
 include/sockets.h          |   13 +++++++++-
 parasite-syscall.c         |   57 +++++++++++++++++++++++++++++++++++++++++++-
 sockets.c                  |   13 ++++++----
 8 files changed, 116 insertions(+), 17 deletions(-)

diff --git a/cr-dump.c b/cr-dump.c
index 4b4cbe2..44dc039 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -274,14 +274,15 @@ err:
 }
 
 static int dump_one_fd(pid_t pid, int pid_fd_dir, int lfd,
-		       struct fd_parms *p, struct cr_fdset *cr_fdset)
+		       struct fd_parms *p, struct cr_fdset *cr_fdset,
+		       struct sk_queue *sk_queue)
 {
 	struct statfs stfs_buf;
 	struct stat st_buf;
 	int err = -1;
 
 	if (lfd < 0) {
-		err = try_dump_socket(pid, p->fd_name, cr_fdset);
+		err = try_dump_socket(pid, p->fd_name, cr_fdset, sk_queue);
 		if (err != 1)
 			return err;
 
@@ -361,7 +362,8 @@ static int read_fd_params(pid_t pid, char *fd, struct fd_parms *p)
 	return 0;
 }
 
-static int dump_task_files(pid_t pid, struct cr_fdset *cr_fdset)
+static int dump_task_files(pid_t pid, struct cr_fdset *cr_fdset,
+			   struct sk_queue *sk_queue)
 {
 	struct dirent *de;
 	unsigned long pos;
@@ -396,7 +398,8 @@ static int dump_task_files(pid_t pid, struct cr_fdset *cr_fdset)
 			return -1;
 
 		lfd = openat(dirfd(fd_dir), de->d_name, O_RDONLY);
-		if (dump_one_fd(pid, dirfd(fd_dir), lfd, &p, cr_fdset))
+		if (dump_one_fd(pid, dirfd(fd_dir), lfd, &p, cr_fdset,
+				sk_queue))
 			return -1;
 	}
 
@@ -1166,6 +1169,7 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
 	struct parasite_ctl *parasite_ctl;
 	int ret = -1;
 	struct parasite_dump_misc misc;
+	struct sk_queue sk_queue = { };
 
 	pr_info("========================================\n");
 	pr_info("Dumping task (pid: %d)\n", pid);
@@ -1194,6 +1198,12 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
 		goto err;
 	}
 
+	ret = dump_task_files(pid, cr_fdset, &sk_queue);
+	if (ret) {
+		pr_err("Dump files (pid: %d) failed with %d\n", pid, ret);
+		goto err;
+	}
+
 	parasite_ctl = parasite_infect_seized(pid, &vma_area_list);
 	if (!parasite_ctl) {
 		pr_err("Can't infect (pid: %d) with parasite\n", pid);
@@ -1236,18 +1246,18 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
 		goto err;
 	}
 
+       ret = parasite_dump_socket_info(parasite_ctl, cr_fdset, &sk_queue);
+       if (ret) {
+               pr_err("Can't dump socket info (pid: %d)\n", pid);
+               goto err;
+       }
+
 	ret = parasite_cure_seized(parasite_ctl);
 	if (ret) {
 		pr_err("Can't cure (pid: %d) from parasite\n", pid);
 		goto err;
 	}
 
-	ret = dump_task_files(pid, cr_fdset);
-	if (ret) {
-		pr_err("Dump files (pid: %d) failed with %d\n", pid, ret);
-		goto err;
-	}
-
 	ret = dump_task_mappings(pid, &vma_area_list, cr_fdset);
 	if (ret) {
 		pr_err("Dump mappings (pid: %d) failed with %d\n", pid, ret);
@@ -1319,6 +1329,16 @@ int cr_dump_tasks(pid_t pid, struct cr_options *opts)
 				goto err;
 		}
 
+		/*
+		 * Prepare for socket queues in advance. They are not per-task,
+		 * but per-someother-task which makes restore tricky. Thus save
+		 * them in "global" image.
+		 * That's why we open the file with tree leader's pid for any
+		 * of it's children.
+		 */
+		if (!cr_dump_fdset_open(pid, CR_FD_DESC_USE(CR_FD_SK_QUEUES), cr_fdset))
+			goto err;
+
 		if (dump_one_task(item, cr_fdset))
 			goto err;
 
diff --git a/crtools.c b/crtools.c
index fd7c707..01703cd 100644
--- a/crtools.c
+++ b/crtools.c
@@ -94,6 +94,11 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = {
 		.magic	= INETSK_MAGIC,
 	},
 
+	[CR_FD_SK_QUEUES] = {
+		.fmt	= FMT_FNAME_SK_QUEUES,
+		.magic	= SK_QUEUES_MAGIC,
+	},
+
 	/* interval timers (itimers) */
 	[CR_FD_ITIMERS] = {
 		.fmt	= FMT_FNAME_ITIMERS,
diff --git a/include/crtools.h b/include/crtools.h
index 08cedae..21738fd 100644
--- a/include/crtools.h
+++ b/include/crtools.h
@@ -42,6 +42,8 @@ enum {
 	CR_FD_IPCNS_MSG,
 	CR_FD_IPCNS_SEM,
 
+	CR_FD_SK_QUEUES,
+
 	CR_FD_MAX
 };
 
@@ -86,6 +88,7 @@ extern struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX];
 #define FMT_FNAME_IPCNS_SHM	"ipcns-shm-%d.img"
 #define FMT_FNAME_IPCNS_MSG	"ipcns-msg-%d.img"
 #define FMT_FNAME_IPCNS_SEM	"ipcns-sem-%d.img"
+#define FMT_FNAME_SK_QUEUES	"sk-queues-%d.img"
 
 extern int get_image_path(char *path, int size, const char *fmt, int pid);
 
diff --git a/include/image.h b/include/image.h
index f37f678..db4015f 100644
--- a/include/image.h
+++ b/include/image.h
@@ -19,6 +19,7 @@
 #define UNIXSK_MAGIC	0x54373943 /* Ryazan */
 #define INETSK_MAGIC	0x56443851 /* Pereslavl */
 #define ITIMERS_MAGIC	0x57464056 /* Kostroma */
+#define SK_QUEUES_MAGIC	0x56264026 /* Suzdal */
 #define UTSNS_MAGIC	0x54473203 /* Smolensk */
 #define CREDS_MAGIC	0x54023547 /* Kozelsk */
 #define IPCNS_VAR_MAGIC	0x53115007 /* Samara */
diff --git a/include/parasite-syscall.h b/include/parasite-syscall.h
index 2ccd6ab..43032ea 100644
--- a/include/parasite-syscall.h
+++ b/include/parasite-syscall.h
@@ -33,6 +33,7 @@ extern int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct cr_fdse
 
 struct parasite_dump_misc;
 extern int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_misc *misc);
+extern int parasite_dump_socket_info(struct parasite_ctl *ctl, struct cr_fdset *fdset, struct sk_queue *queue);
 extern int parasite_dump_pages_seized(struct parasite_ctl *ctl,
 				      struct list_head *vma_area_list,
 				      struct cr_fdset *cr_fdset);
diff --git a/include/sockets.h b/include/sockets.h
index 68597a9..f9f6690 100644
--- a/include/sockets.h
+++ b/include/sockets.h
@@ -11,8 +11,19 @@ struct sk_queue_item {
 	unsigned int	sk_id;
 };
 
+struct sk_queue_entry {
+	struct sk_queue_item item;
+	struct sk_queue_entry *next;
+};
+
+struct sk_queue {
+	unsigned int entries;
+	struct sk_queue_entry *list;
+};
+
 struct cr_fdset;
-extern int try_dump_socket(pid_t pid, int fd, const struct cr_fdset *cr_fdset);
+extern int try_dump_socket(pid_t pid, int fd, const struct cr_fdset *cr_fdset,
+			   struct sk_queue *queue);
 
 extern int collect_sockets(void);
 extern int prepare_sockets(int pid);
diff --git a/parasite-syscall.c b/parasite-syscall.c
index fc04645..a570d70 100644
--- a/parasite-syscall.c
+++ b/parasite-syscall.c
@@ -23,7 +23,7 @@
 #include "util.h"
 #include "util-net.h"
 #include "log.h"
-
+#include "sockets.h"
 #include "processor-flags.h"
 #include "parasite-syscall.h"
 #include "parasite-blob.h"
@@ -455,6 +455,61 @@ int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_mis
 				sizeof(struct parasite_dump_misc));
 }
 
+int parasite_dump_socket_info(struct parasite_ctl *ctl, struct cr_fdset *fdset,
+			      struct sk_queue *queue)
+{
+	int ret, i;
+	struct cr_fdset *fds;
+	unsigned arg_size;
+	struct parasite_dump_sk_queues *arg;
+	struct sk_queue_entry *sk_entry;
+
+	if (queue->entries == 0)
+		return 0;
+
+	pr_info("Dumping socket queues\n");
+
+	arg_size = sizeof(struct parasite_dump_sk_queues) +
+		queue->entries * sizeof(struct sk_queue_item);
+
+	/* FIXME arg size is only enough for ~1k of sockets */
+	if (arg_size > PARASITE_ARG_SIZE) {
+		pr_err("Too many sockets to drain queue from\n");
+		return -1;
+	}
+
+	ret = -1;
+	arg = xzalloc(arg_size);
+	if (arg == NULL)
+		goto err_alloc;
+
+	sk_entry = queue->list;
+	for (i = 0; i < queue->entries; i++, arg->nr_items++) {
+		struct sk_queue_entry *tmp = sk_entry;
+
+		memcpy(&arg->items[i], &sk_entry->item, sizeof(struct sk_queue_item));
+		sk_entry = tmp->next;
+		xfree(tmp);
+	}
+
+	ret = parasite_prep_file(CR_FD_SK_QUEUES, ctl, fdset);
+	if (ret < 0)
+		goto err_prepf;
+
+	ret = parasite_execute(PARASITE_CMD_DUMP_SK_QUEUES, ctl,
+			(parasite_status_t *)arg, arg_size);
+	if (ret < 0)
+		goto err_exec;
+
+	return 0;
+
+err_exec:
+err_prepf:
+	xfree(arg);
+err_alloc:
+	return -1;
+}
+
 /*
  * This routine drives parasite code (been previously injected into a victim
  * process) and tells it to dump pages into the file.
diff --git a/sockets.c b/sockets.c
index 2666968..52bf91e 100644
--- a/sockets.c
+++ b/sockets.c
@@ -214,7 +214,8 @@ static int can_dump_inet_sk(const struct inet_sk_desc *sk)
 }
 
 static int dump_one_inet(const struct socket_desc *_sk, int fd,
-		const struct cr_fdset *cr_fdset)
+			 const struct cr_fdset *cr_fdset,
+			 struct sk_queue *queue)
 {
 	const struct inet_sk_desc *sk = (struct inet_sk_desc *)_sk;
 	struct inet_sk_entry ie;
@@ -283,7 +284,8 @@ static int can_dump_unix_sk(const struct unix_sk_desc *sk)
 }
 
 static int dump_one_unix(const struct socket_desc *_sk, int fd,
-		const struct cr_fdset *cr_fdset)
+			 const struct cr_fdset *cr_fdset,
+			 struct sk_queue *queue)
 {
 	const struct unix_sk_desc *sk = (struct unix_sk_desc *)_sk;
 	struct unix_sk_entry ue;
@@ -347,7 +349,8 @@ err:
 	return -1;
 }
 
-int try_dump_socket(pid_t pid, int fd, const struct cr_fdset *cr_fdset)
+int try_dump_socket(pid_t pid, int fd, const struct cr_fdset *cr_fdset,
+		    struct sk_queue *queue)
 {
 	const struct socket_desc *sk;
 	struct statfs fst;
@@ -380,9 +383,9 @@ int try_dump_socket(pid_t pid, int fd, const struct cr_fdset *cr_fdset)
 
 	switch (sk->family) {
 	case AF_UNIX:
-		return dump_one_unix(sk, fd, cr_fdset);
+		return dump_one_unix(sk, fd, cr_fdset, queue);
 	case AF_INET:
-		return dump_one_inet(sk, fd, cr_fdset);
+		return dump_one_inet(sk, fd, cr_fdset, queue);
 	default:
 		pr_err("BUG! Unknown socket collected\n");
 		break;


More information about the CRIU mailing list