[CRIU] [PATCH 5/6] kdat: Check for KCMP_EPOLL_TFD

Cyrill Gorcunov gorcunov at gmail.com
Tue Apr 3 20:46:49 MSK 2018


This feature will be needed to support duplicated
target file descriptors in epoll.

Signed-off-by: Cyrill Gorcunov <gorcunov at gmail.com>
---
 criu/include/kcmp.h    | 10 ++++++++
 criu/include/kerndat.h |  1 +
 criu/kerndat.c         | 64 +++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/criu/include/kcmp.h b/criu/include/kcmp.h
index 76f557bff047..b6d3519a0c5c 100644
--- a/criu/include/kcmp.h
+++ b/criu/include/kcmp.h
@@ -1,6 +1,8 @@
 #ifndef __CR_KCMP_H__
 #define __CR_KCMP_H__
 
+#include <stdint.h>
+
 enum kcmp_type {
 	KCMP_FILE,
 	KCMP_VM,
@@ -9,8 +11,16 @@ enum kcmp_type {
 	KCMP_SIGHAND,
 	KCMP_IO,
 	KCMP_SYSVSEM,
+	KCMP_EPOLL_TFD,
 
 	KCMP_TYPES,
 };
 
+/* Slot for KCMP_EPOLL_TFD */
+typedef struct {
+	uint32_t efd;		/* epoll file descriptor */
+	uint32_t tfd;		/* target file number */
+	uint32_t toff;		/* target offset within same numbered sequence */
+} kcmp_epoll_slot_t;
+
 #endif /* __CR_KCMP_H__ */
diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h
index 28a84fb0d583..af6b5c5c3a38 100644
--- a/criu/include/kerndat.h
+++ b/criu/include/kerndat.h
@@ -77,6 +77,7 @@ struct kerndat_s {
 	bool has_pid_for_children_ns;
 	bool x86_has_ptrace_fpu_xsave_bug;
 	bool has_inotify_setnextwd;
+	bool has_kcmp_epoll_tfd;
 };
 
 extern struct kerndat_s kdat;
diff --git a/criu/kerndat.c b/criu/kerndat.c
index 227d429f9dde..456adbf2851f 100644
--- a/criu/kerndat.c
+++ b/criu/kerndat.c
@@ -13,7 +13,7 @@
 #include <arpa/inet.h>  /* for sockaddr_in and inet_ntoa() */
 #include <sys/prctl.h>
 #include <sys/inotify.h>
-
+#include <sys/epoll.h>
 
 #include "common/config.h"
 #include "int.h"
@@ -40,6 +40,7 @@
 #include "prctl.h"
 #include "uffd.h"
 #include "vdso.h"
+#include "kcmp.h"
 
 struct kerndat_s kdat = {
 };
@@ -819,6 +820,65 @@ int kerndat_has_inotify_setnextwd(void)
 	return ret;
 }
 
+static int kerndat_has_kcmp_epoll_tfd(void)
+{
+	kcmp_epoll_slot_t epoll_slot = { };
+	struct epoll_event ev;
+	int ret = -1;
+	int pipefd[2];
+	int epollfd;
+	int fddup;
+
+	if (pipe(pipefd)) {
+		pr_perror("Can't create pipe");
+		return -1;
+	}
+
+	epollfd = epoll_create1(0);
+	if (epollfd < 0) {
+		pr_perror("epoll_create1 failed");
+		return -1;
+	}
+
+	memset(&ev, 0xff, sizeof(ev));
+	ev.events = EPOLLIN | EPOLLOUT;
+
+	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, pipefd[0], &ev)) {
+		pr_perror("epoll_ctl failed");
+		return -1;
+	}
+
+	fddup = dup(pipefd[1]);
+	if (fddup < 0) {
+		pr_perror("dup2 failed");
+		goto out;
+	}
+
+	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fddup, &ev)) {
+		pr_perror("epoll_ctl failed");
+		close(fddup);
+		goto out;
+	}
+	close(fddup);
+
+	epoll_slot = (kcmp_epoll_slot_t) {
+		.efd	= epollfd,
+		.tfd	= fddup,
+		.toff	= 0,
+	};
+
+	ret = syscall(SYS_kcmp, getpid(), getpid(),
+		      KCMP_EPOLL_TFD, pipefd[1], (void *)&epoll_slot);
+	if (ret == 0)
+		kdat.has_kcmp_epoll_tfd = true;
+
+out:
+	close(pipefd[0]);
+	close(pipefd[1]);
+	close(epollfd);
+	return ret;
+}
+
 int __attribute__((weak)) kdat_x86_has_ptrace_fpu_xsave_bug(void)
 {
 	return 0;
@@ -1124,6 +1184,8 @@ int kerndat_init(void)
 		ret = kerndat_x86_has_ptrace_fpu_xsave_bug();
 	if (!ret)
 		ret = kerndat_has_inotify_setnextwd();
+	if (!ret)
+		ret = kerndat_has_kcmp_epoll_tfd();
 
 	kerndat_lsm();
 	kerndat_mmap_min_addr();
-- 
2.14.3



More information about the CRIU mailing list