<div dir="auto"><div>This patch doesn't help. I run criu with the -o option, it's a short form of --log-file. I tried to run with --log-file and it's segfaulted too.</div><div dir="auto"><br><div class="gmail_quote" dir="auto"><div dir="ltr" class="gmail_attr">On Sat, Aug 31, 2019, 12:45 PM Anastasia Markina <<a href="mailto:asyamarkina2@gmail.com">asyamarkina2@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div dir="auto">I'm really sorry, I've just found a bug in my criu patch: the crash takes place if log filename is not set via commandline options. The fix is trivial, "flog_ctx.readonly=1; /* don't try to write into it */" inserted into the criu/log.c, line 245, fixes it. It turns flog off if there is no log file name. I checked other cases, but not this one...</div><div dir="auto"><br></div><div dir="auto">If you run criu with —log-file ... parameter, this bug is not activated.</div><div dir="auto"><br></div><div dir="auto">I've updated it in <a href="https://github.com/anastasiamarkina/criu/tree/nastya-flog2" target="_blank" rel="noreferrer">https://github.com/anastasiamarkina/criu/tree/nastya-flog2</a>, and I will be happy to follow with any updates needed. Should I make updated patch into the mailing list?</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">пт, 30 авг. 2019 г., 12:13 Andrei Vagin <<a href="mailto:avagin@gmail.com" target="_blank" rel="noreferrer">avagin@gmail.com</a>>:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Mon, Aug 26, 2019 at 05:49:24PM +0300, Anastasia Markina wrote:<br>
> Hello! I've finalized my work for the GSoC project as a patch, attached to<br>
> this message. As before, it is also available in my github repo,<br>
> <a href="https://github.com/anastasiamarkina/criu/tree/nastya-flog2" rel="noreferrer noreferrer noreferrer" target="_blank">https://github.com/anastasiamarkina/criu/tree/nastya-flog2</a><br>
> <br>
> The next part is a fragment of binlog.txt file included into the patch,<br>
> which explains how to use it:<br>
> <br>
> USAGE: TURNING ON BINARY LOGGING<br>
> <br>
> Classical text logging is done by default.<br>
> Binary logging is turned on by the --binlog command line parameter.<br>
> It should be combined with --log-file filename parameter to specify the log<br>
> file name (this second parameter is used with both text and binary logging).<br>
> <br>
> The example:<br>
> <br>
> criu --log-file /tmp/sdf.bin --binlog check<br>
> <br>
> USAGE: READING BINARY LOG FILE<br>
> <br>
> There is a --print-log parameter which turnes criy into a log reader.<br>
> It should be combined with --log-file filename parameter, which specifies<br>
> the log file name. When these parameters are used, CRIU prints all messages<br>
> from the binary log file on the screen and exits. This looks as follows:<br>
> <br>
> criu --log-file /tmp/sdf.bin --binlog --print-log<br>
<br>
On my laptop, criu segfaulted with binlog:<br>
<br>
$ ./criu/criu check --binlog -o /tmp/test.log<br>
Segmentation fault (core dumped)<br>
<br>
(gdb) bt<br>
#0 0x00007fb629e45120 in __memchr_avx2 () from /lib64/libc.so.6<br>
#1 0x00007fb629d77d4f in memccpy () from /lib64/libc.so.6<br>
#2 0x00000000004c754c in flog_encode_msg (ctx=0x676ca0 <flog_ctx>,<br>
nargs=nargs@entry=7, mask=mask@entry=65, <br>
format=format@entry=0x534888 "\t%s: ino %d peer_ino %d family %4d<br>
type %4d state %2d name %s\n") at flog/src/flog.c:202<br>
#3 0x00000000004a7b62 in show_one_unix (act=act@entry=0x510c69<br>
"Collected", sk=sk@entry=0xf7ab90) at criu/sk-unix.c:133<br>
#4 0x00000000004ac664 in unix_collect_one (ns=0x7ffe4151e830,<br>
tb=0x7ffe4151e660, m=0x56b490 <buf+1968>) at criu/sk-unix.c:764<br>
#5 unix_receive_one (h=h@entry=0x56b480 <buf+1952>,<br>
ns=ns@entry=0x7ffe4151e830, arg=arg@entry=0x7ffe4151e7c0) at<br>
criu/sk-unix.c:783<br>
#6 0x000000000046bc4f in nlmsg_receive (buf=<optimized out>,<br>
arg=<optimized out>, ns=<optimized out>, err_cb=<optimized out>,<br>
cb=<optimized out>, len=<optimized out>)<br>
at criu/libnetlink.c:41<br>
#7 do_rtnl_req (nl=nl@entry=7, req=req@entry=0x7ffe4151e7b0,<br>
size=size@entry=72, receive_callback=0x4ac3e0 <unix_receive_one>,<br>
error_callback=error_callback@entry=0x4ad810 <collect_err>, <br>
ns=ns@entry=0x7ffe4151e830, arg=0x7ffe4151e7c0) at<br>
criu/libnetlink.c:120<br>
#8 0x00000000004af6dc in do_collect_req (arg=0x7ffe4151e7c0,<br>
ns=<optimized out>, error_callback=0x4ad810 <collect_err>,<br>
receive_callback=<optimized out>, size=72, req=0x7ffe4151e7b0, nl=7)<br>
at criu/sockets.c:817<br>
#9 collect_sockets (ns=ns@entry=0x7ffe4151e830) at criu/sockets.c:817<br>
#10 0x000000000043d3fd in check_sock_diag () at criu/cr-check.c:127<br>
#11 0x000000000043f29c in cr_check () at criu/cr-check.c:1331<br>
#12 0x0000000000424b37 in main (argc=<optimized out>,<br>
argv=0x7ffe4151eba8, envp=<optimized out>) at criu/crtools.c:257<br>
<br>
Have you tried to run zdtm tests with this binary logging?<br>
<br>
How do you handle log messages from parasite and restorer?<br>
<br>
Did you run any perfomance tests to compare the text and bin logging<br>
engines?<br>
<br>
> <br>
> P.S. Thank you for the possibility to work with the project!<br>
<br>
> From 515a0edf4ffdbfc173e237553e29eae993e8aab6 Mon Sep 17 00:00:00 2001<br>
> From: Anastasia Markina <<a href="mailto:asyamarkina2@gmail.com" rel="noreferrer noreferrer" target="_blank">asyamarkina2@gmail.com</a>><br>
> Date: Thu, 25 Jul 2019 15:51:04 +0300<br>
> Subject: [PATCH] criu binary logging based on slightly modified flog engine<br>
> merging flog code into criu and making the first working version with binlog<br>
> log file name is specified after the --log-file key as usual; added --binlog<br>
> option to save binary log instead of text; added --print-log option to print<br>
> messages from binary log file and exit added documentation about binlog<br>
><br>
<br>
SOB is required.<br>
<a href="https://criu.org/How_to_submit_patches" rel="noreferrer noreferrer noreferrer" target="_blank">https://criu.org/How_to_submit_patches</a><br>
<br>
> ---<br>
> Documentation/binlog.txt | 52 +++++++++<br>
> Makefile | 13 +++<br>
> criu/Makefile | 1 +<br>
> criu/Makefile.packages | 2 +-<br>
> criu/config.c | 2 +<br>
> criu/crtools.c | 111 ++++++++++++-------<br>
> criu/include/cr_options.h | 2 +<br>
> criu/include/criu-log.h | 1 +<br>
> criu/include/log.h | 36 +++++-<br>
> criu/log.c | 40 +++++--<br>
> flog/Makefile | 8 ++<br>
> flog/include/flog.h | 9 ++<br>
> flog/include/uapi/flog.h | 168 ++++++++++++++++++++++++++++<br>
> flog/src/flog.c | 227 ++++++++++++++++++++++++++++++++++++++<br>
<br>
This patch has to be splitted on five patches or maybe even more:<br>
1. Merge flog<br>
2. Makefile changes<br>
3. Introduce the binlog option<br>
4. Integrate flog with CRIU<br>
5. Documentations<br>
<br>
In addition, we need to add a test for this binary logging.<br>
<br>
> 14 files changed, 620 insertions(+), 52 deletions(-)<br>
> create mode 100644 Documentation/binlog.txt<br>
> create mode 100644 flog/Makefile<br>
> create mode 100644 flog/include/flog.h<br>
> create mode 100644 flog/include/uapi/flog.h<br>
> create mode 100644 flog/src/flog.c<br>
> <br>
> diff --git a/Documentation/binlog.txt b/Documentation/binlog.txt<br>
> new file mode 100644<br>
> index 00000000..1a5c80c1<br>
> --- /dev/null<br>
> +++ b/Documentation/binlog.txt<br>
> @@ -0,0 +1,52 @@<br>
> +CRIU binary logging<br>
> +===================<br>
> +<br>
> +Usage: turning on binary logging<br>
> +--------------------------------<br>
> +<br>
> +Classical text logging is done by default.<br>
> +Binary logging is turned on by the `--binlog` command line parameter.<br>
> +It should be combined with `--log-file filename` parameter to specify<br>
> +the log file name (this second parameter is used with both text and binary logging).<br>
> +<br>
> +The example:<br>
> +<br>
> +`criu --log-file /tmp/sdf.bin --binlog check`<br>
> +<br>
> +Usage: reading binary log file<br>
> +------------------------------<br>
> +<br>
> +There is a `--print-log` parameter which turnes criy into a log reader.<br>
> +It should be combined with `--log-file filename` parameter, which specifies<br>
> +the log file name. When these parameters are used, CRIU prints all messages<br>
> +from the binary log file on the screen and exits. This looks as follows:<br>
> +<br>
> +`criu --log-file /tmp/sdf.bin --binlog --print-log`<br>
> +<br>
> +Binary log file format<br>
> +----------------------<br>
> +<br>
> +Text logging in CRIU is based on the printf functions family, with format string<br>
> +followed by arguments. To make logging in binary form faster, CRIU just stores<br>
> +format string and arguments in binary log without parsing. When binary log file<br>
> +is read with `--print-log` parameter, these data are taken from the binary log<br>
> +records and passed to a printf function.<br>
> +<br>
> +Binary log file format is highly inspired by the [flog experimental project](<a href="https://github.com/cyrillos/flog" rel="noreferrer noreferrer noreferrer" target="_blank">https://github.com/cyrillos/flog</a>).<br>
> +Each log message is stored as a format string aned a variable number of<br>
> +arguments. The variable size record has following structure:<br>
> +<br>
> +<br>
> +| field | datatype | explanation |<br>
> +|---------|--------------|---------------------------------|<br>
> +| magic | unsigned int | magic code, equal to `0x676f6c66` |<br>
> +| version | unsigned int | binlog file version, equal to `1` |<br>
> +| size | unsigned int | actual size of the record (is needed because of variable arguments|<br>
> +| nargs | unsigned int | number of arguments |<br>
> +| mask | unsigned int | mask, which encodes the argument type, e.g. long integer or string|<br>
> +| fmt | long | offset to the format string, starting from the beginning of the record|<br>
> +| args[0] | long | 1st argument: the value, if it is a number, or the offset to the string, starting from the beginning of the record |<br>
> +| ..... | | |<br>
> +| args[nargs-1] | long | last argument: the value, if it is a number, or the offset to the string, starting from the beginning of the record |<br>
> +| ..... | | format string and all other strings passed as arguments, if any |<br>
> +<br>
> diff --git a/Makefile b/Makefile<br>
> index 0140330e..c2091a88 100644<br>
> --- a/Makefile<br>
> +++ b/Makefile<br>
> @@ -127,6 +127,8 @@ ifeq ($(GMON),1)<br>
> export GMON GMONLDOPT<br>
> endif<br>
> <br>
> +CFLAGS += -iquote flog/include/ -iquote flog/include/uapi<br>
> +<br>
> AFLAGS += -D__ASSEMBLY__<br>
> CFLAGS += $(USERCFLAGS) $(WARNINGS) $(DEFINES) -iquote include/<br>
> HOSTCFLAGS += $(WARNINGS) $(DEFINES) -iquote include/<br>
> @@ -218,6 +220,17 @@ soccr/built-in.o: $(CONFIG_HEADER) .FORCE<br>
> $(SOCCR_A): |soccr/built-in.o<br>
> criu-deps += $(SOCCR_A)<br>
> <br>
> +#<br>
> +# Fast logging library<br>
> +FLOG_A := flog/libflog.a<br>
> +flog/Makefile: ;<br>
> +flog/%: $(CONFIG_HEADER) .FORCE<br>
> + $(Q) $(MAKE) $(build)=flog $@<br>
> +flog/built-in.o: $(CONFIG_HEADER) .FORCE<br>
> + $(Q) $(MAKE) $(build)=flog all<br>
> +$(FLOG_A): | flog/built-in.o<br>
> +criu-deps += $(FLOG_A)<br>
> +<br>
> #<br>
> # CRIU building done in own directory<br>
> # with slightly different rules so we<br>
> diff --git a/criu/Makefile b/criu/Makefile<br>
> index 4134e505..ee0aa291 100644<br>
> --- a/criu/Makefile<br>
> +++ b/criu/Makefile<br>
> @@ -70,6 +70,7 @@ PROGRAM-BUILTINS += images/built-in.o<br>
> PROGRAM-BUILTINS += $(obj)/built-in.o<br>
> PROGRAM-BUILTINS += $(ARCH-LIB)<br>
> PROGRAM-BUILTINS += soccr/libsoccr.a<br>
> +PROGRAM-BUILTINS += flog/libflog.a<br>
> PROGRAM-BUILTINS += $(COMPEL_LIBS)<br>
> <br>
> $(obj)/built-in.o: pie<br>
> diff --git a/criu/Makefile.packages b/criu/Makefile.packages<br>
> index f380fa2f..65111f9c 100644<br>
> --- a/criu/Makefile.packages<br>
> +++ b/criu/Makefile.packages<br>
> @@ -32,7 +32,7 @@ REQ-DEB-PKG-NAMES += python-future<br>
> REQ-RPM-PKG-TEST-NAMES += $(PYTHON)-pyyaml<br>
> endif<br>
> <br>
> -export LIBS += -lprotobuf-c -ldl -lnl-3 -lsoccr -Lsoccr/ -lnet<br>
> +export LIBS += -lprotobuf-c -ldl -lnl-3 -lsoccr -Lsoccr/ -lnet -lffi<br>
> <br>
> check-packages-failed:<br>
> $(warning Can not find some of the required libraries)<br>
> diff --git a/criu/config.c b/criu/config.c<br>
> index 3a54afd4..7d79c638 100644<br>
> --- a/criu/config.c<br>
> +++ b/criu/config.c<br>
> @@ -458,6 +458,8 @@ int parse_options(int argc, char **argv, bool *usage_error,<br>
> BOOL_OPT(SK_EST_PARAM, &opts.tcp_established_ok),<br>
> { "close", required_argument, 0, 1043 },<br>
> BOOL_OPT("log-pid", &opts.log_file_per_pid),<br>
> + BOOL_OPT("binlog", &opts.binlog),<br>
> + BOOL_OPT("print-log", &opts.printlog),<br>
> { "version", no_argument, 0, 'V' },<br>
> BOOL_OPT("evasive-devices", &opts.evasive_devices),<br>
> { "pidfile", required_argument, 0, 1046 },<br>
> diff --git a/criu/crtools.c b/criu/crtools.c<br>
> index 97a6d6d6..010d8d11 100644<br>
> --- a/criu/crtools.c<br>
> +++ b/criu/crtools.c<br>
> @@ -48,6 +48,14 @@<br>
> #include "sysctl.h"<br>
> #include "img-remote.h"<br>
> <br>
> +flog_ctx_t flog_ctx;<br>
> +<br>
> +<br>
> +int criu_quit(int ret_val) {<br>
> + log_fini(); <br>
> + exit(ret_val);<br>
> +}<br>
> +<br>
> int main(int argc, char *argv[], char *envp[])<br>
> {<br>
> int ret = -1;<br>
> @@ -55,7 +63,14 @@ int main(int argc, char *argv[], char *envp[])<br>
> bool has_exec_cmd = false;<br>
> bool has_sub_command;<br>
> int state = PARSING_GLOBAL_CONF;<br>
> + <br>
> + flog_ctx.readonly=1; <br>
> + /* It is not known yet if we will have binlog, but let's not try to <br>
> + * write into it for safety reasons <br>
> + */<br>
> + <br>
> <br>
> + /* FIXME: where to put flog_fini? */<br>
> BUILD_BUG_ON(CTL_32 != SYSCTL_TYPE__CTL_32);<br>
> BUILD_BUG_ON(__CTL_STR != SYSCTL_TYPE__CTL_STR);<br>
> /* We use it for fd overlap handling in clone_service_fd() */<br>
> @@ -67,20 +82,34 @@ int main(int argc, char *argv[], char *envp[])<br>
> <br>
> cr_pb_init();<br>
> setproctitle_init(argc, argv, envp);<br>
> -<br>
> - if (argc < 2)<br>
> + <br>
> + if (argc < 2) {<br>
> goto usage;<br>
> -<br>
> + }<br>
> + <br>
> init_opts();<br>
> <br>
> -<br>
> ret = parse_options(argc, argv, &usage_error, &has_exec_cmd, state);<br>
> <br>
> + if (opts.printlog) {<br>
> + <br>
> + if (log_init(opts.output))<br>
> + return 1; <br>
> + /* print and exit */<br>
> + printf("--- printing log from %s file ---\n", opts.output);<br>
> + struct stat st; <br>
> + stat(opts.output, &st); <br>
> + if(st.st_size) <br>
> + flog_decode_all(&flog_ctx, STDOUT_FILENO);<br>
> + printf("--- end of the log ---\n");<br>
> + criu_quit(0);<br>
> + }<br>
> + <br>
> if (ret == 1)<br>
> - return 1;<br>
> + return 1; <br>
> if (ret == 2)<br>
> - goto usage;<br>
> -<br>
> + goto usage; <br>
> + <br>
> log_set_loglevel(opts.log_level);<br>
> <br>
> if (!strcmp(argv[1], "swrk")) {<br>
> @@ -98,6 +127,7 @@ int main(int argc, char *argv[], char *envp[])<br>
> <br>
> if (check_options()) {<br>
> flush_early_log_buffer(STDERR_FILENO);<br>
> + flog_fini(&flog_ctx);<br>
> return 1;<br>
> }<br>
> <br>
> @@ -106,7 +136,7 @@ int main(int argc, char *argv[], char *envp[])<br>
> <br>
> if (opts.work_dir == NULL)<br>
> SET_CHAR_OPTS(work_dir, opts.imgs_dir);<br>
> -<br>
> + <br>
> if (optind >= argc) {<br>
> pr_msg("Error: command is required\n");<br>
> goto usage;<br>
> @@ -131,8 +161,8 @@ int main(int argc, char *argv[], char *envp[])<br>
> }<br>
> <br>
> opts.exec_cmd = xmalloc((argc - optind) * sizeof(char *));<br>
> - if (!opts.exec_cmd)<br>
> - return 1;<br>
> + if (!opts.exec_cmd) <br>
> + criu_quit(1);<br>
> memcpy(opts.exec_cmd, &argv[optind + 1], (argc - optind - 1) * sizeof(char *));<br>
> opts.exec_cmd[argc - optind - 1] = NULL;<br>
> } else {<br>
> @@ -148,7 +178,7 @@ int main(int argc, char *argv[], char *envp[])<br>
> if (strcmp(argv[optind], "service")) {<br>
> ret = open_image_dir(opts.imgs_dir);<br>
> if (ret < 0)<br>
> - return 1;<br>
> + criu_quit(1);<br>
> }<br>
> <br>
> /*<br>
> @@ -163,14 +193,14 @@ int main(int argc, char *argv[], char *envp[])<br>
> <br>
> if (chdir(opts.work_dir)) {<br>
> pr_perror("Can't change directory to %s", opts.work_dir);<br>
> - return 1;<br>
> + criu_quit(1);<br>
> }<br>
> <br>
> if (log_init(opts.output))<br>
> - return 1;<br>
> -<br>
> + return 1; <br>
> + <br>
> if (kerndat_init())<br>
> - return 1;<br>
> + criu_quit(1);<br>
> <br>
> if (opts.deprecated_ok)<br>
> pr_debug("DEPRECATED ON\n");<br>
> @@ -178,7 +208,7 @@ int main(int argc, char *argv[], char *envp[])<br>
> if (!list_empty(&opts.inherit_fds)) {<br>
> if (strcmp(argv[optind], "restore")) {<br>
> pr_err("--inherit-fd is restore-only option\n");<br>
> - return 1;<br>
> + criu_quit(1);<br>
> }<br>
> /* now that log file is set up, print inherit fd list */<br>
> inherit_fd_log();<br>
> @@ -190,7 +220,7 @@ int main(int argc, char *argv[], char *envp[])<br>
> if (!strcmp(argv[optind], "dump")) {<br>
> if (!opts.tree_id)<br>
> goto opt_pid_missing;<br>
> - return cr_dump_tasks(opts.tree_id);<br>
> + criu_quit(cr_dump_tasks(opts.tree_id));<br>
> }<br>
> <br>
> if (!strcmp(argv[optind], "pre-dump")) {<br>
> @@ -199,10 +229,10 @@ int main(int argc, char *argv[], char *envp[])<br>
> <br>
> if (opts.lazy_pages) {<br>
> pr_err("Cannot pre-dump with --lazy-pages\n");<br>
> - return 1;<br>
> + criu_quit(1);<br>
> }<br>
> <br>
> - return cr_pre_dump_tasks(opts.tree_id) != 0;<br>
> + criu_quit(cr_pre_dump_tasks(opts.tree_id) != 0);<br>
> }<br>
> <br>
> if (!strcmp(argv[optind], "restore")) {<br>
> @@ -217,39 +247,41 @@ int main(int argc, char *argv[], char *envp[])<br>
> ret = 1;<br>
> }<br>
> <br>
> - return ret != 0;<br>
> + criu_quit(ret != 0);<br>
> }<br>
> <br>
> if (!strcmp(argv[optind], "lazy-pages"))<br>
> - return cr_lazy_pages(opts.daemon_mode) != 0;<br>
> + criu_quit(cr_lazy_pages(opts.daemon_mode) != 0);<br>
> <br>
> - if (!strcmp(argv[optind], "check"))<br>
> - return cr_check() != 0;<br>
> + if (!strcmp(argv[optind], "check")) {<br>
> + ret = cr_check(); <br>
> + criu_quit(ret != 0);<br>
> + }<br>
> <br>
> if (!strcmp(argv[optind], "page-server"))<br>
> - return cr_page_server(opts.daemon_mode, false, -1) != 0;<br>
> + criu_quit(cr_page_server(opts.daemon_mode, false, -1) != 0);<br>
> <br>
> if (!strcmp(argv[optind], "image-cache")) {<br>
> if (!opts.port)<br>
> goto opt_port_missing;<br>
> - return image_cache(opts.daemon_mode, DEFAULT_CACHE_SOCKET);<br>
> + criu_quit(image_cache(opts.daemon_mode, DEFAULT_CACHE_SOCKET));<br>
> }<br>
> <br>
> if (!strcmp(argv[optind], "image-proxy")) {<br>
> if (!opts.addr) {<br>
> pr_msg("Error: address not specified\n");<br>
> - return 1;<br>
> + criu_quit(1);<br>
> }<br>
> if (!opts.port)<br>
> goto opt_port_missing;<br>
> - return image_proxy(opts.daemon_mode, DEFAULT_PROXY_SOCKET);<br>
> + criu_quit(image_proxy(opts.daemon_mode, DEFAULT_PROXY_SOCKET));<br>
> }<br>
> <br>
> if (!strcmp(argv[optind], "service"))<br>
> - return cr_service(opts.daemon_mode);<br>
> + criu_quit(cr_service(opts.daemon_mode));<br>
> <br>
> if (!strcmp(argv[optind], "dedup"))<br>
> - return cr_dedup() != 0;<br>
> + criu_quit(cr_dedup() != 0);<br>
> <br>
> if (!strcmp(argv[optind], "cpuinfo")) {<br>
> if (!argv[optind + 1]) {<br>
> @@ -259,22 +291,23 @@ int main(int argc, char *argv[], char *envp[])<br>
> if (!strcmp(argv[optind + 1], "dump"))<br>
> return cpuinfo_dump();<br>
> else if (!strcmp(argv[optind + 1], "check"))<br>
> - return cpuinfo_check();<br>
> + criu_quit(cpuinfo_check());<br>
> }<br>
> <br>
> if (!strcmp(argv[optind], "exec")) {<br>
> pr_msg("The \"exec\" action is deprecated by the Compel library.\n");<br>
> - return -1;<br>
> + criu_quit(-1);<br>
> }<br>
> <br>
> if (!strcmp(argv[optind], "show")) {<br>
> pr_msg("The \"show\" action is deprecated by the CRIT utility.\n");<br>
> pr_msg("To view an image use the \"crit decode -i $name --pretty\" command.\n");<br>
> - return -1;<br>
> + criu_quit(-1);<br>
> }<br>
> -<br>
> + <br>
> pr_msg("Error: unknown command: %s\n", argv[optind]);<br>
> usage:<br>
> + printf("usage\n");<br>
> pr_msg("\n"<br>
> "Usage:\n"<br>
> " criu dump|pre-dump -t PID [<options>]\n"<br>
> @@ -302,8 +335,8 @@ usage:<br>
> );<br>
> <br>
> if (usage_error) {<br>
> - pr_msg("\nTry -h|--help for more info\n");<br>
> - return 1;<br>
> + pr_msg("\nTry -h|--help for more info\n"); <br>
> + criu_quit(1);<br>
> }<br>
> <br>
> pr_msg("\n"<br>
> @@ -425,7 +458,9 @@ usage:<br>
> "\n"<br>
> "* Logging:\n"<br>
> " -o|--log-file FILE log file name\n"<br>
> +" --binlog use faster binary log instead of slower text log\n"<br>
> " --log-pid enable per-process logging to separate FILE.pid files\n"<br>
> +" --print-log print log from the binlog file and exit\n"<br>
> " -v[v...]|--verbosity increase verbosity (can use multiple v)\n"<br>
> " -vNUM|--verbosity=NUM set verbosity to NUM (higher level means more output):\n"<br>
> " -v1 - only errors and messages\n"<br>
> @@ -466,13 +501,13 @@ usage:<br>
> " -V|--version show version\n"<br>
> );<br>
> <br>
> - return 0;<br>
> + criu_quit(0);<br>
> <br>
> opt_port_missing:<br>
> pr_msg("Error: port not specified\n");<br>
> - return 1;<br>
> + criu_quit(1);<br>
> <br>
> opt_pid_missing:<br>
> pr_msg("Error: pid not specified\n");<br>
> - return 1;<br>
> + criu_quit(1);<br>
> }<br>
> diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h<br>
> index c519c740..a79bdebc 100644<br>
> --- a/criu/include/cr_options.h<br>
> +++ b/criu/include/cr_options.h<br>
> @@ -81,6 +81,8 @@ struct cr_options {<br>
> int evasive_devices;<br>
> int link_remap_ok;<br>
> int log_file_per_pid;<br>
> + int binlog;<br>
> + int printlog;<br>
> bool swrk_restore;<br>
> char *output;<br>
> char *root;<br>
> diff --git a/criu/include/criu-log.h b/criu/include/criu-log.h<br>
> index 21ef5430..57792a44 100644<br>
> --- a/criu/include/criu-log.h<br>
> +++ b/criu/include/criu-log.h<br>
> @@ -25,6 +25,7 @@<br>
> struct timeval;<br>
> <br>
> extern int log_init(const char *output);<br>
> +<br>
> extern void log_fini(void);<br>
> extern int log_init_by_pid(pid_t pid);<br>
> extern void log_closedir(void);<br>
> diff --git a/criu/include/log.h b/criu/include/log.h<br>
> index 15787b09..08c57381 100644<br>
> --- a/criu/include/log.h<br>
> +++ b/criu/include/log.h<br>
> @@ -9,6 +9,11 @@<br>
> #include <errno.h><br>
> #include <stdarg.h><br>
> <br>
> +#include "flog.h"<br>
> +<br>
> +/* FIXME: Should be in options? */<br>
> +extern flog_ctx_t flog_ctx;<br>
> +<br>
> extern void vprint_on_level(unsigned int loglevel, const char *format,<br>
> va_list params);<br>
> <br>
> @@ -32,35 +37,53 @@ extern void print_on_level(unsigned int loglevel, const char *format, ...)<br>
> <br>
> void flush_early_log_buffer(int fd);<br>
> <br>
> +#ifdef CR_NOGLIBC<br>
> +#undef flog_encode<br>
> +#define flog_encode(ctx, fmt, ...)<br>
> +#endif<br>
> +<br>
> #define print_once(loglevel, fmt, ...) \<br>
> do { \<br>
> static bool __printed; \<br>
> if (!__printed) { \<br>
> + flog_encode(&flog_ctx, fmt, ##__VA_ARGS__); \<br>
> print_on_level(loglevel, fmt, ##__VA_ARGS__); \<br>
> __printed = 1; \<br>
> } \<br>
> } while (0)<br>
> <br>
> #define pr_msg(fmt, ...) \<br>
> + do { \<br>
> + flog_encode(&flog_ctx, fmt, ##__VA_ARGS__); \<br>
> print_on_level(LOG_MSG, \<br>
> - fmt, ##__VA_ARGS__)<br>
> + fmt, ##__VA_ARGS__); \<br>
> + } while (0)<br>
> <br>
> #define pr_info(fmt, ...) \<br>
> + do { \<br>
> + flog_encode(&flog_ctx, fmt, ##__VA_ARGS__); \<br>
> print_on_level(LOG_INFO, \<br>
> - LOG_PREFIX fmt, ##__VA_ARGS__)<br>
> + LOG_PREFIX fmt, ##__VA_ARGS__); \<br>
> + } while (0)<br>
> <br>
> #define pr_err(fmt, ...) \<br>
> + do { \<br>
> + flog_encode(&flog_ctx, fmt, ##__VA_ARGS__); \<br>
> print_on_level(LOG_ERROR, \<br>
> "Error (%s:%d): " LOG_PREFIX fmt, \<br>
> - __FILE__, __LINE__, ##__VA_ARGS__)<br>
> + __FILE__, __LINE__, ##__VA_ARGS__); \<br>
> + } while (0)<br>
> <br>
> #define pr_err_once(fmt, ...) \<br>
> print_once(LOG_ERROR, fmt, ##__VA_ARGS__)<br>
> <br>
> #define pr_warn(fmt, ...) \<br>
> + do { \<br>
> + flog_encode(&flog_ctx, fmt, ##__VA_ARGS__); \<br>
> print_on_level(LOG_WARN, \<br>
> "Warn (%s:%d): " LOG_PREFIX fmt, \<br>
> - __FILE__, __LINE__, ##__VA_ARGS__)<br>
> + __FILE__, __LINE__, ##__VA_ARGS__); \<br>
> + } while (0)<br>
> <br>
> #define pr_warn_once(fmt, ...) \<br>
> print_once(LOG_WARN, \<br>
> @@ -68,8 +91,11 @@ void flush_early_log_buffer(int fd);<br>
> __FILE__, __LINE__, ##__VA_ARGS__)<br>
> <br>
> #define pr_debug(fmt, ...) \<br>
> + do { \<br>
> + flog_encode(&flog_ctx, fmt, ##__VA_ARGS__); \<br>
> print_on_level(LOG_DEBUG, \<br>
> - LOG_PREFIX fmt, ##__VA_ARGS__)<br>
> + LOG_PREFIX fmt, ##__VA_ARGS__); \<br>
> + } while (0)<br>
> <br>
> #ifndef CR_NOGLIBC<br>
> <br>
> diff --git a/criu/log.c b/criu/log.c<br>
> index 8bdf8353..723fe72d 100644<br>
> --- a/criu/log.c<br>
> +++ b/criu/log.c<br>
> @@ -10,6 +10,7 @@<br>
> #include <sys/time.h><br>
> #include <sys/resource.h><br>
> #include <sys/utsname.h><br>
> +#include <sys/stat.h><br>
> <br>
> #include <fcntl.h><br>
> <br>
> @@ -207,10 +208,11 @@ void flush_early_log_buffer(int fd)<br>
> int log_init(const char *output)<br>
> {<br>
> int new_logfd, fd;<br>
> + int log_file_open_mode, log_file_perm;<br>
> <br>
> gettimeofday(&start, NULL);<br>
> reset_buf_off();<br>
> -<br>
> + memset(&flog_ctx, 0, sizeof(flog_ctx));<br>
> if (output && !strncmp(output, "-", 2)) {<br>
> new_logfd = dup(STDOUT_FILENO);<br>
> if (new_logfd < 0) {<br>
> @@ -218,7 +220,23 @@ int log_init(const char *output)<br>
> return -1;<br>
> }<br>
> } else if (output) {<br>
> - new_logfd = open(output, O_CREAT|O_TRUNC|O_WRONLY|O_APPEND, 0600);<br>
> + if (opts.printlog) {<br>
> + /* read old binlog */<br>
> + log_file_open_mode = O_RDONLY;<br>
> + flog_ctx.readonly=1; /* don't try to write into it */<br>
> + struct stat st; <br>
> + stat(opts.output, &st); <br>
> + flog_ctx.size=st.st_size;<br>
> + }<br>
> + else if (opts.binlog) {<br>
> + log_file_open_mode = O_RDWR | O_CREAT | O_TRUNC;<br>
> + }<br>
> + else {<br>
> + flog_ctx.readonly=1; /* no binlog, don't try to write into it */<br>
> + log_file_open_mode = O_CREAT|O_TRUNC|O_WRONLY|O_APPEND;<br>
> + }<br>
> + log_file_perm = opts.binlog?0644:0600;<br>
> + new_logfd = open(output, log_file_open_mode, log_file_perm);<br>
> if (new_logfd < 0) {<br>
> pr_perror("Can't create log file %s", output);<br>
> return -1;<br>
> @@ -234,15 +252,19 @@ int log_init(const char *output)<br>
> fd = install_service_fd(LOG_FD_OFF, new_logfd);<br>
> if (fd < 0)<br>
> goto err;<br>
> -<br>
> + <br>
> + if (opts.binlog||opts.printlog) {<br>
> + <br>
> + flog_map_buf(fd, &flog_ctx);<br>
> + }<br>
> + <br>
> + <br>
> init_done = 1;<br>
> <br>
> /*<br>
> * Once logging is setup this write out all early log messages.<br>
> * Only those messages which have to correct log level are printed.<br>
> */<br>
> - flush_early_log_buffer(fd);<br>
> -<br>
> print_versions();<br>
> <br>
> return 0;<br>
> @@ -277,7 +299,9 @@ int log_init_by_pid(pid_t pid)<br>
> <br>
> void log_fini(void)<br>
> {<br>
> - close_service_fd(LOG_FD_OFF);<br>
> + flog_fini(&flog_ctx);<br>
> + <br>
> + <br>
> }<br>
> <br>
> static void soccr_print_on_level(unsigned int loglevel, const char *format, ...)<br>
> @@ -392,9 +416,9 @@ void vprint_on_level(unsigned int loglevel, const char *format, va_list params)<br>
> }<br>
> <br>
> void print_on_level(unsigned int loglevel, const char *format, ...)<br>
> -{<br>
> +{ <br>
> va_list params;<br>
> -<br>
> + if (opts.binlog) return;<br>
> va_start(params, format);<br>
> vprint_on_level(loglevel, format, params);<br>
> va_end(params);<br>
> diff --git a/flog/Makefile b/flog/Makefile<br>
> new file mode 100644<br>
> index 00000000..71e398ed<br>
> --- /dev/null<br>
> +++ b/flog/Makefile<br>
> @@ -0,0 +1,8 @@<br>
> +ccflags-y += -iquote flog/include<br>
> +ccflags-y += -iquote include<br>
> +ccflags-y += -fno-strict-aliasing<br>
> +ldflags-y += -r<br>
> +<br>
> +lib-name := libflog.a<br>
> +<br>
> +lib-y += src/flog.o<br>
> diff --git a/flog/include/flog.h b/flog/include/flog.h<br>
> new file mode 100644<br>
> index 00000000..f00c2054<br>
> --- /dev/null<br>
> +++ b/flog/include/flog.h<br>
> @@ -0,0 +1,9 @@<br>
> +#ifndef __FLOG_H__<br>
> +#define __FLOG_H__<br>
> +<br>
> +#include <string.h><br>
> +#include <errno.h><br>
> +<br>
> +#include "uapi/flog.h"<br>
> +<br>
> +#endif /* __FLOG_H__ */<br>
> diff --git a/flog/include/uapi/flog.h b/flog/include/uapi/flog.h<br>
> new file mode 100644<br>
> index 00000000..8ab3566c<br>
> --- /dev/null<br>
> +++ b/flog/include/uapi/flog.h<br>
> @@ -0,0 +1,168 @@<br>
> +#ifndef __UAPI_FLOG_H__<br>
> +#define __UAPI_FLOG_H__<br>
> +<br>
> +#include <stdbool.h><br>
> +#include <string.h><br>
> +#include <errno.h><br>
> +<br>
> +/*<br>
> + * We work with up to 32 arguments in macros here.<br>
> + * If more provided -- behaviour is undefined.<br>
> + */<br>
> +<br>
> +/*<br>
> + * By Laurent Deniau at <a href="https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s" rel="noreferrer noreferrer noreferrer" target="_blank">https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s</a><br>
> + */<br>
> +#define FLOG_PP_NARG_(...) FLOG_PP_ARG_N(__VA_ARGS__)<br>
> +#define FLOG_PP_NARG(...) FLOG_PP_NARG_(1, ##__VA_ARGS__, FLOG_PP_RSEQ_N())<br>
> +<br>
> +#define FLOG_PP_ARG_N( _0, _1, _2, _3, _4, \<br>
> + _5, _6, _7, _8, _9, \<br>
> + _10,_11,_12,_13,_14, \<br>
> + _15,_16,_17,_18,_19, \<br>
> + _20,_21,_22,_23,_24, \<br>
> + _25,_26,_27,_28,_29, \<br>
> + _30,_31, N, ...) N<br>
> +<br>
> +#define FLOG_PP_RSEQ_N() \<br>
> + 31, 30, 29, 28, 27, \<br>
> + 26, 25, 24, 23, 22, \<br>
> + 21, 20, 19, 18, 17, \<br>
> + 16, 15, 14, 13, 12, \<br>
> + 11, 10, 9, 8, 7, \<br>
> + 6, 5, 4, 3, 2, \<br>
> + 1, 0<br>
> +<br>
> +#define FLOG_GENMASK_0(N, x) 0<br>
> +#define FLOG_GENMASK_1(N, op, x, ...) (op(N, 0, x))<br>
> +#define FLOG_GENMASK_2(N, op, x, ...) ((op(N, 1, x)) | FLOG_GENMASK_1(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_3(N, op, x, ...) ((op(N, 2, x)) | FLOG_GENMASK_2(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_4(N, op, x, ...) ((op(N, 3, x)) | FLOG_GENMASK_3(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_5(N, op, x, ...) ((op(N, 4, x)) | FLOG_GENMASK_4(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_6(N, op, x, ...) ((op(N, 5, x)) | FLOG_GENMASK_5(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_7(N, op, x, ...) ((op(N, 6, x)) | FLOG_GENMASK_6(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_8(N, op, x, ...) ((op(N, 7, x)) | FLOG_GENMASK_7(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_9(N, op, x, ...) ((op(N, 8, x)) | FLOG_GENMASK_8(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_10(N, op, x, ...) ((op(N, 9, x)) | FLOG_GENMASK_9(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_11(N, op, x, ...) ((op(N, 10, x)) | FLOG_GENMASK_10(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_12(N, op, x, ...) ((op(N, 11, x)) | FLOG_GENMASK_11(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_13(N, op, x, ...) ((op(N, 12, x)) | FLOG_GENMASK_12(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_14(N, op, x, ...) ((op(N, 13, x)) | FLOG_GENMASK_13(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_15(N, op, x, ...) ((op(N, 14, x)) | FLOG_GENMASK_14(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_16(N, op, x, ...) ((op(N, 15, x)) | FLOG_GENMASK_15(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_17(N, op, x, ...) ((op(N, 16, x)) | FLOG_GENMASK_16(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_18(N, op, x, ...) ((op(N, 17, x)) | FLOG_GENMASK_17(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_19(N, op, x, ...) ((op(N, 18, x)) | FLOG_GENMASK_18(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_20(N, op, x, ...) ((op(N, 19, x)) | FLOG_GENMASK_19(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_21(N, op, x, ...) ((op(N, 20, x)) | FLOG_GENMASK_20(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_22(N, op, x, ...) ((op(N, 21, x)) | FLOG_GENMASK_21(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_23(N, op, x, ...) ((op(N, 22, x)) | FLOG_GENMASK_22(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_24(N, op, x, ...) ((op(N, 23, x)) | FLOG_GENMASK_23(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_25(N, op, x, ...) ((op(N, 24, x)) | FLOG_GENMASK_24(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_26(N, op, x, ...) ((op(N, 25, x)) | FLOG_GENMASK_25(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_27(N, op, x, ...) ((op(N, 26, x)) | FLOG_GENMASK_26(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_28(N, op, x, ...) ((op(N, 27, x)) | FLOG_GENMASK_27(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_29(N, op, x, ...) ((op(N, 28, x)) | FLOG_GENMASK_28(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_30(N, op, x, ...) ((op(N, 29, x)) | FLOG_GENMASK_29(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_31(N, op, x, ...) ((op(N, 30, x)) | FLOG_GENMASK_30(N, op, __VA_ARGS__))<br>
> +#define FLOG_GENMASK_32(N, op, x, ...) ((op(N, 31, x)) | FLOG_GENMASK_31(N, op, __VA_ARGS__))<br>
> +<br>
> +#define FLOG_CONCAT(arg1, arg2) FLOG_CONCAT1(arg1, arg2)<br>
> +#define FLOG_CONCAT1(arg1, arg2) FLOG_CONCAT2(arg1, arg2)<br>
> +#define FLOG_CONCAT2(arg1, arg2) arg1##arg2<br>
> +<br>
> +#define FLOG_GENMASK_(N, op, ...) FLOG_CONCAT(FLOG_GENMASK_, N)(N, op, ##__VA_ARGS__)<br>
> +#define FLOG_GENMASK(op, ...) FLOG_GENMASK_(FLOG_PP_NARG(__VA_ARGS__), op, ##__VA_ARGS__)<br>
> +<br>
> +#define flog_genbit(ord, n, v, ...) \<br>
> + _Generic((v), \<br>
> + \<br>
> + /* Basic types */ \<br>
> + char: 0, \<br>
> + signed char: 0, \<br>
> + unsigned char: 0, \<br>
> + signed short int: 0, \<br>
> + unsigned short int: 0, \<br>
> + signed int: 0, \<br>
> + unsigned int: 0, \<br>
> + signed long: 0, \<br>
> + unsigned long: 0, \<br>
> + signed long long: 0, \<br>
> + unsigned long long: 0, \<br>
> + \<br>
> + /* Not used for a while */ \<br>
> + /* float: 12, */ \<br>
> + /* double: 13, */ \<br>
> + /* long double: 14, */ \<br>
> + \<br>
> + /* Basic poniters */ \<br>
> + char *: (1u << (ord - n - 1)), \<br>
> + signed char *: (1u << (ord - n - 1)), \<br>
> + unsigned char *: (1u << (ord - n - 1)), \<br>
> + signed short int *: 0, \<br>
> + unsigned short int *: 0, \<br>
> + signed int *: 0, \<br>
> + unsigned int *: 0, \<br>
> + signed long *: 0, \<br>
> + unsigned long *: 0, \<br>
> + signed long long *: 0, \<br>
> + unsigned long long *: 0, \<br>
> + void *: 0, \<br>
> + \<br>
> + /* Const basic pointers */ \<br>
> + const char *: (1u << (ord - n - 1)), \<br>
> + const signed char *: (1u << (ord - n - 1)), \<br>
> + const unsigned char *: (1u << (ord - n - 1)), \<br>
> + const signed short int *: 0, \<br>
> + const unsigned short int *: 0, \<br>
> + const signed int *: 0, \<br>
> + const unsigned int *: 0, \<br>
> + const signed long *: 0, \<br>
> + const unsigned long *: 0, \<br>
> + const signed long long *: 0, \<br>
> + const unsigned long long *: 0, \<br>
> + const void *: 0, \<br>
> + \<br>
> + /* Systypes and pointers */ \<br>
> + default: -1)<br>
> +<br>
> +#define FLOG_MAGIC 0x676f6c66<br>
> +#define FLOG_VERSION 1<br>
> +<br>
> +typedef struct {<br>
> + unsigned int magic;<br>
> + unsigned int version;<br>
> + unsigned int size;<br>
> + unsigned int nargs;<br>
> + unsigned int mask;<br>
> + long fmt;<br>
> + long args[0];<br>
> +} flog_msg_t;<br>
> +<br>
> +typedef struct {<br>
> + char *buf;<br>
> + char *pos;<br>
> + size_t size;<br>
> + size_t left;<br>
> + int readonly;<br>
> +} flog_ctx_t;<br>
> +<br>
> +extern int flog_init(flog_ctx_t *ctx);<br>
> +extern void flog_fini(flog_ctx_t *ctx);<br>
> +<br>
> +extern void flog_decode_all(flog_ctx_t *ctx, int fdout);<br>
> +<br>
> +extern int flog_encode_msg(flog_ctx_t *ctx,<br>
> + unsigned int nargs, unsigned int mask,<br>
> + const char *format, ...);<br>
> +extern int flog_decode_msg(flog_msg_t *m, int fdout);<br>
> +<br>
> +extern int flog_map_buf(int fdout, flog_ctx_t *flog_ctx);<br>
> +<br>
> +#define flog_encode(ctx, fmt, ...) \<br>
> + flog_encode_msg(ctx, \<br>
> + FLOG_PP_NARG(__VA_ARGS__), \<br>
> + FLOG_GENMASK(flog_genbit, ##__VA_ARGS__), \<br>
> + fmt, ##__VA_ARGS__)<br>
> +<br>
> +#endif /* __UAPI_FLOG_H__ */<br>
> diff --git a/flog/src/flog.c b/flog/src/flog.c<br>
> new file mode 100644<br>
> index 00000000..9a538795<br>
> --- /dev/null<br>
> +++ b/flog/src/flog.c<br>
> @@ -0,0 +1,227 @@<br>
> +#include <stdio.h><br>
> +#include <stdlib.h><br>
> +#include <stdarg.h><br>
> +#include <unistd.h><br>
> +#include <stdint.h><br>
> +<br>
> +#include <sys/param.h><br>
> +#include <sys/mman.h><br>
> +<br>
> +#include <ffi.h><br>
> +<br>
> +#include "common/compiler.h"<br>
> +<br>
> +#include "flog.h"<br>
> +<br>
> +#define BUF_SIZE (1<<20)<br>
> +<br>
> +static char _mbuf[BUF_SIZE];<br>
> +static char *mbuf = _mbuf;<br>
> +static char *fbuf;<br>
> +static uint64_t fsize;<br>
> +static uint64_t mbuf_size = sizeof(_mbuf);<br>
> +static int binlog_fd;<br>
> +<br>
> +int flog_map_buf(int fdout, flog_ctx_t *flog_ctx)<br>
> +{<br>
> + uint64_t off = 0;<br>
> + void *addr;<br>
> + <br>
> + mbuf_size = 2 * BUF_SIZE;<br>
> + <br>
> + if (flog_ctx->size==0) flog_ctx->size=BUF_SIZE;<br>
> +<br>
> + /*<br>
> + * Two buffers are mmaped into memory. A new one is mapped when a first<br>
> + * one is completly filled.<br>
> + */<br>
> + if (fbuf && (mbuf - fbuf < BUF_SIZE))<br>
> + return 0;<br>
> +<br>
> + if (fbuf) {<br>
> + if (munmap(fbuf, BUF_SIZE * 2)) {<br>
> + fprintf(stderr, "Unable to unmap a buffer: %m");<br>
> + return 1;<br>
> + }<br>
> + off = mbuf - fbuf - BUF_SIZE;<br>
> + fbuf = NULL;<br>
> + }<br>
> +<br>
> + if (fsize == 0)<br>
> + fsize += BUF_SIZE;<br>
> + fsize += BUF_SIZE;<br>
> +<br>
> + if (!flog_ctx->readonly) {<br>
> + if (ftruncate(fdout, fsize)) {<br>
> + fprintf(stderr, "Unable to truncate a file: %m");<br>
> + return -1;<br>
> + }<br>
> + } <br>
> + if (!fbuf) {<br>
> + if (!flog_ctx->readonly) { <br>
> + addr = mmap(NULL, BUF_SIZE * 2, PROT_WRITE | PROT_READ,<br>
> + MAP_FILE | MAP_SHARED, fdout, fsize - 2 * BUF_SIZE);<br>
> + }<br>
> + else { <br>
> + addr = mmap(NULL, flog_ctx->size, PROT_READ,<br>
> + MAP_FILE | MAP_SHARED, fdout, 0);<br>
> + mbuf_size = flog_ctx->size;<br>
> + }<br>
> + }<br>
> + else {<br>
> + addr = mremap(fbuf + BUF_SIZE, BUF_SIZE,<br>
> + BUF_SIZE * 2, MREMAP_FIXED, fbuf);<br>
> + }<br>
> + if (addr == MAP_FAILED) {<br>
> + fprintf(stderr, "Unable to map a buffer: %m");<br>
> + return -1;<br>
> + }<br>
> + <br>
> + fbuf = addr;<br>
> + mbuf = fbuf + off;<br>
> +<br>
> + binlog_fd=fdout;<br>
> + flog_init(flog_ctx);<br>
> + return 0;<br>
> +}<br>
> +<br>
> +int flog_init(flog_ctx_t *ctx)<br>
> +{<br>
> + ctx->size = ctx->left = mbuf_size; <br>
> + ctx->pos = ctx->buf = mbuf;<br>
> + if (!ctx->buf)<br>
> + return -ENOMEM;<br>
> + <br>
> + return 0;<br>
> +}<br>
> +<br>
> +void flog_fini(flog_ctx_t *ctx)<br>
> +{<br>
> + if (mbuf == _mbuf)<br>
> + return;<br>
> + munmap(ctx->buf, BUF_SIZE * 2);<br>
> + ctx->size=(size_t) (ctx->pos - ctx->buf);<br>
> + if (!ctx->readonly) {<br>
> + if (ftruncate(binlog_fd, ctx->size)) {<br>
> + fprintf(stderr, "Unable to truncate a file: %m");<br>
> + }<br>
> + }<br>
> + <br>
> +}<br>
> +<br>
> +int flog_decode_msg(flog_msg_t *ro_m, int fdout)<br>
> +{<br>
> + ffi_type *args[34] = {<br>
> + [0] = &ffi_type_sint,<br>
> + [1] = &ffi_type_pointer,<br>
> + [2 ... 33] = &ffi_type_slong<br>
> + };<br>
> + void *values[34];<br>
> + ffi_cif cif;<br>
> + ffi_arg rc;<br>
> + flog_msg_t *m;<br>
> + size_t i, ret = 0;<br>
> + char *fmt;<br>
> +<br>
> + m=malloc(ro_m->size);<br>
> + memcpy(m, ro_m, ro_m->size);<br>
> + values[0] = (void *)&fdout;<br>
> + if (m->magic != FLOG_MAGIC) {<br>
> + return -EINVAL;<br>
> + }<br>
> + if (m->version != FLOG_VERSION) {<br>
> + return -EINVAL;<br>
> + }<br>
> +<br>
> + fmt = (void *)m + m->fmt;<br>
> + values[1] = &fmt;<br>
> + <br>
> + for (i = 0; i < m->nargs; i++) { <br>
> + values[i + 2] = (void *)&m->args[i];<br>
> + if (m->mask & (1u << i)) {<br>
> + m->args[i] = (long)((void *)m + m->args[i]);<br>
> + } <br>
> + <br>
> + }<br>
> + <br>
> + int sdf=ffi_prep_cif(&cif, FFI_DEFAULT_ABI, m->nargs + 2,<br>
> + &ffi_type_sint, args);<br>
> + if ( sdf == FFI_OK) {<br>
> + ffi_call(&cif, FFI_FN(dprintf), &rc, values);<br>
> + } else<br>
> + ret = -1;<br>
> + <br>
> + free(m);<br>
> + return ret;<br>
> +}<br>
> +<br>
> +void flog_decode_all(flog_ctx_t *ctx, int fdout)<br>
> +{<br>
> + flog_msg_t *m;<br>
> + char *pos;<br>
> + printf("log size is %ld\n", ctx->size);<br>
> + if (ctx->size == 0)<br>
> + return;<br>
> + if (ctx->readonly) ctx->pos=ctx->buf + ctx->size;<br>
> + for (pos = ctx->buf; pos < ctx->pos; ) {<br>
> + m = (void *)pos;<br>
> + flog_decode_msg(m ,fdout);<br>
> + pos += m->size;<br>
> + }<br>
> +}<br>
> +<br>
> +int flog_encode_msg(flog_ctx_t *ctx, unsigned int nargs, unsigned int mask, const char *format, ...)<br>
> +{ <br>
> + if (ctx->readonly) { <br>
> + return 0;<br>
> + }<br>
> + flog_msg_t *m = (void *)ctx->pos;<br>
> + char *str_start, *p;<br>
> + va_list argptr;<br>
> + size_t i;<br>
> +<br>
> + m->nargs = nargs;<br>
> + m->mask = mask;<br>
> +<br>
> + str_start = (void *)m->args + sizeof(m->args[0]) * nargs;<br>
> + p = memccpy(str_start, format, 0, ctx->left - (str_start - ctx->pos));<br>
> + if (!p)<br>
> + return -ENOMEM;<br>
> +<br>
> + m->fmt = str_start - ctx->pos;<br>
> + str_start = p;<br>
> + va_start(argptr, format);<br>
> + for (i = 0; i < nargs; i++) {<br>
> + m->args[i] = (long)va_arg(argptr, long);<br>
> + /*<br>
> + * If we got a string, we should either<br>
> + * reference it when in rodata, or make<br>
> + * a copy (FIXME implement rodata refs).<br>
> + */<br>
> + if (mask & (1u << i)) {<br>
> + p = memccpy(str_start, (void *)m->args[i], 0, ctx->left - (str_start - ctx->pos));<br>
> + if (!p)<br>
> + return -ENOMEM;<br>
> + m->args[i] = str_start - ctx->pos;<br>
> + str_start = p;<br>
> + }<br>
> + }<br>
> + va_end(argptr);<br>
> + m->size = str_start - ctx->pos;<br>
> +<br>
> + /*<br>
> + * A magic is required to know where we stop writing into a log file,<br>
> + * if it was not properly closed. The file is mapped into memory, so a<br>
> + * space in the file is allocated in advance and at the end it can have<br>
> + * some unused tail.<br>
> + */<br>
> + m->magic = FLOG_MAGIC;<br>
> + m->version = FLOG_VERSION;<br>
> +<br>
> + m->size = round_up(m->size, 8);<br>
> +<br>
> + /* Advance position and left bytes in context memory */<br>
> + ctx->left -= m->size;<br>
> + ctx->pos += m->size;<br>
> + return 0;<br>
> +}<br>
> -- <br>
> 2.22.0<br>
> <br>
<br>
> _______________________________________________<br>
> CRIU mailing list<br>
> <a href="mailto:CRIU@openvz.org" rel="noreferrer noreferrer" target="_blank">CRIU@openvz.org</a><br>
> <a href="https://lists.openvz.org/mailman/listinfo/criu" rel="noreferrer noreferrer noreferrer" target="_blank">https://lists.openvz.org/mailman/listinfo/criu</a><br>
<br>
</blockquote></div>
</blockquote></div></div></div>