[CRIU] [PATCH v2] rework criu check logic
Adrian Reber
adrian at lisas.de
Fri Mar 11 02:00:20 PST 2016
On Thu, Mar 10, 2016 at 01:01:18PM -0800, Saied Kazemi wrote:
> Pavel and Adrian,
>
> Please take a look at this patch and let me know what you think.
Saied, thanks for looking into this. I like the new check functionality.
Especially that on older kernels I now get no errors/warning for the
minimal functionality check. Another nice change is to be able to check
for a single feature.
> As you will see, I have changed some pr_error() to pr_warn() when calling
> "criu check --extra" because we're saying that the extra features do not
> necessarily cause dump/restore failures. But we can't change all
> pr_error() calls to pr_warn() indiscriminately in the functions that are
> called by "criu check --extra" because some of them are real errors.
In the cases where you replaced pr_error() with pr_warn() you have to
add a '\n' for correct printout. pr_error() adds a '\n'; all other pr_*
seem to not add it.
> Another item of discussion is the exit code. Obviously, if there are no
> errors or warnings the exit code has to be zero. But what if there's a
> warning on an extra or specific feature? Currently, the exit code is
> non-zero but one can argue that for warnings it should still be zero.
Yes, I also had a look at the exit codes and I am also undecided what
should be returned if only warnings have been found. I think your
current implementation does the right thing. Non-zero if a warning was
found. If somebody is looking at the return code of --extra and/or
--experimental I would say it is an explicit check for added
functionality and if it does not exist I would expect a non-zero return
code.
Adrian
> The current patch is a definite improvement (because it was broken) but to
> make it "perfect" will require more time and iterations. It's also very
> difficult to test all permutations.
>
> --Saied
>
>
> On Thu, Mar 10, 2016 at 12:31 PM, Saied Kazemi <saied at google.com> wrote:
>
> > The "criu check" command to check if the kernel is properly configured
> > to run criu is broken.
> >
> > The "criu check --ms" command used to be the way to tell criu to check
> > only for features that have been merged upstream. But recent kernels
> > have a set of features whose presence doesn't necessarily mean that
> > dump or restore will fail but rather *may* fail depending on whether
> > the process tree uses those features.
> >
> > This patch deprecates --ms and introduces --extra, --experimental,
> > and --all. See "criu --help" or "man criu" for more info.
> >
> > Typical use cases are:
> >
> > $ sudo criu check
> > Looks good.
> > $ echo $?
> > 0
> >
> > $ sudo criu check --extra
> > Looks good.
> >
> > $ sudo criu check --extra
> > <one or more warnings...>
> > Looks good but some kernel features are missing
> > which, depending on your process tree, may cause
> > dump or restore failure.
> > $ echo $?
> > 1
> >
> > $ sudo criu check --feature list
> > mnt_id aio_remap timerfd tun userns fdinfo_lock seccomp_suspend \
> > seccomp_filters loginuid cgroupns
> >
> > $ sudo criu check --feature mnt_id
> > Warn (cr-check.c:283): fdinfo doesn't contain the mnt_id field
> > $ echo $?
> > 1
> >
> > $ sudo criu check --feature tun
> > tun is supported
> > $ echo $?
> > 0
> >
> > Signed-off-by: Saied Kazemi <saied at google.com>
> > ---
> > Documentation/criu.txt | 48 ++++++++--
> > criu/cr-check.c | 217
> > ++++++++++++++++++++++++++--------------------
> > criu/cr-service.c | 3 -
> > criu/crtools.c | 40 +++++++--
> > criu/include/cr_options.h | 3 +-
> > criu/timerfd.c | 2 +-
> > 6 files changed, 196 insertions(+), 117 deletions(-)
> >
> > diff --git a/Documentation/criu.txt b/Documentation/criu.txt
> > index e7ba6dd..bd246bf 100644
> > --- a/Documentation/criu.txt
> > +++ b/Documentation/criu.txt
> > @@ -194,7 +194,7 @@ In other words, do not use it until really needed.
> >
> > *-j*, *--shell-job*::
> > Allow one to dump shell jobs. This implies the restored task will
> > inherit session and
> > - process group ID from the criu itself. Also this option allows one to
> > migrate a
> > + process group ID from the *criu* itself. Also this option allows one
> > to migrate a
> > single external tty connection, in other words this option allows one
> > to migrate
> > such application as "top" and friends. If passed on *dump* it must be
> > specified on *restore* as well.
> > @@ -267,7 +267,7 @@ The '<mode>' may be one of below.
> > *--ext-mount-map* *auto*::
> > This is a special case. If this flag is passed, when an external
> > mount is missing from the command line '*--ext-mount-map*
> > <KEY>:<VAL>' syntax,
> > - criu attempts to automatically resolve this mount from its namespace.
> > + *criu* attempts to automatically resolve this mount from its
> > namespace.
> >
> > *--enable-external-sharing*, *--enable-external-masters*::
> > These flags enable external shared or slave mounts to be resolved
> > @@ -278,7 +278,7 @@ The '<mode>' may be one of below.
> >
> > *-j*, *--shell-job*::
> > Restore shell jobs, in other words inherit session and process group
> > - ID from the criu itself.
> > + ID from the *criu* itself.
> >
> > *--cpu-cap* ['<cap>','<cap>']::
> > Specify '<cap>' CPU capability to be present on the CPU the process is
> > @@ -314,15 +314,45 @@ relaxing capability with *--cpu-cap*=*none*
> > parameter.
> >
> > *check*
> > ~~~~~~~
> > -Tests whether the kernel support is up to date.
> > +Checks whether the kernel supports the features that *criu* needs to
> > +successfully dump and restore a process tree.
> >
> > -*--ms*::
> > - Do not check not yet merged features.
> > +There are three categories of kernel support as described below. *criu
> > +check* always checks Category 1 features unless *--feature* is specified
> > +which only checks the specified feature.
> > +
> > +If there are no errors or warnings, *criu* prints "Looks good." and its
> > +exit code is 0. Otherwise, *criu* prints appropriate error and warning
> > +messages and its exit code is non-zero.
> > +
> > +- *Category 1*. Absolutely required. These are features like
> > + '/proc/<pid>/map_files', 'NETLINK_SOCK_DIAG' socket
> > + monitoring, '/proc/sys/kernel/ns_last_pid', etc.
> > +
> > +- *Category 2*. Required only for specific cases. These are features
> > + like aio remap, '/dev/net/tun', etc. that are
> > + required if the process being dumped or restored
> > + is using them.
> > +
> > +- *Category 3*. Experimental. These are features like task-diag that
> > + are used for experimental purposes (mostly
> > + during development).
> > +
> > +Without an argument, *criu check* checks Category 1 features. This
> > behavior
> > +can change with the following options:
> > +
> > +*--extra*::
> > + Check kernel support for Category 2 features.
> > +
> > +*--experimental*::
> > + Check kernel support for Category 3 features.
> > +
> > +*--all*::
> > + Check kernel support for Category 1, 2, and 3 features.
> >
> > *--feature* '<name>'::
> > - Check a particular feature. Instead of checking everything one may
> > specify
> > - which exactly feature is to be tested. The '<name>' may be: *mnt_id*,
> > - *aio_remap*, *timerfd*, *tun*, *userns*.
> > + Check a specific feature. If '<name>' is 'list', a list of valid
> > + kernel feature names that can be checked will be printed.
> >
> > *page-server*
> > ~~~~~~~~~~~~~
> > diff --git a/criu/cr-check.c b/criu/cr-check.c
> > index 2896b02..f3f2021 100644
> > --- a/criu/cr-check.c
> > +++ b/criu/cr-check.c
> > @@ -41,6 +41,8 @@
> > #include "pstree.h"
> > #include "cr_options.h"
> >
> > +static char *feature_name(int (*func)());
> > +
> > static int check_tty(void)
> > {
> > int master = -1, slave = -1;
> > @@ -169,9 +171,8 @@ static int check_kcmp(void)
> > return -1;
> > }
> >
> > -static int check_prctl(void)
> > +static int check_prctl(int pr_set_mm_map)
> > {
> > - unsigned long user_auxv = 0;
> > unsigned int *tid_addr;
> > unsigned int size = 0;
> > int ret;
> > @@ -182,38 +183,13 @@ static int check_prctl(void)
> > return -1;
> > }
> >
> > - /*
> > - * Either new or old interface must be supported in the kernel.
> > - */
> > - ret = prctl(PR_SET_MM, PR_SET_MM_MAP_SIZE, (unsigned long)&size,
> > 0, 0);
> > - if (ret) {
> > - if (!opts.check_ms_kernel) {
> > - pr_msg("prctl: PR_SET_MM_MAP is not supported,
> > which "
> > - "is required for restoring user
> > namespaces\n");
> > - return -1;
> > - } else
> > - pr_warn("Skipping unssuported PR_SET_MM_MAP\n");
> > -
> > - ret = prctl(PR_SET_MM, PR_SET_MM_BRK, brk(0), 0, 0);
> > - if (ret) {
> > - if (ret == -EPERM)
> > - pr_msg("prctl: One needs CAP_SYS_RESOURCE
> > capability to perform testing\n");
> > - else
> > - pr_msg("prctl: PR_SET_MM is not
> > supported\n");
> > - return -1;
> > - }
> > -
> > - ret = prctl(PR_SET_MM, PR_SET_MM_EXE_FILE, -1, 0, 0);
> > - if (ret != -EBADF) {
> > - pr_msg("prctl: PR_SET_MM_EXE_FILE is not supported
> > (%d)\n", ret);
> > - return -1;
> > - }
> > -
> > - ret = prctl(PR_SET_MM, PR_SET_MM_AUXV, (long)&user_auxv,
> > sizeof(user_auxv), 0);
> > - if (ret) {
> > - pr_msg("prctl: PR_SET_MM_AUXV is not supported\n");
> > - return -1;
> > - }
> > + if (pr_set_mm_map) {
> > + /*
> > + * PR_SET_MM_MAP is optional because criu/pie/restorer.c
> > + * has proper fall-back in case this API is not supported.
> > + */
> > + if (prctl(PR_SET_MM, PR_SET_MM_MAP_SIZE, (unsigned
> > long)&size, 0, 0))
> > + pr_warn("prctl: PR_SET_MM_MAP is not supported\n");
> > }
> >
> > return 0;
> > @@ -304,7 +280,7 @@ int check_mnt_id(void)
> > return -1;
> >
> > if (fdinfo.mnt_id == -1) {
> > - pr_err("fdinfo doesn't contain the mnt_id field\n");
> > + pr_warn("fdinfo doesn't contain the mnt_id field\n");
> > return -1;
> > }
> >
> > @@ -626,7 +602,7 @@ static int check_ptrace_suspend_seccomp(void)
> >
> > if (ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_SUSPEND_SECCOMP)
> > < 0) {
> > if (errno == EINVAL) {
> > - pr_err("Kernel doesn't support
> > PTRACE_O_SUSPEND_SECCOMP\n");
> > + pr_warn("Kernel doesn't support
> > PTRACE_O_SUSPEND_SECCOMP\n");
> > } else {
> > pr_perror("couldn't suspend seccomp");
> > }
> > @@ -670,7 +646,7 @@ static int check_ptrace_dump_seccomp_filters(void)
> > len = ptrace(PTRACE_SECCOMP_GET_FILTER, pid, 0, NULL);
> > if (len < 0) {
> > ret = -1;
> > - pr_perror("Dumping seccomp filters not supported");
> > + pr_warn("Dumping seccomp filters not supported");
> > }
> >
> > kill(pid, SIGKILL);
> > @@ -766,11 +742,8 @@ static int check_aio_remap(void)
> > ctx = (aio_context_t)naddr;
> > r = syscall(SYS_io_getevents, ctx, 0, 1, NULL, NULL);
> > if (r < 0) {
> > - if (!opts.check_ms_kernel) {
> > - pr_err("AIO remap doesn't work properly\n");
> > - return -1;
> > - } else
> > - pr_warn("Skipping unsupported AIO remap\n");
> > + pr_warn("AIO remap doesn't work properly\n");
> > + return -1;
> > }
> >
> > return 0;
> > @@ -782,12 +755,8 @@ static int check_fdinfo_lock(void)
> > return -1;
> >
> > if (!kdat.has_fdinfo_lock) {
> > - if (!opts.check_ms_kernel) {
> > - pr_err("fdinfo doesn't contain the lock field\n");
> > - return -1;
> > - } else {
> > - pr_warn("fdinfo doesn't contain the lock field\n");
> > - }
> > + pr_warn("fdinfo doesn't contain the lock field\n");
> > + return -1;
> > }
> >
> > return 0;
> > @@ -823,14 +792,10 @@ static int check_clone_parent_vs_pid()
> > static int check_cgroupns(void)
> > {
> > int ret;
> > - if (opts.check_ms_kernel) {
> > - pr_warn("Skipping cgroup namespaces check\n");
> > - return 0;
> > - }
> >
> > ret = access("/proc/self/ns/cgroup", F_OK);
> > if (ret < 0) {
> > - pr_err("cgroupns not supported. This is not fatal.\n");
> > + pr_warn("cgroupns not supported. This is not fatal.\n");
> > return -1;
> > }
> >
> > @@ -839,6 +804,22 @@ static int check_cgroupns(void)
> >
> > static int (*chk_feature)(void);
> >
> > +/*
> > + * There are three categories of kernel features:
> > + *
> > + * 1. Absolutely required (/proc/pid/map_files, ptrace PEEKSIGINFO, etc.).
> > + * 2. Required only for specific cases (aio remap, tun, etc.).
> > + * Checked when --extra or --all is specified.
> > + * 3. Experimental (task-diag).
> > + * Checked when --experimental or --all is specified.
> > + *
> > + * We fail if any feature in category 1 is missing but tolerate failures
> > + * in the other categories. Currently, there is nothing in category 3.
> > + */
> > +#define GOOD "Looks good."
> > +#define GOOD_BUT "Looks good but some kernel features are
> > missing\n" \
> > + "which, depending on your process tree, may
> > cause\n" \
> > + "dump or restore failure."
> > int cr_check(void)
> > {
> > struct ns_id ns = { .type = NS_CRIU, .ns_pid = PROC_SELF, .nd =
> > &mnt_ns_desc };
> > @@ -863,16 +844,22 @@ int cr_check(void)
> > return -1;
> >
> > if (chk_feature) {
> > - ret = chk_feature();
> > - goto out;
> > + if (chk_feature())
> > + return -1;
> > + print_on_level(DEFAULT_LOGLEVEL, "%s is supported\n",
> > + feature_name(chk_feature));
> > + return 0;
> > }
> >
> > + /*
> > + * Category 1 - absolutely required.
> > + */
> > ret |= check_map_files();
> > ret |= check_sock_diag();
> > ret |= check_ns_last_pid();
> > ret |= check_sock_peek_off();
> > ret |= check_kcmp();
> > - ret |= check_prctl();
> > + ret |= check_prctl(0);
> > ret |= check_fcntl();
> > ret |= check_proc_stat();
> > ret |= check_tcp();
> > @@ -883,22 +870,39 @@ int cr_check(void)
> > ret |= check_ipc();
> > ret |= check_sigqueuinfo();
> > ret |= check_ptrace_peeksiginfo();
> > - ret |= check_ptrace_suspend_seccomp();
> > - ret |= check_ptrace_dump_seccomp_filters();
> > - ret |= check_mem_dirty_track();
> > - ret |= check_posix_timers();
> > - ret |= check_tun_cr(0);
> > - ret |= check_timerfd();
> > - ret |= check_mnt_id();
> > - ret |= check_aio_remap();
> > - ret |= check_fdinfo_lock();
> > - ret |= check_clone_parent_vs_pid();
> > - ret |= check_cgroupns();
> > + if (ret)
> > + return ret;
> >
> > -out:
> > - if (!ret)
> > - print_on_level(DEFAULT_LOGLEVEL, "Looks good.\n");
> > + /*
> > + * Category 2 - required for specific cases.
> > + */
> > + if (opts.check_extra_features) {
> > + ret |= check_prctl(1);
> > + ret |= check_ptrace_suspend_seccomp();
> > + ret |= check_ptrace_dump_seccomp_filters();
> > + ret |= check_mem_dirty_track();
> > + ret |= check_posix_timers();
> > + ret |= check_tun_cr(0);
> > + ret |= check_timerfd();
> > + ret |= check_mnt_id();
> > + ret |= check_aio_remap();
> > + ret |= check_fdinfo_lock();
> > + ret |= check_clone_parent_vs_pid();
> > + ret |= check_cgroupns();
> > + }
> >
> > + /*
> > + * Category 3 - experimental.
> > + */
> > + if (opts.check_experimental_features) {
> > + /*
> > + * Place holder as currently there are no checks.
> > + * Remove this comment when adding checks for
> > + * experimental features.
> > + */
> > + }
> > +
> > + print_on_level(DEFAULT_LOGLEVEL, "%s\n", ret ? GOOD_BUT : GOOD);
> > return ret;
> > }
> >
> > @@ -920,14 +924,14 @@ static int check_userns(void)
> >
> > ret = access("/proc/self/ns/user", F_OK);
> > if (ret) {
> > - pr_perror("No userns proc file");
> > + pr_warn("No userns proc file");
> > return -1;
> > }
> >
> > ret = prctl(PR_SET_MM, PR_SET_MM_MAP_SIZE, (unsigned long)&size,
> > 0, 0);
> > if (ret) {
> > errno = -ret;
> > - pr_perror("No new prctl API");
> > + pr_warn("No new prctl API");
> > return -1;
> > }
> >
> > @@ -947,32 +951,53 @@ static int check_loginuid(void)
> > return 0;
> > }
> >
> > +struct feature_list {
> > + char *name;
> > + int (*func)();
> > +};
> > +
> > +static struct feature_list feature_list[] = {
> > + { "mnt_id", check_mnt_id },
> > + { "aio_remap", check_aio_remap },
> > + { "timerfd", check_timerfd },
> > + { "tun", check_tun },
> > + { "userns", check_userns },
> > + { "fdinfo_lock", check_fdinfo_lock },
> > + { "seccomp_suspend", check_ptrace_suspend_seccomp },
> > + { "seccomp_filters", check_ptrace_dump_seccomp_filters },
> > + { "loginuid", check_loginuid },
> > + { "cgroupns", check_cgroupns },
> > + { NULL, NULL },
> > +};
> > +
> > int check_add_feature(char *feat)
> > {
> > - if (!strcmp(feat, "mnt_id"))
> > - chk_feature = check_mnt_id;
> > - else if (!strcmp(feat, "aio_remap"))
> > - chk_feature = check_aio_remap;
> > - else if (!strcmp(feat, "timerfd"))
> > - chk_feature = check_timerfd;
> > - else if (!strcmp(feat, "tun"))
> > - chk_feature = check_tun;
> > - else if (!strcmp(feat, "userns"))
> > - chk_feature = check_userns;
> > - else if (!strcmp(feat, "fdinfo_lock"))
> > - chk_feature = check_fdinfo_lock;
> > - else if (!strcmp(feat, "seccomp_suspend"))
> > - chk_feature = check_ptrace_suspend_seccomp;
> > - else if (!strcmp(feat, "seccomp_filters"))
> > - chk_feature = check_ptrace_dump_seccomp_filters;
> > - else if (!strcmp(feat, "loginuid"))
> > - chk_feature = check_loginuid;
> > - else if (!strcmp(feat, "cgroupns"))
> > - chk_feature = check_cgroupns;
> > - else {
> > - pr_err("Unknown feature %s\n", feat);
> > - return -1;
> > + struct feature_list *fl;
> > +
> > + if (!strcmp(feat, "list")) {
> > + for (fl = feature_list; fl->name; fl++)
> > + pr_msg("%s ", fl->name);
> > + pr_msg("\n");
> > + return 1;
> > }
> >
> > - return 0;
> > + for (fl = feature_list; fl->name; fl++) {
> > + if (!strcmp(feat, fl->name)) {
> > + chk_feature = fl->func;
> > + return 0;
> > + }
> > + }
> > + pr_err("Unknown feature %s\n", feat);
> > + return -1;
> > +}
> > +
> > +static char *feature_name(int (*func)())
> > +{
> > + struct feature_list *fl;
> > +
> > + for (fl = feature_list; fl->func; fl++) {
> > + if (fl->func == func)
> > + return fl->name;
> > + }
> > + return NULL;
> > }
> > diff --git a/criu/cr-service.c b/criu/cr-service.c
> > index 88d4af7..032c763 100644
> > --- a/criu/cr-service.c
> > +++ b/criu/cr-service.c
> > @@ -567,9 +567,6 @@ static int check(int sk)
> >
> > setproctitle("check --rpc");
> >
> > - /* Check only minimal kernel support */
> > - opts.check_ms_kernel = true;
> > -
> > if (!cr_check())
> > resp.success = true;
> >
> > diff --git a/criu/crtools.c b/criu/crtools.c
> > index d6e8672..db4c2d5 100644
> > --- a/criu/crtools.c
> > +++ b/criu/crtools.c
> > @@ -275,6 +275,9 @@ int main(int argc, char *argv[], char *envp[])
> > { "timeout", required_argument, 0,
> > 1072 },
> > { "external", required_argument, 0,
> > 1073 },
> > { "empty-ns", required_argument, 0,
> > 1074 },
> > + { "extra", no_argument, 0,
> > 1075 },
> > + { "experimental", no_argument, 0,
> > 1076 },
> > + { "all", no_argument, 0,
> > 1077 },
> > { },
> > };
> >
> > @@ -455,8 +458,8 @@ int main(int argc, char *argv[], char *envp[])
> > opts.force_irmap = true;
> > break;
> > case 1054:
> > - opts.check_ms_kernel = true;
> > - break;
> > + pr_err("--ms is deprecated; see \"Check options\"
> > of criu --help\n");
> > + return 1;
> > case 'L':
> > opts.libdir = optarg;
> > break;
> > @@ -490,8 +493,11 @@ int main(int argc, char *argv[], char *envp[])
> > return 1;
> > break;
> > case 1063:
> > - if (check_add_feature(optarg) < 0)
> > + ret = check_add_feature(optarg);
> > + if (ret < 0) /* invalid kernel feature name */
> > return 1;
> > + if (ret > 0) /* list kernel features and exit */
> > + return 0;
> > break;
> > case 1064:
> > if (!add_skip_mount(optarg))
> > @@ -554,6 +560,16 @@ int main(int argc, char *argv[], char *envp[])
> > return 1;
> > }
> > break;
> > + case 1075:
> > + opts.check_extra_features = true;
> > + break;
> > + case 1076:
> > + opts.check_experimental_features = true;
> > + break;
> > + case 1077:
> > + opts.check_extra_features = true;
> > + opts.check_experimental_features = true;
> > + break;
> > case 'V':
> > pr_msg("Version: %s\n", CRIU_VERSION);
> > if (strcmp(CRIU_GITID, "0"))
> > @@ -715,7 +731,7 @@ usage:
> > "Usage:\n"
> > " criu dump|pre-dump -t PID [<options>]\n"
> > " criu restore [<options>]\n"
> > -" criu check [--ms]\n"
> > +" criu check [--feature FEAT]\n"
> > " criu exec -p PID <syscall-string>\n"
> > " criu page-server\n"
> > " criu service [<options>]\n"
> > @@ -808,8 +824,19 @@ usage:
> > " socket[inode]\n"
> > " file[mnt_id:inode]\n"
> > " --empty-ns {net}\n"
> > -" Create a namespace, but don't restore its
> > properies.\n"
> > -" An user will retore them from action scripts.\n"
> > +" Create a namespace, but don't restore its
> > properies.\n"
> > +" An user will retore them from action scripts.\n"
> > +"Check options:\n"
> > +" without any arguments, \"criu check\" checks availability of
> > absolutely required\n"
> > +" kernel features; if any of these features is missing dump and restore
> > will fail\n"
> > +" --extra also check availability of extra kernel
> > features\n"
> > +" --experimental also check availability of experimental kernel
> > features\n"
> > +" --all also check availability of extra and
> > experimental kernel features\n"
> > +" --feature FEAT only check availability of one of the following
> > kernel features\n"
> > +" "
> > + );
> > + check_add_feature("list");
> > + pr_msg(
> > "\n"
> > "* Logging:\n"
> > " -o|--log-file FILE log file name\n"
> > @@ -837,7 +864,6 @@ usage:
> > "Other options:\n"
> > " -h|--help show this text\n"
> > " -V|--version show version\n"
> > -" --ms don't check not yet merged kernel features\n"
> > );
> >
> > return 0;
> > diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h
> > index a6f0b3e..5e1cc21 100644
> > --- a/criu/include/cr_options.h
> > +++ b/criu/include/cr_options.h
> > @@ -56,7 +56,8 @@ struct cr_options {
> > int final_state;
> > char *show_dump_file;
> > char *show_fmt;
> > - bool check_ms_kernel;
> > + bool check_extra_features;
> > + bool check_experimental_features;
> > bool show_pages_content;
> > union {
> > bool restore_detach;
> > diff --git a/criu/timerfd.c b/criu/timerfd.c
> > index 942e5e6..13a6570 100644
> > --- a/criu/timerfd.c
> > +++ b/criu/timerfd.c
> > @@ -52,7 +52,7 @@ int check_timerfd(void)
> > ret = ioctl(fd, TFD_IOC_SET_TICKS, NULL);
> > if (ret < 0) {
> > if (errno != EFAULT)
> > - pr_perror("No timerfd support for c/r");
> > + pr_warn("No timerfd support for c/r");
> > else
> > ret = 0;
> > }
> > --
> > 2.7.0.rc3.207.g0ac5344
> >
> >
More information about the CRIU
mailing list