[v4,09/13] epoll: Add support for multiple duped fds

Submitted by Cyrill Gorcunov on July 2, 2018, 8:13 p.m.

Details

Message ID 20180702201333.3087-10-gorcunov@gmail.com
State New
Series "epoll: Add support for duped targets"
Headers show

Commit Message

Cyrill Gorcunov July 2, 2018, 8:13 p.m.
Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---
 criu/eventpoll.c | 52 +++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 37 insertions(+), 15 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/eventpoll.c b/criu/eventpoll.c
index 90fac99488f4..1ac6d5d9aff1 100644
--- a/criu/eventpoll.c
+++ b/criu/eventpoll.c
@@ -68,17 +68,18 @@  static int tfd_cmp(const void *a, const void *b)
  * fds in fd_parms are sorted so we can use binary search
  * for better performance.
  */
-static int find_tfd(pid_t pid, int efd, int fds[], size_t nr_fds, int tfd)
+static int find_tfd(pid_t pid, int efd, int fds[], size_t nr_fds, int tfd,
+		    unsigned int toff)
 {
 	kcmp_epoll_slot_t slot = {
 		.efd	= efd,
 		.tfd	= tfd,
-		.toff	= 0,
+		.toff	= toff,
 	};
 	int *tfd_found;
 	size_t i;
 
-	pr_debug("find_tfd: pid %d efd %d tfd %d\n", pid, efd, tfd);
+	pr_debug("find_tfd: pid %d efd %d tfd %d toff %u\n", pid, efd, tfd, toff);
 
 	/*
 	 * Optimistic case: the target fd belongs to us
@@ -88,13 +89,13 @@  static int find_tfd(pid_t pid, int efd, int fds[], size_t nr_fds, int tfd)
 	if (tfd_found) {
 		if (kdat.has_kcmp_epoll_tfd) {
 			if (syscall(SYS_kcmp, pid, pid, KCMP_EPOLL_TFD, tfd, &slot) == 0) {
-				pr_debug("find_tfd (kcmp-yes): bsearch match pid %d efd %d tfd %d\n",
-					 pid, efd, tfd);
+				pr_debug("find_tfd (kcmp-yes): bsearch match pid %d efd %d tfd %d toff %u\n",
+					 pid, efd, tfd, toff);
 				return tfd;
 			}
 		} else {
-			pr_debug("find_tfd (kcmp-no): bsearch match pid %d efd %d tfd %d\n",
-				 pid, efd, tfd);
+			pr_debug("find_tfd (kcmp-no): bsearch match pid %d efd %d tfd %d toff %u\n",
+				 pid, efd, tfd, toff);
 			return tfd;
 		}
 	}
@@ -106,21 +107,21 @@  static int find_tfd(pid_t pid, int efd, int fds[], size_t nr_fds, int tfd)
 	 */
 
 	if (!kdat.has_kcmp_epoll_tfd) {
-		pr_debug("find_tfd (kcmp-no): no match pid %d efd %d tfd %d\n",
-			 pid, efd, tfd);
+		pr_debug("find_tfd (kcmp-no): no match pid %d efd %d tfd %d toff %u\n",
+			 pid, efd, tfd, toff);
 		return -1;
 	}
 
 	for (i = 0; i < nr_fds; i++) {
 		if (syscall(SYS_kcmp, pid, pid, KCMP_EPOLL_TFD, fds[i], &slot) == 0) {
-			pr_debug("find_tfd (kcmp-yes): nsearch match pid %d efd %d tfd %d -> %d\n",
-				 pid, efd, tfd, fds[i]);
+			pr_debug("find_tfd (kcmp-yes): nsearch match pid %d efd %d tfd %d toff %u -> %d\n",
+				 pid, efd, tfd, toff, fds[i]);
 			return fds[i];
 		}
 	}
 
-	pr_debug("find_tfd (kcmp-yes): no match pid %d efd %d tfd %d\n",
-		 pid, efd, tfd);
+	pr_debug("find_tfd (kcmp-yes): no match pid %d efd %d tfd %d toff %u\n",
+		 pid, efd, tfd, toff);
 	return -1;
 }
 
@@ -129,7 +130,8 @@  static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p)
 	FileEntry fe = FILE_ENTRY__INIT;
 	EventpollFileEntry e = EVENTPOLL_FILE_ENTRY__INIT;
 	EventpollTfdEntry **tfd_cpy = NULL;
-	size_t i, j, n_tfd_cpy;
+	ssize_t i, j, n_tfd_cpy;
+	uint32_t *toff = NULL;
 	int ret = -1;
 
 	e.id = id;
@@ -148,6 +150,25 @@  static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p)
 	if (!tfd_cpy)
 		goto out;
 
+	/*
+	 * In regular case there is no so many dup'ed
+	 * descriptors so instead of complex mappings
+	 * lets rather walk over members with O(n^2)
+	 */
+	if (p->dfds) {
+		toff = xzalloc(sizeof(*toff) * e.n_tfd);
+		if (!toff)
+			goto out;
+		for (i = 1; i < e.n_tfd; i++) {
+			for (j = i - 1; j < e.n_tfd && j >= 0; j--) {
+				if (e.tfd[i]->tfd == e.tfd[j]->tfd) {
+					toff[i] = toff[j] + 1;
+					break;
+				}
+			}
+		}
+	}
+
 	/*
 	 * Handling dup'ed or transferred target
 	 * files is tricky: we need to use kcmp
@@ -159,7 +180,7 @@  static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p)
 	if (p->dfds) {
 		for (i = j = 0; i < e.n_tfd; i++) {
 			int tfd = find_tfd(p->pid, p->fd, p->dfds->fds,
-					   p->dfds->nr_fds, e.tfd[i]->tfd);
+					   p->dfds->nr_fds, e.tfd[i]->tfd, toff[i]);
 			if (tfd == -1) {
 				pr_warn("Escaped/closed fd descriptor %d on pid %d, ignoring\n",
 					e.tfd[i]->tfd, p->pid);
@@ -186,6 +207,7 @@  static int dump_one_eventpoll(int lfd, u32 id, const struct fd_parms *p)
 		eventpoll_tfd_entry__free_unpacked(e.tfd[i], NULL);
 	xfree(tfd_cpy);
 	xfree(e.tfd);
+	xfree(toff);
 
 	return ret;
 }