[CRIU] [PATCH 2/5] locks: Add c/r of breaking leases (kernel >=v4.1)

Pavel Begunkov asml.silence at gmail.com
Mon Aug 14 01:27:06 MSK 2017


Because leases can be taken out only on regular files, it gets file path
and trying to open the file with it in order to break the lease.

task #39

Signed-off-by: Pavel Begunkov <asml.silence at gmail.com>
---
 criu/file-lock.c         | 89 +++++++++++++++++++++++++++++++++++++++++++++++-
 criu/files.c             |  1 +
 criu/include/file-lock.h |  3 ++
 criu/proc_parse.c        |  7 ++--
 4 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/criu/file-lock.c b/criu/file-lock.c
index 92d8bd394..496eac74d 100644
--- a/criu/file-lock.c
+++ b/criu/file-lock.c
@@ -18,6 +18,8 @@
 #include "proc_parse.h"
 #include "servicefd.h"
 #include "file-lock.h"
+#include "pstree.h"
+#include "files-reg.h"
 
 struct file_lock_rst {
 	FileLockEntry *fle;
@@ -332,6 +334,91 @@ int note_file_lock(struct pid *pid, int fd, int lfd, struct fd_parms *p)
 	return 0;
 }
 
+static int open_break_cb(int ns_root_fd, struct reg_file_info *rfi, void *arg)
+{
+	int fd, flags = *(int *)arg | O_NONBLOCK;
+
+	fd = openat(ns_root_fd, rfi->path, flags);
+	if (fd >= 0) {
+		pr_err("Conflicting lease wasn't found\n");
+		close(fd);
+		return -1;
+	}
+	if (errno != EWOULDBLOCK) {
+		pr_perror("Can't open file to break lease\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int set_lease_for_breaking(int fd, int fd_type)
+{
+	int lease_type;
+
+	if (fd_type == O_RDONLY) {
+		lease_type = F_RDLCK;
+	} else if (fd_type == O_WRONLY) {
+		lease_type = F_WRLCK;
+	} else {
+		pr_err("Incompatible with lease file type (%i)\n", fd_type);
+		return -1;
+	}
+
+	if (fcntl(fd, F_SETLEASE, lease_type) < 0) {
+		pr_perror("Can't set lease to fd %#x\n", fd);
+		return -1;
+	}
+	return 0;
+}
+
+static struct fdinfo_list_entry *find_fd(struct pstree_item *task, int fd)
+{
+	struct list_head *head = &rsti(task)->fds;
+	struct fdinfo_list_entry *fle;
+
+	list_for_each_entry_reverse(fle, head, ps_list) {
+		if (fle->fe->fd == fd)
+			return fle;
+	}
+	return NULL;
+}
+
+static int restore_breaking_file_lease(FileLockEntry *fle)
+{
+	struct fdinfo_list_entry *fdle;
+	int break_flags;
+	int lease_break_type = fle->type & (~LEASE_BREAKING);
+
+	fdle = find_fd(current, fle->fd);
+	if (fdle == NULL) {
+		pr_err("Can't get file description\n");
+		return -1;
+	}
+
+	if (set_lease_for_breaking(fle->fd, fdle->desc->ops->type))
+		return -1;
+
+	if (lease_break_type == F_UNLCK) {
+		break_flags = O_WRONLY;
+	} else if (lease_break_type == F_RDLCK) {
+		break_flags = O_RDONLY;
+	} else {
+		pr_err("Incorrect breaking type of lease\n");
+		return -1;
+	}
+	if (open_path(fdle->desc, open_break_cb, (void *)&break_flags) < 0)
+		return -1;
+	return 0;
+}
+
+static int restore_file_lease(FileLockEntry *fle)
+{
+	if (fle->type & LEASE_BREAKING)
+		return restore_breaking_file_lease(fle);
+	else
+		return fcntl(fle->fd, F_SETLEASE, fle->type);
+}
+
 static int restore_file_lock(FileLockEntry *fle)
 {
 	int ret = -1;
@@ -399,7 +486,7 @@ static int restore_file_lock(FileLockEntry *fle)
 			goto err;
 		}
 	} else if (fle->flag & FL_LEASE) {
-		ret = fcntl(fle->fd, F_SETLEASE, fle->type);
+		ret = restore_file_lease(fle);
 		if (ret < 0) {
 			pr_perror("Can't set lease!\n");
 			goto err;
diff --git a/criu/files.c b/criu/files.c
index 01cd4c0e9..2c3389e3f 100644
--- a/criu/files.c
+++ b/criu/files.c
@@ -14,6 +14,7 @@
 #include <stdlib.h>
 
 #include "types.h"
+#include "kerndat.h"
 #include "files.h"
 #include "file-ids.h"
 #include "files-reg.h"
diff --git a/criu/include/file-lock.h b/criu/include/file-lock.h
index f70739adb..7280e0b55 100644
--- a/criu/include/file-lock.h
+++ b/criu/include/file-lock.h
@@ -38,6 +38,9 @@
 #define LOCK_WRITE	128	/* which allows concurrent write operations */
 #define LOCK_RW		192	/* which allows concurrent read & write ops */
 
+/* for leases */
+#define LEASE_BREAKING	4
+
 struct file_lock {
 	long long	fl_id;
 	int		fl_kind;
diff --git a/criu/proc_parse.c b/criu/proc_parse.c
index d3893272c..89be4ceb5 100644
--- a/criu/proc_parse.c
+++ b/criu/proc_parse.c
@@ -1996,6 +1996,10 @@ static int parse_file_lock_buf(char *buf, struct file_lock *fl,
 	else
 		fl->fl_kind = FL_UNKNOWN;
 
+	if (fl->fl_kind == FL_LEASE && !strcmp(fl_type, "BREAKING")) {
+		fl->fl_ltype |= LEASE_BREAKING;
+	}
+
 	if (!strcmp(fl_type, "MSNFS")) {
 		fl->fl_ltype |= LOCK_MAND;
 
@@ -2009,9 +2013,6 @@ static int parse_file_lock_buf(char *buf, struct file_lock *fl,
 			pr_err("Unknown lock option!\n");
 			return -1;
 		}
-	} else if (fl->fl_kind == FL_LEASE && !strcmp(fl_type, "BREAKING")) {
-		pr_err("Breaking leases are not supported (%d): %s\n",
-			num, buf);
 	} else {
 		if (!strcmp(fl_option, "UNLCK")) {
 			fl->fl_ltype |= F_UNLCK;
-- 
2.11.1



More information about the CRIU mailing list