<div dir="ltr">Thank you both for your feedback. I agree that testing the minimal requirements (category 1) would be a better default action. I was trying to maintain some sort of compatibility with how it worked before. But if that's not an issue, how about the following?<div><br></div><div>1. criu check // category 1 only</div><div>2. criu check --extra // category 2 only</div><div>3. criu check --experimental // category 3 only</div><div>4. criu check --all // all categories</div><div>5. criu check --feature FEAT // specific feature</div><div><br></div><div>--Saied</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Mar 1, 2016 at 2:58 AM, Adrian Reber <span dir="ltr"><<a href="mailto:adrian@lisas.de" target="_blank">adrian@lisas.de</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Tue, Mar 01, 2016 at 12:59:03PM +0300, Pavel Emelyanov wrote:<br>
> On 03/01/2016 01:58 AM, Saied Kazemi wrote:<br>
> > Pavel and Adrian,<br>
> ><br>
> > Had some time this morning and did a quick rework of criu check hopefully without having broken anything. Haven't had time for thorough testing but in the interest of time wanted to send the patch for everyone's comments.<br>
> ><br>
> > With this patch, "criu check --abs" passes on 3.19 but fails on 3.13 due to PR_SET_MM_MAP.<br>
><br>
> I like the patch and have only two suggestions:<br>
><br>
> 1. Isn't it better to make 'criu check' w/o any option to check for minimally<br>
> required set of features? And, the --full (or smth like this) to check for<br>
> all the possible functionality.<br>
<br>
</span>This is also what I would expect. For a new criu user the check command<br>
is a good start to see if criu is usable on his platform. Only checking<br>
for the minimum which is required to run criu would make sense and if<br>
advanced features are needed/desired a more detailed or better check can<br>
be run.<br>
<div class="HOEnZb"><div class="h5"><br>
> 2. The PR_SET_MM_MAP is really optional. The criu/pie/restorer.c has proper<br>
> fall-back in case this API is not supported and there are cases when restore<br>
> w/o this kernel API work. So I suggest to fix the check_prctl to be optional.<br>
><br>
> What do you think?<br>
><br>
> -- Pavel<br>
><br>
> > Look forward to your review and feedback.<br>
> ><br>
> > --Saied<br>
> ><br>
> ><br>
> > On Mon, Feb 29, 2016 at 2:52 PM, Saied Kazemi <<a href="mailto:saied@google.com">saied@google.com</a> <mailto:<a href="mailto:saied@google.com">saied@google.com</a>>> wrote:<br>
> ><br>
> > The "criu check" command to check if the kernel is properly configured<br>
> > to run criu is broken.<br>
> ><br>
> > The "criu check --ms" command used to be the way to tell criu to check<br>
> > only for features that have been merged upstream. But recent kernels<br>
> > have a set of features whose presence doesn't necessarily mean dump will<br>
> > fail but rather *may* fail to dump or restore (e.g., soft dirty tracker,<br>
> > tun support, seccomp).<br>
> ><br>
> > This patch deprecates --ms and introduces --abs for absolutely needed<br>
> > features.<br>
> ><br>
> > Typical use cases are:<br>
> ><br>
> > $ sudo criu check --abs<br>
> > Looks good.<br>
> > $ sudo criu check<br>
> > <zero or more errors...><br>
> > Looks good but some kernel features are missing.<br>
> > $ sudo criu check --feature mnt_id<br>
> > Looks good.<br>
> > $ sudo criu check --feature seccomp_suspend<br>
> > Error (cr-check.c:604): Kernel doesn't support PTRACE_O_SUSPEND_SECCOMP<br>
> > $ sudo criu check --feature list<br>
> > mnt_id aio_remap timerfd tun userns fdinfo_lock seccomp_suspend \<br>
> > seccomp_filters loginuid cgroupns<br>
> ><br>
> > Signed-off-by: Saied Kazemi <<a href="mailto:saied@google.com">saied@google.com</a> <mailto:<a href="mailto:saied@google.com">saied@google.com</a>>><br>
> > ---<br>
> > criu/cr-check.c | 178 +++++++++++++++++++++++-----------------------<br>
> > criu/cr-service.c | 4 +-<br>
> > criu/crtools.c | 28 ++++++--<br>
> > criu/include/cr_options.h | 2 +-<br>
> > 4 files changed, 112 insertions(+), 100 deletions(-)<br>
> ><br>
> > diff --git a/criu/cr-check.c b/criu/cr-check.c<br>
> > index a67ee2d..d08e085 100644<br>
> > --- a/criu/cr-check.c<br>
> > +++ b/criu/cr-check.c<br>
> > @@ -171,7 +171,6 @@ static int check_kcmp(void)<br>
> ><br>
> > static int check_prctl(void)<br>
> > {<br>
> > - unsigned long user_auxv = 0;<br>
> > unsigned int *tid_addr;<br>
> > unsigned int size = 0;<br>
> > int ret;<br>
> > @@ -183,37 +182,13 @@ static int check_prctl(void)<br>
> > }<br>
> ><br>
> > /*<br>
> > - * Either new or old interface must be supported in the kernel.<br>
> > + * The new interface must be supported in the kernel.<br>
> > */<br>
> > ret = prctl(PR_SET_MM, PR_SET_MM_MAP_SIZE, (unsigned long)&size, 0, 0);<br>
> > if (ret) {<br>
> > - if (!opts.check_ms_kernel) {<br>
> > - pr_msg("prctl: PR_SET_MM_MAP is not supported, which "<br>
> > - "is required for restoring user namespaces\n");<br>
> > - return -1;<br>
> > - } else<br>
> > - pr_warn("Skipping unssuported PR_SET_MM_MAP\n");<br>
> > -<br>
> > - ret = prctl(PR_SET_MM, PR_SET_MM_BRK, brk(0), 0, 0);<br>
> > - if (ret) {<br>
> > - if (ret == -EPERM)<br>
> > - pr_msg("prctl: One needs CAP_SYS_RESOURCE capability to perform testing\n");<br>
> > - else<br>
> > - pr_msg("prctl: PR_SET_MM is not supported\n");<br>
> > - return -1;<br>
> > - }<br>
> > -<br>
> > - ret = prctl(PR_SET_MM, PR_SET_MM_EXE_FILE, -1, 0, 0);<br>
> > - if (ret != -EBADF) {<br>
> > - pr_msg("prctl: PR_SET_MM_EXE_FILE is not supported (%d)\n", ret);<br>
> > - return -1;<br>
> > - }<br>
> > -<br>
> > - ret = prctl(PR_SET_MM, PR_SET_MM_AUXV, (long)&user_auxv, sizeof(user_auxv), 0);<br>
> > - if (ret) {<br>
> > - pr_msg("prctl: PR_SET_MM_AUXV is not supported\n");<br>
> > - return -1;<br>
> > - }<br>
> > + pr_msg("prctl: PR_SET_MM_MAP is not supported, which "<br>
> > + "is required for restoring user namespaces\n");<br>
> > + return -1;<br>
> > }<br>
> ><br>
> > return 0;<br>
> > @@ -766,11 +741,8 @@ static int check_aio_remap(void)<br>
> > ctx = (aio_context_t)naddr;<br>
> > r = syscall(SYS_io_getevents, ctx, 0, 1, NULL, NULL);<br>
> > if (r < 0) {<br>
> > - if (!opts.check_ms_kernel) {<br>
> > - pr_err("AIO remap doesn't work properly\n");<br>
> > - return -1;<br>
> > - } else<br>
> > - pr_warn("Skipping unsupported AIO remap\n");<br>
> > + pr_err("AIO remap doesn't work properly\n");<br>
> > + return -1;<br>
> > }<br>
> ><br>
> > return 0;<br>
> > @@ -782,12 +754,8 @@ static int check_fdinfo_lock(void)<br>
> > return -1;<br>
> ><br>
> > if (!kdat.has_fdinfo_lock) {<br>
> > - if (!opts.check_ms_kernel) {<br>
> > - pr_err("fdinfo doesn't contain the lock field\n");<br>
> > - return -1;<br>
> > - } else {<br>
> > - pr_warn("fdinfo doesn't contain the lock field\n");<br>
> > - }<br>
> > + pr_err("fdinfo doesn't contain the lock field\n");<br>
> > + return -1;<br>
> > }<br>
> ><br>
> > return 0;<br>
> > @@ -823,14 +791,10 @@ static int check_clone_parent_vs_pid()<br>
> > static int check_cgroupns(void)<br>
> > {<br>
> > int ret;<br>
> > - if (opts.check_ms_kernel) {<br>
> > - pr_warn("Skipping cgroup namespaces check\n");<br>
> > - return 0;<br>
> > - }<br>
> ><br>
> > ret = access("/proc/self/ns/cgroup", F_OK);<br>
> > if (ret < 0) {<br>
> > - pr_err("cgroupns not supported. This is not fatal.");<br>
> > + pr_err("cgroupns not supported. This is not fatal.\n");<br>
> > return -1;<br>
> > }<br>
> ><br>
> > @@ -839,9 +803,22 @@ static int check_cgroupns(void)<br>
> ><br>
> > static int (*chk_feature)(void);<br>
> ><br>
> > +/*<br>
> > + * There are three categories of kernel features:<br>
> > + *<br>
> > + * 1. Absolutely required (/proc/pid/map_files, ptrace PEEKSIGINFO, etc.)<br>
> > + * 2. Required only for specific cases (aio remap, tun, etc.)<br>
> > + * 3. Experimental (task-diag)<br>
> > + *<br>
> > + * We fail if any feature in category 1 is missing but tolerate failures<br>
> > + * in the other categories. Currently, there is nothing in category 3.<br>
> > + */<br>
> > +#define GOOD "Looks good."<br>
> > +#define GOOD_BUT "Looks good but some kernel features are missing."<br>
> > int cr_check(void)<br>
> > {<br>
> > struct ns_id ns = { .type = NS_CRIU, .ns_pid = PROC_SELF, .nd = &mnt_ns_desc };<br>
> > + int absret = 0;<br>
> > int ret = 0;<br>
> ><br>
> > if (!is_root_user())<br>
> > @@ -863,26 +840,39 @@ int cr_check(void)<br>
> > return -1;<br>
> ><br>
> > if (chk_feature) {<br>
> > - ret = chk_feature();<br>
> > + if (chk_feature())<br>
> > + return -1;<br>
> > goto out;<br>
> > }<br>
> ><br>
> > - ret |= check_map_files();<br>
> > - ret |= check_sock_diag();<br>
> > - ret |= check_ns_last_pid();<br>
> > - ret |= check_sock_peek_off();<br>
> > - ret |= check_kcmp();<br>
> > - ret |= check_prctl();<br>
> > - ret |= check_fcntl();<br>
> > - ret |= check_proc_stat();<br>
> > - ret |= check_tcp();<br>
> > - ret |= check_fdinfo_ext();<br>
> > - ret |= check_unaligned_vmsplice();<br>
> > - ret |= check_tty();<br>
> > - ret |= check_so_gets();<br>
> > - ret |= check_ipc();<br>
> > - ret |= check_sigqueuinfo();<br>
> > - ret |= check_ptrace_peeksiginfo();<br>
> > + /*<br>
> > + * Category 1 - absolutely required.<br>
> > + */<br>
> > + absret |= check_map_files();<br>
> > + absret |= check_sock_diag();<br>
> > + absret |= check_ns_last_pid();<br>
> > + absret |= check_sock_peek_off();<br>
> > + absret |= check_kcmp();<br>
> > + absret |= check_prctl();<br>
> > + absret |= check_fcntl();<br>
> > + absret |= check_proc_stat();<br>
> > + absret |= check_tcp();<br>
> > + absret |= check_fdinfo_ext();<br>
> > + absret |= check_unaligned_vmsplice();<br>
> > + absret |= check_tty();<br>
> > + absret |= check_so_gets();<br>
> > + absret |= check_ipc();<br>
> > + absret |= check_sigqueuinfo();<br>
> > + absret |= check_ptrace_peeksiginfo();<br>
> > + if (absret || opts.check_abs_features) {<br>
> > + if (!absret)<br>
> > + print_on_level(DEFAULT_LOGLEVEL, "%s\n", GOOD);<br>
> > + return absret;<br>
> > + }<br>
> > +<br>
> > + /*<br>
> > + * Category 2 - required for specific cases.<br>
> > + */<br>
> > ret |= check_ptrace_suspend_seccomp();<br>
> > ret |= check_ptrace_dump_seccomp_filters();<br>
> > ret |= check_mem_dirty_track();<br>
> > @@ -896,10 +886,8 @@ int cr_check(void)<br>
> > ret |= check_cgroupns();<br>
> ><br>
> > out:<br>
> > - if (!ret)<br>
> > - print_on_level(DEFAULT_LOGLEVEL, "Looks good.\n");<br>
> > -<br>
> > - return ret;<br>
> > + print_on_level(DEFAULT_LOGLEVEL, "%s\n", ret ? GOOD_BUT : GOOD);<br>
> > + return 0;<br>
> > }<br>
> ><br>
> > static int check_tun(void)<br>
> > @@ -947,32 +935,42 @@ static int check_loginuid(void)<br>
> > return 0;<br>
> > }<br>
> ><br>
> > +struct feature_list {<br>
> > + char *name;<br>
> > + int (*func)();<br>
> > +};<br>
> > +<br>
> > +static struct feature_list feature_list[] = {<br>
> > + { "mnt_id", check_mnt_id },<br>
> > + { "aio_remap", check_aio_remap },<br>
> > + { "timerfd", check_timerfd },<br>
> > + { "tun", check_tun },<br>
> > + { "userns", check_userns },<br>
> > + { "fdinfo_lock", check_fdinfo_lock },<br>
> > + { "seccomp_suspend", check_ptrace_suspend_seccomp },<br>
> > + { "seccomp_filters", check_ptrace_dump_seccomp_filters },<br>
> > + { "loginuid", check_loginuid },<br>
> > + { "cgroupns", check_cgroupns },<br>
> > + { NULL, NULL },<br>
> > +};<br>
> > +<br>
> > int check_add_feature(char *feat)<br>
> > {<br>
> > - if (!strcmp(feat, "mnt_id"))<br>
> > - chk_feature = check_mnt_id;<br>
> > - else if (!strcmp(feat, "aio_remap"))<br>
> > - chk_feature = check_aio_remap;<br>
> > - else if (!strcmp(feat, "timerfd"))<br>
> > - chk_feature = check_timerfd;<br>
> > - else if (!strcmp(feat, "tun"))<br>
> > - chk_feature = check_tun;<br>
> > - else if (!strcmp(feat, "userns"))<br>
> > - chk_feature = check_userns;<br>
> > - else if (!strcmp(feat, "fdinfo_lock"))<br>
> > - chk_feature = check_fdinfo_lock;<br>
> > - else if (!strcmp(feat, "seccomp_suspend"))<br>
> > - chk_feature = check_ptrace_suspend_seccomp;<br>
> > - else if (!strcmp(feat, "seccomp_filters"))<br>
> > - chk_feature = check_ptrace_dump_seccomp_filters;<br>
> > - else if (!strcmp(feat, "loginuid"))<br>
> > - chk_feature = check_loginuid;<br>
> > - else if (!strcmp(feat, "cgroupns"))<br>
> > - chk_feature = check_cgroupns;<br>
> > - else {<br>
> > - pr_err("Unknown feature %s\n", feat);<br>
> > - return -1;<br>
> > + struct feature_list *fl;<br>
> > +<br>
> > + if (!strcmp(feat, "list")) {<br>
> > + for (fl = feature_list; fl->name; fl++)<br>
> > + pr_msg("%s ", fl->name);<br>
> > + pr_msg("\n");<br>
> > + return 1;<br>
> > }<br>
> ><br>
> > - return 0;<br>
> > + for (fl = feature_list; fl->name; fl++) {<br>
> > + if (!strcmp(feat, fl->name)) {<br>
> > + chk_feature = fl->func;<br>
> > + return 0;<br>
> > + }<br>
> > + }<br>
> > + pr_err("Unknown feature %s\n", feat);<br>
> > + return -1;<br>
> > }<br>
> > diff --git a/criu/cr-service.c b/criu/cr-service.c<br>
> > index 88d4af7..a1d843d 100644<br>
> > --- a/criu/cr-service.c<br>
> > +++ b/criu/cr-service.c<br>
> > @@ -567,8 +567,8 @@ static int check(int sk)<br>
> ><br>
> > setproctitle("check --rpc");<br>
> ><br>
> > - /* Check only minimal kernel support */<br>
> > - opts.check_ms_kernel = true;<br>
> > + /* Check only abolutely needed kernel features */<br>
> > + opts.check_abs_features = true;<br>
> ><br>
> > if (!cr_check())<br>
> > resp.success = true;<br>
> > diff --git a/criu/crtools.c b/criu/crtools.c<br>
> > index a8ddb82..2120082 100644<br>
> > --- a/criu/crtools.c<br>
> > +++ b/criu/crtools.c<br>
> > @@ -275,6 +275,7 @@ int main(int argc, char *argv[], char *envp[])<br>
> > { "timeout", required_argument, 0, 1072 },<br>
> > { "external", required_argument, 0, 1073 },<br>
> > { "empty-ns", required_argument, 0, 1074 },<br>
> > + { "abs", no_argument, 0, 1075 },<br>
> > { },<br>
> > };<br>
> ><br>
> > @@ -455,8 +456,8 @@ int main(int argc, char *argv[], char *envp[])<br>
> > opts.force_irmap = true;<br>
> > break;<br>
> > case 1054:<br>
> > - opts.check_ms_kernel = true;<br>
> > - break;<br>
> > + pr_err("--ms is deprecated, use --abs instead\n");<br>
> > + return 1;<br>
> > case 'L':<br>
> > opts.libdir = optarg;<br>
> > break;<br>
> > @@ -490,8 +491,11 @@ int main(int argc, char *argv[], char *envp[])<br>
> > return 1;<br>
> > break;<br>
> > case 1063:<br>
> > - if (check_add_feature(optarg) < 0)<br>
> > + ret = check_add_feature(optarg);<br>
> > + if (ret < 0) /* invalid kernel feature name */<br>
> > return 1;<br>
> > + if (ret > 0) /* list kernel features and exit */<br>
> > + return 0;<br>
> > break;<br>
> > case 1064:<br>
> > if (!add_skip_mount(optarg))<br>
> > @@ -554,6 +558,9 @@ int main(int argc, char *argv[], char *envp[])<br>
> > return 1;<br>
> > }<br>
> > break;<br>
> > + case 1075:<br>
> > + opts.check_abs_features = true;<br>
> > + break;<br>
> > case 'V':<br>
> > pr_msg("Version: %s\n", CRIU_VERSION);<br>
> > if (strcmp(CRIU_GITID, "0"))<br>
> > @@ -714,7 +721,7 @@ usage:<br>
> > "Usage:\n"<br>
> > " criu dump|pre-dump -t PID [<options>]\n"<br>
> > " criu restore [<options>]\n"<br>
> > -" criu check [--ms]\n"<br>
> > +" criu check [--feature FEAT]\n"<br>
> > " criu exec -p PID <syscall-string>\n"<br>
> > " criu page-server\n"<br>
> > " criu service [<options>]\n"<br>
> > @@ -807,8 +814,16 @@ usage:<br>
> > " socket[inode]\n"<br>
> > " file[mnt_id:inode]\n"<br>
> > " --empty-ns {net}\n"<br>
> > -" Create a namespace, but don't restore its properies.\n"<br>
> > -" An user will retore them from action scripts.\n"<br>
> > +" Create a namespace, but don't restore its properies.\n"<br>
> > +" An user will retore them from action scripts.\n"<br>
> > +"Check options:\n"<br>
> > +" --abs check availability of absolutely needed kernel features\n"<br>
> > +" --ms deprecated, use --abs (don't check not yet merged kernel features)\n"<br>
> > +" --feature FEAT check availability of one of the following kernel features\n"<br>
> > +" "<br>
> > + );<br>
> > + check_add_feature("list");<br>
> > + pr_msg(<br>
> > "\n"<br>
> > "* Logging:\n"<br>
> > " -o|--log-file FILE log file name\n"<br>
> > @@ -836,7 +851,6 @@ usage:<br>
> > "Other options:\n"<br>
> > " -h|--help show this text\n"<br>
> > " -V|--version show version\n"<br>
> > -" --ms don't check not yet merged kernel features\n"<br>
> > );<br>
> ><br>
> > return 0;<br>
> > diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h<br>
> > index a6f0b3e..ba2633a 100644<br>
> > --- a/criu/include/cr_options.h<br>
> > +++ b/criu/include/cr_options.h<br>
> > @@ -56,7 +56,7 @@ struct cr_options {<br>
> > int final_state;<br>
> > char *show_dump_file;<br>
> > char *show_fmt;<br>
> > - bool check_ms_kernel;<br>
> > + bool check_abs_features;<br>
> > bool show_pages_content;<br>
> > union {<br>
> > bool restore_detach;<br>
> > --<br>
> > 2.7.0.rc3.207.g0ac5344<br>
> ><br>
> ><br>
</div></div></blockquote></div><br></div>