[CRIU] [PATCH 06/11] crtools: collect and check file locks

Qiang Huang h.huangqiang at huawei.com
Thu Jan 17 03:09:32 EST 2013


We collect all file locks to a golbal list, so we can use them easily
in dump_one_task. For optimizaton, we only collect file locks hold by
tasks in the pstree.

Thanks to the ptrace-seize machanism, we can aviod the blocked file lock
issue, makes the work simpler.

Right now, the check handles only one situation:
-- Dumping tasks with file locks hold without the -l option.

This covers for the most part. But we still need some more work to make
it perfect robust in the future.

Signed-off-by: Qiang Huang <h.huangqiang at huawei.com>
---
 Makefile             |    1 +
 cr-dump.c            |   40 +++++++++++++++++++++
 file-lock.c          |   30 ++++++++++++++++
 include/file-lock.h  |   28 +++++++++++++++
 include/proc_parse.h |    1 +
 proc_parse.c         |   95 ++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 195 insertions(+), 0 deletions(-)
 create mode 100644 file-lock.c
 create mode 100644 include/file-lock.h

diff --git a/Makefile b/Makefile
index 6f0d479..a57b713 100644
--- a/Makefile
+++ b/Makefile
@@ -118,6 +118,7 @@ OBJS		+= protobuf.o
 OBJS		+= tty.o
 OBJS		+= cr-exec.o
 OBJS		+= cpu.o
+OBJS		+= file-lock.o
 
 DEPS		:= $(patsubst %.o,%.d,$(OBJS))
 
diff --git a/cr-dump.c b/cr-dump.c
index 00af534..9480fdb 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -29,6 +29,7 @@
 #include "protobuf/mm.pb-c.h"
 #include "protobuf/creds.pb-c.h"
 #include "protobuf/core.pb-c.h"
+#include "protobuf/file-lock.pb-c.h"
 
 #include "types.h"
 #include "list.h"
@@ -63,6 +64,7 @@
 #include "cpu.h"
 #include "fpu.h"
 #include "elf.h"
+#include "file-lock.h"
 
 #ifndef CONFIG_X86_64
 # error No x86-32 support yet
@@ -1348,6 +1350,40 @@ try_again:
 	return ret;
 }
 
+static int collect_file_locks(const struct cr_options *opts)
+{
+	if (parse_file_locks())
+		return -1;
+
+	if (opts->handle_file_locks)
+		/*
+		 * If the handle file locks option is set,
+		 * collect work is over.
+		 */
+		return 0;
+
+	/*
+	 * If the handle file locks option is not set, we need to do
+	 * the check, any file locks hold by tasks in our pstree is
+	 * not allowed.
+	 *
+	 * It's hard to do it carefully, there might be some other
+	 * issues like tasks beyond pstree would use flocks hold by
+	 * dumping tasks, but we can't know it in dumping time.
+	 * We need to make sure these flocks only used by dumping tasks.
+	 * We might have to do the check that this option would only
+	 * be used by container dumping.
+	 */
+	if (!list_empty(&file_lock_list)) {
+		pr_perror("Some file locks are hold by dumping tasks!"
+			  "You can try -l to dump them.");
+		return -1;
+	}
+
+	return 0;
+
+}
+
 static int dump_task_thread(struct parasite_ctl *parasite_ctl, struct pid *tid)
 {
 	CoreEntry *core;
@@ -1703,6 +1739,9 @@ int cr_dump_tasks(pid_t pid, const struct cr_options *opts)
 	if (collect_pstree(pid, opts))
 		goto err;
 
+	if (collect_file_locks(opts))
+		goto err;
+
 	if (mntns_collect_root(root_item->pid.real))
 		goto err;
 
@@ -1765,6 +1804,7 @@ err:
 	pstree_switch_state(root_item,
 			ret ? TASK_ALIVE : opts->final_state);
 	free_pstree(root_item);
+	free_file_locks();
 
 	close_safe(&pidns_proc);
 
diff --git a/file-lock.c b/file-lock.c
new file mode 100644
index 0000000..2760079
--- /dev/null
+++ b/file-lock.c
@@ -0,0 +1,30 @@
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "file-lock.h"
+
+struct list_head file_lock_list = LIST_HEAD_INIT(file_lock_list);
+
+struct file_lock *alloc_file_lock(void)
+{
+	struct file_lock *flock;
+
+	flock = xzalloc(sizeof(*flock));
+	if (!flock)
+		return NULL;
+
+	INIT_LIST_HEAD(&flock->list);
+
+	return flock;
+}
+
+void free_file_locks(void)
+{
+	struct file_lock *flock, *tmp;
+
+	list_for_each_entry_safe(flock, tmp, &file_lock_list, list) {
+		xfree(flock);
+	}
+
+	INIT_LIST_HEAD(&file_lock_list);
+}
diff --git a/include/file-lock.h b/include/file-lock.h
new file mode 100644
index 0000000..9fdaa39
--- /dev/null
+++ b/include/file-lock.h
@@ -0,0 +1,28 @@
+#ifndef __FILE_LOCK_H__
+#define __FILE_LOCK_H__
+
+#include "crtools.h"
+#include "protobuf.h"
+#include "../protobuf/file-lock.pb-c.h"
+
+struct file_lock {
+	long long	fl_id;
+	char		fl_flag[10];
+	char		fl_type[15];
+	char		fl_option[10];
+
+	pid_t		fl_owner;
+	int		maj, min;
+	unsigned long	i_no;
+	long long	start;
+	char		end[32];
+
+	struct list_head list;		/* list of all file locks */
+};
+
+extern struct list_head file_lock_list;
+
+extern struct file_lock *alloc_file_lock(void);
+extern void free_file_locks(void);
+
+#endif /* __FILE_LOCK_H__ */
diff --git a/include/proc_parse.h b/include/proc_parse.h
index df72ef7..9464fea 100644
--- a/include/proc_parse.h
+++ b/include/proc_parse.h
@@ -139,5 +139,6 @@ union fdinfo_entries {
 extern int parse_fdinfo(int fd, int type,
 		int (*cb)(union fdinfo_entries *e, void *arg), void *arg);
 extern int parse_cpuinfo_features(void);
+extern int parse_file_locks(void);
 
 #endif /* __CR_PROC_PARSE_H__ */
diff --git a/proc_parse.c b/proc_parse.c
index a7de1d1..94a12b6 100644
--- a/proc_parse.c
+++ b/proc_parse.c
@@ -15,6 +15,8 @@
 #include "crtools.h"
 #include "mount.h"
 #include "cpu.h"
+#include "file-lock.h"
+#include "pstree.h"
 
 #include "proc_parse.h"
 #include "protobuf.h"
@@ -978,3 +980,96 @@ parse_err:
 	pr_perror("%s: error parsing [%s] for %d\n", __func__, str, type);
 	return -1;
 }
+
+static int parse_file_lock_buf(char *buf, struct file_lock *fl,
+				bool is_blocked)
+{
+	int  num;
+
+	if (is_blocked) {
+		num = sscanf(buf, "%lld: -> %s %s %s %d %02x:%02x:%ld %lld %s",
+			&fl->fl_id, fl->fl_flag, fl->fl_type, fl->fl_option,
+			&fl->fl_owner, &fl->maj, &fl->min, &fl->i_no,
+			&fl->start, fl->end);
+	} else {
+		num = sscanf(buf, "%lld:%s %s %s %d %02x:%02x:%ld %lld %s",
+			&fl->fl_id, fl->fl_flag, fl->fl_type, fl->fl_option,
+			&fl->fl_owner, &fl->maj, &fl->min, &fl->i_no,
+			&fl->start, fl->end);
+	}
+
+	if (num < 10) {
+		pr_perror("Invalid file lock info!");
+		return -1;
+	}
+
+	return 0;
+}
+
+int parse_file_locks(void)
+{
+	struct file_lock *fl;
+
+	FILE	*fl_locks;
+	int	ret = 0;
+	bool	is_blocked = false;
+
+	fl_locks = fopen("/proc/locks", "r");
+	if (!fl_locks) {
+		pr_perror("Can't open file locks file!");
+		return -1;
+	}
+
+	while (fgets(buf, BUF_SIZE, fl_locks)) {
+		if (strstr(buf, "->"))
+			is_blocked = true;
+
+		fl = alloc_file_lock();
+		if (!fl) {
+			pr_perror("Alloc file lock failed!");
+			ret = -1;
+			goto err;
+		}
+
+		if (parse_file_lock_buf(buf, fl, is_blocked)) {
+			xfree(fl);
+			ret = -1;
+			goto err;
+		}
+
+		if (!pid_in_pstree(fl->fl_owner)) {
+			/*
+			 * We only care about tasks which are taken
+			 * into dump, so we only collect file locks
+			 * belong to these tasks.
+			 */
+			xfree(fl);
+			continue;
+		}
+
+		if (is_blocked) {
+			/*
+			 * Here the task is in the pstree.
+			 * If it is blocked on a flock, when we try to
+			 * ptrace-seize it, the kernel will unblock task
+			 * from flock and will stop it in another place.
+			 * So in dumping, a blocked file lock should never
+			 * be here.
+			 */
+			pr_perror("We have a blocked file lock!");
+			ret = -1;
+			goto err;
+		}
+
+		pr_info("lockinfo: %lld:%s %s %s %d %02x:%02x:%ld %lld %s\n",
+			fl->fl_id, fl->fl_flag, fl->fl_type, fl->fl_option,
+			fl->fl_owner, fl->maj, fl->min, fl->i_no,
+			fl->start, fl->end);
+
+		list_add_tail(&fl->list, &file_lock_list);
+	}
+
+err:
+	fclose(fl_locks);
+	return ret;
+}
-- 
1.7.1




More information about the CRIU mailing list