[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