[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