[CRIU] [PATCH 3/4] lazy-pages: handle exit() based on uffdio_copy return value

Mike Rapoport rppt at linux.vnet.ibm.com
Wed Apr 5 05:28:40 PDT 2017


The UFFDIO_EVENT_EXIT didn't make it upstream because of possible races in
exit() syscall [1].
The only way to detect that the monitored process is exited is checking for
ENOSPC errno value set by uffdio_copy.

[1] http://www.spinics.net/lists/linux-mm/msg122467.html

Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
---
 criu/uffd.c | 54 ++++++++++++++++++++++--------------------------------
 1 file changed, 22 insertions(+), 32 deletions(-)

diff --git a/criu/uffd.c b/criu/uffd.c
index f8767de..b2cf102 100644
--- a/criu/uffd.c
+++ b/criu/uffd.c
@@ -50,7 +50,6 @@
 #define lp_perror(lpi, fmt, arg...) pr_perror("%d-%d: " fmt, lpi->pid, lpi->lpfd.fd, ##arg)
 
 #define NEED_UFFD_API_FEATURES (UFFD_FEATURE_EVENT_FORK |	    \
-				UFFD_FEATURE_EVENT_EXIT |	    \
 				UFFD_FEATURE_EVENT_REMAP |	    \
 				UFFD_FEATURE_EVENT_UNMAP |	    \
 				UFFD_FEATURE_EVENT_REMOVE)
@@ -662,6 +661,20 @@ out:
 	return -1;
 }
 
+static int handle_exit(struct lazy_pages_info *lpi)
+{
+	lp_debug(lpi, "EXIT\n");
+	if (epoll_del_rfd(epollfd, &lpi->lpfd))
+		return -1;
+	free_lazy_iovs(lpi);
+	close(lpi->lpfd.fd);
+
+	/* keep it for summary */
+	list_move_tail(&lpi->l, &lpis);
+
+	return 0;
+}
+
 static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages)
 {
 	struct uffdio_copy uffdio_copy;
@@ -677,11 +690,15 @@ static int uffd_copy(struct lazy_pages_info *lpi, __u64 address, int nr_pages)
 	lp_debug(lpi, "uffd_copy: 0x%llx/%ld\n", uffdio_copy.dst, len);
 	rc = ioctl(lpi->lpfd.fd, UFFDIO_COPY, &uffdio_copy);
 	if (rc) {
-		/* real retval in ufdio_copy.copy */
-		lp_err(lpi, "UFFDIO_COPY failed: rc:%d copy:%Ld\n", rc,
-		       uffdio_copy.copy);
-		if (uffdio_copy.copy != -EEXIST)
+		if (errno == ENOSPC) {
+			handle_exit(lpi);
+			return 0;
+		}
+		if (uffdio_copy.copy != -EEXIST) {
+			lp_debug(lpi, "uffd_copy: rc:%d copy:%Ld, errno:%d\n",
+				 rc, uffdio_copy.copy, errno);
 			return -1;
+		}
 	} else if (uffdio_copy.copy != len) {
 		lp_err(lpi, "UFFDIO_COPY unexpected size %Ld\n", uffdio_copy.copy);
 		return -1;
@@ -848,29 +865,6 @@ static int handle_remap(struct lazy_pages_info *lpi, struct uffd_msg *msg)
 	return remap_lazy_iovs(lpi, from, to, len);
 }
 
-static int handle_exit(struct lazy_pages_info *lpi, struct uffd_msg *msg)
-{
-	lp_debug(lpi, "EXIT\n");
-	list_move(&lpi->l, &exiting_lpis);
-	return 1;
-}
-
-static int complete_exits(int epollfd)
-{
-	struct lazy_pages_info *lpi, *n;
-
-	list_for_each_entry_safe(lpi, n, &exiting_lpis, l) {
-		if (epoll_del_rfd(epollfd, &lpi->lpfd))
-			return -1;
-		free_lazy_iovs(lpi);
-		close(lpi->lpfd.fd);
-		/* keep it for summary */
-		list_move_tail(&lpi->l, &lpis);
-	}
-
-	return 0;
-}
-
 static int handle_fork(struct lazy_pages_info *parent_lpi, struct uffd_msg *msg)
 {
 	struct lazy_pages_info *lpi;
@@ -989,8 +983,6 @@ static int handle_uffd_event(struct epoll_rfd *lpfd)
 		return handle_remove(lpi, &msg);
 	case UFFD_EVENT_REMAP:
 		return handle_remap(lpi, &msg);
-	case UFFD_EVENT_EXIT:
-		return handle_exit(lpi, &msg);
 	case UFFD_EVENT_FORK:
 		return handle_fork(lpi, &msg);
 	default:
@@ -1035,8 +1027,6 @@ static int handle_requests(int epollfd, struct epoll_event *events, int nr_fds)
 		if (ret > 0) {
 			if (complete_forks(epollfd, &events, &nr_fds))
 				return -1;
-			if (complete_exits(epollfd))
-				return -1;
 			continue;
 		}
 
-- 
1.9.1



More information about the CRIU mailing list