[CRIU] [PATCH CRIU 7/7] log_dirty: count dirty pages for one pid in pagemap

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Thu Apr 7 06:28:46 PDT 2016


read lines from /proc/<pid>/maps and for each memory region
check PME_SOFT_DIRTY for every page using /proc/<pid>/pagemap
and summup pages and dirty pages.

Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
 criu/dirty-logger.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/criu/dirty-logger.c b/criu/dirty-logger.c
index 6b7cbf4..8109bcf 100644
--- a/criu/dirty-logger.c
+++ b/criu/dirty-logger.c
@@ -3,6 +3,8 @@
 #include <pthread.h>
 #include <sys/time.h>
 
+#include "util.h"
+#include "mem.h"
 #include "imgset.h"
 #include "pstree.h"
 
@@ -22,8 +24,83 @@ static int sleep_us(long us) {
 	return 0;
 }
 
+#define MAPS_PATH "/proc/%d/maps"
+#define MAX_MAPS_PATH 50
+#define BUFF_SIZE 500000
+#define LINELEN 256
+
 static int pid_log_dirty_total(pid_t pid, long *total_pages, long *total_dirty_pages)
 {
+	char maps_path[MAX_MAPS_PATH];
+	FILE * maps;
+	int pagemap_fd;
+
+	u64 pfn[BUFF_SIZE];
+	char line[LINELEN];
+
+	sprintf(maps_path, MAPS_PATH, pid);
+	maps = fopen(maps_path, "r");
+	if (maps == NULL) {
+		pr_perror("Can't open pid %d maps", pid);
+		return -1;
+	}
+	pthread_cleanup_push(fclose, maps);
+
+	pagemap_fd = open_proc(pid, "pagemap");
+	if (pagemap_fd < 0) {
+		pr_perror("Can't open pid %d pagemap", pid);
+		return -1;
+	}
+	pthread_cleanup_push(close, pagemap_fd);
+
+	/*
+	 * For each line in maps
+	 */
+	while (fgets(line, LINELEN, maps) != NULL) {
+		char * pend;
+		uint64_t start, end;
+		off_t off;
+		long j;
+		int ret;
+
+		start = strtoul(line, &pend, 16);
+		end = strtoul(pend + 1, NULL, 16);
+		if (start >= end)
+			continue;
+
+		off = (start / PAGE_SIZE) * sizeof(u64);
+		pr_debug("Read pagemap from %lx to %lx\n", start, end);
+		if (lseek (pagemap_fd, off, SEEK_SET) != off) {
+			pr_perror("Failed to seek address %lx\n", off);
+			return -1;
+		}
+
+		if ((end - start) / PAGE_SIZE > BUFF_SIZE) {
+			pr_err("Buffer overflow for pid %d\n", pid);
+			return -1;
+		}
+
+		ret = read(pagemap_fd, pfn, ((end - start) / PAGE_SIZE) * sizeof(u64));
+		if (ret != ((end - start) / PAGE_SIZE) * sizeof(u64)) {
+			if (ret == 0) {
+				pr_debug("Can't read because of EOF\n");
+				continue;
+			}
+			pr_perror("Can't read pme for pid %d", pid);
+			return -1;
+		}
+
+		*total_pages += ret/sizeof(u64);
+		for (j = 0; j < ret/sizeof(u64); j++) {
+			if (pfn[j] & PME_SOFT_DIRTY) {
+				(*total_dirty_pages)++;
+			}
+		}
+		pr_debug("Pid %d: %ld pages read, %ld dirty\n", pid, *total_pages, *total_dirty_pages);
+	}
+
+	pthread_cleanup_pop(1);
+	pthread_cleanup_pop(1);
 	return 0;
 }
 
-- 
1.9.3



More information about the CRIU mailing list