[v3,5/8] epoll: Drop duped and closed targets

Submitted by Cyrill Gorcunov on March 28, 2019, 10:41 a.m.

Details

Message ID 20190328104101.GA25504@uranus
State New
Series "epoll: Add support for migrated targets"
Headers show

Commit Message

Cyrill Gorcunov March 28, 2019, 10:41 a.m.
Due to kernel epoll engine specifics we may have a case
where some target file are present in fdinfo twice and
only one local file descriptor is present: an easy
reproduction is to dup fd, add it into epoll and
close it then.

Thus for such case we resolve all targets but then
run validation procedure that every target is unique.

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---
 v3: Fix qsort args passing

 criu/eventpoll.c       | 42 ++++++++++++++++++++++++++++++++++++++++++
 images/eventpoll.proto |  3 +++
 2 files changed, 45 insertions(+)

Patch hide | download patch | download mbox

diff --git a/criu/eventpoll.c b/criu/eventpoll.c
index be43161b2668..c1bbceea9efa 100644
--- a/criu/eventpoll.c
+++ b/criu/eventpoll.c
@@ -122,6 +122,22 @@  static void dequeue_dinfo(struct eventpoll_dinfo *dinfo)
 	xfree(dinfo);
 }
 
+static int etfd_cmp(const void *__a, const void *__b)
+{
+	EventpollTfdEntry *a = *(EventpollTfdEntry **)__a;
+	EventpollTfdEntry *b = *(EventpollTfdEntry **)__b;
+
+	if (a->tfd > b->tfd)
+		return 1;
+	if (a->tfd < b->tfd)
+		return -1;
+	if (a->pid < b->pid)
+		return 1;
+	if (a->pid > b->pid)
+		return -1;
+	return 0;
+}
+
 int flush_eventpoll_dinfo_queue(void)
 {
 	struct eventpoll_dinfo *dinfo, *tmp;
@@ -188,6 +204,32 @@  int flush_eventpoll_dinfo_queue(void)
 
 		e->n_tfd = j;
 
+		/*
+		 * Once we've resolved all targets we should drop those
+		 * which are in state of dup/add/close (epoll kernel engine
+		 * saves all records while the target may simply not exist).
+		 *
+		 * tfd:        4 events:       1d data: ...
+		 * tfd:      704 events:       1d data: ...
+		 *
+		 * Here an application added fd=4 to an epoll, then dup'ed
+		 * fd=4 to fd=704, added it to the epoll and then closed fd=704.
+		 * Thus after the resolve with kcmp help we will have two tf=4
+		 * records in the queue.
+		 */
+		if (e->n_tfd) {
+			qsort(e->tfd, e->n_tfd, sizeof(e->tfd[0]), etfd_cmp);
+			for (j = i = 1; i < e->n_tfd; i++) {
+				if (!etfd_cmp(&e->tfd[i], &e->tfd[i-1])) {
+					pr_debug("kid_lookup_epoll: id %#x same tfd %u pid %d\n",
+						 e->id, e->tfd[i]->pid, e->tfd[i]->tfd);
+					continue;
+				}
+				e->tfd[j++] = e->tfd[i];
+			}
+			e->n_tfd = j;
+		}
+
 		pr_info_eventpoll("Dumping ", e);
 		ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), dinfo->fe, PB_FILE);
 		if (!ret) {
diff --git a/images/eventpoll.proto b/images/eventpoll.proto
index 4a8d1b834ef8..ac387d0f3109 100644
--- a/images/eventpoll.proto
+++ b/images/eventpoll.proto
@@ -12,6 +12,9 @@  message eventpoll_tfd_entry {
 	optional uint32		dev	= 5;
 	optional uint64		inode	= 6;
 	optional uint64		pos	= 7;
+
+	/* to find foreigner targets */
+	optional uint32		pid	= 8;
 }
 
 message eventpoll_file_entry {