[CRIU] [PATCH] criu: cr_service for crtools and criu_dump_me for libcriu

Ruslan Kupreev kupruser at gmail.com
Mon Jul 29 17:42:57 EDT 2013


Hello all!

I make a cr_service() function for crtools. It will be used to interact 
with programs though function criu_dump_me() from criu library. 
cr_service() opens socket and listening to connections to it. 
criu_dump_me() gets as an argument a link to struct criu_dump_args, 
that, for now, contain images_dir_fd and flags(temporarily unused). And 
sends it to socket.
criu.org/Self_dump for more details.

Signed-off-by: Ruslan Kupreev kupruser at gmail.com


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openvz.org/pipermail/criu/attachments/20130730/c2f515b7/attachment.html>
-------------- next part --------------
commit 79cb7f9696bee760959fad9673c084829ae9e973
Author: Ruslan Kupreev <kupruser at gmail.com>
Date:   Tue Jul 30 00:08:06 2013 +0300

    criu.org/Self_dump.

diff --git a/Makefile b/Makefile
index e3a2608..8a58110 100644
--- a/Makefile
+++ b/Makefile
@@ -101,7 +101,6 @@ endif
 CFLAGS		+= $(WARNINGS) $(DEFINES)
 SYSCALL-LIB	:= arch/$(ARCH)/syscalls.built-in.o
 ARCH-LIB	:= arch/$(ARCH)/crtools.built-in.o
-CRIU-LIB	:= lib/libcriu.so
 
 export CC MAKE CFLAGS LIBS ARCH DEFINES MAKEFLAGS
 export SRC_DIR SYSCALL-LIB SH RM ARCH_DIR OBJCOPY LDARCH LD
diff --git a/cr-dump.c b/cr-dump.c
index 49677db..2d83cd8 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -994,7 +994,7 @@ static int collect_pstree_ids(void)
 	return 0;
 }
 
-static int collect_pstree(pid_t pid)
+int collect_pstree(pid_t pid)
 {
 	int ret, attempts = 5;
 
@@ -1772,3 +1772,129 @@ err:
 
 	return post_dump_ret ? : ret;
 }
+
+int cr_dump_tasks_continue(pid_t pid)
+{
+	struct pstree_item *item;
+	int post_dump_ret = 0;
+	int ret = -1;
+
+	pr_info("========================================\n");
+	pr_info("Dumping processes (pid: %d)\n", pid);
+	pr_info("========================================\n");
+
+	if (kerndat_init())
+		goto err;
+
+	if (cpu_init())
+		goto err;
+
+	if (vdso_init())
+		goto err;
+
+	if (write_img_inventory())
+		goto err;
+
+	if (connect_to_page_server())
+		goto err;
+
+	if (collect_pstree_ids())
+		goto err;
+
+	if (network_lock())
+		goto err;
+
+	if (collect_file_locks())
+		goto err;
+
+	if (collect_mount_info(pid))
+		goto err;
+
+	if (mntns_collect_root(root_item->pid.real))
+		goto err;
+
+	if (collect_sockets(pid))
+		goto err;
+
+	glob_fdset = cr_glob_fdset_open(O_DUMP);
+	if (!glob_fdset)
+		goto err;
+
+	for_each_pstree_item(item) {
+		if (dump_one_task(item))
+			goto err;
+	}
+
+	if (dump_verify_tty_sids())
+		goto err;
+
+	if (dump_zombies())
+		goto err;
+
+	if (dump_pstree(root_item))
+		goto err;
+
+	if (current_ns_mask)
+		if (dump_namespaces(&root_item->pid, current_ns_mask) < 0)
+			goto err;
+
+	ret = cr_dump_shmem();
+	if (ret)
+		goto err;
+
+	ret = fix_external_unix_sockets();
+	if (ret)
+		goto err;
+
+	ret = tty_verify_active_pairs();
+	if (ret)
+		goto err;
+
+	fd_id_show_tree();
+err:
+	close_cr_fdset(&glob_fdset);
+
+	if (!ret) {
+		/*
+		 * It might be a migration case, where we're asked
+		 * to dump everything, then some script transfer
+		 * image on a new node and we're supposed to kill
+		 * dumpee because it continue running somewhere
+		 * else.
+		 *
+		 * Thus ask user via script if we're to break
+		 * checkpoint.
+		 */
+		post_dump_ret = run_scripts("post-dump");
+		if (post_dump_ret) {
+			post_dump_ret = WEXITSTATUS(post_dump_ret);
+			pr_info("Post dump script passed with %d\n", post_dump_ret);
+		}
+	}
+
+	/*
+	 * If we've failed to do anything -- unlock all TCP sockets
+	 * so that the connections can go on. But if we succeeded --
+	 * don't, just close them silently.
+	 */
+	if (ret || post_dump_ret)
+		network_unlock();
+	pstree_switch_state(root_item,
+			    (ret || post_dump_ret) ?
+			    TASK_ALIVE : opts.final_state);
+	timing_stop(TIME_FROZEN);
+	free_pstree(root_item);
+	free_file_locks();
+
+	close_safe(&pidns_proc);
+
+	if (ret) {
+		kill_inventory();
+		pr_err("Dumping FAILED.\n");
+	} else {
+		write_stats(DUMP_STATS);
+		pr_info("Dumping finished successfully\n");
+	}
+
+	return post_dump_ret ? : ret;
+}
diff --git a/cr-service.c b/cr-service.c
new file mode 100644
index 0000000..75b3634
--- /dev/null
+++ b/cr-service.c
@@ -0,0 +1,172 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /*for struct ucred*/
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include "crtools.h"
+#include "cr-dump.h"
+#include "log.h"
+
+int cr_service(void) {
+
+	/*sockets initialization*/
+	
+	int server_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+	int client_fd;
+	
+	if (server_fd == -1) {
+		pr_perror("socket() failed");
+		exit(1);
+	}
+	
+	struct sockaddr_un server_addr, client_addr;
+	memset(&server_addr, 0, sizeof(server_addr));
+	memset(&client_addr, 0, sizeof(client_addr));
+	socklen_t server_addr_len, client_addr_len;
+	server_addr.sun_family = AF_LOCAL;
+	strcpy(server_addr.sun_path, "/tmp/criu_service.soc");
+	
+	server_addr_len = strlen(server_addr.sun_path) + sizeof(server_addr.sun_family);
+	client_addr_len = sizeof(client_addr);
+
+	unlink(server_addr.sun_path);
+	
+	if (bind(server_fd, (struct sockaddr *) &server_addr, server_addr_len) == -1) {
+		pr_perror("bind() failed");
+		exit(1);
+	
+	}
+
+	if (chmod(server_addr.sun_path, 0777)) {
+		pr_perror("chmod() failed");
+		exit(1);
+	}
+	
+	if (listen(server_fd, 16) == -1) {
+		pr_perror("listen() failed");
+		exit(1);
+	}
+
+	struct criu_dump_args* criu_arg = (struct criu_dump_args*)malloc(sizeof(struct criu_dump_args));
+	int child_pid;
+	struct ucred ids;
+	socklen_t ids_len = sizeof(struct ucred);
+	while(1) {		
+		pr_info("Waiting for connection...");
+		
+		if ( (client_fd = accept(server_fd, &client_addr, &client_addr_len)) == -1) {
+			pr_perror("accept() failed");
+			continue;
+		}
+		
+		pr_info("Connected.");
+		
+		/* calling fork() twice to avoid zombies */
+		switch(child_pid = fork()) {
+		case -1:
+			pr_perror("fork() failed");
+			continue;
+		case 0:
+			switch(child_pid = fork()) {
+			case -1:
+				pr_perror("second fork() failed");
+				exit(1);
+			case 0:
+				/*make dump*/
+				if ( getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &ids, &ids_len)) {
+					pr_perror("getsockopt() failed");
+					exit(1);
+				}
+
+				if ( (client_addr_len = criu_recv_dump_arg(client_fd, criu_arg)) == -1) {
+					pr_perror("criu_recv_dump_arg() failed");
+					exit(1);
+				}
+
+				if ( fchdir(criu_arg->images_dir_fd)) {
+					pr_perror("fchdir() failed");
+					exit(1);
+				}
+				 
+				if ( open_image_dir() < 0) {
+					pr_perror("could not open current directory");
+					exit(1);
+				}
+
+				collect_pstree(ids.pid);/*freezing the process*/
+				
+				close(client_fd);
+				
+				cr_dump_tasks_continue(ids.pid);
+				
+				exit(0);
+			default:
+				close(client_fd);
+				exit(0);
+			}
+		default:
+			close(client_fd);
+			if (waitpid(child_pid, NULL, 0) != child_pid) {
+				pr_perror("waitpid() failed");
+				continue;	
+			}
+		}
+	}
+	return 0;
+}
+
+static int recv_fd(int socket_fd) {
+	struct msghdr msg;
+	struct iovec iov[1];
+	struct cmsghdr *cmsg = NULL;
+	char cbuf[CMSG_SPACE(sizeof(int))];
+	char data[1];
+	int res;
+	
+	memset(&msg, 0, sizeof(struct msghdr));
+	memset(cbuf, 0, CMSG_SPACE(sizeof(int)));
+
+	/*dummy data*/
+	iov[0].iov_base = data;
+	iov[0].iov_len = sizeof(data);
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_control = cbuf;
+	msg.msg_controllen = CMSG_SPACE(sizeof(int));
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 1;
+
+	if((res = recvmsg(socket_fd, &msg, 0)) <= 0)
+		return -1;
+
+	/*iterate through header to find if there is a file descriptor*/
+	for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg))
+		if( (cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SCM_RIGHTS) ) 
+			return *((int *) CMSG_DATA(cmsg));
+
+	return -1;
+}
+
+int criu_recv_dump_arg(int socket_fd, struct criu_dump_args* arg) {
+	int ret;
+	if ((arg->images_dir_fd = recv_fd(socket_fd)) == -1) {
+		pr_perror("recv_fd() failed");
+		return -1;
+	}
+	if ((ret = recv(socket_fd, &(arg->flags), sizeof(unsigned long) , 0)) == -1) {
+		pr_perror("recv() failed");
+		return -1;
+	}
+	return 0;
+}
diff --git a/crtools.c b/crtools.c
index 51d188a..b191378 100644
--- a/crtools.c
+++ b/crtools.c
@@ -337,6 +337,9 @@ int main(int argc, char *argv[])
 	if (!strcmp(argv[optind], "page-server"))
 		return cr_page_server(opts.restore_detach);
 
+	if (!strcmp(argv[optind], "service"))
+		return cr_service();
+
 	pr_msg("Unknown command \"%s\"\n", argv[optind]);
 usage:
 	pr_msg("\n"
@@ -347,6 +350,7 @@ usage:
 "  criu check [--ms]\n"
 "  criu exec -p PID <syscall-string>\n"
 "  criu page-server\n"
+"  criu service\n"
 "\n"
 "Commands:\n"
 "  dump           checkpoint a process/tree identified by pid\n"
@@ -356,6 +360,7 @@ usage:
 "  check          checks whether the kernel support is up-to-date\n"
 "  exec           execute a system call by other task\n"
 "  page-server    launch page server\n"
+"  service        launch server, that can be requested to dump a process\n"
 	);
 
 	if (argc < 2) {
diff --git a/include/cr-dump.h b/include/cr-dump.h
new file mode 100644
index 0000000..fb6b9c4
--- /dev/null
+++ b/include/cr-dump.h
@@ -0,0 +1,2 @@
+int collect_pstree(pid_t pid);
+int cr_dump_tasks_continue(pid_t pid);
diff --git a/include/crtools.h b/include/crtools.h
index 81e89e1..701901e 100644
--- a/include/crtools.h
+++ b/include/crtools.h
@@ -10,6 +10,7 @@
 #include "image.h"
 #include "lock.h"
 #include "cr-show.h"
+#include "libcriu.h"
 
 #include "protobuf/vma.pb-c.h"
 
@@ -119,6 +120,7 @@ int cr_show(int pid);
 int convert_to_elf(char *elf_path, int fd_core);
 int cr_check(void);
 int cr_exec(int pid, char **opts);
+int cr_service(void);
 
 #define O_DUMP	(O_RDWR | O_CREAT | O_EXCL)
 #define O_SHOW	(O_RDONLY)
diff --git a/include/libcriu.h b/include/libcriu.h
new file mode 100644
index 0000000..ada3703
--- /dev/null
+++ b/include/libcriu.h
@@ -0,0 +1,10 @@
+struct criu_dump_args {
+	int images_dir_fd;
+	unsigned long flags;
+};
+
+int criu_dump_me(struct criu_dump_args * arg);
+
+/*??????????? ? ???????????? ?????*/
+int criu_send_dump_arg(int socket_fd, struct criu_dump_args * arg);
+int criu_recv_dump_arg(int socket_fd, struct criu_dump_args * arg);
diff --git a/lib/Makefile b/lib/Makefile
index 368883e..3d61831 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -2,11 +2,12 @@
 
 all: libcriu.so
 
-libcriu.so: criu.o
-	$(Q) $(CC) $(CFLAGS) -shared -o $@ criu.o
 
-criu.o:
-	$(Q) $(CC) $(CFLAGS) -fPIC -c criu.c -I ../include/
+libcriu.so: libcriu.o
+	$(Q) $(CC) $(CFLAGS) -shared -o $@ libcriu.o
+
+libcriu.o: libcriu.c
+	$(Q) $(CC) $(CFLAGS) -fPIC -c libcriu.c -I ../include/
 
 clean:
 	$(Q) $(RM) -f *.o
diff --git a/lib/libcriu.c b/lib/libcriu.c
new file mode 100644
index 0000000..1797e55
--- /dev/null
+++ b/lib/libcriu.c
@@ -0,0 +1,95 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libcriu.h"
+#include "version.h"
+
+const char* criu_lib_version = version;
+
+int criu_dump_me(struct criu_dump_args * arg) {
+	int socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if (socket_fd == -1) { 
+		perror("socket() failed");
+		exit(1);
+	}	
+
+	struct sockaddr_un server_addr;
+	memset(&server_addr, 0, sizeof(server_addr));
+	server_addr.sun_family = AF_LOCAL;
+	strcpy(server_addr.sun_path, "/tmp/criu_service.soc");
+	size_t server_addr_len = strlen(server_addr.sun_path) + sizeof(server_addr.sun_family);	
+
+	if ( connect(socket_fd, (struct sockaddr *) &server_addr, server_addr_len) != 0) {
+		perror("connect() fail");
+		exit(1);
+	}
+
+	if (criu_send_dump_arg(socket_fd, arg) == -1) {
+		perror("criu_send_dump_arg() failed");
+		exit(1);
+	}
+	
+	char buf;
+	int ret;
+
+	ret = read(socket_fd, &buf, 1);
+	(void)ret;
+	close(socket_fd);
+	
+	return 0;
+}
+
+static int send_fd(int socket_fd, int fd) {
+	struct msghdr msg;
+	struct iovec iov[1];
+	struct cmsghdr *cmsg = NULL;
+	char cbuf[CMSG_SPACE(sizeof(int))];
+	char data[1];
+	
+	memset(&msg, 0, sizeof(struct msghdr));
+	memset(cbuf, 0, CMSG_SPACE(sizeof(int)));
+	
+	/*passing one byte so recvmsg() will not return 0*/
+	data[0] = ' ';
+	iov[0].iov_base = data;
+	iov[0].iov_len = sizeof(data);
+	
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 1;
+	msg.msg_controllen =  CMSG_SPACE(sizeof(int));
+	msg.msg_control = cbuf;
+	
+	cmsg = CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type = SCM_RIGHTS;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+	
+	memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
+	
+	return sendmsg(socket_fd, &msg, 0);
+}
+
+int criu_send_dump_arg(int socket_fd, struct criu_dump_args * arg) {
+	
+	if (send_fd(socket_fd, arg->images_dir_fd) == -1) {
+		perror("send_fd() failed");	
+		return -1;
+	}
+
+	if (send(socket_fd, &(arg->flags), sizeof(unsigned long), 0) == -1) {
+		perror("send() failed");
+		return -1;
+	}
+
+	return 0;
+}


More information about the CRIU mailing list