Commit 286801d4 authored by Qiang Huang's avatar Qiang Huang Committed by Pavel Emelyanov

crtools: collect and check file locks

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: 's avatarQiang Huang <h.huangqiang@huawei.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent b08836cc
...@@ -123,6 +123,7 @@ OBJS += protobuf.o ...@@ -123,6 +123,7 @@ OBJS += protobuf.o
OBJS += tty.o OBJS += tty.o
OBJS += cr-exec.o OBJS += cr-exec.o
OBJS += cpu.o OBJS += cpu.o
OBJS += file-lock.o
OBJS += $(ARCH_DIR)/crtools.o OBJS += $(ARCH_DIR)/crtools.o
DEPS := $(patsubst %.o,%.d,$(OBJS)) DEPS := $(patsubst %.o,%.d,$(OBJS))
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "protobuf/mm.pb-c.h" #include "protobuf/mm.pb-c.h"
#include "protobuf/creds.pb-c.h" #include "protobuf/creds.pb-c.h"
#include "protobuf/core.pb-c.h" #include "protobuf/core.pb-c.h"
#include "protobuf/file-lock.pb-c.h"
#include "protobuf/rlimit.pb-c.h" #include "protobuf/rlimit.pb-c.h"
#include "asm/types.h" #include "asm/types.h"
...@@ -64,6 +65,7 @@ ...@@ -64,6 +65,7 @@
#include "cpu.h" #include "cpu.h"
#include "fpu.h" #include "fpu.h"
#include "elf.h" #include "elf.h"
#include "file-lock.h"
#include "asm/dump.h" #include "asm/dump.h"
...@@ -1204,6 +1206,40 @@ try_again: ...@@ -1204,6 +1206,40 @@ try_again:
return ret; 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) static int dump_task_thread(struct parasite_ctl *parasite_ctl, struct pid *tid)
{ {
CoreEntry *core; CoreEntry *core;
...@@ -1568,6 +1604,9 @@ int cr_dump_tasks(pid_t pid, const struct cr_options *opts) ...@@ -1568,6 +1604,9 @@ int cr_dump_tasks(pid_t pid, const struct cr_options *opts)
if (collect_pstree(pid, opts)) if (collect_pstree(pid, opts))
goto err; goto err;
if (collect_file_locks(opts))
goto err;
if (collect_mount_info()) if (collect_mount_info())
goto err; goto err;
...@@ -1633,6 +1672,7 @@ err: ...@@ -1633,6 +1672,7 @@ err:
pstree_switch_state(root_item, pstree_switch_state(root_item,
ret ? TASK_ALIVE : opts->final_state); ret ? TASK_ALIVE : opts->final_state);
free_pstree(root_item); free_pstree(root_item);
free_file_locks();
close_safe(&pidns_proc); close_safe(&pidns_proc);
......
#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);
}
#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__ */
...@@ -140,5 +140,6 @@ union fdinfo_entries { ...@@ -140,5 +140,6 @@ union fdinfo_entries {
extern int parse_fdinfo(int fd, int type, extern int parse_fdinfo(int fd, int type,
int (*cb)(union fdinfo_entries *e, void *arg), void *arg); int (*cb)(union fdinfo_entries *e, void *arg), void *arg);
extern int parse_cpuinfo_features(void); extern int parse_cpuinfo_features(void);
extern int parse_file_locks(void);
#endif /* __CR_PROC_PARSE_H__ */ #endif /* __CR_PROC_PARSE_H__ */
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include "crtools.h" #include "crtools.h"
#include "mount.h" #include "mount.h"
#include "cpu.h" #include "cpu.h"
#include "file-lock.h"
#include "pstree.h"
#include "fsnotify.h" #include "fsnotify.h"
#include "proc_parse.h" #include "proc_parse.h"
...@@ -1063,3 +1065,96 @@ parse_err: ...@@ -1063,3 +1065,96 @@ parse_err:
pr_perror("%s: error parsing [%s] for %d\n", __func__, str, type); pr_perror("%s: error parsing [%s] for %d\n", __func__, str, type);
return -1; 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment